[go: nahoru, domu]

Correct calculation of page area clipping when printing.

We'd end up clipping 1px or so at the page area edges, because we were
rounding the size towards the page center. Use ToEnclosingRect()
instead.

MockPrinter needed some updates, so that it's possible to print twice
from the same test. Also make it possible to toggle headers/footers.

Bug: 1459250
Change-Id: Idd862ea19579a8b5b21c81e18a9bbd2c1af0b345
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4767545
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Morten Stenshorne <mstensho@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1183567}
diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc
index cd4cb98f1..df4cbd7 100644
--- a/components/printing/renderer/print_render_frame_helper.cc
+++ b/components/printing/renderer/print_render_frame_helper.cc
@@ -324,7 +324,7 @@
   float page_height = page_layout.content_height + page_layout.margin_top +
                       page_layout.margin_bottom;
   *page_size = gfx::ToRoundedSize(gfx::SizeF(page_width, page_height));
-  *content_area = gfx::ToEnclosedRect(
+  *content_area = gfx::ToEnclosingRect(
       gfx::RectF(page_layout.margin_left, page_layout.margin_top,
                  page_layout.content_width, page_layout.content_height));
   *canvas_area =
diff --git a/components/printing/test/mock_printer.cc b/components/printing/test/mock_printer.cc
index d5e84be..c875be8 100644
--- a/components/printing/test/mock_printer.cc
+++ b/components/printing/test/mock_printer.cc
@@ -56,9 +56,10 @@
 MockPrinter::~MockPrinter() {
 }
 
-void MockPrinter::ResetPrinter() {
-  printer_status_ = PRINTER_READY;
-  document_cookie_.reset();
+void MockPrinter::Reset() {
+  Finish();
+  pages_.clear();
+  page_count_ = 0;
 }
 
 printing::mojom::PrintParamsPtr MockPrinter::GetDefaultPrintSettings() {
@@ -118,8 +119,7 @@
   // RenderViewTest class can verify the this function finishes without errors.
   EXPECT_EQ(PRINTER_PRINTING, printer_status_);
   EXPECT_EQ(document_cookie_, params->document_cookie);
-
-  pages_.clear();
+  EXPECT_TRUE(pages_.empty());
 
 #if defined(MOCK_PRINTER_SUPPORTS_PAGE_IMAGES)
   if (should_generate_page_images_) {
@@ -164,7 +164,7 @@
   }
 #endif  // MOCK_PRINTER_SUPPORTS_PAGE_IMAGES
 
-  ResetPrinter();
+  Finish();
 }
 
 int MockPrinter::GetPageCount() const {
@@ -224,3 +224,8 @@
   params->url = url_;
   params->prefer_css_page_size = true;
 }
+
+void MockPrinter::Finish() {
+  printer_status_ = PRINTER_READY;
+  document_cookie_.reset();
+}
diff --git a/components/printing/test/mock_printer.h b/components/printing/test/mock_printer.h
index 4172fcb..c46df0d 100644
--- a/components/printing/test/mock_printer.h
+++ b/components/printing/test/mock_printer.h
@@ -69,6 +69,9 @@
   void set_should_print_backgrounds(bool val) {
     should_print_backgrounds_ = val;
   }
+  void set_should_display_header_footer(bool val) {
+    display_header_footer_ = val;
+  }
 
 #if defined(MOCK_PRINTER_SUPPORTS_PAGE_IMAGES)
   void set_should_generate_page_images(bool val) {
@@ -76,8 +79,9 @@
   }
 #endif  // MOCK_PRINTER_SUPPORTS_PAGE_IMAGES
 
-  // Functions that changes settings of a pseudo printer.
-  void ResetPrinter();
+  // Reset the printer, to prepare for another print job.
+  void Reset();
+
   void SetDefaultPrintSettings(const printing::mojom::PrintParams& params);
 
   // Functions that handle mojo messages.
@@ -111,6 +115,9 @@
   // Helper function to fill the fields in |params|.
   void GetPrintParams(printing::mojom::PrintParams* params) const;
 
+  // Set the printer in a finished state after printing.
+  void Finish();
+
   // In pixels according to dpi_x and dpi_y.
   gfx::SizeF page_size_;
   gfx::SizeF content_size_;
diff --git a/components/printing/test/print_render_frame_helper_browsertest.cc b/components/printing/test/print_render_frame_helper_browsertest.cc
index 0dad41c..df22e9e 100644
--- a/components/printing/test/print_render_frame_helper_browsertest.cc
+++ b/components/printing/test/print_render_frame_helper_browsertest.cc
@@ -681,7 +681,7 @@
 
   // Unblock script initiated printing and verify printing works.
   GetPrintRenderFrameHelper()->scripting_throttler_.Reset();
-  printer()->ResetPrinter();
+  printer()->Reset();
   print_manager()->SetExpectedPagesCount(1);
   PrintWithJavaScript();
   VerifyPagesPrinted(true);
@@ -704,7 +704,7 @@
   VerifyPagesPrinted(false);
 
   // Try again as if user initiated, without resetting the print count.
-  printer()->ResetPrinter();
+  printer()->Reset();
   LoadHTML(kPrintOnUserAction);
   gfx::Size new_size(200, 100);
   Resize(new_size, false);
@@ -910,6 +910,73 @@
   EXPECT_EQ(second_image.pixel_at(3, 14), 0xffffffU);
 }
 
+TEST_F(MAYBE_PrintRenderFrameHelperTest, RoundingAndHeadersAndFooters) {
+  // Use values that end up as fractional values. The output is converted from
+  // CSS pixels (96 DPI) to points (72 DPI), and also via 300 DPI, and some
+  // rounding is applied on the way. See also crbug.com/1466995
+  LoadHTML(R"HTML(
+    <style>
+      @page {
+        size: 21px;
+        margin: 4px;
+      }
+      body {
+        margin: 0;
+        background: #0000ff;
+      }
+    </style>
+    <body></body>
+  )HTML");
+
+  // Print without headers and footers.
+  printer()->set_should_print_backgrounds(true);
+  printer()->set_should_generate_page_images(true);
+  printer()->set_should_display_header_footer(false);
+  OnPrintPages();
+  const MockPrinterPage* page = printer()->GetPrinterPage(0);
+  ASSERT_TRUE(page);
+  printing::Image image(page->image());
+
+  printer()->Reset();
+
+  // Print again, this time with headers and footers. Note that no headers or
+  // footers will actually be shown, since the page margins are so small, so
+  // this should look identical to the output with headers and footers turned
+  // off.
+  printer()->set_should_display_header_footer(true);
+
+  OnPrintPages();
+
+  page = printer()->GetPrinterPage(0);
+  ASSERT_TRUE(page);
+
+  // First check that the two results are identical.
+  ASSERT_EQ(image, page->image());
+
+  // Then check the size, and some pixels. Just check the corners. Note that
+  // assumptions about how subpixels are treated are being made here, meaning
+  // that if code changes cause the following expectations to fail, maybe it's
+  // the test that needs to be adjusted.
+
+  ASSERT_EQ(image.size(), gfx::Size(17, 17));
+
+  // Top left corner:
+  EXPECT_EQ(image.pixel_at(2, 2), 0xffffffU);
+  EXPECT_EQ(image.pixel_at(3, 3), 0x0000ffU);
+
+  // Top right corner:
+  EXPECT_EQ(image.pixel_at(13, 2), 0xffffffU);
+  EXPECT_EQ(image.pixel_at(12, 3), 0x0000ffU);
+
+  // Bottom right corner:
+  EXPECT_EQ(image.pixel_at(13, 13), 0xffffffU);
+  EXPECT_EQ(image.pixel_at(12, 12), 0x0000ffU);
+
+  // Bottom left corner:
+  EXPECT_EQ(image.pixel_at(2, 13), 0xffffffU);
+  EXPECT_EQ(image.pixel_at(3, 12), 0x0000ffU);
+}
+
 #endif  // MOCK_PRINTER_SUPPORTS_PAGE_IMAGES
 
 TEST_F(MAYBE_PrintRenderFrameHelperTest, SpecifiedPageSize1) {
diff --git a/printing/image.cc b/printing/image.cc
index 7984109..1e5e900 100644
--- a/printing/image.cc
+++ b/printing/image.cc
@@ -15,4 +15,9 @@
 
 Image::~Image() = default;
 
+bool Image::operator==(const Image& other) const {
+  return size_ == other.size_ && row_length_ == other.row_length_ &&
+         data_ == other.data_;
+}
+
 }  // namespace printing
diff --git a/printing/image.h b/printing/image.h
index c6d17ee..6ee0e6f 100644
--- a/printing/image.h
+++ b/printing/image.h
@@ -27,6 +27,8 @@
 
   ~Image();
 
+  bool operator==(const Image& other) const;
+
   const gfx::Size& size() const { return size_; }
 
   // Returns the 0x0RGB value of the pixel at the given location.