pdf_metafile_cg_mac_unittest.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. // Copyright (c) 2011 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "printing/pdf_metafile_cg_mac.h"
  5. #import <ApplicationServices/ApplicationServices.h>
  6. #include <stdint.h>
  7. #include <memory>
  8. #include <string>
  9. #include <vector>
  10. #include "base/files/file_util.h"
  11. #include "base/hash/sha1.h"
  12. #include "base/path_service.h"
  13. #include "printing/mojom/print.mojom.h"
  14. #include "testing/gtest/include/gtest/gtest.h"
  15. #include "ui/gfx/codec/png_codec.h"
  16. #include "ui/gfx/geometry/rect.h"
  17. namespace printing {
  18. namespace {
  19. base::FilePath GetPdfTestData(const base::FilePath::StringType& filename) {
  20. base::FilePath root_path;
  21. if (!base::PathService::Get(base::DIR_SOURCE_ROOT, &root_path))
  22. return base::FilePath();
  23. return root_path.Append("pdf").Append("test").Append("data").Append(filename);
  24. }
  25. base::FilePath GetPrintingTestData(const base::FilePath::StringType& filename) {
  26. base::FilePath root_path;
  27. if (!base::PathService::Get(base::DIR_SOURCE_ROOT, &root_path))
  28. return base::FilePath();
  29. return root_path.Append("printing")
  30. .Append("test")
  31. .Append("data")
  32. .Append("pdf_cg")
  33. .Append(filename);
  34. }
  35. std::unique_ptr<PdfMetafileCg> GetPdfMetafile(
  36. const base::FilePath::StringType& pdf_filename) {
  37. // Get test data.
  38. base::FilePath pdf_file = GetPdfTestData(pdf_filename);
  39. if (pdf_file.empty())
  40. return nullptr;
  41. std::string pdf_data;
  42. if (!base::ReadFileToString(pdf_file, &pdf_data))
  43. return nullptr;
  44. // Initialize and check metafile.
  45. auto pdf_cg = std::make_unique<PdfMetafileCg>();
  46. if (!pdf_cg->InitFromData(base::as_bytes(base::make_span(pdf_data))))
  47. return nullptr;
  48. return pdf_cg;
  49. }
  50. void RenderedPdfSha1(const base::FilePath::StringType& pdf_filename,
  51. size_t page_number,
  52. const gfx::Rect& expected_page_bounds,
  53. const gfx::Size& dest_size,
  54. bool autorotate,
  55. bool fit_to_page,
  56. base::SHA1Digest* rendered_hash) {
  57. // Initialize and verify the metafile.
  58. std::unique_ptr<PdfMetafileCg> pdf_cg = GetPdfMetafile(pdf_filename);
  59. ASSERT_TRUE(pdf_cg);
  60. ASSERT_LE(page_number, pdf_cg->GetPageCount());
  61. const gfx::Rect bounds = pdf_cg->GetPageBounds(page_number);
  62. ASSERT_EQ(expected_page_bounds, bounds);
  63. // Set up rendering context.
  64. constexpr size_t kBitsPerComponent = 8;
  65. constexpr size_t kBytesPerPixel = 4;
  66. const size_t kStride = dest_size.width() * kBytesPerPixel;
  67. std::vector<uint8_t> rendered_bitmap(dest_size.height() * kStride);
  68. base::ScopedCFTypeRef<CGColorSpaceRef> color_space(
  69. CGColorSpaceCreateDeviceRGB());
  70. base::ScopedCFTypeRef<CGContextRef> context(CGBitmapContextCreate(
  71. rendered_bitmap.data(), dest_size.width(), dest_size.height(),
  72. kBitsPerComponent, kStride, color_space,
  73. uint32_t{kCGImageAlphaPremultipliedFirst} | kCGBitmapByteOrder32Little));
  74. // Render using metafile and calculate the output hash.
  75. ASSERT_TRUE(pdf_cg->RenderPage(page_number, context,
  76. gfx::Rect(dest_size).ToCGRect(), autorotate,
  77. fit_to_page));
  78. *rendered_hash = base::SHA1HashSpan(rendered_bitmap);
  79. }
  80. void ExpectedPngSha1(const base::FilePath::StringType& expected_png_filename,
  81. const gfx::Size& expected_png_size,
  82. base::SHA1Digest* expected_hash) {
  83. base::FilePath expected_png_file = GetPrintingTestData(expected_png_filename);
  84. ASSERT_FALSE(expected_png_file.empty());
  85. std::string expected_png_data;
  86. ASSERT_TRUE(base::ReadFileToString(expected_png_file, &expected_png_data));
  87. // Decode expected PNG and calculate the output hash.
  88. std::vector<uint8_t> expected_png_bitmap;
  89. int png_width;
  90. int png_height;
  91. ASSERT_TRUE(gfx::PNGCodec::Decode(
  92. reinterpret_cast<const uint8_t*>(expected_png_data.data()),
  93. expected_png_data.size(), gfx::PNGCodec::FORMAT_BGRA,
  94. &expected_png_bitmap, &png_width, &png_height));
  95. ASSERT_EQ(expected_png_size.width(), png_width);
  96. ASSERT_EQ(expected_png_size.height(), png_height);
  97. *expected_hash = base::SHA1HashSpan(expected_png_bitmap);
  98. }
  99. void TestRenderPageWithTransformParams(
  100. const base::FilePath::StringType& pdf_filename,
  101. size_t page_number,
  102. const gfx::Rect& expected_page_bounds,
  103. const base::FilePath::StringType& expected_png_filename,
  104. const gfx::Size& dest_size,
  105. bool autorotate,
  106. bool fit_to_page) {
  107. base::SHA1Digest rendered_hash;
  108. RenderedPdfSha1(pdf_filename, page_number, expected_page_bounds, dest_size,
  109. autorotate, fit_to_page, &rendered_hash);
  110. base::SHA1Digest expected_hash;
  111. ExpectedPngSha1(expected_png_filename, dest_size, &expected_hash);
  112. // Make sure the hashes match.
  113. EXPECT_EQ(expected_hash, rendered_hash);
  114. }
  115. void TestRenderPage(const base::FilePath::StringType& pdf_filename,
  116. size_t page_number,
  117. const gfx::Rect& expected_page_bounds,
  118. const base::FilePath::StringType& expected_png_filename,
  119. const gfx::Size& dest_size) {
  120. TestRenderPageWithTransformParams(
  121. pdf_filename, page_number, expected_page_bounds, expected_png_filename,
  122. dest_size, /*autorotate=*/true, /*fit_to_page=*/false);
  123. }
  124. } // namespace
  125. TEST(PdfMetafileCgTest, Pdf) {
  126. // Test in-renderer constructor.
  127. PdfMetafileCg pdf;
  128. EXPECT_TRUE(pdf.Init());
  129. EXPECT_TRUE(pdf.context());
  130. // Render page 1.
  131. constexpr gfx::Rect kRect1(10, 10, 520, 700);
  132. constexpr gfx::Size kSize1(540, 720);
  133. pdf.StartPage(kSize1, kRect1, 1.25, mojom::PageOrientation::kUpright);
  134. pdf.FinishPage();
  135. // Render page 2.
  136. constexpr gfx::Rect kRect2(10, 10, 520, 700);
  137. constexpr gfx::Size kSize2(720, 540);
  138. pdf.StartPage(kSize2, kRect2, 2.0, mojom::PageOrientation::kUpright);
  139. pdf.FinishPage();
  140. pdf.FinishDocument();
  141. // Check data size.
  142. const uint32_t size = pdf.GetDataSize();
  143. EXPECT_GT(size, 0U);
  144. // Get resulting data.
  145. std::vector<char> buffer(size, 0);
  146. pdf.GetData(&buffer.front(), size);
  147. // Test browser-side constructor.
  148. PdfMetafileCg pdf2;
  149. // TODO(thestig): Make `buffer` uint8_t and avoid the base::as_bytes() call.
  150. EXPECT_TRUE(pdf2.InitFromData(base::as_bytes(base::make_span(buffer))));
  151. // Get the first 4 characters from pdf2.
  152. std::vector<char> buffer2(4, 0);
  153. pdf2.GetData(&buffer2.front(), 4);
  154. // Test that the header begins with "%PDF".
  155. std::string header(&buffer2.front(), 4);
  156. EXPECT_EQ(0U, header.find("%PDF", 0));
  157. // Test that the PDF is correctly reconstructed.
  158. EXPECT_EQ(2U, pdf2.GetPageCount());
  159. gfx::Size page_size = pdf2.GetPageBounds(1).size();
  160. EXPECT_EQ(540, page_size.width());
  161. EXPECT_EQ(720, page_size.height());
  162. page_size = pdf2.GetPageBounds(2).size();
  163. EXPECT_EQ(720, page_size.width());
  164. EXPECT_EQ(540, page_size.height());
  165. }
  166. TEST(PdfMetafileCgTest, GetPageBounds) {
  167. // Get test data.
  168. base::FilePath pdf_file = GetPdfTestData("rectangles_multi_pages.pdf");
  169. ASSERT_FALSE(pdf_file.empty());
  170. std::string pdf_data;
  171. ASSERT_TRUE(base::ReadFileToString(pdf_file, &pdf_data));
  172. // Initialize and check metafile.
  173. PdfMetafileCg pdf_cg;
  174. ASSERT_TRUE(pdf_cg.InitFromData(base::as_bytes(base::make_span(pdf_data))));
  175. ASSERT_EQ(5u, pdf_cg.GetPageCount());
  176. // Since the input into GetPageBounds() is a 1-indexed page number, 0 and 6
  177. // are out of bounds.
  178. gfx::Rect bounds;
  179. for (size_t i : {0, 6}) {
  180. bounds = pdf_cg.GetPageBounds(i);
  181. EXPECT_EQ(0, bounds.x());
  182. EXPECT_EQ(0, bounds.y());
  183. EXPECT_EQ(0, bounds.width());
  184. EXPECT_EQ(0, bounds.height());
  185. }
  186. // Whereas 1-5 are in bounds.
  187. for (size_t i = 1; i < 6; ++i) {
  188. bounds = pdf_cg.GetPageBounds(i);
  189. EXPECT_EQ(0, bounds.x());
  190. EXPECT_EQ(0, bounds.y());
  191. EXPECT_EQ(200, bounds.width());
  192. EXPECT_EQ(250, bounds.height());
  193. }
  194. }
  195. TEST(PdfMetafileCgTest, RenderPortraitRectangles) {
  196. constexpr gfx::Rect kPageBounds(200, 300);
  197. constexpr gfx::Size kDestinationSize(200, 300);
  198. TestRenderPage("rectangles.pdf", /*page_number=*/1, kPageBounds,
  199. "render_portrait_rectangles_expected.0.png", kDestinationSize);
  200. }
  201. TEST(PdfMetafileCgTest, RenderAutorotatedPortraitRectangles) {
  202. constexpr gfx::Rect kPageBounds(200, 300);
  203. constexpr gfx::Size kDestinationSize(300, 200);
  204. TestRenderPage("rectangles.pdf", /*page_number=*/1, kPageBounds,
  205. "render_autorotated_portrait_rectangles_expected.0.png",
  206. kDestinationSize);
  207. }
  208. TEST(PdfMetafileCgTest, RenderLargePortraitRectangles) {
  209. constexpr gfx::Rect kPageBounds(200, 300);
  210. constexpr gfx::Size kDestinationSize(100, 120);
  211. TestRenderPage("rectangles.pdf", /*page_number=*/1, kPageBounds,
  212. "render_large_portrait_rectangles_expected.0.png",
  213. kDestinationSize);
  214. }
  215. TEST(PdfMetafileCgTest, RenderSmallPortraitRectangles) {
  216. constexpr gfx::Rect kPageBounds(200, 300);
  217. constexpr gfx::Size kDestinationSize(300, 450);
  218. TestRenderPage("rectangles.pdf", /*page_number=*/1, kPageBounds,
  219. "render_small_portrait_rectangles_expected.0.png",
  220. kDestinationSize);
  221. }
  222. TEST(PdfMetafileCgTest, RenderLandscapeRectangles) {
  223. constexpr gfx::Rect kPageBounds(800, 500);
  224. constexpr gfx::Size kDestinationSize(400, 600);
  225. TestRenderPage("landscape_rectangles.pdf", /*page_number=*/1, kPageBounds,
  226. "render_landscape_rectangles_expected.0.png",
  227. kDestinationSize);
  228. }
  229. TEST(PdfMetafileCgTest, RenderRotatedRectangles) {
  230. constexpr gfx::Rect kPageBounds(800, 500);
  231. constexpr gfx::Size kLandscapeDestinationSize(600, 400);
  232. constexpr gfx::Size kPortraitDestinationSize(400, 600);
  233. TestRenderPage("rotated_rectangles.pdf", /*page_number=*/1, kPageBounds,
  234. "render_rotated_rectangles_expected.0.png",
  235. kLandscapeDestinationSize);
  236. TestRenderPage("rotated_rectangles.pdf", /*page_number=*/2, kPageBounds,
  237. "render_rotated_rectangles_expected.1.png",
  238. kPortraitDestinationSize);
  239. TestRenderPage("rotated_rectangles.pdf", /*page_number=*/3, kPageBounds,
  240. "render_rotated_rectangles_expected.2.png",
  241. kLandscapeDestinationSize);
  242. TestRenderPage("rotated_rectangles.pdf", /*page_number=*/4, kPageBounds,
  243. "render_rotated_rectangles_expected.3.png",
  244. kPortraitDestinationSize);
  245. TestRenderPage("rotated_rectangles.pdf", /*page_number=*/1, kPageBounds,
  246. "render_autorotated_rotated_rectangles_expected.0.png",
  247. kPortraitDestinationSize);
  248. TestRenderPage("rotated_rectangles.pdf", /*page_number=*/2, kPageBounds,
  249. "render_autorotated_rotated_rectangles_expected.1.png",
  250. kLandscapeDestinationSize);
  251. TestRenderPage("rotated_rectangles.pdf", /*page_number=*/3, kPageBounds,
  252. "render_autorotated_rotated_rectangles_expected.2.png",
  253. kPortraitDestinationSize);
  254. TestRenderPage("rotated_rectangles.pdf", /*page_number=*/4, kPageBounds,
  255. "render_autorotated_rotated_rectangles_expected.3.png",
  256. kLandscapeDestinationSize);
  257. }
  258. TEST(PdfMetafileCgTest, RenderLargeLandscapeRectangles) {
  259. constexpr gfx::Rect kPageBounds(800, 500);
  260. constexpr gfx::Size kDestinationSize(200, 300);
  261. TestRenderPage("landscape_rectangles.pdf", /*page_number=*/1, kPageBounds,
  262. "render_large_landscape_rectangles_expected.0.png",
  263. kDestinationSize);
  264. }
  265. TEST(PdfMetafileCgTest, RenderSmallLandscapeRectangles) {
  266. constexpr gfx::Rect kPageBounds(800, 500);
  267. constexpr gfx::Size kDestinationSize(600, 900);
  268. TestRenderPage("landscape_rectangles.pdf", /*page_number=*/1, kPageBounds,
  269. "render_small_landscape_rectangles_expected.0.png",
  270. kDestinationSize);
  271. }
  272. TEST(PdfMetafileCgTest, RenderScaledLargeLandscapeRectangles) {
  273. constexpr gfx::Rect kPageBounds(800, 500);
  274. constexpr gfx::Size kDestinationSize(300, 450);
  275. TestRenderPageWithTransformParams(
  276. "landscape_rectangles.pdf", /*page_number=*/1, kPageBounds,
  277. "render_scaled_large_landscape_rectangles_expected.0.png",
  278. kDestinationSize,
  279. /*autorotate=*/true, /*fit_to_page=*/true);
  280. }
  281. TEST(PdfMetafileCgTest, RenderScaledSmallLandscapeRectangles) {
  282. constexpr gfx::Rect kPageBounds(800, 500);
  283. constexpr gfx::Size kDestinationSize(600, 900);
  284. TestRenderPageWithTransformParams(
  285. "landscape_rectangles.pdf", /*page_number=*/1, kPageBounds,
  286. "render_scaled_small_landscape_rectangles_expected.0.png",
  287. kDestinationSize,
  288. /*autorotate=*/true, /*fit_to_page=*/true);
  289. }
  290. } // namespace printing