[go: nahoru, domu]

More cross-platform pixel test support in MockPrinter.

It used to only work on Mac (maybe; no pixels were actually tested
due to no test coverage), and possibly Windows as well, using platform
code. It should now work in Linux, Mac and Windows, but not Android
(because PDF isn't enabled there).

Remove platform-specific code from printing::Image. Instead provide a
constructor that takes raw pixel data. Generate the raw pixel data
from PDF in MockPrinter.

MockPrinter::PrintPage() was confused (now named OnDocumentPrinted()).
It expected to be called once per page, but it is in fact only called
once per print job. Not that it really mattered, since no tests tested
more than one page. :-p

Enable PrintRenderFrameHelperTest.PrintWithIframe on all platforms that
support pixel testing.
Remove PrintRenderFrameHelperTest.PrintLayoutTest, since it's not very
useful. It was only enabled on Mac, and it essentially only tested if
the page size was *roughly* as expected. We can do better than this
now. Add PrintRenderFrameHelperTest.Pixels, which checks all the
pixels in a two-page printed document with mixed page size.

Change-Id: If275acb230b5834c0f843365d0ea9dfa26a70e78
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4765574
Commit-Queue: Morten Stenshorne <mstensho@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1183555}
diff --git a/components/printing/test/BUILD.gn b/components/printing/test/BUILD.gn
index 670d8f0..c00a0a1 100644
--- a/components/printing/test/BUILD.gn
+++ b/components/printing/test/BUILD.gn
@@ -21,6 +21,8 @@
     "//content/public/renderer",
     "//content/test:test_support",
     "//ipc",
+    "//pdf",
+    "//pdf:buildflags",
     "//printing",
     "//printing:test_support",
     "//printing/mojom",
diff --git a/components/printing/test/DEPS b/components/printing/test/DEPS
index 6ede09e..84e3e17 100644
--- a/components/printing/test/DEPS
+++ b/components/printing/test/DEPS
@@ -1,6 +1,5 @@
 include_rules = [
-  # The test directory can do whatever it wants within components/printing.
-  # Same for content/public.
   "+components/printing",
   "+content/public",
+  "+pdf",
 ]
diff --git a/components/printing/test/mock_printer.cc b/components/printing/test/mock_printer.cc
index 1840c46..d5e84be 100644
--- a/components/printing/test/mock_printer.cc
+++ b/components/printing/test/mock_printer.cc
@@ -17,9 +17,10 @@
 #include "printing/print_settings.h"
 #include "printing/units.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/size_conversions.h"
 
-#if BUILDFLAG(IS_APPLE)
-#include "printing/pdf_metafile_cg_mac.h"
+#if defined(MOCK_PRINTER_SUPPORTS_PAGE_IMAGES)
+#include "pdf/pdf.h"
 #endif
 
 MockPrinterPage::MockPrinterPage(const printing::Image& image)
@@ -33,8 +34,7 @@
       selection_only_(false),
       should_print_backgrounds_(false),
       printer_status_(PRINTER_READY),
-      number_pages_(0u),
-      page_number_(0u),
+      page_count_(0),
       is_first_request_(true),
       print_to_pdf_(false),
       preview_request_id_(0),
@@ -107,77 +107,96 @@
   // RenderViewTest class can verify the this function finishes without errors.
   EXPECT_EQ(document_cookie_, cookie);
   EXPECT_EQ(PRINTER_PRINTING, printer_status_);
-  EXPECT_EQ(0u, number_pages_);
-  EXPECT_EQ(0u, page_number_);
+  EXPECT_EQ(0, page_count_);
 
-  // Initialize the job status.
-  number_pages_ = number_pages;
-  page_number_ = 0u;
-  pages_.clear();
+  page_count_ = number_pages;
 }
 
