// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdint.h>
#include <string.h>
#include <string>
#include <utility>
#include <vector>
#include "base/functional/bind.h"
#include "base/test/task_environment.h"
#include "build/chromeos_buildflags.h"
#include "chrome/services/pdf/pdf_thumbnailer.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/codec/SkCodec.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkImageInfo.h"
namespace pdf {
namespace {
constexpr int kThumbWidth = 256;
constexpr int kThumbHeight = 192;
constexpr int kHorizontalDpi = 300;
constexpr int kVerticalDpi = 300;
constexpr bool kStretch = true;
constexpr bool kKeepRatio = true;
const char kPdfContent[] = R"(%PDF-1.2
9 0 obj
<<
>>
stream
BT/ 9 Tf(Test)' ET
endstream
endobj
4 0 obj
<<
/Type /Page
/Parent 5 0 R
/Contents 9 0 R
>>
endobj
5 0 obj
<<
/Kids [4 0 R ]
/Count 1
/Type /Pages
/MediaBox [ 0 0 99 9 ]
>>
endobj
3 0 obj
<<
/Pages 5 0 R
/Type /Catalog
>>
endobj
trailer
<<
/Root 3 0 R
>>
%%EOF)";
} // namespace
class PdfThumbnailerTest : public testing::Test {
public:
void SetUp() override {
params_ = mojom::ThumbParams::New(gfx::Size(kThumbWidth, kThumbHeight),
gfx::Size(kHorizontalDpi, kVerticalDpi),
kStretch, kKeepRatio);
}
// Copies bytes from |bitmap| into |bitmap_|. This method is here due
// to the fact that GetThumbnail() needs to be run in a single-threaded
// context. More info at docs/threading_and_tasks_testing.md
void StoreResult(base::OnceClosure callback, const SkBitmap& bitmap) {
bitmap_ = std::move(bitmap);
std::move(callback).Run();
}
// Helper method that converts a PDF string to a shared memory region.
base::ReadOnlySharedMemoryRegion CreatePdfRegion(const std::string& content) {
auto pdf_region = base::ReadOnlySharedMemoryRegion::Create(content.size());
EXPECT_TRUE(pdf_region.IsValid());
memcpy(pdf_region.mapping.memory(), content.data(), content.size());
return std::move(pdf_region.region);
}
base::test::SingleThreadTaskEnvironment task_environment_;
PdfThumbnailer thumbnailer_;
mojom::ThumbParamsPtr params_;
SkBitmap bitmap_;
base::WeakPtrFactory<PdfThumbnailerTest> weak_factory_{this};
};
#if BUILDFLAG(IS_CHROMEOS_ASH)
// A valid PDF should produce a valid PNG thumbnail.
TEST_F(PdfThumbnailerTest, CreatePdfThumbnail) {
base::RunLoop run_loop;
auto pdf_region = CreatePdfRegion(kPdfContent);
thumbnailer_.GetThumbnail(
std::move(params_), std::move(pdf_region),
base::BindOnce(&PdfThumbnailerTest::StoreResult,
weak_factory_.GetWeakPtr(), run_loop.QuitClosure()));
run_loop.Run();
EXPECT_FALSE(bitmap_.isNull());
EXPECT_EQ(kThumbWidth, bitmap_.width());
EXPECT_EQ(kThumbHeight, bitmap_.height());
}
// A low DPI, non-stretched thumbnail.
TEST_F(PdfThumbnailerTest, CreateLowResUnstretchedPdfThumbnail) {
base::RunLoop run_loop;
auto pdf_region = CreatePdfRegion(kPdfContent);
auto params = mojom::ThumbParams::New(gfx::Size(kThumbWidth, kThumbHeight),
gfx::Size(15, 15), false, kKeepRatio);
thumbnailer_.GetThumbnail(
std::move(params), std::move(pdf_region),
base::BindOnce(&PdfThumbnailerTest::StoreResult,
weak_factory_.GetWeakPtr(), run_loop.QuitClosure()));
run_loop.Run();
EXPECT_FALSE(bitmap_.isNull());
// The bitmap size is still the requested size, even though the thumbnail
// itself does not fill the entire bitmap.
EXPECT_EQ(kThumbWidth, bitmap_.width());
EXPECT_EQ(kThumbHeight, bitmap_.height());
}
// An invalid PDF should cause failure (null bitmap returned).
TEST_F(PdfThumbnailerTest, CreatePdfThumbnailFailure) {
base::RunLoop run_loop;
auto pdf_region = CreatePdfRegion("%PDF-1.2 not a valid PDF document");
thumbnailer_.GetThumbnail(
std::move(params_), std::move(pdf_region),
base::BindOnce(&PdfThumbnailerTest::StoreResult,
weak_factory_.GetWeakPtr(), run_loop.QuitClosure()));
run_loop.Run();
EXPECT_TRUE(bitmap_.isNull());
}
// An invalid (zero) thumbnail size should cause failure (null bitmap returned).
TEST_F(PdfThumbnailerTest, InvalidThumbnailSize) {
base::RunLoop run_loop;
auto pdf_region = CreatePdfRegion(kPdfContent);
auto params = mojom::ThumbParams::New(gfx::Size(0, 0),
gfx::Size(kHorizontalDpi, kVerticalDpi),
kStretch, kKeepRatio);
thumbnailer_.GetThumbnail(
std::move(params), std::move(pdf_region),
base::BindOnce(&PdfThumbnailerTest::StoreResult,
weak_factory_.GetWeakPtr(), run_loop.QuitClosure()));
run_loop.Run();
EXPECT_TRUE(bitmap_.isNull());
}
// A thumbnail size that is larger than maximum should cause failure (null
// bitmap returned).
TEST_F(PdfThumbnailerTest, TooLargeThumbnailSize) {
base::RunLoop run_loop;
auto pdf_region = CreatePdfRegion(kPdfContent);
auto params = mojom::ThumbParams::New(
gfx::Size(pdf::mojom::PdfThumbnailer::kMaxWidthPixels + 1,
pdf::mojom::PdfThumbnailer::kMaxHeightPixels + 1),
gfx::Size(kHorizontalDpi, kVerticalDpi), kStretch, kKeepRatio);
thumbnailer_.GetThumbnail(
std::move(params), std::move(pdf_region),
base::BindOnce(&PdfThumbnailerTest::StoreResult,
weak_factory_.GetWeakPtr(), run_loop.QuitClosure()));
run_loop.Run();
EXPECT_TRUE(bitmap_.isNull());
}
TEST_F(PdfThumbnailerTest, CreatePdfThumbnailWithSkiaPolicyEnabled) {
base::RunLoop run_loop;
auto pdf_region = CreatePdfRegion(kPdfContent);
thumbnailer_.SetUseSkiaRendererPolicy(/*use_skia=*/true);
thumbnailer_.GetThumbnail(
std::move(params_), std::move(pdf_region),
base::BindOnce(&PdfThumbnailerTest::StoreResult,
weak_factory_.GetWeakPtr(), run_loop.QuitClosure()));
run_loop.Run();
EXPECT_FALSE(bitmap_.isNull());
EXPECT_EQ(kThumbWidth, bitmap_.width());
EXPECT_EQ(kThumbHeight, bitmap_.height());
}
TEST_F(PdfThumbnailerTest, CreatePdfThumbnailWithSkiaPolicyDisabled) {
base::RunLoop run_loop;
auto pdf_region = CreatePdfRegion(kPdfContent);
thumbnailer_.SetUseSkiaRendererPolicy(/*use_skia=*/false);
thumbnailer_.GetThumbnail(
std::move(params_), std::move(pdf_region),
base::BindOnce(&PdfThumbnailerTest::StoreResult,
weak_factory_.GetWeakPtr(), run_loop.QuitClosure()));
run_loop.Run();
EXPECT_FALSE(bitmap_.isNull());
EXPECT_EQ(kThumbWidth, bitmap_.width());
EXPECT_EQ(kThumbHeight, bitmap_.height());
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
} // namespace pdf