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