-void MockPrinter::PrintPage(printing::mojom::DidPrintDocumentParamsPtr params) {
+void MockPrinter::OnDocumentPrinted(
+    printing::mojom::DidPrintDocumentParamsPtr params) {
   // Verify the input parameter and update the printer status so that the
   // RenderViewTest class can verify the this function finishes without errors.
   EXPECT_EQ(PRINTER_PRINTING, printer_status_);
   EXPECT_EQ(document_cookie_, params->document_cookie);
 
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE)
-  // Load the data sent from a RenderView object and create a PageData object.
-  ASSERT_TRUE(params->content->metafile_data_region.IsValid());
-  base::ReadOnlySharedMemoryMapping mapping =
-      params->content->metafile_data_region.Map();
-  ASSERT_TRUE(mapping.IsValid());
-  EXPECT_GT(mapping.size(), 0U);
+  pages_.clear();
 
-#if BUILDFLAG(IS_APPLE)
-  printing::PdfMetafileCg metafile;
-#else
-  printing::MetafileSkia metafile;
-#endif
-  metafile.InitFromData(mapping.GetMemoryAsSpan<const uint8_t>());
-  printing::Image image(metafile);
-  pages_.push_back(base::MakeRefCounted<MockPrinterPage>(image));
-#endif
+#if defined(MOCK_PRINTER_SUPPORTS_PAGE_IMAGES)
+  if (should_generate_page_images_) {
+    // Load the data sent from a RenderView object and create a PageData object.
+    ASSERT_TRUE(params->content->metafile_data_region.IsValid());
+    base::ReadOnlySharedMemoryMapping mapping =
+        params->content->metafile_data_region.Map();
+    ASSERT_TRUE(mapping.IsValid());
+    EXPECT_GT(mapping.size(), 0U);
 
-  // We finish printing a printing job.
-  // Reset the job status and the printer status.
-  ++page_number_;
-  if (number_pages_ == page_number_)
-    ResetPrinter();
+    base::span<const uint8_t> pdf_buffer =
+        mapping.GetMemoryAsSpan<const uint8_t>();
+
+    int page_count;
+    bool success = chrome_pdf::GetPDFDocInfo(pdf_buffer, &page_count, nullptr);
+    ASSERT_TRUE(success);
+    for (int page_index = 0; page_index < page_count; page_index++) {
+      absl::optional<gfx::SizeF> page_size =
+          chrome_pdf::GetPDFPageSizeByIndex(pdf_buffer, page_index);
+      ASSERT_TRUE(page_size);
+      gfx::Size size = gfx::ToCeiledSize(*page_size);
+      ASSERT_GT(size.width(), 0);
+      ASSERT_GT(size.height(), 0);
+      int line_stride = size.width() * sizeof(uint32_t);
+      std::vector<unsigned char> pixel_buffer;
+      pixel_buffer.resize(line_stride * size.height());
+      gfx::Size dpi(72, 72);
+      chrome_pdf::RenderOptions options = {
+          /* stretch_to_bounds=*/false,
+          /* keep_aspect_ratio=*/false,
+          /* autorotate=*/false,
+          /* use_color=*/true, chrome_pdf::RenderDeviceType::kDisplay};
+
+      success = chrome_pdf::RenderPDFPageToBitmap(
+          pdf_buffer, page_index, pixel_buffer.data(), size, dpi, options);
+      ASSERT_TRUE(success);
+
+      printing::Image image(size, line_stride, std::move(pixel_buffer));
+      ASSERT_FALSE(image.size().IsEmpty());
+      pages_.push_back(base::MakeRefCounted<MockPrinterPage>(image));
+    }
+  }
+#endif  // MOCK_PRINTER_SUPPORTS_PAGE_IMAGES
+
+  ResetPrinter();
 }
 
