#include "pdf/pdfium/pdfium_print.h"
#include <array>
#include <memory>
#include <optional>
#include <string_view>
#include "base/containers/span.h"
#include "base/files/file_path.h"
#include "base/strings/stringprintf.h"
#include "pdf/pdfium/pdfium_engine.h"
#include "pdf/pdfium/pdfium_engine_exports.h"
#include "pdf/pdfium/pdfium_test_base.h"
#include "pdf/test/test_client.h"
#include "pdf/test/test_helpers.h"
#include "printing/pdf_render_settings.h"
#include "printing/units.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "third_party/blink/public/web/web_print_params.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/geometry/skia_conversions.h"
namespace chrome_pdf {
using PDFiumPrintTest = PDFiumTestBase;
using ::testing::ElementsAre;
namespace {
using ExpectedDimensions = std::vector<gfx::SizeF>;
std::string GenerateRendererSpecificFileName(const std::string& file_name,
bool use_skia_renderer) {
return base::StringPrintf("%s%s.png", file_name.c_str(),
use_skia_renderer ? "_skia" : "");
}
base::FilePath GetReferenceFilePath(std::string_view test_filename) {
return base::FilePath(FILE_PATH_LITERAL("pdfium_print"))
.AppendASCII(test_filename);
}
void CheckPdfDimensions(base::span<const uint8_t> pdf_data,
const ExpectedDimensions& expected_dimensions) {
PDFiumEngineExports exports;
int page_count;
ASSERT_TRUE(exports.GetPDFDocInfo(pdf_data, &page_count, nullptr));
ASSERT_GT(page_count, 0);
ASSERT_EQ(expected_dimensions.size(), static_cast<size_t>(page_count));
for (int i = 0; i < page_count; ++i) {
std::optional<gfx::SizeF> page_size =
exports.GetPDFPageSizeByIndex(pdf_data, i);
ASSERT_TRUE(page_size.has_value());
EXPECT_EQ(expected_dimensions[i], page_size.value());
}
}
void CheckPdfRendering(base::span<const uint8_t> pdf_data,
int page_number,
const gfx::SizeF& size_in_points,
std::string_view expected_png_filename) {
int width_in_pixels =
printing::ConvertUnit(size_in_points.width(), printing::kPointsPerInch,
printing::kDefaultPdfDpi);
int height_in_pixels =
printing::ConvertUnit(size_in_points.height(), printing::kPointsPerInch,
printing::kDefaultPdfDpi);
const gfx::Rect page_rect(width_in_pixels, height_in_pixels);
SkBitmap page_bitmap;
page_bitmap.allocPixels(
SkImageInfo::Make(gfx::SizeToSkISize(page_rect.size()),
kBGRA_8888_SkColorType, kPremul_SkAlphaType));
PDFiumEngineExports::RenderingSettings settings(
gfx::Size(printing::kDefaultPdfDpi, printing::kDefaultPdfDpi), page_rect,
true,
false,
true,
true,
false, true, true);
PDFiumEngineExports exports;
ASSERT_TRUE(exports.RenderPDFPageToBitmap(pdf_data, page_number, settings,
page_bitmap.getPixels()));
EXPECT_TRUE(MatchesPngFile(*page_bitmap.asImage(),
GetReferenceFilePath(expected_png_filename)));
}
}
TEST_P(PDFiumPrintTest, Basic) {
TestClient client;
std::unique_ptr<PDFiumEngine> engine =
InitializeEngine(&client, FILE_PATH_LITERAL("hello_world2.pdf"));
ASSERT_TRUE(engine);
PDFiumPrint print(engine.get());
blink::WebPrintParams print_params = GetDefaultPrintParams();
blink::WebPrintParams print_params_raster = print_params;
print_params_raster.rasterize_pdf = true;
{
const ExpectedDimensions kExpectedDimensions = {{612.0, 792.0},
{612.0, 792.0}};
static constexpr std::array<int, 2> kPageIndices = {0, 1};
std::vector<uint8_t> pdf_data =
print.PrintPagesAsPdf(kPageIndices, print_params);
CheckPdfDimensions(pdf_data, kExpectedDimensions);
pdf_data = print.PrintPagesAsPdf(kPageIndices, print_params_raster);
CheckPdfDimensions(pdf_data, kExpectedDimensions);
}
{
const ExpectedDimensions kExpectedDimensions = {{612.0, 792.0}};
static constexpr std::array<int, 1> kPageIndices = {0};
std::vector<uint8_t> pdf_data =
print.PrintPagesAsPdf(kPageIndices, print_params);
CheckPdfDimensions(pdf_data, kExpectedDimensions);
pdf_data = print.PrintPagesAsPdf(kPageIndices, print_params_raster);
CheckPdfDimensions(pdf_data, kExpectedDimensions);
}
{
const ExpectedDimensions kExpectedDimensions = {{612.0, 792.0}};
static constexpr std::array<int, 1> kPageIndices = {1};
std::vector<uint8_t> pdf_data =
print.PrintPagesAsPdf(kPageIndices, print_params);
CheckPdfDimensions(pdf_data, kExpectedDimensions);
pdf_data = print.PrintPagesAsPdf(kPageIndices, print_params_raster);
CheckPdfDimensions(pdf_data, kExpectedDimensions);
}
}
TEST_P(PDFiumPrintTest, AlterScalingDefault) {
TestClient client;
std::unique_ptr<PDFiumEngine> engine =
InitializeEngine(&client, FILE_PATH_LITERAL("rectangles.pdf"));
ASSERT_TRUE(engine);
PDFiumPrint print(engine.get());
const ExpectedDimensions kExpectedDimensions = {{612.0, 792.0}};
static constexpr std::array<int, 1> kPageIndices = {0};
blink::WebPrintParams print_params = GetDefaultPrintParams();
print_params.printable_area_in_css_pixels = kPrintableAreaRect;
std::vector<uint8_t> pdf_data =
print.PrintPagesAsPdf(kPageIndices, print_params);
CheckPdfDimensions(pdf_data, kExpectedDimensions);
CheckPdfRendering(
pdf_data, 0, kExpectedDimensions[0],
GenerateRendererSpecificFileName("alter_scaling_default",
GetParam()));
print_params.rasterize_pdf = true;
pdf_data = print.PrintPagesAsPdf(kPageIndices, print_params);
CheckPdfDimensions(pdf_data, kExpectedDimensions);
CheckPdfRendering(
pdf_data, 0, kExpectedDimensions[0],
GenerateRendererSpecificFileName("alter_scaling_default_raster",
GetParam()));
}
TEST_P(PDFiumPrintTest, AlterScalingFitPaper) {
TestClient client;
std::unique_ptr<PDFiumEngine> engine =
InitializeEngine(&client, FILE_PATH_LITERAL("rectangles.pdf"));
ASSERT_TRUE(engine);
PDFiumPrint print(engine.get());
const ExpectedDimensions kExpectedDimensions = {{612.0, 792.0}};
static constexpr std::array<int, 1> kPageIndices = {0};
blink::WebPrintParams print_params = GetDefaultPrintParams();
print_params.printable_area_in_css_pixels = kPrintableAreaRect;
print_params.print_scaling_option =
printing::mojom::PrintScalingOption::kFitToPaper;
std::vector<uint8_t> pdf_data =
print.PrintPagesAsPdf(kPageIndices, print_params);
CheckPdfDimensions(pdf_data, kExpectedDimensions);
CheckPdfRendering(
pdf_data, 0, kExpectedDimensions[0],
GenerateRendererSpecificFileName("alter_scaling_fit-paper",
GetParam()));
print_params.rasterize_pdf = true;
pdf_data = print.PrintPagesAsPdf(kPageIndices, print_params);
CheckPdfDimensions(pdf_data, kExpectedDimensions);
CheckPdfRendering(
pdf_data, 0, kExpectedDimensions[0],
GenerateRendererSpecificFileName("alter_scaling_fit-paper_raster",
GetParam()));
}
TEST_P(PDFiumPrintTest, AlterScalingFitPrintable) {
TestClient client;
std::unique_ptr<PDFiumEngine> engine =
InitializeEngine(&client, FILE_PATH_LITERAL("rectangles.pdf"));
ASSERT_TRUE(engine);
PDFiumPrint print(engine.get());
const ExpectedDimensions kExpectedDimensions = {{612.0, 792.0}};
static constexpr std::array<int, 1> kPageIndices = {0};
blink::WebPrintParams print_params = GetDefaultPrintParams();
print_params.printable_area_in_css_pixels = kPrintableAreaRect;
print_params.print_scaling_option =
printing::mojom::PrintScalingOption::kFitToPrintableArea;
std::vector<uint8_t> pdf_data =
print.PrintPagesAsPdf(kPageIndices, print_params);
CheckPdfDimensions(pdf_data, kExpectedDimensions);
CheckPdfRendering(
pdf_data, 0, kExpectedDimensions[0],
GenerateRendererSpecificFileName("alter_scaling_fit-printable",
GetParam()));
print_params.rasterize_pdf = true;
pdf_data = print.PrintPagesAsPdf(kPageIndices, print_params);
CheckPdfDimensions(pdf_data, kExpectedDimensions);
CheckPdfRendering(
pdf_data, 0, kExpectedDimensions[0],
GenerateRendererSpecificFileName("alter_scaling_fit-printable_raster",
GetParam()));
}
TEST_P(PDFiumPrintTest, CenterPositionCenterShrinkToFitPaper) {
TestClient client;
std::unique_ptr<PDFiumEngine> engine =
InitializeEngine(&client, FILE_PATH_LITERAL("rectangles.pdf"));
ASSERT_TRUE(engine);
PDFiumPrint print(engine.get());
const ExpectedDimensions kExpectedDimensions = {{612.0, 792.0}};
static constexpr std::array<int, 1> kPageIndices = {0};
blink::WebPrintParams print_params = GetDefaultPrintParams();
print_params.printable_area_in_css_pixels = kPrintableAreaRect;
print_params.print_scaling_option =
printing::mojom::PrintScalingOption::kCenterShrinkToFitPaper;
std::vector<uint8_t> pdf_data =
print.PrintPagesAsPdf(kPageIndices, print_params);
CheckPdfDimensions(pdf_data, kExpectedDimensions);
CheckPdfRendering(
pdf_data, 0, kExpectedDimensions[0],
GenerateRendererSpecificFileName(
"center_position_center-shrink-to-fit-paper", GetParam()));
print_params.rasterize_pdf = true;
pdf_data = print.PrintPagesAsPdf(kPageIndices, print_params);
CheckPdfDimensions(pdf_data, kExpectedDimensions);
CheckPdfRendering(
pdf_data, 0, kExpectedDimensions[0],
GenerateRendererSpecificFileName(
"center_position_center-shrink-to-fit-paper_raster", GetParam()));
}
TEST_P(PDFiumPrintTest, CenterPositionRotatedCenterShrinkToFitPaper) {
TestClient client;
std::unique_ptr<PDFiumEngine> engine = InitializeEngine(
&client,
FILE_PATH_LITERAL("rotated_rectangles_smaller_than_size_letter.pdf"));
ASSERT_TRUE(engine);
PDFiumPrint print(engine.get());
const ExpectedDimensions kExpectedDimensions = {{792.0, 612.0}};
static constexpr std::array<int, 1> kPageIndices = {0};
blink::WebPrintParams print_params = GetDefaultPrintParams();
print_params.printable_area_in_css_pixels = kPrintableAreaRect;
print_params.print_scaling_option =
printing::mojom::PrintScalingOption::kCenterShrinkToFitPaper;
std::vector<uint8_t> pdf_data =
print.PrintPagesAsPdf(kPageIndices, print_params);
CheckPdfDimensions(pdf_data, kExpectedDimensions);
CheckPdfRendering(
pdf_data, 0, kExpectedDimensions[0],
GenerateRendererSpecificFileName(
"center_position_rotated_center-shrink-to-fit-paper", GetParam()));
print_params.rasterize_pdf = true;
pdf_data = print.PrintPagesAsPdf(kPageIndices, print_params);
CheckPdfDimensions(pdf_data, kExpectedDimensions);
CheckPdfRendering(
pdf_data, 0, kExpectedDimensions[0],
GenerateRendererSpecificFileName(
"center_position_rotated_center-shrink-to-fit-paper_raster",
GetParam()));
}
TEST_P(PDFiumPrintTest, AlterScalingCenterShrinkToFitPaper) {
TestClient client;
std::unique_ptr<PDFiumEngine> engine =
InitializeEngine(&client, FILE_PATH_LITERAL("A4_rects.pdf"));
ASSERT_TRUE(engine);
PDFiumPrint print(engine.get());
const ExpectedDimensions kExpectedDimensions = {{612.0, 792.0}};
static constexpr std::array<int, 1> kPageIndices = {0};
blink::WebPrintParams print_params = GetDefaultPrintParams();
print_params.printable_area_in_css_pixels = kPrintableAreaRect;
print_params.print_scaling_option =
printing::mojom::PrintScalingOption::kCenterShrinkToFitPaper;
std::vector<uint8_t> pdf_data =
print.PrintPagesAsPdf(kPageIndices, print_params);
CheckPdfDimensions(pdf_data, kExpectedDimensions);
CheckPdfRendering(
pdf_data, 0, kExpectedDimensions[0],
GenerateRendererSpecificFileName(
"alter_scaling_center-shrink-to-fit-paper", GetParam()));
print_params.rasterize_pdf = true;
pdf_data = print.PrintPagesAsPdf(kPageIndices, print_params);
CheckPdfDimensions(pdf_data, kExpectedDimensions);
CheckPdfRendering(
pdf_data, 0, kExpectedDimensions[0],
GenerateRendererSpecificFileName(
"alter_scaling_center-shrink-to-fit-paper_raster", GetParam()));
}
INSTANTIATE_TEST_SUITE_P(All, PDFiumPrintTest, testing::Bool());
}