1 // Copyright 2015 PDFium 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 
5 #include <cmath>
6 #include <limits>
7 #include <memory>
8 #include <string>
9 #include <vector>
10 
11 #include "build/build_config.h"
12 #include "core/fpdfapi/parser/cpdf_document.h"
13 #include "fpdfsdk/cpdfsdk_helpers.h"
14 #include "fpdfsdk/fpdf_view_c_api_test.h"
15 #include "public/cpp/fpdf_scopers.h"
16 #include "public/fpdfview.h"
17 #include "testing/embedder_test.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "testing/utils/file_util.h"
20 #include "testing/utils/path_service.h"
21 
22 namespace {
23 
24 #if defined(OS_WIN)
25 const char kExpectedRectanglePostScript[] = R"(
26 save
27 /im/initmatrix load def
28 /n/newpath load def/m/moveto load def/l/lineto load def/c/curveto load def/h/closepath load def
29 /f/fill load def/F/eofill load def/s/stroke load def/W/clip load def/W*/eoclip load def
30 /rg/setrgbcolor load def/k/setcmykcolor load def
31 /J/setlinecap load def/j/setlinejoin load def/w/setlinewidth load def/M/setmiterlimit load def/d/setdash load def
32 /q/gsave load def/Q/grestore load def/iM/imagemask load def
33 /Tj/show load def/Ff/findfont load def/Fs/scalefont load def/Sf/setfont load def
34 /cm/concat load def/Cm/currentmatrix load def/mx/matrix load def/sm/setmatrix load def
35 0 300 m 0 0 l 200 0 l 200 300 l 0 300 l h W n
36 q
37 0 300 m 0 0 l 200 0 l 200 300 l 0 300 l h W n
38 q
39 0 J
40 []0 d
41 0 j
42 1 w
43 10 M
44 mx Cm [1 0 0 -1 0 300]cm 0 290 m 10 290 l 10 300 l 0 300 l 0 290 l h 0 0 0 rg
45 q F Q s sm
46 mx Cm [1 0 0 -1 0 300]cm 10 150 m 60 150 l 60 180 l 10 180 l 10 150 l h q F Q s sm
47 mx Cm [1 0 0 -1 0 300]cm 190 290 m 200 290 l 200 300 l 190 300 l 190 290 l h 0 0 1 rg
48 q F Q 0 0 0 rg
49 s sm
50 mx Cm [1 0 0 -1 0 300]cm 70 232 m 120 232 l 120 262 l 70 262 l 70 232 l h 0 0 1 rg
51 q F Q 0 0 0 rg
52 s sm
53 mx Cm [1 0 0 -1 0 300]cm 190 0 m 200 0 l 200 10 l 190 10 l 190 0 l h 0 1 0 rg
54 q F Q 0 0 0 rg
55 s sm
56 mx Cm [1 0 0 -1 0 300]cm 130 150 m 180 150 l 180 180 l 130 180 l 130 150 l h 0 1 0 rg
57 q F Q 0 0 0 rg
58 s sm
59 mx Cm [1 0 0 -1 0 300]cm 0 0 m 10 0 l 10 10 l 0 10 l 0 0 l h 1 0 0 rg
60 q F Q 0 0 0 rg
61 s sm
62 mx Cm [1 0 0 -1 0 300]cm 70 67 m 120 67 l 120 97 l 70 97 l 70 67 l h 1 0 0 rg
63 q F Q 0 0 0 rg
64 s sm
65 Q
66 Q
67 Q
68 
69 restore
70 )";
71 #endif  // defined(OS_WIN)
72 
73 class MockDownloadHints final : public FX_DOWNLOADHINTS {
74  public:
SAddSegment(FX_DOWNLOADHINTS * pThis,size_t offset,size_t size)75   static void SAddSegment(FX_DOWNLOADHINTS* pThis, size_t offset, size_t size) {
76   }
77 
MockDownloadHints()78   MockDownloadHints() {
79     FX_DOWNLOADHINTS::version = 1;
80     FX_DOWNLOADHINTS::AddSegment = SAddSegment;
81   }
82 
~MockDownloadHints()83   ~MockDownloadHints() {}
84 };
85 
86 }  // namespace
87 
TEST(fpdf,CApiTest)88 TEST(fpdf, CApiTest) {
89   EXPECT_TRUE(CheckPDFiumCApi());
90 }
91 
92 class FPDFViewEmbedderTest : public EmbedderTest {
93  protected:
TestRenderPageBitmapWithMatrix(FPDF_PAGE page,int bitmap_width,int bitmap_height,const FS_MATRIX & matrix,const FS_RECTF & rect,const char * expected_md5)94   void TestRenderPageBitmapWithMatrix(FPDF_PAGE page,
95                                       int bitmap_width,
96                                       int bitmap_height,
97                                       const FS_MATRIX& matrix,
98                                       const FS_RECTF& rect,
99                                       const char* expected_md5) {
100     ScopedFPDFBitmap bitmap(FPDFBitmap_Create(bitmap_width, bitmap_height, 0));
101     FPDFBitmap_FillRect(bitmap.get(), 0, 0, bitmap_width, bitmap_height,
102                         0xFFFFFFFF);
103     FPDF_RenderPageBitmapWithMatrix(bitmap.get(), page, &matrix, &rect, 0);
104     CompareBitmap(bitmap.get(), bitmap_width, bitmap_height, expected_md5);
105   }
106 
TestRenderPageBitmapWithFlags(FPDF_PAGE page,int flags,const char * expected_md5)107   void TestRenderPageBitmapWithFlags(FPDF_PAGE page,
108                                      int flags,
109                                      const char* expected_md5) {
110     int bitmap_width = static_cast<int>(FPDF_GetPageWidth(page));
111     int bitmap_height = static_cast<int>(FPDF_GetPageHeight(page));
112     ScopedFPDFBitmap bitmap(FPDFBitmap_Create(bitmap_width, bitmap_height, 0));
113     FPDFBitmap_FillRect(bitmap.get(), 0, 0, bitmap_width, bitmap_height,
114                         0xFFFFFFFF);
115     FPDF_RenderPageBitmap(bitmap.get(), page, 0, 0, bitmap_width, bitmap_height,
116                           0, flags);
117     CompareBitmap(bitmap.get(), bitmap_width, bitmap_height, expected_md5);
118   }
119 
TestRenderPageBitmapWithExternalMemory(FPDF_PAGE page,int format,const char * expected_md5)120   void TestRenderPageBitmapWithExternalMemory(FPDF_PAGE page,
121                                               int format,
122                                               const char* expected_md5) {
123     int bitmap_width = static_cast<int>(FPDF_GetPageWidth(page));
124     int bitmap_height = static_cast<int>(FPDF_GetPageHeight(page));
125     int bytes_per_pixel = BytesPerPixelForFormat(format);
126     ASSERT_NE(0, bytes_per_pixel);
127 
128     int bitmap_stride = bytes_per_pixel * bitmap_width;
129     std::vector<uint8_t> external_memory(bitmap_stride * bitmap_height);
130     ScopedFPDFBitmap bitmap(FPDFBitmap_CreateEx(bitmap_width, bitmap_height,
131                                                 format, external_memory.data(),
132                                                 bitmap_stride));
133     FPDFBitmap_FillRect(bitmap.get(), 0, 0, bitmap_width, bitmap_height,
134                         0xFFFFFFFF);
135     FPDF_RenderPageBitmap(bitmap.get(), page, 0, 0, bitmap_width, bitmap_height,
136                           0, 0);
137     CompareBitmap(bitmap.get(), bitmap_width, bitmap_height, expected_md5);
138   }
139 };
140 
141 // Test for conversion of a point in device coordinates to page coordinates
TEST_F(FPDFViewEmbedderTest,DeviceCoordinatesToPageCoordinates)142 TEST_F(FPDFViewEmbedderTest, DeviceCoordinatesToPageCoordinates) {
143   EXPECT_TRUE(OpenDocument("about_blank.pdf"));
144   FPDF_PAGE page = LoadPage(0);
145   EXPECT_NE(nullptr, page);
146 
147   // Error tolerance for floating point comparison
148   const double kTolerance = 0.0001;
149 
150   // Display bounds in device coordinates
151   int start_x = 0;
152   int start_y = 0;
153   int size_x = 640;
154   int size_y = 480;
155 
156   // Page Orientation normal
157   int rotate = 0;
158 
159   // Device coordinate to be converted
160   int device_x = 10;
161   int device_y = 10;
162 
163   double page_x = 0.0;
164   double page_y = 0.0;
165   EXPECT_TRUE(FPDF_DeviceToPage(page, start_x, start_y, size_x, size_y, rotate,
166                                 device_x, device_y, &page_x, &page_y));
167   EXPECT_NEAR(9.5625, page_x, kTolerance);
168   EXPECT_NEAR(775.5, page_y, kTolerance);
169 
170   // Rotate 90 degrees clockwise
171   rotate = 1;
172   EXPECT_TRUE(FPDF_DeviceToPage(page, start_x, start_y, size_x, size_y, rotate,
173                                 device_x, device_y, &page_x, &page_y));
174   EXPECT_NEAR(12.75, page_x, kTolerance);
175   EXPECT_NEAR(12.375, page_y, kTolerance);
176 
177   // Rotate 180 degrees
178   rotate = 2;
179   EXPECT_TRUE(FPDF_DeviceToPage(page, start_x, start_y, size_x, size_y, rotate,
180                                 device_x, device_y, &page_x, &page_y));
181   EXPECT_NEAR(602.4374, page_x, kTolerance);
182   EXPECT_NEAR(16.5, page_y, kTolerance);
183 
184   // Rotate 90 degrees counter-clockwise
185   rotate = 3;
186   EXPECT_TRUE(FPDF_DeviceToPage(page, start_x, start_y, size_x, size_y, rotate,
187                                 device_x, device_y, &page_x, &page_y));
188   EXPECT_NEAR(599.25, page_x, kTolerance);
189   EXPECT_NEAR(779.625, page_y, kTolerance);
190 
191   // FPDF_DeviceToPage() converts |rotate| into legal rotation by taking
192   // modulo by 4. A value of 4 is expected to be converted into 0 (normal
193   // rotation)
194   rotate = 4;
195   EXPECT_TRUE(FPDF_DeviceToPage(page, start_x, start_y, size_x, size_y, rotate,
196                                 device_x, device_y, &page_x, &page_y));
197   EXPECT_NEAR(9.5625, page_x, kTolerance);
198   EXPECT_NEAR(775.5, page_y, kTolerance);
199 
200   // FPDF_DeviceToPage returns untransformed coordinates if |rotate| % 4 is
201   // negative.
202   rotate = -1;
203   EXPECT_TRUE(FPDF_DeviceToPage(page, start_x, start_y, size_x, size_y, rotate,
204                                 device_x, device_y, &page_x, &page_y));
205   EXPECT_NEAR(device_x, page_x, kTolerance);
206   EXPECT_NEAR(device_y, page_y, kTolerance);
207 
208   // Negative case - invalid page
209   page_x = 1234.0;
210   page_y = 5678.0;
211   EXPECT_FALSE(FPDF_DeviceToPage(nullptr, start_x, start_y, size_x, size_y,
212                                  rotate, device_x, device_y, &page_x, &page_y));
213   // Out parameters are expected to remain unchanged
214   EXPECT_NEAR(1234.0, page_x, kTolerance);
215   EXPECT_NEAR(5678.0, page_y, kTolerance);
216 
217   // Negative case - invalid output parameters
218   EXPECT_FALSE(FPDF_DeviceToPage(page, start_x, start_y, size_x, size_y, rotate,
219                                  device_x, device_y, nullptr, nullptr));
220 
221   UnloadPage(page);
222 }
223 
224 // Test for conversion of a point in page coordinates to device coordinates.
TEST_F(FPDFViewEmbedderTest,PageCoordinatesToDeviceCoordinates)225 TEST_F(FPDFViewEmbedderTest, PageCoordinatesToDeviceCoordinates) {
226   EXPECT_TRUE(OpenDocument("about_blank.pdf"));
227   FPDF_PAGE page = LoadPage(0);
228   EXPECT_NE(nullptr, page);
229 
230   // Display bounds in device coordinates
231   int start_x = 0;
232   int start_y = 0;
233   int size_x = 640;
234   int size_y = 480;
235 
236   // Page Orientation normal
237   int rotate = 0;
238 
239   // Page coordinate to be converted
240   double page_x = 9.0;
241   double page_y = 775.0;
242 
243   int device_x = 0;
244   int device_y = 0;
245   EXPECT_TRUE(FPDF_PageToDevice(page, start_x, start_y, size_x, size_y, rotate,
246                                 page_x, page_y, &device_x, &device_y));
247 
248   EXPECT_EQ(9, device_x);
249   EXPECT_EQ(10, device_y);
250 
251   // Rotate 90 degrees clockwise
252   rotate = 1;
253   EXPECT_TRUE(FPDF_PageToDevice(page, start_x, start_y, size_x, size_y, rotate,
254                                 page_x, page_y, &device_x, &device_y));
255   EXPECT_EQ(626, device_x);
256   EXPECT_EQ(7, device_y);
257 
258   // Rotate 180 degrees
259   rotate = 2;
260   EXPECT_TRUE(FPDF_PageToDevice(page, start_x, start_y, size_x, size_y, rotate,
261                                 page_x, page_y, &device_x, &device_y));
262   EXPECT_EQ(631, device_x);
263   EXPECT_EQ(470, device_y);
264 
265   // Rotate 90 degrees counter-clockwise
266   rotate = 3;
267   EXPECT_TRUE(FPDF_PageToDevice(page, start_x, start_y, size_x, size_y, rotate,
268                                 page_x, page_y, &device_x, &device_y));
269   EXPECT_EQ(14, device_x);
270   EXPECT_EQ(473, device_y);
271 
272   // FPDF_PageToDevice() converts |rotate| into legal rotation by taking
273   // modulo by 4. A value of 4 is expected to be converted into 0 (normal
274   // rotation)
275   rotate = 4;
276   EXPECT_TRUE(FPDF_PageToDevice(page, start_x, start_y, size_x, size_y, rotate,
277                                 page_x, page_y, &device_x, &device_y));
278   EXPECT_EQ(9, device_x);
279   EXPECT_EQ(10, device_y);
280 
281   // FPDF_PageToDevice() returns untransformed coordinates if |rotate| % 4 is
282   // negative.
283   rotate = -1;
284   EXPECT_TRUE(FPDF_PageToDevice(page, start_x, start_y, size_x, size_y, rotate,
285                                 page_x, page_y, &device_x, &device_y));
286   EXPECT_EQ(start_x, device_x);
287   EXPECT_EQ(start_y, device_y);
288 
289   // Negative case - invalid page
290   device_x = 1234;
291   device_y = 5678;
292   EXPECT_FALSE(FPDF_PageToDevice(nullptr, start_x, start_y, size_x, size_y,
293                                  rotate, page_x, page_y, &device_x, &device_y));
294   // Out parameters are expected to remain unchanged
295   EXPECT_EQ(1234, device_x);
296   EXPECT_EQ(5678, device_y);
297 
298   // Negative case - invalid output parameters
299   EXPECT_FALSE(FPDF_PageToDevice(page, start_x, start_y, size_x, size_y, rotate,
300                                  page_x, page_y, nullptr, nullptr));
301 
302   UnloadPage(page);
303 }
304 
TEST_F(FPDFViewEmbedderTest,MultipleInitDestroy)305 TEST_F(FPDFViewEmbedderTest, MultipleInitDestroy) {
306   FPDF_InitLibrary();  // Redundant given call in SetUp(), but safe.
307   FPDF_InitLibrary();  // Doubly-redundant even, but safe.
308 
309   EXPECT_TRUE(OpenDocument("about_blank.pdf"));
310   CloseDocument();
311   CloseDocument();  // Redundant given above, but safe.
312   CloseDocument();  // Doubly-redundant even, but safe.
313 
314   FPDF_DestroyLibrary();  // Doubly-redundant even, but safe.
315   FPDF_DestroyLibrary();  // Redundant given call in TearDown(), but safe.
316 }
317 
TEST_F(FPDFViewEmbedderTest,Document)318 TEST_F(FPDFViewEmbedderTest, Document) {
319   EXPECT_TRUE(OpenDocument("about_blank.pdf"));
320   EXPECT_EQ(1, GetPageCount());
321   EXPECT_EQ(0, GetFirstPageNum());
322 
323   int version;
324   EXPECT_TRUE(FPDF_GetFileVersion(document(), &version));
325   EXPECT_EQ(14, version);
326 
327   EXPECT_EQ(0xFFFFFFFF, FPDF_GetDocPermissions(document()));
328   EXPECT_EQ(-1, FPDF_GetSecurityHandlerRevision(document()));
329 }
330 
TEST_F(FPDFViewEmbedderTest,LoadNonexistentDocument)331 TEST_F(FPDFViewEmbedderTest, LoadNonexistentDocument) {
332   FPDF_DOCUMENT doc = FPDF_LoadDocument("nonexistent_document.pdf", "");
333   ASSERT_FALSE(doc);
334   EXPECT_EQ(static_cast<int>(FPDF_GetLastError()), FPDF_ERR_FILE);
335 }
336 
337 // See https://crbug.com/pdfium/465
TEST_F(FPDFViewEmbedderTest,EmptyDocument)338 TEST_F(FPDFViewEmbedderTest, EmptyDocument) {
339   EXPECT_TRUE(CreateEmptyDocument());
340   {
341     int version = 42;
342     EXPECT_FALSE(FPDF_GetFileVersion(document(), &version));
343     EXPECT_EQ(0, version);
344   }
345   {
346 #ifdef PDF_ENABLE_XFA
347     const unsigned long kExpected = static_cast<uint32_t>(-1);
348 #else   // PDF_ENABLE_XFA
349     const unsigned long kExpected = 0;
350 #endif  // PDF_ENABLE_XFA
351     EXPECT_EQ(kExpected, FPDF_GetDocPermissions(document()));
352   }
353   EXPECT_EQ(-1, FPDF_GetSecurityHandlerRevision(document()));
354   EXPECT_EQ(0, FPDF_GetPageCount(document()));
355   EXPECT_TRUE(FPDF_VIEWERREF_GetPrintScaling(document()));
356   EXPECT_EQ(1, FPDF_VIEWERREF_GetNumCopies(document()));
357   EXPECT_EQ(DuplexUndefined, FPDF_VIEWERREF_GetDuplex(document()));
358 
359   char buf[100];
360   EXPECT_EQ(0U, FPDF_VIEWERREF_GetName(document(), "foo", nullptr, 0));
361   EXPECT_EQ(0U, FPDF_VIEWERREF_GetName(document(), "foo", buf, sizeof(buf)));
362   EXPECT_EQ(0u, FPDF_CountNamedDests(document()));
363 }
364 
TEST_F(FPDFViewEmbedderTest,SandboxDocument)365 TEST_F(FPDFViewEmbedderTest, SandboxDocument) {
366   uint16_t buf[200];
367   unsigned long len;
368 
369   ASSERT_TRUE(CreateEmptyDocument());
370   len = FPDF_GetMetaText(document(), "CreationDate", buf, sizeof(buf));
371   EXPECT_GT(len, 2u);  // Not just "double NUL" end-of-string indicator.
372   EXPECT_NE(0u, buf[0]);
373   CloseDocument();
374 
375   FPDF_SetSandBoxPolicy(FPDF_POLICY_MACHINETIME_ACCESS, false);
376   ASSERT_TRUE(CreateEmptyDocument());
377   len = FPDF_GetMetaText(document(), "CreationDate", buf, sizeof(buf));
378   EXPECT_EQ(2u, len);  // Only a "double NUL" end-of-string indicator.
379   EXPECT_EQ(0u, buf[0]);
380   CloseDocument();
381 
382   constexpr unsigned long kNoSuchPolicy = 102;
383   FPDF_SetSandBoxPolicy(kNoSuchPolicy, true);
384   ASSERT_TRUE(CreateEmptyDocument());
385   len = FPDF_GetMetaText(document(), "CreationDate", buf, sizeof(buf));
386   EXPECT_EQ(2u, len);  // Only a "double NUL" end-of-string indicator.
387   EXPECT_EQ(0u, buf[0]);
388   CloseDocument();
389 
390   FPDF_SetSandBoxPolicy(FPDF_POLICY_MACHINETIME_ACCESS, true);
391   ASSERT_TRUE(CreateEmptyDocument());
392   len = FPDF_GetMetaText(document(), "CreationDate", buf, sizeof(buf));
393   EXPECT_GT(len, 2u);  // Not just "double NUL" end-of-string indicator.
394   EXPECT_NE(0u, buf[0]);
395   CloseDocument();
396 }
397 
TEST_F(FPDFViewEmbedderTest,LinearizedDocument)398 TEST_F(FPDFViewEmbedderTest, LinearizedDocument) {
399   EXPECT_TRUE(OpenDocumentLinearized("feature_linearized_loading.pdf"));
400   int version;
401   EXPECT_TRUE(FPDF_GetFileVersion(document(), &version));
402   EXPECT_EQ(16, version);
403 }
404 
TEST_F(FPDFViewEmbedderTest,LoadCustomDocumentWithoutFileAccess)405 TEST_F(FPDFViewEmbedderTest, LoadCustomDocumentWithoutFileAccess) {
406   EXPECT_FALSE(FPDF_LoadCustomDocument(nullptr, ""));
407 }
408 
409 // See https://crbug.com/pdfium/1261
TEST_F(FPDFViewEmbedderTest,LoadCustomDocumentWithShortLivedFileAccess)410 TEST_F(FPDFViewEmbedderTest, LoadCustomDocumentWithShortLivedFileAccess) {
411   std::string file_contents_string;  // Must outlive |doc|.
412   ScopedFPDFDocument doc;
413   {
414     // Read a PDF, and copy it into |file_contents_string|.
415     std::string pdf_path;
416     size_t pdf_length;
417     ASSERT_TRUE(PathService::GetTestFilePath("rectangles.pdf", &pdf_path));
418     auto file_contents = GetFileContents(pdf_path.c_str(), &pdf_length);
419     ASSERT_TRUE(file_contents);
420     for (size_t i = 0; i < pdf_length; ++i)
421       file_contents_string.push_back(file_contents.get()[i]);
422 
423     // Define a FPDF_FILEACCESS object that will go out of scope, while the
424     // loaded document in |doc| remains valid.
425     FPDF_FILEACCESS file_access = {};
426     file_access.m_FileLen = pdf_length;
427     file_access.m_GetBlock = GetBlockFromString;
428     file_access.m_Param = &file_contents_string;
429     doc.reset(FPDF_LoadCustomDocument(&file_access, nullptr));
430     ASSERT_TRUE(doc);
431   }
432 
433   // Now try to access |doc| and make sure it still works.
434   ScopedFPDFPage page(FPDF_LoadPage(doc.get(), 0));
435   ASSERT_TRUE(page);
436   EXPECT_FLOAT_EQ(200.0f, FPDF_GetPageWidthF(page.get()));
437   EXPECT_FLOAT_EQ(300.0f, FPDF_GetPageHeightF(page.get()));
438 }
439 
TEST_F(FPDFViewEmbedderTest,Page)440 TEST_F(FPDFViewEmbedderTest, Page) {
441   EXPECT_TRUE(OpenDocument("about_blank.pdf"));
442   FPDF_PAGE page = LoadPage(0);
443   EXPECT_TRUE(page);
444 
445   EXPECT_FLOAT_EQ(612.0f, FPDF_GetPageWidthF(page));
446   EXPECT_FLOAT_EQ(792.0f, FPDF_GetPageHeightF(page));
447 
448   FS_RECTF rect;
449   EXPECT_TRUE(FPDF_GetPageBoundingBox(page, &rect));
450   EXPECT_EQ(0.0, rect.left);
451   EXPECT_EQ(0.0, rect.bottom);
452   EXPECT_EQ(612.0, rect.right);
453   EXPECT_EQ(792.0, rect.top);
454 
455   // Null arguments return errors rather than crashing,
456   EXPECT_EQ(0.0, FPDF_GetPageWidth(nullptr));
457   EXPECT_EQ(0.0, FPDF_GetPageHeight(nullptr));
458   EXPECT_FALSE(FPDF_GetPageBoundingBox(nullptr, &rect));
459   EXPECT_FALSE(FPDF_GetPageBoundingBox(page, nullptr));
460 
461   UnloadPage(page);
462   EXPECT_FALSE(LoadPage(1));
463 }
464 
TEST_F(FPDFViewEmbedderTest,ViewerRefDummy)465 TEST_F(FPDFViewEmbedderTest, ViewerRefDummy) {
466   EXPECT_TRUE(OpenDocument("about_blank.pdf"));
467   EXPECT_TRUE(FPDF_VIEWERREF_GetPrintScaling(document()));
468   EXPECT_EQ(1, FPDF_VIEWERREF_GetNumCopies(document()));
469   EXPECT_EQ(DuplexUndefined, FPDF_VIEWERREF_GetDuplex(document()));
470 
471   char buf[100];
472   EXPECT_EQ(0U, FPDF_VIEWERREF_GetName(document(), "foo", nullptr, 0));
473   EXPECT_EQ(0U, FPDF_VIEWERREF_GetName(document(), "foo", buf, sizeof(buf)));
474 
475   FPDF_PAGERANGE page_range = FPDF_VIEWERREF_GetPrintPageRange(document());
476   EXPECT_FALSE(page_range);
477   EXPECT_EQ(0U, FPDF_VIEWERREF_GetPrintPageRangeCount(page_range));
478   EXPECT_EQ(-1, FPDF_VIEWERREF_GetPrintPageRangeElement(page_range, 0));
479   EXPECT_EQ(-1, FPDF_VIEWERREF_GetPrintPageRangeElement(page_range, 1));
480 }
481 
TEST_F(FPDFViewEmbedderTest,ViewerRef)482 TEST_F(FPDFViewEmbedderTest, ViewerRef) {
483   EXPECT_TRUE(OpenDocument("viewer_ref.pdf"));
484   EXPECT_TRUE(FPDF_VIEWERREF_GetPrintScaling(document()));
485   EXPECT_EQ(5, FPDF_VIEWERREF_GetNumCopies(document()));
486   EXPECT_EQ(DuplexUndefined, FPDF_VIEWERREF_GetDuplex(document()));
487 
488   // Test some corner cases.
489   char buf[100];
490   EXPECT_EQ(0U, FPDF_VIEWERREF_GetName(document(), "", buf, sizeof(buf)));
491   EXPECT_EQ(0U, FPDF_VIEWERREF_GetName(document(), "foo", nullptr, 0));
492   EXPECT_EQ(0U, FPDF_VIEWERREF_GetName(document(), "foo", buf, sizeof(buf)));
493 
494   // Make sure |buf| does not get written into when it appears to be too small.
495   // NOLINTNEXTLINE(runtime/printf)
496   strcpy(buf, "ABCD");
497   EXPECT_EQ(4U, FPDF_VIEWERREF_GetName(document(), "Foo", buf, 1));
498   EXPECT_STREQ("ABCD", buf);
499 
500   // Note "Foo" is a different key from "foo".
501   EXPECT_EQ(4U,
502             FPDF_VIEWERREF_GetName(document(), "Foo", nullptr, sizeof(buf)));
503   ASSERT_EQ(4U, FPDF_VIEWERREF_GetName(document(), "Foo", buf, sizeof(buf)));
504   EXPECT_STREQ("foo", buf);
505 
506   // Try to retrieve a boolean and an integer.
507   EXPECT_EQ(
508       0U, FPDF_VIEWERREF_GetName(document(), "HideToolbar", buf, sizeof(buf)));
509   EXPECT_EQ(0U,
510             FPDF_VIEWERREF_GetName(document(), "NumCopies", buf, sizeof(buf)));
511 
512   // Try more valid cases.
513   ASSERT_EQ(4U,
514             FPDF_VIEWERREF_GetName(document(), "Direction", buf, sizeof(buf)));
515   EXPECT_STREQ("R2L", buf);
516   ASSERT_EQ(8U,
517             FPDF_VIEWERREF_GetName(document(), "ViewArea", buf, sizeof(buf)));
518   EXPECT_STREQ("CropBox", buf);
519 
520   FPDF_PAGERANGE page_range = FPDF_VIEWERREF_GetPrintPageRange(document());
521   EXPECT_TRUE(page_range);
522   EXPECT_EQ(4U, FPDF_VIEWERREF_GetPrintPageRangeCount(page_range));
523   EXPECT_EQ(0, FPDF_VIEWERREF_GetPrintPageRangeElement(page_range, 0));
524   EXPECT_EQ(2, FPDF_VIEWERREF_GetPrintPageRangeElement(page_range, 1));
525   EXPECT_EQ(4, FPDF_VIEWERREF_GetPrintPageRangeElement(page_range, 2));
526   EXPECT_EQ(4, FPDF_VIEWERREF_GetPrintPageRangeElement(page_range, 3));
527   EXPECT_EQ(-1, FPDF_VIEWERREF_GetPrintPageRangeElement(page_range, 4));
528 }
529 
TEST_F(FPDFViewEmbedderTest,NamedDests)530 TEST_F(FPDFViewEmbedderTest, NamedDests) {
531   EXPECT_TRUE(OpenDocument("named_dests.pdf"));
532   long buffer_size;
533   char fixed_buffer[512];
534   FPDF_DEST dest;
535 
536   // Query the size of the first item.
537   buffer_size = 2000000;  // Absurdly large, check not used for this case.
538   dest = FPDF_GetNamedDest(document(), 0, nullptr, &buffer_size);
539   EXPECT_NE(nullptr, dest);
540   EXPECT_EQ(12, buffer_size);
541 
542   // Try to retrieve the first item with too small a buffer.
543   buffer_size = 10;
544   dest = FPDF_GetNamedDest(document(), 0, fixed_buffer, &buffer_size);
545   EXPECT_NE(nullptr, dest);
546   EXPECT_EQ(-1, buffer_size);
547 
548   // Try to retrieve the first item with correctly sized buffer. Item is
549   // taken from Dests NameTree in named_dests.pdf.
550   buffer_size = 12;
551   dest = FPDF_GetNamedDest(document(), 0, fixed_buffer, &buffer_size);
552   EXPECT_NE(nullptr, dest);
553   EXPECT_EQ(12, buffer_size);
554   EXPECT_EQ(std::string("F\0i\0r\0s\0t\0\0\0", 12),
555             std::string(fixed_buffer, buffer_size));
556 
557   // Try to retrieve the second item with ample buffer. Item is taken
558   // from Dests NameTree but has a sub-dictionary in named_dests.pdf.
559   buffer_size = sizeof(fixed_buffer);
560   dest = FPDF_GetNamedDest(document(), 1, fixed_buffer, &buffer_size);
561   EXPECT_NE(nullptr, dest);
562   EXPECT_EQ(10, buffer_size);
563   EXPECT_EQ(std::string("N\0e\0x\0t\0\0\0", 10),
564             std::string(fixed_buffer, buffer_size));
565 
566   // Try to retrieve third item with ample buffer. Item is taken
567   // from Dests NameTree but has a bad sub-dictionary in named_dests.pdf.
568   // in named_dests.pdf).
569   buffer_size = sizeof(fixed_buffer);
570   dest = FPDF_GetNamedDest(document(), 2, fixed_buffer, &buffer_size);
571   EXPECT_EQ(nullptr, dest);
572   EXPECT_EQ(sizeof(fixed_buffer),
573             static_cast<size_t>(buffer_size));  // unmodified.
574 
575   // Try to retrieve the forth item with ample buffer. Item is taken
576   // from Dests NameTree but has a vale of the wrong type in named_dests.pdf.
577   buffer_size = sizeof(fixed_buffer);
578   dest = FPDF_GetNamedDest(document(), 3, fixed_buffer, &buffer_size);
579   EXPECT_EQ(nullptr, dest);
580   EXPECT_EQ(sizeof(fixed_buffer),
581             static_cast<size_t>(buffer_size));  // unmodified.
582 
583   // Try to retrieve fifth item with ample buffer. Item taken from the
584   // old-style Dests dictionary object in named_dests.pdf.
585   buffer_size = sizeof(fixed_buffer);
586   dest = FPDF_GetNamedDest(document(), 4, fixed_buffer, &buffer_size);
587   EXPECT_NE(nullptr, dest);
588   EXPECT_EQ(30, buffer_size);
589   EXPECT_EQ(std::string("F\0i\0r\0s\0t\0A\0l\0t\0e\0r\0n\0a\0t\0e\0\0\0", 30),
590             std::string(fixed_buffer, buffer_size));
591 
592   // Try to retrieve sixth item with ample buffer. Item istaken from the
593   // old-style Dests dictionary object but has a sub-dictionary in
594   // named_dests.pdf.
595   buffer_size = sizeof(fixed_buffer);
596   dest = FPDF_GetNamedDest(document(), 5, fixed_buffer, &buffer_size);
597   EXPECT_NE(nullptr, dest);
598   EXPECT_EQ(28, buffer_size);
599   EXPECT_EQ(std::string("L\0a\0s\0t\0A\0l\0t\0e\0r\0n\0a\0t\0e\0\0\0", 28),
600             std::string(fixed_buffer, buffer_size));
601 
602   // Try to retrieve non-existent item with ample buffer.
603   buffer_size = sizeof(fixed_buffer);
604   dest = FPDF_GetNamedDest(document(), 6, fixed_buffer, &buffer_size);
605   EXPECT_EQ(nullptr, dest);
606   EXPECT_EQ(sizeof(fixed_buffer),
607             static_cast<size_t>(buffer_size));  // unmodified.
608 
609   // Try to underflow/overflow the integer index.
610   buffer_size = sizeof(fixed_buffer);
611   dest = FPDF_GetNamedDest(document(), std::numeric_limits<int>::max(),
612                            fixed_buffer, &buffer_size);
613   EXPECT_EQ(nullptr, dest);
614   EXPECT_EQ(sizeof(fixed_buffer),
615             static_cast<size_t>(buffer_size));  // unmodified.
616 
617   buffer_size = sizeof(fixed_buffer);
618   dest = FPDF_GetNamedDest(document(), std::numeric_limits<int>::min(),
619                            fixed_buffer, &buffer_size);
620   EXPECT_EQ(nullptr, dest);
621   EXPECT_EQ(sizeof(fixed_buffer),
622             static_cast<size_t>(buffer_size));  // unmodified.
623 
624   buffer_size = sizeof(fixed_buffer);
625   dest = FPDF_GetNamedDest(document(), -1, fixed_buffer, &buffer_size);
626   EXPECT_EQ(nullptr, dest);
627   EXPECT_EQ(sizeof(fixed_buffer),
628             static_cast<size_t>(buffer_size));  // unmodified.
629 }
630 
TEST_F(FPDFViewEmbedderTest,NamedDestsByName)631 TEST_F(FPDFViewEmbedderTest, NamedDestsByName) {
632   EXPECT_TRUE(OpenDocument("named_dests.pdf"));
633 
634   // Null pointer returns nullptr.
635   FPDF_DEST dest = FPDF_GetNamedDestByName(document(), nullptr);
636   EXPECT_EQ(nullptr, dest);
637 
638   // Empty string returns nullptr.
639   dest = FPDF_GetNamedDestByName(document(), "");
640   EXPECT_EQ(nullptr, dest);
641 
642   // Item from Dests NameTree.
643   dest = FPDF_GetNamedDestByName(document(), "First");
644   EXPECT_NE(nullptr, dest);
645 
646   long ignore_len = 0;
647   FPDF_DEST dest_by_index =
648       FPDF_GetNamedDest(document(), 0, nullptr, &ignore_len);
649   EXPECT_EQ(dest_by_index, dest);
650 
651   // Item from Dests dictionary.
652   dest = FPDF_GetNamedDestByName(document(), "FirstAlternate");
653   EXPECT_NE(nullptr, dest);
654 
655   ignore_len = 0;
656   dest_by_index = FPDF_GetNamedDest(document(), 4, nullptr, &ignore_len);
657   EXPECT_EQ(dest_by_index, dest);
658 
659   // Bad value type for item from Dests NameTree array.
660   dest = FPDF_GetNamedDestByName(document(), "WrongType");
661   EXPECT_EQ(nullptr, dest);
662 
663   // No such destination in either Dest NameTree or dictionary.
664   dest = FPDF_GetNamedDestByName(document(), "Bogus");
665   EXPECT_EQ(nullptr, dest);
666 }
667 
668 // The following tests pass if the document opens without crashing.
TEST_F(FPDFViewEmbedderTest,Crasher_113)669 TEST_F(FPDFViewEmbedderTest, Crasher_113) {
670   EXPECT_TRUE(OpenDocument("bug_113.pdf"));
671 }
672 
TEST_F(FPDFViewEmbedderTest,Crasher_451830)673 TEST_F(FPDFViewEmbedderTest, Crasher_451830) {
674   // Document is damaged and can't be opened.
675   EXPECT_FALSE(OpenDocument("bug_451830.pdf"));
676 }
677 
TEST_F(FPDFViewEmbedderTest,Crasher_452455)678 TEST_F(FPDFViewEmbedderTest, Crasher_452455) {
679   EXPECT_TRUE(OpenDocument("bug_452455.pdf"));
680   FPDF_PAGE page = LoadPage(0);
681   EXPECT_NE(nullptr, page);
682   UnloadPage(page);
683 }
684 
TEST_F(FPDFViewEmbedderTest,Crasher_454695)685 TEST_F(FPDFViewEmbedderTest, Crasher_454695) {
686   // Document is damaged and can't be opened.
687   EXPECT_FALSE(OpenDocument("bug_454695.pdf"));
688 }
689 
TEST_F(FPDFViewEmbedderTest,Crasher_572871)690 TEST_F(FPDFViewEmbedderTest, Crasher_572871) {
691   EXPECT_TRUE(OpenDocument("bug_572871.pdf"));
692 }
693 
694 // It tests that document can still be loaded even the trailer has no 'Size'
695 // field if other information is right.
TEST_F(FPDFViewEmbedderTest,Failed_213)696 TEST_F(FPDFViewEmbedderTest, Failed_213) {
697   EXPECT_TRUE(OpenDocument("bug_213.pdf"));
698 }
699 
700 // The following tests pass if the document opens without infinite looping.
TEST_F(FPDFViewEmbedderTest,Hang_298)701 TEST_F(FPDFViewEmbedderTest, Hang_298) {
702   EXPECT_FALSE(OpenDocument("bug_298.pdf"));
703 }
704 
TEST_F(FPDFViewEmbedderTest,Crasher_773229)705 TEST_F(FPDFViewEmbedderTest, Crasher_773229) {
706   EXPECT_TRUE(OpenDocument("bug_773229.pdf"));
707 }
708 
709 // Test if the document opens without infinite looping.
710 // Previously this test will hang in a loop inside LoadAllCrossRefV4. After
711 // the fix, LoadAllCrossRefV4 will return false after detecting a cross
712 // reference loop. Cross references will be rebuilt successfully.
TEST_F(FPDFViewEmbedderTest,CrossRefV4Loop)713 TEST_F(FPDFViewEmbedderTest, CrossRefV4Loop) {
714   EXPECT_TRUE(OpenDocument("bug_xrefv4_loop.pdf"));
715   MockDownloadHints hints;
716 
717   // Make sure calling FPDFAvail_IsDocAvail() on this file does not infinite
718   // loop either. See bug 875.
719   int ret = PDF_DATA_NOTAVAIL;
720   while (ret == PDF_DATA_NOTAVAIL)
721     ret = FPDFAvail_IsDocAvail(avail_, &hints);
722   EXPECT_EQ(PDF_DATA_AVAIL, ret);
723 }
724 
725 // The test should pass when circular references to ParseIndirectObject will not
726 // cause infinite loop.
TEST_F(FPDFViewEmbedderTest,Hang_343)727 TEST_F(FPDFViewEmbedderTest, Hang_343) {
728   EXPECT_FALSE(OpenDocument("bug_343.pdf"));
729 }
730 
731 // The test should pass when the absence of 'Contents' field in a signature
732 // dictionary will not cause an infinite loop in CPDF_SyntaxParser::GetObject().
TEST_F(FPDFViewEmbedderTest,Hang_344)733 TEST_F(FPDFViewEmbedderTest, Hang_344) {
734   EXPECT_FALSE(OpenDocument("bug_344.pdf"));
735 }
736 
737 // The test should pass when there is no infinite recursion in
738 // CPDF_SyntaxParser::GetString().
TEST_F(FPDFViewEmbedderTest,Hang_355)739 TEST_F(FPDFViewEmbedderTest, Hang_355) {
740   EXPECT_FALSE(OpenDocument("bug_355.pdf"));
741 }
742 // The test should pass even when the file has circular references to pages.
TEST_F(FPDFViewEmbedderTest,Hang_360)743 TEST_F(FPDFViewEmbedderTest, Hang_360) {
744   EXPECT_FALSE(OpenDocument("bug_360.pdf"));
745 }
746 
747 // Deliberately damaged version of linearized.pdf with bad data in the shared
748 // object hint table.
TEST_F(FPDFViewEmbedderTest,Hang_1055)749 TEST_F(FPDFViewEmbedderTest, Hang_1055) {
750   EXPECT_TRUE(OpenDocumentLinearized("linearized_bug_1055.pdf"));
751   int version;
752   EXPECT_TRUE(FPDF_GetFileVersion(document(), &version));
753   EXPECT_EQ(16, version);
754 }
755 
756 // TODO(crbug.com/pdfium/11): Fix this test and enable.
757 #if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
758 #define MAYBE_FPDF_RenderPageBitmapWithMatrix \
759   DISABLED_FPDF_RenderPageBitmapWithMatrix
760 #else
761 #define MAYBE_FPDF_RenderPageBitmapWithMatrix FPDF_RenderPageBitmapWithMatrix
762 #endif
TEST_F(FPDFViewEmbedderTest,MAYBE_FPDF_RenderPageBitmapWithMatrix)763 TEST_F(FPDFViewEmbedderTest, MAYBE_FPDF_RenderPageBitmapWithMatrix) {
764   const char kOriginalMD5[] = "0a90de37f52127619c3dfb642b5fa2fe";
765   const char kClippedMD5[] = "a84cab93c102b9b9290fba3047ba702c";
766   const char kTopLeftQuarterMD5[] = "f11a11137c8834389e31cf555a4a6979";
767   const char kHoriStretchedMD5[] = "48ef9205941ed19691ccfa00d717187e";
768   const char kRotated90ClockwiseMD5[] = "d8da2c7bf77521550d0f2752b9cf3482";
769   const char kRotated180ClockwiseMD5[] = "0113386bb0bd45125bacc6dee78bfe78";
770   const char kRotated270ClockwiseMD5[] = "a287e0f74ce203699cda89f9cc97a240";
771   const char kMirrorHoriMD5[] = "6e8d7a6fde39d8e720fb9e620102918c";
772   const char kMirrorVertMD5[] = "8f3a555ef9c0d5031831ae3715273707";
773   const char kLargerTopLeftQuarterMD5[] = "172a2f4adafbadbe98017b1c025b9e27";
774   const char kLargerMD5[] = "c806145641c3e6fc4e022c7065343749";
775   const char kLargerClippedMD5[] = "091d3b1c7933c8f6945eb2cb41e588e9";
776   const char kLargerRotatedMD5[] = "115f13353ebfc82ddb392d1f0059eb12";
777   const char kLargerRotatedLandscapeMD5[] = "c901239d17d84ac84cb6f2124da71b0d";
778   const char kLargerRotatedDiagonalMD5[] = "3d62417468bdaff0eb14391a0c30a3b1";
779   const char kTileMD5[] = "0a190003c97220bf8877684c8d7e89cf";
780 
781   EXPECT_TRUE(OpenDocument("rectangles.pdf"));
782   FPDF_PAGE page = LoadPage(0);
783   ASSERT_TRUE(page);
784   const int page_width = static_cast<int>(FPDF_GetPageWidthF(page));
785   const int page_height = static_cast<int>(FPDF_GetPageHeightF(page));
786   EXPECT_EQ(200, page_width);
787   EXPECT_EQ(300, page_height);
788 
789   ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
790   CompareBitmap(bitmap.get(), page_width, page_height, kOriginalMD5);
791 
792   FS_RECTF page_rect{0, 0, page_width, page_height};
793 
794   // Try rendering with an identity matrix. The output should be the same as
795   // the RenderLoadedPage() output.
796   FS_MATRIX identity_matrix{1, 0, 0, 1, 0, 0};
797   TestRenderPageBitmapWithMatrix(page, page_width, page_height, identity_matrix,
798                                  page_rect, kOriginalMD5);
799 
800   // Again render with an identity matrix but with a smaller clipping rect.
801   FS_RECTF middle_of_page_rect{page_width / 4, page_height / 4,
802                                page_width * 3 / 4, page_height * 3 / 4};
803   TestRenderPageBitmapWithMatrix(page, page_width, page_height, identity_matrix,
804                                  middle_of_page_rect, kClippedMD5);
805 
806   // Now render again with the image scaled smaller.
807   FS_MATRIX half_scale_matrix{0.5, 0, 0, 0.5, 0, 0};
808   TestRenderPageBitmapWithMatrix(page, page_width, page_height,
809                                  half_scale_matrix, page_rect,
810                                  kTopLeftQuarterMD5);
811 
812   // Now render again with the image scaled larger horizontally (the right half
813   // will be clipped).
814   FS_MATRIX stretch_x_matrix{2, 0, 0, 1, 0, 0};
815   TestRenderPageBitmapWithMatrix(page, page_width, page_height,
816                                  stretch_x_matrix, page_rect,
817                                  kHoriStretchedMD5);
818 
819   // Try a 90 degree rotation clockwise but with the same bitmap size, so part
820   // will be clipped.
821   FS_MATRIX rotate_90_matrix{0, 1, -1, 0, page_width, 0};
822   TestRenderPageBitmapWithMatrix(page, page_width, page_height,
823                                  rotate_90_matrix, page_rect,
824                                  kRotated90ClockwiseMD5);
825 
826   // 180 degree rotation clockwise.
827   FS_MATRIX rotate_180_matrix{-1, 0, 0, -1, page_width, page_height};
828   TestRenderPageBitmapWithMatrix(page, page_width, page_height,
829                                  rotate_180_matrix, page_rect,
830                                  kRotated180ClockwiseMD5);
831 
832   // 270 degree rotation clockwise.
833   FS_MATRIX rotate_270_matrix{0, -1, 1, 0, 0, page_width};
834   TestRenderPageBitmapWithMatrix(page, page_width, page_height,
835                                  rotate_270_matrix, page_rect,
836                                  kRotated270ClockwiseMD5);
837 
838   // Mirror horizontally.
839   FS_MATRIX mirror_hori_matrix{-1, 0, 0, 1, page_width, 0};
840   TestRenderPageBitmapWithMatrix(page, page_width, page_height,
841                                  mirror_hori_matrix, page_rect, kMirrorHoriMD5);
842 
843   // Mirror vertically.
844   FS_MATRIX mirror_vert_matrix{1, 0, 0, -1, 0, page_height};
845   TestRenderPageBitmapWithMatrix(page, page_width, page_height,
846                                  mirror_vert_matrix, page_rect, kMirrorVertMD5);
847 
848   // Tests rendering to a larger bitmap
849   const int bitmap_width = page_width * 2;
850   const int bitmap_height = page_height * 2;
851 
852   // Render using an identity matrix and the whole bitmap area as clipping rect.
853   FS_RECTF bitmap_rect{0, 0, bitmap_width, bitmap_height};
854   TestRenderPageBitmapWithMatrix(page, bitmap_width, bitmap_height,
855                                  identity_matrix, bitmap_rect,
856                                  kLargerTopLeftQuarterMD5);
857 
858   // Render using a scaling matrix to fill the larger bitmap.
859   FS_MATRIX double_scale_matrix{2, 0, 0, 2, 0, 0};
860   TestRenderPageBitmapWithMatrix(page, bitmap_width, bitmap_height,
861                                  double_scale_matrix, bitmap_rect, kLargerMD5);
862 
863   // Render the larger image again but with clipping.
864   FS_RECTF middle_of_bitmap_rect{bitmap_width / 4, bitmap_height / 4,
865                                  bitmap_width * 3 / 4, bitmap_height * 3 / 4};
866   TestRenderPageBitmapWithMatrix(page, bitmap_width, bitmap_height,
867                                  double_scale_matrix, middle_of_bitmap_rect,
868                                  kLargerClippedMD5);
869 
870   // On the larger bitmap, try a 90 degree rotation but with the same bitmap
871   // size, so part will be clipped.
872   FS_MATRIX rotate_90_scale_2_matrix{0, 2, -2, 0, bitmap_width, 0};
873   TestRenderPageBitmapWithMatrix(page, bitmap_width, bitmap_height,
874                                  rotate_90_scale_2_matrix, bitmap_rect,
875                                  kLargerRotatedMD5);
876 
877   // On the larger bitmap, apply 90 degree rotation to a bitmap with the
878   // appropriate dimensions.
879   const int landscape_bitmap_width = bitmap_height;
880   const int landscape_bitmap_height = bitmap_width;
881   FS_RECTF landscape_bitmap_rect{0, 0, landscape_bitmap_width,
882                                  landscape_bitmap_height};
883   FS_MATRIX landscape_rotate_90_scale_2_matrix{
884       0, 2, -2, 0, landscape_bitmap_width, 0};
885   TestRenderPageBitmapWithMatrix(
886       page, landscape_bitmap_width, landscape_bitmap_height,
887       landscape_rotate_90_scale_2_matrix, landscape_bitmap_rect,
888       kLargerRotatedLandscapeMD5);
889 
890   // On the larger bitmap, apply 45 degree rotation to a bitmap with the
891   // appropriate dimensions.
892   const float sqrt2 = 1.41421356f;
893   const int diagonal_bitmap_size = ceil((bitmap_width + bitmap_height) / sqrt2);
894   FS_RECTF diagonal_bitmap_rect{0, 0, diagonal_bitmap_size,
895                                 diagonal_bitmap_size};
896   FS_MATRIX rotate_45_scale_2_matrix{
897       sqrt2, sqrt2, -sqrt2, sqrt2, bitmap_height / sqrt2, 0};
898   TestRenderPageBitmapWithMatrix(page, diagonal_bitmap_size,
899                                  diagonal_bitmap_size, rotate_45_scale_2_matrix,
900                                  diagonal_bitmap_rect,
901                                  kLargerRotatedDiagonalMD5);
902 
903   // Render the (2, 1) tile of the page (third column, second row) when the page
904   // is divided in 50x50 pixel tiles. The tile is scaled by a factor of 7.
905   const float scale = 7.0;
906   const int tile_size = 50;
907   const int tile_x = 2;
908   const int tile_y = 1;
909   int tile_bitmap_size = scale * tile_size;
910   FS_RECTF tile_bitmap_rect{0, 0, tile_bitmap_size, tile_bitmap_size};
911   FS_MATRIX tile_2_1_matrix{scale,
912                             0,
913                             0,
914                             scale,
915                             -tile_x * tile_bitmap_size,
916                             -tile_y * tile_bitmap_size};
917   TestRenderPageBitmapWithMatrix(page, tile_bitmap_size, tile_bitmap_size,
918                                  tile_2_1_matrix, tile_bitmap_rect, kTileMD5);
919 
920   UnloadPage(page);
921 }
922 
TEST_F(FPDFViewEmbedderTest,FPDF_GetPageSizeByIndexF)923 TEST_F(FPDFViewEmbedderTest, FPDF_GetPageSizeByIndexF) {
924   EXPECT_TRUE(OpenDocument("rectangles.pdf"));
925 
926   FS_SIZEF size;
927   EXPECT_FALSE(FPDF_GetPageSizeByIndexF(nullptr, 0, &size));
928   EXPECT_FALSE(FPDF_GetPageSizeByIndexF(document(), 0, nullptr));
929 
930   // Page -1 doesn't exist.
931   EXPECT_FALSE(FPDF_GetPageSizeByIndexF(document(), -1, &size));
932 
933   // Page 1 doesn't exist.
934   EXPECT_FALSE(FPDF_GetPageSizeByIndexF(document(), 1, &size));
935 
936   // Page 0 exists.
937   EXPECT_TRUE(FPDF_GetPageSizeByIndexF(document(), 0, &size));
938   EXPECT_FLOAT_EQ(200.0f, size.width);
939   EXPECT_FLOAT_EQ(300.0f, size.height);
940 
941   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document());
942 #ifdef PDF_ENABLE_XFA
943   // TODO(tsepez): XFA must obtain this size without parsing.
944   EXPECT_EQ(1u, pDoc->GetParsedPageCountForTesting());
945 #else   // PDF_ENABLE_XFA
946   EXPECT_EQ(0u, pDoc->GetParsedPageCountForTesting());
947 #endif  // PDF_ENABLE_XFA
948 
949   // Double-check against values from when page is actually parsed.
950   FPDF_PAGE page = LoadPage(0);
951   ASSERT_TRUE(page);
952   EXPECT_FLOAT_EQ(size.width, FPDF_GetPageWidthF(page));
953   EXPECT_FLOAT_EQ(size.height, FPDF_GetPageHeightF(page));
954   EXPECT_EQ(1u, pDoc->GetParsedPageCountForTesting());
955   UnloadPage(page);
956 }
957 
TEST_F(FPDFViewEmbedderTest,FPDF_GetPageSizeByIndex)958 TEST_F(FPDFViewEmbedderTest, FPDF_GetPageSizeByIndex) {
959   EXPECT_TRUE(OpenDocument("rectangles.pdf"));
960 
961   double width = 0;
962   double height = 0;
963 
964   EXPECT_FALSE(FPDF_GetPageSizeByIndex(nullptr, 0, &width, &height));
965   EXPECT_FALSE(FPDF_GetPageSizeByIndex(document(), 0, nullptr, &height));
966   EXPECT_FALSE(FPDF_GetPageSizeByIndex(document(), 0, &width, nullptr));
967 
968   // Page -1 doesn't exist.
969   EXPECT_FALSE(FPDF_GetPageSizeByIndex(document(), -1, &width, &height));
970 
971   // Page 1 doesn't exist.
972   EXPECT_FALSE(FPDF_GetPageSizeByIndex(document(), 1, &width, &height));
973 
974   // Page 0 exists.
975   EXPECT_TRUE(FPDF_GetPageSizeByIndex(document(), 0, &width, &height));
976   EXPECT_EQ(200.0, width);
977   EXPECT_EQ(300.0, height);
978 
979   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document());
980 #ifdef PDF_ENABLE_XFA
981   // TODO(tsepez): XFA must obtain this size without parsing.
982   EXPECT_EQ(1u, pDoc->GetParsedPageCountForTesting());
983 #else   // PDF_ENABLE_XFA
984   EXPECT_EQ(0u, pDoc->GetParsedPageCountForTesting());
985 #endif  // PDF_ENABLE_XFA
986 
987   // Double-check against values from when page is actually parsed.
988   FPDF_PAGE page = LoadPage(0);
989   ASSERT_TRUE(page);
990   EXPECT_EQ(width, FPDF_GetPageWidth(page));
991   EXPECT_EQ(height, FPDF_GetPageHeight(page));
992   EXPECT_EQ(1u, pDoc->GetParsedPageCountForTesting());
993   UnloadPage(page);
994 }
995 
996 class RecordUnsupportedErrorDelegate final : public EmbedderTest::Delegate {
997  public:
998   RecordUnsupportedErrorDelegate() = default;
999   ~RecordUnsupportedErrorDelegate() override = default;
1000 
UnsupportedHandler(int type)1001   void UnsupportedHandler(int type) override { type_ = type; }
1002 
1003   int type_ = -1;
1004 };
1005 
TEST_F(FPDFViewEmbedderTest,UnSupportedOperations_NotFound)1006 TEST_F(FPDFViewEmbedderTest, UnSupportedOperations_NotFound) {
1007   RecordUnsupportedErrorDelegate delegate;
1008   SetDelegate(&delegate);
1009   ASSERT_TRUE(OpenDocument("hello_world.pdf"));
1010   EXPECT_EQ(delegate.type_, -1);
1011   SetDelegate(nullptr);
1012 }
1013 
TEST_F(FPDFViewEmbedderTest,UnSupportedOperations_LoadCustomDocument)1014 TEST_F(FPDFViewEmbedderTest, UnSupportedOperations_LoadCustomDocument) {
1015   RecordUnsupportedErrorDelegate delegate;
1016   SetDelegate(&delegate);
1017   ASSERT_TRUE(OpenDocument("unsupported_feature.pdf"));
1018   EXPECT_EQ(FPDF_UNSP_DOC_PORTABLECOLLECTION, delegate.type_);
1019   SetDelegate(nullptr);
1020 }
1021 
TEST_F(FPDFViewEmbedderTest,UnSupportedOperations_LoadDocument)1022 TEST_F(FPDFViewEmbedderTest, UnSupportedOperations_LoadDocument) {
1023   std::string file_path;
1024   ASSERT_TRUE(
1025       PathService::GetTestFilePath("unsupported_feature.pdf", &file_path));
1026 
1027   RecordUnsupportedErrorDelegate delegate;
1028   SetDelegate(&delegate);
1029   FPDF_DOCUMENT doc = FPDF_LoadDocument(file_path.c_str(), "");
1030   EXPECT_TRUE(doc != nullptr);
1031   EXPECT_EQ(FPDF_UNSP_DOC_PORTABLECOLLECTION, delegate.type_);
1032   FPDF_CloseDocument(doc);
1033   SetDelegate(nullptr);
1034 }
1035 
TEST_F(FPDFViewEmbedderTest,DocumentHasValidCrossReferenceTable)1036 TEST_F(FPDFViewEmbedderTest, DocumentHasValidCrossReferenceTable) {
1037   ASSERT_TRUE(OpenDocument("hello_world.pdf"));
1038   EXPECT_TRUE(FPDF_DocumentHasValidCrossReferenceTable(document()));
1039 }
1040 
TEST_F(FPDFViewEmbedderTest,DocumentHasInvalidCrossReferenceTable)1041 TEST_F(FPDFViewEmbedderTest, DocumentHasInvalidCrossReferenceTable) {
1042   EXPECT_FALSE(FPDF_DocumentHasValidCrossReferenceTable(nullptr));
1043 
1044   ASSERT_TRUE(OpenDocument("bug_664284.pdf"));
1045   EXPECT_FALSE(FPDF_DocumentHasValidCrossReferenceTable(document()));
1046 }
1047 
1048 // Related to https://crbug.com/pdfium/1197
TEST_F(FPDFViewEmbedderTest,LoadDocumentWithEmptyXRefConsistently)1049 TEST_F(FPDFViewEmbedderTest, LoadDocumentWithEmptyXRefConsistently) {
1050   ASSERT_TRUE(OpenDocument("empty_xref.pdf"));
1051   EXPECT_TRUE(FPDF_DocumentHasValidCrossReferenceTable(document()));
1052 
1053   std::string file_path;
1054   ASSERT_TRUE(PathService::GetTestFilePath("empty_xref.pdf", &file_path));
1055   {
1056     ScopedFPDFDocument doc(FPDF_LoadDocument(file_path.c_str(), ""));
1057     ASSERT_TRUE(doc);
1058     EXPECT_TRUE(FPDF_DocumentHasValidCrossReferenceTable(doc.get()));
1059   }
1060   {
1061     size_t file_length = 0;
1062     std::unique_ptr<char, pdfium::FreeDeleter> file_contents =
1063         GetFileContents(file_path.c_str(), &file_length);
1064     ASSERT(file_contents);
1065     ScopedFPDFDocument doc(
1066         FPDF_LoadMemDocument(file_contents.get(), file_length, ""));
1067     ASSERT_TRUE(doc);
1068     EXPECT_TRUE(FPDF_DocumentHasValidCrossReferenceTable(doc.get()));
1069   }
1070 }
1071 
TEST_F(FPDFViewEmbedderTest,RenderManyRectanglesWithFlags)1072 TEST_F(FPDFViewEmbedderTest, RenderManyRectanglesWithFlags) {
1073   static const char kNormalMD5[] = "b0170c575b65ecb93ebafada0ff0f038";
1074   static const char kGrayscaleMD5[] = "7b553f1052069a9c61237a05db0955d6";
1075   static const char kNoSmoothpathMD5[] = "ff6e5c509d1f6984bcdfd18b26a4203a";
1076 
1077   ASSERT_TRUE(OpenDocument("many_rectangles.pdf"));
1078   FPDF_PAGE page = LoadPage(0);
1079   ASSERT_TRUE(page);
1080 
1081   TestRenderPageBitmapWithFlags(page, 0, kNormalMD5);
1082   TestRenderPageBitmapWithFlags(page, FPDF_ANNOT, kNormalMD5);
1083   TestRenderPageBitmapWithFlags(page, FPDF_LCD_TEXT, kNormalMD5);
1084   TestRenderPageBitmapWithFlags(page, FPDF_NO_NATIVETEXT, kNormalMD5);
1085   TestRenderPageBitmapWithFlags(page, FPDF_GRAYSCALE, kGrayscaleMD5);
1086   TestRenderPageBitmapWithFlags(page, FPDF_RENDER_LIMITEDIMAGECACHE,
1087                                 kNormalMD5);
1088   TestRenderPageBitmapWithFlags(page, FPDF_RENDER_FORCEHALFTONE, kNormalMD5);
1089   TestRenderPageBitmapWithFlags(page, FPDF_PRINTING, kNormalMD5);
1090   TestRenderPageBitmapWithFlags(page, FPDF_RENDER_NO_SMOOTHTEXT, kNormalMD5);
1091   TestRenderPageBitmapWithFlags(page, FPDF_RENDER_NO_SMOOTHIMAGE, kNormalMD5);
1092   TestRenderPageBitmapWithFlags(page, FPDF_RENDER_NO_SMOOTHPATH,
1093                                 kNoSmoothpathMD5);
1094 
1095   UnloadPage(page);
1096 }
1097 
TEST_F(FPDFViewEmbedderTest,RenderManyRectanglesWithExternalMemory)1098 TEST_F(FPDFViewEmbedderTest, RenderManyRectanglesWithExternalMemory) {
1099   static const char kNormalMD5[] = "b0170c575b65ecb93ebafada0ff0f038";
1100   static const char kGrayMD5[] = "b561c11edc44dc3972125a9b8744fa2f";
1101   static const char kBgrMD5[] = "ab6312e04c0d3f4e46fb302a45173d05";
1102 
1103   ASSERT_TRUE(OpenDocument("many_rectangles.pdf"));
1104   FPDF_PAGE page = LoadPage(0);
1105   ASSERT_TRUE(page);
1106 
1107   TestRenderPageBitmapWithExternalMemory(page, FPDFBitmap_Gray, kGrayMD5);
1108   TestRenderPageBitmapWithExternalMemory(page, FPDFBitmap_BGR, kBgrMD5);
1109   TestRenderPageBitmapWithExternalMemory(page, FPDFBitmap_BGRx, kNormalMD5);
1110   TestRenderPageBitmapWithExternalMemory(page, FPDFBitmap_BGRA, kNormalMD5);
1111   UnloadPage(page);
1112 }
1113 
1114 #if defined(OS_LINUX)
TEST_F(FPDFViewEmbedderTest,RenderHelloWorldWithFlags)1115 TEST_F(FPDFViewEmbedderTest, RenderHelloWorldWithFlags) {
1116   static const char kNormalMD5[] = "2baa4c0e1758deba1b9c908e1fbd04ed";
1117   static const char kLcdTextMD5[] = "825e881f39e48254e64e2808987a6b8c";
1118   static const char kNoSmoothtextMD5[] = "3d01e234120b783a3fffb27273ea1ea8";
1119 
1120   ASSERT_TRUE(OpenDocument("hello_world.pdf"));
1121   FPDF_PAGE page = LoadPage(0);
1122   ASSERT_TRUE(page);
1123 
1124   TestRenderPageBitmapWithFlags(page, 0, kNormalMD5);
1125   TestRenderPageBitmapWithFlags(page, FPDF_ANNOT, kNormalMD5);
1126   TestRenderPageBitmapWithFlags(page, FPDF_LCD_TEXT, kLcdTextMD5);
1127   TestRenderPageBitmapWithFlags(page, FPDF_NO_NATIVETEXT, kNormalMD5);
1128   TestRenderPageBitmapWithFlags(page, FPDF_GRAYSCALE, kNormalMD5);
1129   TestRenderPageBitmapWithFlags(page, FPDF_RENDER_LIMITEDIMAGECACHE,
1130                                 kNormalMD5);
1131   TestRenderPageBitmapWithFlags(page, FPDF_RENDER_FORCEHALFTONE, kNormalMD5);
1132   TestRenderPageBitmapWithFlags(page, FPDF_PRINTING, kNormalMD5);
1133   TestRenderPageBitmapWithFlags(page, FPDF_RENDER_NO_SMOOTHTEXT,
1134                                 kNoSmoothtextMD5);
1135   TestRenderPageBitmapWithFlags(page, FPDF_RENDER_NO_SMOOTHIMAGE, kNormalMD5);
1136   TestRenderPageBitmapWithFlags(page, FPDF_RENDER_NO_SMOOTHPATH, kNormalMD5);
1137 
1138   UnloadPage(page);
1139 }
1140 #endif  // defined(OS_LINUX)
1141 
1142 #if defined(OS_WIN)
TEST_F(FPDFViewEmbedderTest,FPDFRenderPageEmf)1143 TEST_F(FPDFViewEmbedderTest, FPDFRenderPageEmf) {
1144   ASSERT_TRUE(OpenDocument("rectangles.pdf"));
1145   FPDF_PAGE page = LoadPage(0);
1146   ASSERT_TRUE(page);
1147 
1148   std::vector<uint8_t> emf_normal = RenderPageWithFlagsToEmf(page, 0);
1149   EXPECT_EQ(3772u, emf_normal.size());
1150 
1151   // FPDF_REVERSE_BYTE_ORDER is ignored since EMFs are always BGR.
1152   std::vector<uint8_t> emf_reverse_byte_order =
1153       RenderPageWithFlagsToEmf(page, FPDF_REVERSE_BYTE_ORDER);
1154   EXPECT_EQ(emf_normal, emf_reverse_byte_order);
1155 
1156   UnloadPage(page);
1157 }
1158 
1159 class PostScriptRenderEmbedderTestBase : public FPDFViewEmbedderTest {
1160  protected:
1161   ~PostScriptRenderEmbedderTestBase() override = default;
1162 
1163   // FPDFViewEmbedderTest:
TearDown()1164   void TearDown() override {
1165     FPDF_SetPrintMode(FPDF_PRINTMODE_EMF);
1166     FPDFViewEmbedderTest::TearDown();
1167   }
1168 };
1169 
1170 class PostScriptLevel2EmbedderTest : public PostScriptRenderEmbedderTestBase {
1171  public:
1172   PostScriptLevel2EmbedderTest() = default;
1173   ~PostScriptLevel2EmbedderTest() override = default;
1174 
1175  protected:
1176   // FPDFViewEmbedderTest:
SetUp()1177   void SetUp() override {
1178     FPDFViewEmbedderTest::SetUp();
1179     FPDF_SetPrintMode(FPDF_PRINTMODE_POSTSCRIPT2);
1180   }
1181 };
1182 
1183 class PostScriptLevel3EmbedderTest : public PostScriptRenderEmbedderTestBase {
1184  public:
1185   PostScriptLevel3EmbedderTest() = default;
1186   ~PostScriptLevel3EmbedderTest() override = default;
1187 
1188  protected:
1189   // FPDFViewEmbedderTest:
SetUp()1190   void SetUp() override {
1191     FPDFViewEmbedderTest::SetUp();
1192     FPDF_SetPrintMode(FPDF_PRINTMODE_POSTSCRIPT3);
1193   }
1194 };
1195 
TEST_F(PostScriptLevel2EmbedderTest,Rectangles)1196 TEST_F(PostScriptLevel2EmbedderTest, Rectangles) {
1197   ASSERT_TRUE(OpenDocument("rectangles.pdf"));
1198   FPDF_PAGE page = LoadPage(0);
1199   ASSERT_TRUE(page);
1200 
1201   std::vector<uint8_t> emf_normal = RenderPageWithFlagsToEmf(page, 0);
1202   std::string ps_data = GetPostScriptFromEmf(emf_normal);
1203   EXPECT_STREQ(kExpectedRectanglePostScript, ps_data.c_str());
1204 
1205   // FPDF_REVERSE_BYTE_ORDER is ignored since PostScript is not bitmap-based.
1206   std::vector<uint8_t> emf_reverse_byte_order =
1207       RenderPageWithFlagsToEmf(page, FPDF_REVERSE_BYTE_ORDER);
1208   EXPECT_EQ(emf_normal, emf_reverse_byte_order);
1209 
1210   UnloadPage(page);
1211 }
1212 
TEST_F(PostScriptLevel3EmbedderTest,Rectangles)1213 TEST_F(PostScriptLevel3EmbedderTest, Rectangles) {
1214   ASSERT_TRUE(OpenDocument("rectangles.pdf"));
1215   FPDF_PAGE page = LoadPage(0);
1216   ASSERT_TRUE(page);
1217 
1218   std::vector<uint8_t> emf_normal = RenderPageWithFlagsToEmf(page, 0);
1219   std::string ps_data = GetPostScriptFromEmf(emf_normal);
1220   EXPECT_STREQ(kExpectedRectanglePostScript, ps_data.c_str());
1221 
1222   // FPDF_REVERSE_BYTE_ORDER is ignored since PostScript is not bitmap-based.
1223   std::vector<uint8_t> emf_reverse_byte_order =
1224       RenderPageWithFlagsToEmf(page, FPDF_REVERSE_BYTE_ORDER);
1225   EXPECT_EQ(emf_normal, emf_reverse_byte_order);
1226 
1227   UnloadPage(page);
1228 }
1229 
TEST_F(PostScriptLevel2EmbedderTest,Image)1230 TEST_F(PostScriptLevel2EmbedderTest, Image) {
1231   const char kExpected[] =
1232       "\n"
1233       "save\n"
1234       "/im/initmatrix load def\n"
1235       "/n/newpath load def/m/moveto load def/l/lineto load def/c/curveto load "
1236       "def/h/closepath load def\n"
1237       "/f/fill load def/F/eofill load def/s/stroke load def/W/clip load "
1238       "def/W*/eoclip load def\n"
1239       "/rg/setrgbcolor load def/k/setcmykcolor load def\n"
1240       "/J/setlinecap load def/j/setlinejoin load def/w/setlinewidth load "
1241       "def/M/setmiterlimit load def/d/setdash load def\n"
1242       "/q/gsave load def/Q/grestore load def/iM/imagemask load def\n"
1243       "/Tj/show load def/Ff/findfont load def/Fs/scalefont load def/Sf/setfont "
1244       "load def\n"
1245       "/cm/concat load def/Cm/currentmatrix load def/mx/matrix load "
1246       "def/sm/setmatrix load def\n"
1247       "0 792 m 0 0 l 612 0 l 612 792 l 0 792 l h W n\n"
1248       "q\n"
1249       "0 792 m 0 0 l 612 0 l 612 792 l 0 792 l h W n\n"
1250       "q\n"
1251       "Q\n"
1252       "q\n"
1253       "281 106.7 m 331 106.7 l 331 56.7 l 281 56.7 l 281 106.7 l h W* n\n"
1254       "q\n"
1255       "[49.9 0 0 -50 281.1 106.6]cm 50 50 8[50 0 0 -50 0 "
1256       "50]currentfile/ASCII85Decode filter /DCTDecode filter false 3 "
1257       "colorimage\n"
1258       "s4IA0!\"_al8O`[\\!<<*#!!*'\"s4[N@!!ic5#6k>;#6tJ?#m^kH'FbHY$Odmc'+Yct)"
1259       "BU\"@)B9_>\r\n"
1260       ",VCGe+tOrY*%3`p/2/e81c-:%3B]>W4>&EH1B6)/"
1261       "6NIK\"#n.1M(_$ok1*IV\\1,:U?1,:U?1,:U?\r\n"
1262       "1,:U?1,:U?1,:U?1,:U?1,:U?1,:U?1,:U?1,:U?1,:U?1,AmF!\"fJ:1&s'3!?qLF&HMtG!"
1263       "WU(<\r\n"
1264       "*rl9A\"T\\W)!<E3$z!!!!\"!WrQ/\"pYD?$4HmP!4<@<!W`B*!X&T/"
1265       "\"U\"r.!!.KK!WrE*&Hrdj0gQ!W\r\n"
1266       ";.0\\RE>10ZOeE%*6F\"?A;UOtZ1LbBV#mqFa(`=5<-7:2j.Ps\"@2`NfY6UX@47n?3D;"
1267       "cHat='/U/\r\n"
1268       "@q9._B4u!oF*)PJGBeCZK7nr5LPUeEP*;,qQC!u,R\\HRQV5C/"
1269       "hWN*81['d?O\\@K2f_o0O6a2lBF\r\n"
1270       "daQ^rf%8R-g>V&OjQ5OekiqC&o(2MHp@n@XqZ\"J6*ru?D!<E3%!<E3%!<<*\"!!!!\"!"
1271       "WrQ/\"pYD?\r\n"
1272       "$4HmP!4<C=!W`?*\"9Sc3\"U\"r.!<RHF!<N?8\"9fr'\"qj4!#@VTc+u4]T'LIqUZ,$_"
1273       "k1K*]W@WKj'\r\n"
1274       "(*k`q-1Mcg)&ahL-n-W'2E*TU3^Z;(7Rp!@8lJ\\h<``C+>%;)SAnPdkC3+K>G'A1VH@gd&"
1275       "KnbA=\r\n"
1276       "M2II[Pa.Q$R$jD;USO``Vl6SpZEppG[^WcW]#)A'`Q#s>ai`&\\eCE.%f\\,!<j5f="
1277       "akNM0qo(2MH\r\n"
1278       "p@n@XqZ#7L$j-M1!YGMH!'^JZre`+s!fAD!!fAD!!fAD!!fAD!!fAD!!fAD!!fAD!!fAD!!"
1279       "fAD!\r\n"
1280       "!fAD!!fAD!!fAD!!fAD!!fAD!!fAD!&-(;~>\n"
1281       "Q\n"
1282       "Q\n"
1283       "q\n"
1284       "q\n"
1285       "Q\n"
1286       "Q\n"
1287       "Q\n"
1288       "Q\n"
1289       "\n"
1290       "restore\n";
1291 
1292   ASSERT_TRUE(OpenDocument("tagged_alt_text.pdf"));
1293   FPDF_PAGE page = LoadPage(0);
1294   ASSERT_TRUE(page);
1295 
1296   std::vector<uint8_t> emf = RenderPageWithFlagsToEmf(page, 0);
1297   std::string ps_data = GetPostScriptFromEmf(emf);
1298   EXPECT_STREQ(kExpected, ps_data.c_str());
1299 
1300   UnloadPage(page);
1301 }
1302 
TEST_F(PostScriptLevel3EmbedderTest,Image)1303 TEST_F(PostScriptLevel3EmbedderTest, Image) {
1304   const char kExpected[] = R"(
1305 save
1306 /im/initmatrix load def
1307 /n/newpath load def/m/moveto load def/l/lineto load def/c/curveto load def/h/closepath load def
1308 /f/fill load def/F/eofill load def/s/stroke load def/W/clip load def/W*/eoclip load def
1309 /rg/setrgbcolor load def/k/setcmykcolor load def
1310 /J/setlinecap load def/j/setlinejoin load def/w/setlinewidth load def/M/setmiterlimit load def/d/setdash load def
1311 /q/gsave load def/Q/grestore load def/iM/imagemask load def
1312 /Tj/show load def/Ff/findfont load def/Fs/scalefont load def/Sf/setfont load def
1313 /cm/concat load def/Cm/currentmatrix load def/mx/matrix load def/sm/setmatrix load def
1314 0 792 m 0 0 l 612 0 l 612 792 l 0 792 l h W n
1315 q
1316 0 792 m 0 0 l 612 0 l 612 792 l 0 792 l h W n
1317 q
1318 Q
1319 q
1320 281 106.7 m 331 106.7 l 331 56.7 l 281 56.7 l 281 106.7 l h W* n
1321 q
1322 [49.9 0 0 -50 281.1 106.6]cm 50 50 8[50 0 0 -50 0 50]currentfile/ASCII85Decode filter /FlateDecode filter false 3 colorimage
1323 Gb"0;0`_7S!5bE%:[N')TE"rlzGQSs[!!*~>
1324 Q
1325 Q
1326 q
1327 q
1328 Q
1329 Q
1330 Q
1331 Q
1332 
1333 restore
1334 )";
1335 
1336   ASSERT_TRUE(OpenDocument("tagged_alt_text.pdf"));
1337   FPDF_PAGE page = LoadPage(0);
1338   ASSERT_TRUE(page);
1339 
1340   std::vector<uint8_t> emf = RenderPageWithFlagsToEmf(page, 0);
1341   std::string ps_data = GetPostScriptFromEmf(emf);
1342   EXPECT_STREQ(kExpected, ps_data.c_str());
1343 
1344   UnloadPage(page);
1345 }
1346 #endif  // defined(OS_WIN)
1347