-int MockPrinter::GetPrintedPages() const {
+int MockPrinter::GetPageCount() const {
   if (printer_status_ != PRINTER_READY)
     return -1;
-  return page_number_;
+  return page_count_;
 }
 
-const MockPrinterPage* MockPrinter::GetPrintedPage(unsigned int pageno) const {
+#if defined(MOCK_PRINTER_SUPPORTS_PAGE_IMAGES)
+
+const MockPrinterPage* MockPrinter::GetPrinterPage(unsigned int pageno) const {
+  EXPECT_TRUE(should_generate_page_images_);
   if (pageno >= pages_.size())
     return nullptr;
   return pages_[pageno].get();
 }
 
 int MockPrinter::GetWidth(unsigned int page) const {
+  EXPECT_TRUE(should_generate_page_images_);
   if (printer_status_ != PRINTER_READY || page >= pages_.size())
     return -1;
   return pages_[page]->width();
 }
 
 int MockPrinter::GetHeight(unsigned int page) const {
+  EXPECT_TRUE(should_generate_page_images_);
   if (printer_status_ != PRINTER_READY || page >= pages_.size())
     return -1;
   return pages_[page]->height();
 }
 
-bool MockPrinter::GetBitmapChecksum(unsigned int page,
-                                    std::string* checksum) const {
-  if (printer_status_ != PRINTER_READY || page >= pages_.size())
-    return false;
-  *checksum = pages_[page]->image().checksum();
-  return true;
-}
+#endif  // MOCK_PRINTER_SUPPORTS_PAGE_IMAGES
 
 void MockPrinter::CreateDocumentCookie() {
   EXPECT_FALSE(document_cookie_.has_value());
@@ -203,4 +222,5 @@
   params->display_header_footer = display_header_footer_;
   params->title = title_;
   params->url = url_;
+  params->prefer_css_page_size = true;
 }
diff --git a/components/printing/test/mock_printer.h b/components/printing/test/mock_printer.h
index d425ed1d..4172fcb 100644
--- a/components/printing/test/mock_printer.h
+++ b/components/printing/test/mock_printer.h
@@ -13,12 +13,17 @@
 
 #include "base/memory/ref_counted.h"
 #include "components/printing/common/print.mojom-forward.h"
+#include "pdf/buildflags.h"
 #include "printing/image.h"
 #include "printing/mojom/print.mojom.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/geometry/size_f.h"
 
+#if BUILDFLAG(ENABLE_PDF)
+#define MOCK_PRINTER_SUPPORTS_PAGE_IMAGES
+#endif
+
 // A class which represents an output page used in the MockPrinter class.
 // The MockPrinter class stores output pages in a vector, so, this class
 // inherits the base::RefCounted<> class so that the MockPrinter class can use
@@ -61,6 +66,16 @@
   MockPrinter& operator=(const MockPrinter&) = delete;
   ~MockPrinter();
 
+  void set_should_print_backgrounds(bool val) {
+    should_print_backgrounds_ = val;
+  }
+
+#if defined(MOCK_PRINTER_SUPPORTS_PAGE_IMAGES)
+  void set_should_generate_page_images(bool val) {
+    should_generate_page_images_ = val;
+  }
+#endif  // MOCK_PRINTER_SUPPORTS_PAGE_IMAGES
+
   // Functions that changes settings of a pseudo printer.
   void ResetPrinter();
   void SetDefaultPrintSettings(const printing::mojom::PrintParams& params);
@@ -74,19 +89,20 @@
                      uint32_t expected_pages_count,
                      bool has_selection,
                      printing::mojom::PrintPagesParams* settings);
-  void PrintPage(printing::mojom::DidPrintDocumentParamsPtr params);
+  void OnDocumentPrinted(printing::mojom::DidPrintDocumentParamsPtr params);
 
   // Functions that retrieve the output pages.
   Status GetPrinterStatus() const { return printer_status_; }
-  int GetPrintedPages() const;
+  int GetPageCount() const;
 
+#if defined(MOCK_PRINTER_SUPPORTS_PAGE_IMAGES)
   // Get a pointer to the printed page, returns NULL if pageno has not been
   // printed.  The pointer is for read only view and should not be deleted.
-  const MockPrinterPage* GetPrintedPage(unsigned int pageno) const;
+  const MockPrinterPage* GetPrinterPage(unsigned int pageno) const;
 
   int GetWidth(unsigned int page) const;
   int GetHeight(unsigned int page) const;
-  bool GetBitmapChecksum(unsigned int page, std::string* checksum) const;
+#endif  // MOCK_PRINTER_SUPPORTS_PAGE_IMAGES
 
  private:
   // Sets `document_cookie_` based on `use_invalid_settings_`.
@@ -117,9 +133,8 @@
   // The current status of this printer.
   Status printer_status_;
 
-  // The output of a printing job.
-  uint32_t number_pages_;
-  uint32_t page_number_;
+  // The number of pages printed.
+  int page_count_;
 
   // Used only in the preview sequence.
   bool is_first_request_;
@@ -138,6 +153,13 @@
   // Used for generating invalid settings.
   bool use_invalid_settings_;
 
+#if defined(MOCK_PRINTER_SUPPORTS_PAGE_IMAGES)
+  // If true, one MockPrinterPage object (including an Image) will be generated
+  // for each page, so that tests that want to look at pixels can do that. This
+  // operation is surprisingly expensive, so it's false by default.
+  bool should_generate_page_images_ = false;
+#endif  // MOCK_PRINTER_SUPPORTS_PAGE_IMAGES
+
   std::vector<scoped_refptr<MockPrinterPage>> pages_;
 };
 
diff --git a/components/printing/test/print_render_frame_helper_browsertest.cc b/components/printing/test/print_render_frame_helper_browsertest.cc
index 0363054a..0dad41c 100644
--- a/components/printing/test/print_render_frame_helper_browsertest.cc
+++ b/components/printing/test/print_render_frame_helper_browsertest.cc
@@ -11,6 +11,7 @@
 #include <utility>
 
 #include "base/command_line.h"
+#include "base/files/file_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/run_loop.h"
 #include "base/strings/string_piece.h"
@@ -27,6 +28,7 @@
 #include "content/public/test/render_view_test.h"
 #include "ipc/ipc_listener.h"
 #include "printing/buildflags/buildflags.h"
+#include "printing/image.h"
 #include "printing/mojom/print.mojom.h"
 #include "printing/page_range.h"
 #include "printing/print_job_constants.h"
@@ -46,14 +48,9 @@
 #include "printing/print_settings_conversion.h"
 #endif
 
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE)
-#include "base/files/file_util.h"
-#include "printing/image.h"
-
 using blink::WebFrame;
 using blink::WebLocalFrame;
 using blink::WebString;
-#endif
 
 namespace printing {
 
@@ -322,7 +319,7 @@
   void DidPrintDocument(mojom::DidPrintDocumentParamsPtr params,
                         DidPrintDocumentCallback callback) override {
     base::RunLoop().RunUntilIdle();
-    printer_->PrintPage(std::move(params));
+    printer_->OnDocumentPrinted(std::move(params));
     std::move(callback).Run(true);
     is_printed_ = true;
   }
@@ -830,6 +827,91 @@
   OnPrintPages();
 }
 
+#if defined(MOCK_PRINTER_SUPPORTS_PAGE_IMAGES)
+
+TEST_F(MAYBE_PrintRenderFrameHelperTest, Pixels) {
+  // This test should generate two pages. The first should be 16x16 CSS pixels
+  // large, and the second should be 24x24. The pixels and page size information
+  // are going on a ride through the machineries, so use size values carefully,
+  // to avoid subpixel issues. At some point on the journey, everything will be
+  // changed to 300 DPI, and the page sizes involved will be rounded to integers
+  // (so we need something that ends up with integers after having been
+  // multiplied by 300/72 and back). See crbug.com/1466995 . Furthermore, the
+  // final output will be in points, not CSS pixels, which is why the
+  // expectation is to get 12x12 and 18x18 pages instead of 16x16 and 24x24 (and
+  // a 4px border becomes a 3pt border).
+  LoadHTML(R"HTML(
+    <style>
+      @page {
+        size: 24px;
+        margin: 0;
+      }
+      @page:first {
+        size: 16px;
+      }
+      body {
+        margin: 0;
+      }
+      div {
+        box-sizing: border-box;
+        border: 4px solid;
+      }
+    </style>
+    <div style="width:16px; height:16px; border-color:#00ff00;"></div>
+    <div style="width:24px; height:24px; border-color:#0000ff;"></div>
+  )HTML");
+
+  printer()->set_should_print_backgrounds(true);
+  printer()->set_should_generate_page_images(true);
+  OnPrintPages();
+
+  // First page:
+  const MockPrinterPage* page = printer()->GetPrinterPage(0);
+  ASSERT_TRUE(page);
+  const Image& first_image = page->image();
+  ASSERT_EQ(first_image.size(), gfx::Size(12, 12));
+  // Top left corner:
+  EXPECT_EQ(first_image.pixel_at(0, 0), 0x00ff00U);
+  EXPECT_EQ(first_image.pixel_at(2, 2), 0x00ff00U);
+  EXPECT_EQ(first_image.pixel_at(3, 3), 0xffffffU);
+  // Top right corner:
+  EXPECT_EQ(first_image.pixel_at(11, 0), 0x00ff00U);
+  EXPECT_EQ(first_image.pixel_at(9, 2), 0x00ff00U);
+  EXPECT_EQ(first_image.pixel_at(8, 3), 0xffffffU);
+  // Bottom right corner:
+  EXPECT_EQ(first_image.pixel_at(11, 11), 0x00ff00U);
+  EXPECT_EQ(first_image.pixel_at(9, 9), 0x00ff00U);
+  EXPECT_EQ(first_image.pixel_at(8, 8), 0xffffffU);
+  // Bottom left corner:
+  EXPECT_EQ(first_image.pixel_at(0, 11), 0x00ff00U);
+  EXPECT_EQ(first_image.pixel_at(2, 9), 0x00ff00U);
+  EXPECT_EQ(first_image.pixel_at(3, 8), 0xffffffU);
+
+  // Second page:
+  page = printer()->GetPrinterPage(1);
+  ASSERT_TRUE(page);
+  const Image& second_image = page->image();
+  ASSERT_EQ(second_image.size(), gfx::Size(18, 18));
+  // Top left corner:
+  EXPECT_EQ(second_image.pixel_at(0, 0), 0x0000ffU);
+  EXPECT_EQ(second_image.pixel_at(2, 2), 0x0000ffU);
+  EXPECT_EQ(second_image.pixel_at(3, 3), 0xffffffU);
+  // Top right corner:
+  EXPECT_EQ(second_image.pixel_at(0, 17), 0x0000ffU);
+  EXPECT_EQ(second_image.pixel_at(2, 15), 0x0000ffU);
+  EXPECT_EQ(second_image.pixel_at(3, 14), 0xffffffU);
+  // Bottom right corner:
+  EXPECT_EQ(second_image.pixel_at(17, 17), 0x0000ffU);
+  EXPECT_EQ(second_image.pixel_at(15, 15), 0x0000ffU);
+  EXPECT_EQ(second_image.pixel_at(14, 14), 0xffffffU);
+  // Bottom left corner:
+  EXPECT_EQ(second_image.pixel_at(0, 17), 0x0000ffU);
+  EXPECT_EQ(second_image.pixel_at(2, 15), 0x0000ffU);
+  EXPECT_EQ(second_image.pixel_at(3, 14), 0xffffffU);
+}
+
+#endif  // MOCK_PRINTER_SUPPORTS_PAGE_IMAGES
+
 TEST_F(MAYBE_PrintRenderFrameHelperTest, SpecifiedPageSize1) {
   LoadHTML(R"HTML(
     <style>
@@ -909,11 +991,8 @@
   VerifyPagesPrinted(true);
 }
 
-#if BUILDFLAG(IS_APPLE)
-// TODO(estade): I don't think this test is worth porting to Linux. We will have
-// to rip out and replace most of the IPC code if we ever plan to improve
-// printing, and the comment below by sverrir suggests that it doesn't do much
-// for us anyway.
+#if defined(MOCK_PRINTER_SUPPORTS_PAGE_IMAGES)
+
 TEST_F(MAYBE_PrintRenderFrameHelperTest, PrintWithIframe) {
   // Document that populates an iframe.
   static const char html[] =
@@ -925,6 +1004,7 @@
       "  frames['sub1'].document.close();"
       "</script></body></html>";
 
+  printer()->set_should_generate_page_images(true);
   LoadHTML(html);
 
   // Find the frame and set it as the focused one.  This should mean that that
@@ -942,8 +1022,8 @@
 
   // Verify output through MockPrinter.
   const MockPrinter* mock_printer(printer());
-  ASSERT_EQ(1, mock_printer->GetPrintedPages());
-  const Image& image1(mock_printer->GetPrintedPage(0)->image());
+  ASSERT_EQ(1, mock_printer->GetPageCount());
+  const Image& image1(mock_printer->GetPrinterPage(0)->image());
 
   // TODO(sverrir): Figure out a way to improve this test to actually print
   // only the content of the iframe.  Currently image1 will contain the full
@@ -951,88 +1031,8 @@
   EXPECT_NE(0, image1.size().width());
   EXPECT_NE(0, image1.size().height());
 }
-#endif  // BUILDFLAG(IS_APPLE)
 
-// Tests if we can print a page and verify its results.
-// This test prints HTML pages into a pseudo printer and check their outputs,
-// i.e. a simplified version of the PrintingLayoutTextTest UI test.
-namespace {
-// Test cases used in this test.
-struct TestPageData {
-  const char* page;
-  size_t printed_pages;
-  int width;
-  int height;
-  const char* checksum;
-  const wchar_t* file;
-};
-
-#if BUILDFLAG(IS_APPLE)
-const TestPageData kTestPages[] = {
-    {
-        "<html>"
-        "<head>"
-        "<meta"
-        "  http-equiv=\"Content-Type\""
-        "  content=\"text/html; charset=utf-8\"/>"
-        "<title>Test 1</title>"
-        "</head>"
-        "<body style=\"background-color: white;\">"
-        "<p style=\"font-family: arial;\">Hello World!</p>"
-        "</body>",
-        1,
-        // Mac printing code compensates for the WebKit scale factor while
-        // generating the metafile, so we expect smaller pages. (On non-Mac
-        // platforms, this would be 675x900).
-        600, 780, nullptr, nullptr,
-    },
-};
-#endif  // BUILDFLAG(IS_APPLE)
-}  // namespace
-
-// TODO(estade): need to port MockPrinter to get this on Linux. This involves
-// hooking up Cairo to read a pdf stream, or accessing the cairo surface in the
-// metafile directly.
-// Same for printing via PDF on Windows.
-#if BUILDFLAG(IS_APPLE)
-TEST_F(MAYBE_PrintRenderFrameHelperTest, PrintLayoutTest) {
-  EXPECT_TRUE(printer());
-  for (size_t i = 0; i < std::size(kTestPages); ++i) {
-    // Load an HTML page and print it.
-    LoadHTML(kTestPages[i].page);
-    OnPrintPages();
-    VerifyPagesPrinted(true);
-
-    // MockRenderThread::Send() just calls MockRenderThread::OnReceived().
-    // So, all IPC messages sent in the above RenderView::OnPrintPages() call
-    // has been handled by the MockPrinter object, i.e. this printing job
-    // has been already finished.
-    // So, we can start checking the output pages of this printing job.
-    // Retrieve the number of pages actually printed.
-    size_t pages = printer()->GetPrintedPages();
-    EXPECT_EQ(kTestPages[i].printed_pages, pages);
-
-    // Retrieve the width and height of the output page.
-    int width = printer()->GetWidth(0);
-    int height = printer()->GetHeight(0);
-
-    // Check with margin for error.  This has been failing with a one pixel
-    // offset on our buildbot.
-    const int kErrorMargin = 5;  // 5%
-    EXPECT_GT(kTestPages[i].width * (100 + kErrorMargin) / 100, width);
-    EXPECT_LT(kTestPages[i].width * (100 - kErrorMargin) / 100, width);
-    EXPECT_GT(kTestPages[i].height * (100 + kErrorMargin) / 100, height);
-    EXPECT_LT(kTestPages[i].height * (100 - kErrorMargin) / 100, height);
-
-    // Retrieve the checksum of the bitmap data from the pseudo printer and
-    // compare it with the expected result.
-    std::string bitmap_actual;
-    EXPECT_TRUE(printer()->GetBitmapChecksum(0, &bitmap_actual));
-    if (kTestPages[i].checksum)
-      EXPECT_EQ(kTestPages[i].checksum, bitmap_actual);
-  }
-}
-#endif  // BUILDFLAG(IS_APPLE)
+#endif  // MOCK_PRINTER_SUPPORTS_PAGE_IMAGES
 
 // These print preview tests do not work on Chrome OS yet.
 #if !BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/printing/BUILD.gn b/printing/BUILD.gn
index 23c324c..a65c201 100644
--- a/printing/BUILD.gn
+++ b/printing/BUILD.gn
@@ -327,20 +327,6 @@
     "//skia",
     "//ui/gfx",
   ]
-
-  if (is_android) {
-    sources += [ "image_android.cc" ]
-  }
-
-  if (is_linux || is_chromeos || is_fuchsia) {
-    sources += [ "image_linux.cc" ]
-  }
-  if (is_apple) {
-    sources += [ "image_mac.cc" ]
-  }
-  if (is_win) {
-    sources += [ "image_win.cc" ]
-  }
 }
 
 if (enable_printing_unittests) {
diff --git a/printing/image.cc b/printing/image.cc
index 7cab342c..7984109 100644
--- a/printing/image.cc
+++ b/printing/image.cc
@@ -4,23 +4,15 @@
 
 #include "printing/image.h"
 
-#include "base/hash/md5.h"
-#include "printing/metafile.h"
+#include <utility>
 
 namespace printing {
 
-Image::Image(const Metafile& metafile) : row_length_(0) {
-  LoadMetafile(metafile);
-}
+Image::Image(gfx::Size size, int line_stride, std::vector<unsigned char> buffer)
+    : size_(size), row_length_(line_stride), data_(std::move(buffer)) {}
 
 Image::Image(const Image& image) = default;
 
 Image::~Image() = default;
 
-std::string Image::checksum() const {
-  base::MD5Digest digest;
-  base::MD5Sum(&data_[0], data_.size(), &digest);
-  return base::MD5DigestToBase16(digest);
-}
-
 }  // namespace printing
diff --git a/printing/image.h b/printing/image.h
index 7ffc2d5..c6d17ee 100644
--- a/printing/image.h
+++ b/printing/image.h
@@ -8,7 +8,6 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include <string>
 #include <vector>
 
 #include "base/check.h"
@@ -16,15 +15,12 @@
 
 namespace printing {
 
-class Metafile;
-
 // Lightweight raw-bitmap management. The image, once initialized, is immutable.
 // The only purpose is testing image contents.
 class Image {
  public:
-  // Creates the image from the metafile.  Deduces bounds based on bounds in
-  // metafile.  If loading fails size().IsEmpty() will be true.
-  explicit Image(const Metafile& metafile);
+  // Creates an image from raw ARGB pixel data, 32 bits per pixel.
+  Image(gfx::Size size, int line_stride, std::vector<unsigned char> buffer);
 
   // Copy constructor.
   explicit Image(const Image& image);
@@ -33,9 +29,6 @@
 
   const gfx::Size& size() const { return size_; }
 
-  // Return a checksum of the image (MD5 over the internal data structure).
-  std::string checksum() const;
-
   // Returns the 0x0RGB value of the pixel at the given location.
   uint32_t Color(uint32_t color) const {
     return color & 0xFFFFFF;  // Strip out alpha channel.
@@ -50,18 +43,15 @@
   }
 
  private:
-  // Loads the first page from `metafile`.
-  bool LoadMetafile(const Metafile& metafile);
-
   // Pixel dimensions of the image.
-  gfx::Size size_;
+  const gfx::Size size_;
 
   // Length of a line in bytes.
-  int row_length_;
+  const int row_length_;
 
   // Actual bitmap data in arrays of RGBAs (so when loaded as uint32_t, it's
   // 0xABGR).
-  std::vector<unsigned char> data_;
+  const std::vector<unsigned char> data_;
 
   // Prevent operator= (this function has no implementation)
   Image& operator=(const Image& image);
diff --git a/printing/image_android.cc b/printing/image_android.cc
deleted file mode 100644
index 8ba6540..0000000
--- a/printing/image_android.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2013 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "printing/image.h"
-
-#include "base/notreached.h"
-
-namespace printing {
-
-bool Image::LoadMetafile(const Metafile& metafile) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-}  // namespace printing
diff --git a/printing/image_linux.cc b/printing/image_linux.cc
deleted file mode 100644
index d4cc1d9..0000000
--- a/printing/image_linux.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2011 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "printing/image.h"
-
-#include "base/notreached.h"
-
-namespace printing {
-
-bool Image::LoadMetafile(const Metafile& metafile) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-}  // namespace printing
diff --git a/printing/image_mac.cc b/printing/image_mac.cc
deleted file mode 100644
index 04b37cc..0000000
--- a/printing/image_mac.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2012 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "printing/image.h"
-
-#include <CoreGraphics/CoreGraphics.h>
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/mac/scoped_cftyperef.h"
-#include "printing/metafile.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace printing {
-
-bool Image::LoadMetafile(const Metafile& metafile) {
-  // Load only the first page of `metafile`, just like Windows.
-  const unsigned int page_number = 1;
-  gfx::Rect rect(metafile.GetPageBounds(page_number));
-  if (rect.width() < 1 || rect.height() < 1)
-    return false;
-
-  size_ = rect.size();
-  row_length_ = size_.width() * sizeof(uint32_t);
-  size_t bytes = row_length_ * size_.height();
-  DCHECK(bytes);
-
-  data_.resize(bytes);
-  base::ScopedCFTypeRef<CGColorSpaceRef> color_space(
-      CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB));
-  base::ScopedCFTypeRef<CGContextRef> bitmap_context(CGBitmapContextCreate(
-      &*data_.begin(), size_.width(), size_.height(), 8, row_length_,
-      color_space, kCGImageAlphaPremultipliedLast));
-  DCHECK(bitmap_context.get());
-
-  return metafile.RenderPage(page_number, bitmap_context, rect.ToCGRect(),
-                             /*autorotate=*/false, /*fit_to_page=*/true);
-}
-
-}  // namespace printing
diff --git a/printing/image_win.cc b/printing/image_win.cc
deleted file mode 100644
index f4e92679a..0000000
--- a/printing/image_win.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2011 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "printing/image.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/win/scoped_gdi_object.h"
-#include "base/win/scoped_hdc.h"
-#include "base/win/scoped_select_object.h"
-#include "printing/metafile.h"
-#include "skia/ext/skia_utils_win.h"
-#include "ui/gfx/gdi_util.h"  // EMF support
-#include "ui/gfx/geometry/rect.h"
-
-namespace printing {
-
-bool Image::LoadMetafile(const Metafile& metafile) {
-  gfx::Rect rect(metafile.GetPageBounds(1));
-
-  // Create a temporary HDC and bitmap to retrieve the rendered data.
-  base::win::ScopedCreateDC hdc(::CreateCompatibleDC(NULL));
-  BITMAPV4HEADER hdr;
-  DCHECK_EQ(rect.x(), 0);
-  DCHECK_EQ(rect.y(), 0);
-  DCHECK_GE(rect.width(), 0);  // Metafile could be empty.
-  DCHECK_GE(rect.height(), 0);
-
-  if (rect.width() < 1 || rect.height() < 1)
-    return false;
-
-  size_ = rect.size();
-  // The data in this `bitmap` will be tightly-packed 32-bit ARGB data.
-  gfx::CreateBitmapV4HeaderForARGB888(rect.width(), rect.height(), &hdr);
-  unsigned char* bits = NULL;
-  base::win::ScopedBitmap bitmap(
-      ::CreateDIBSection(hdc.Get(), reinterpret_cast<BITMAPINFO*>(&hdr), 0,
-                         reinterpret_cast<void**>(&bits), NULL, 0));
-  DCHECK(bitmap.is_valid());
-  base::win::ScopedSelectObject select_object(hdc.Get(), bitmap.get());
-
-  skia::InitializeDC(hdc.Get());
-
-  bool success = metafile.Playback(hdc.Get(), NULL);
-
-  row_length_ = size_.width() * sizeof(uint32_t);
-  size_t bytes = row_length_ * size_.height();
-  DCHECK(bytes);
-
-  data_.assign(bits, bits + bytes);
-
-  return success;
-}
-
-}  // namespace printing