Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
fpdf_edit_embeddertest.cpp
Go to the documentation of this file.
1// Copyright 2016 The PDFium Authors
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 <limits>
6#include <memory>
7#include <ostream>
8#include <string>
9#include <utility>
10#include <vector>
11
12#include "build/build_config.h"
13#include "core/fpdfapi/font/cpdf_font.h"
14#include "core/fpdfapi/page/cpdf_page.h"
15#include "core/fpdfapi/page/cpdf_pageobject.h"
16#include "core/fpdfapi/parser/cpdf_array.h"
17#include "core/fpdfapi/parser/cpdf_dictionary.h"
18#include "core/fpdfapi/parser/cpdf_number.h"
19#include "core/fpdfapi/parser/cpdf_stream.h"
20#include "core/fpdfapi/parser/cpdf_stream_acc.h"
21#include "core/fxcrt/fx_codepage.h"
22#include "core/fxcrt/fx_system.h"
23#include "core/fxge/cfx_defaultrenderdevice.h"
24#include "core/fxge/fx_font.h"
25#include "fpdfsdk/cpdfsdk_helpers.h"
26#include "public/cpp/fpdf_scopers.h"
27#include "public/fpdf_annot.h"
28#include "public/fpdf_edit.h"
29#include "public/fpdfview.h"
30#include "testing/embedder_test.h"
31#include "testing/embedder_test_constants.h"
32#include "testing/fx_string_testhelpers.h"
33#include "testing/gmock/include/gmock/gmock-matchers.h"
34#include "testing/gtest/include/gtest/gtest.h"
35#include "testing/utils/file_util.h"
36#include "testing/utils/hash.h"
37#include "testing/utils/path_service.h"
38#include "third_party/base/check.h"
39
40using pdfium::HelloWorldChecksum;
41using testing::HasSubstr;
42using testing::Not;
43using testing::UnorderedElementsAreArray;
44
45namespace {
46
47const char kAllRemovedChecksum[] = "eee4600ac08b458ac7ac2320e225674c";
48
49const wchar_t kBottomText[] = L"I'm at the bottom of the page";
50
51const char* BottomTextChecksum() {
52 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
53#if BUILDFLAG(IS_WIN)
54 return "5d8f2b613a2f9591a52373c72d6b88ee";
55#elif BUILDFLAG(IS_APPLE)
56 return "8ca7dc6269ee68507389aa40eebcb9f8";
57#else
58 return "c62d315856a558d2666b80d474831efe";
59#endif
60 }
61#if BUILDFLAG(IS_APPLE)
62 return "81636489006a31fcb00cf29efcdf7909";
63#else
64 return "891dcb6e914c8360998055f1f47c9727";
65#endif
66}
67
68const char* FirstRemovedChecksum() {
69 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
70#if BUILDFLAG(IS_WIN)
71 return "251007e902e512d0359240ad957ee2dc";
72#elif BUILDFLAG(IS_APPLE)
73 return "dcb929fae86d5b935888ce7f9f1ab71b";
74#else
75 return "3006ab2b12d27246eae4faad509ac575";
76#endif
77 }
78#if BUILDFLAG(IS_APPLE)
79 return "a1dc2812692fcc7ee4f01ca77435df9d";
80#else
81 return "e1477dc3b5b3b9c560814c4d1135a02b";
82#endif
83}
84
85const wchar_t kLoadedFontText[] = L"I am testing my loaded font, WEE.";
86
87const char* LoadedFontTextChecksum() {
88 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
89#if BUILDFLAG(IS_WIN)
90 return "b0efd562e84958f06bb006ba27d5f4bd";
91#elif BUILDFLAG(IS_APPLE)
92 return "23e7874d160692b0ef3e0c8780f73dab";
93#else
94 return "fc2334c350cbd0d2ae6076689da09741";
95#endif
96 }
97#if BUILDFLAG(IS_APPLE)
98 return "0f3e4a7d71f9e7eb8a1a0d69403b9848";
99#else
100 return "d58570cc045dfb818b92cbabbd1a364c";
101#endif
102}
103
104const char kRedRectangleChecksum[] = "66d02eaa6181e2c069ce2ea99beda497";
105
106// In embedded_images.pdf.
107const char kEmbeddedImage33Checksum[] = "cb3637934bb3b95a6e4ae1ea9eb9e56e";
108
109struct FPDFEditMoveEmbedderTestCase {
110 std::vector<int> page_indices;
111 int page_indices_len;
112 int dest_page_index;
113 // whether FPDF_MovePages() will succeed or fail
114 bool expected_result;
115 // expected order of pages if `expected_result` is true
116 std::vector<int> expected_order;
117 const char* const name;
118};
119
120std::ostream& operator<<(std::ostream& os,
121 const FPDFEditMoveEmbedderTestCase& t) {
122 os << t.name << ": Indices are {";
123 for (size_t i = 0; i < t.page_indices.size(); ++i) {
124 os << t.page_indices[i];
125 if (i != t.page_indices.size() - 1) {
126 os << ", ";
127 }
128 }
129 os << "}, page order len is " << t.page_indices_len << ", dest page index is "
130 << t.dest_page_index << ", expected result is " << t.expected_result;
131 return os;
132}
133
134} // namespace
135
137 protected:
138 FPDF_DOCUMENT CreateNewDocument() {
140 cpdf_doc_ = CPDFDocumentFromFPDFDocument(document());
141 return document();
142 }
143
144 void CheckFontDescriptor(const CPDF_Dictionary* font_dict,
145 int font_type,
146 bool bold,
147 bool italic,
148 pdfium::span<const uint8_t> span) {
149 RetainPtr<const CPDF_Dictionary> font_desc =
150 font_dict->GetDictFor("FontDescriptor");
151 ASSERT_TRUE(font_desc);
152 EXPECT_EQ("FontDescriptor", font_desc->GetNameFor("Type"));
153 ByteString font_name = font_desc->GetNameFor("FontName");
154 EXPECT_FALSE(font_name.IsEmpty());
155 EXPECT_EQ(font_dict->GetNameFor("BaseFont"), font_name);
156
157 // Check that the font descriptor has the required keys according to spec
158 // 1.7 Table 5.19
159 ASSERT_TRUE(font_desc->KeyExist("Flags"));
160
161 int font_flags = font_desc->GetIntegerFor("Flags");
162 EXPECT_EQ(bold, FontStyleIsForceBold(font_flags));
163 EXPECT_EQ(italic, FontStyleIsItalic(font_flags));
164 EXPECT_TRUE(FontStyleIsNonSymbolic(font_flags));
165 ASSERT_TRUE(font_desc->KeyExist("FontBBox"));
166
167 RetainPtr<const CPDF_Array> fontBBox = font_desc->GetArrayFor("FontBBox");
168 ASSERT_TRUE(fontBBox);
169 EXPECT_EQ(4u, fontBBox->size());
170 // Check that the coordinates are in the preferred order according to spec
171 // 1.7 Section 3.8.4
172 EXPECT_TRUE(fontBBox->GetIntegerAt(0) < fontBBox->GetIntegerAt(2));
173 EXPECT_TRUE(fontBBox->GetIntegerAt(1) < fontBBox->GetIntegerAt(3));
174
175 EXPECT_TRUE(font_desc->KeyExist("ItalicAngle"));
176 EXPECT_TRUE(font_desc->KeyExist("Ascent"));
177 EXPECT_TRUE(font_desc->KeyExist("Descent"));
178 EXPECT_TRUE(font_desc->KeyExist("CapHeight"));
179 EXPECT_TRUE(font_desc->KeyExist("StemV"));
180 ByteString present("FontFile");
181 ByteString absent("FontFile2");
182 if (font_type == FPDF_FONT_TRUETYPE)
183 std::swap(present, absent);
184 EXPECT_TRUE(font_desc->KeyExist(present));
185 EXPECT_FALSE(font_desc->KeyExist(absent));
186
187 auto streamAcc =
188 pdfium::MakeRetain<CPDF_StreamAcc>(font_desc->GetStreamFor(present));
189 streamAcc->LoadAllDataRaw();
190
191 // Check that the font stream is the one that was provided
192 ASSERT_EQ(span.size(), streamAcc->GetSize());
193 if (font_type == FPDF_FONT_TRUETYPE) {
194 ASSERT_EQ(static_cast<int>(span.size()), streamAcc->GetLength1ForTest());
195 }
196
197 pdfium::span<const uint8_t> stream_data = streamAcc->GetSpan();
198 for (size_t j = 0; j < span.size(); j++)
199 EXPECT_EQ(span[j], stream_data[j]) << " at byte " << j;
200 }
201
202 void CheckCompositeFontWidths(const CPDF_Array* widths_array,
203 CPDF_Font* typed_font) {
204 // Check that W array is in a format that conforms to PDF spec 1.7 section
205 // "Glyph Metrics in CIDFonts" (these checks are not
206 // implementation-specific).
207 EXPECT_GT(widths_array->size(), 1u);
208 int num_cids_checked = 0;
209 int cur_cid = 0;
210 for (size_t idx = 0; idx < widths_array->size(); idx++) {
211 int cid = widths_array->GetFloatAt(idx);
212 EXPECT_GE(cid, cur_cid);
213 ASSERT_FALSE(++idx == widths_array->size());
214 RetainPtr<const CPDF_Object> next = widths_array->GetObjectAt(idx);
215 if (next->IsArray()) {
216 // We are in the c [w1 w2 ...] case
217 const CPDF_Array* arr = next->AsArray();
218 int cnt = static_cast<int>(arr->size());
219 size_t inner_idx = 0;
220 for (cur_cid = cid; cur_cid < cid + cnt; cur_cid++) {
221 int width = arr->GetFloatAt(inner_idx++);
222 EXPECT_EQ(width, typed_font->GetCharWidthF(cur_cid))
223 << " at cid " << cur_cid;
224 }
225 num_cids_checked += cnt;
226 continue;
227 }
228 // Otherwise, are in the c_first c_last w case.
229 ASSERT_TRUE(next->IsNumber());
230 int last_cid = next->AsNumber()->GetInteger();
231 ASSERT_FALSE(++idx == widths_array->size());
232 int width = widths_array->GetFloatAt(idx);
233 for (cur_cid = cid; cur_cid <= last_cid; cur_cid++) {
234 EXPECT_EQ(width, typed_font->GetCharWidthF(cur_cid))
235 << " at cid " << cur_cid;
236 }
237 num_cids_checked += last_cid - cid + 1;
238 }
239 // Make sure we have a good amount of cids described
240 EXPECT_GT(num_cids_checked, 200);
241 }
242 CPDF_Document* cpdf_doc() { return cpdf_doc_; }
243
244 private:
245 CPDF_Document* cpdf_doc_;
246};
247
248namespace {
249
250const char kExpectedPDF[] =
251 "%PDF-1.7\r\n"
252 "%\xA1\xB3\xC5\xD7\r\n"
253 "1 0 obj\r\n"
254 "<</Pages 2 0 R /Type/Catalog>>\r\n"
255 "endobj\r\n"
256 "2 0 obj\r\n"
257 "<</Count 1/Kids\\[ 4 0 R \\]/Type/Pages>>\r\n"
258 "endobj\r\n"
259 "3 0 obj\r\n"
260 "<</CreationDate\\‍(D:.*\\‍)/Creator\\‍(PDFium\\‍)>>\r\n"
261 "endobj\r\n"
262 "4 0 obj\r\n"
263 "<</MediaBox\\[ 0 0 640 480\\]/Parent 2 0 R "
264 "/Resources<<>>"
265 "/Rotate 0/Type/Page"
266 ">>\r\n"
267 "endobj\r\n"
268 "xref\r\n"
269 "0 5\r\n"
270 "0000000000 65535 f\r\n"
271 "0000000017 00000 n\r\n"
272 "0000000066 00000 n\r\n"
273 "0000000122 00000 n\r\n"
274 "0000000192 00000 n\r\n"
275 "trailer\r\n"
276 "<<\r\n"
277 "/Root 1 0 R\r\n"
278 "/Info 3 0 R\r\n"
279 "/Size 5/ID\\[<.*><.*>\\]>>\r\n"
280 "startxref\r\n"
281 "285\r\n"
282 "%%EOF\r\n";
283
284} // namespace
285
287 CreateEmptyDocument();
288 ScopedFPDFPage page(FPDFPage_New(document(), 0, 400, 400));
289 std::string font_path;
290 ASSERT_TRUE(PathService::GetThirdPartyFilePath(
291 "NotoSansCJK/NotoSansSC-Regular.subset.otf", &font_path));
292
293 std::vector<uint8_t> font_data = GetFileContents(font_path.c_str());
294 ASSERT_FALSE(font_data.empty());
295
296 ScopedFPDFFont font(FPDFText_LoadFont(document(), font_data.data(),
297 font_data.size(), FPDF_FONT_TRUETYPE,
298 /*cid=*/true));
299 FPDF_PAGEOBJECT text_object =
300 FPDFPageObj_CreateTextObj(document(), font.get(), 20.0f);
301 EXPECT_TRUE(text_object);
302
303 // Test the characters which are either mapped to one single unicode or
304 // multiple unicodes in the embedded font.
305 ScopedFPDFWideString text = GetFPDFWideString(L"这是第一句。 这是第二行。");
306 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
307
308 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 50, 200);
309 FPDFPage_InsertObject(page.get(), text_object);
310 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
311
312 const char* checksum = []() {
313 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
314#if BUILDFLAG(IS_WIN)
315 return "a1bc9e4007dc2155e9f56bf16234573e";
316#elif BUILDFLAG(IS_APPLE)
317 return "9a31fb87d1c6d2346bba22d1196041cd";
318#else
319 return "5bb65e15fc0a685934cd5006dec08a76";
320#endif
321 }
322 return "9a31fb87d1c6d2346bba22d1196041cd";
323 }();
324 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
325 CompareBitmap(page_bitmap.get(), 400, 400, checksum);
326
327 ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
328 VerifySavedDocument(400, 400, checksum);
329}
330
332 CreateEmptyDocument();
333 ScopedFPDFPage page(FPDFPage_New(document(), 0, 400, 400));
334 std::string font_path;
335 ASSERT_TRUE(PathService::GetThirdPartyFilePath(
336 "NotoSansCJK/NotoSansSC-Regular.subset.otf", &font_path));
337
338 std::vector<uint8_t> font_data = GetFileContents(font_path.c_str());
339 ASSERT_FALSE(font_data.empty());
340
341 ScopedFPDFFont font(FPDFText_LoadFont(document(), font_data.data(),
342 font_data.size(), FPDF_FONT_TRUETYPE,
343 /*cid=*/true));
344 FPDF_PAGEOBJECT text_object =
345 FPDFPageObj_CreateTextObj(document(), font.get(), 20.0f);
346 EXPECT_TRUE(text_object);
347
348 // Same as `text` in the EmbedNotoSansSCFont test case above.
349 const std::vector<uint32_t> charcodes = {9, 6, 7, 3, 5, 2, 1,
350 9, 6, 7, 4, 8, 2};
351 EXPECT_TRUE(
352 FPDFText_SetCharcodes(text_object, charcodes.data(), charcodes.size()));
353
354 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 50, 200);
355 FPDFPage_InsertObject(page.get(), text_object);
356 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
357
358 const char* checksum = []() {
359 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
360#if BUILDFLAG(IS_WIN)
361 return "a1bc9e4007dc2155e9f56bf16234573e";
362#elif BUILDFLAG(IS_APPLE)
363 return "9a31fb87d1c6d2346bba22d1196041cd";
364#else
365 return "5bb65e15fc0a685934cd5006dec08a76";
366#endif
367 }
368 return "9a31fb87d1c6d2346bba22d1196041cd";
369 }();
370 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
371 CompareBitmap(page_bitmap.get(), 400, 400, checksum);
372
373 ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
374 VerifySavedDocument(400, 400, checksum);
375}
376
378 CreateEmptyDocument();
379 ScopedFPDFPage page(FPDFPage_New(document(), 0, 400, 400));
380 std::string font_path = PathService::GetTestFilePath("fonts/bug_2094.ttf");
381 ASSERT_FALSE(font_path.empty());
382
383 std::vector<uint8_t> font_data = GetFileContents(font_path.c_str());
384 ASSERT_FALSE(font_data.empty());
385
386 ScopedFPDFFont font(FPDFText_LoadFont(document(), font_data.data(),
387 font_data.size(), FPDF_FONT_TRUETYPE,
388 /*cid=*/true));
389 EXPECT_TRUE(font);
390}
391
393 CreateEmptyDocument();
394 FPDF_PAGE page = FPDFPage_New(document(), 0, 640.0, 480.0);
395 EXPECT_TRUE(page);
396 // The FPDFPage_GenerateContent call should do nothing.
397 EXPECT_TRUE(FPDFPage_GenerateContent(page));
398 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
399
400 EXPECT_THAT(GetString(), testing::MatchesRegex(std::string(
401 kExpectedPDF, sizeof(kExpectedPDF))));
403}
404
405// Regression test for https://crbug.com/667012
407 const char kAllBlackChecksum[] = "5708fc5c4a8bd0abde99c8e8f0390615";
408
409 // Get the bitmap for the original document.
410 ScopedFPDFBitmap orig_bitmap;
411 {
412 ASSERT_TRUE(OpenDocument("black.pdf"));
413 FPDF_PAGE orig_page = LoadPage(0);
414 ASSERT_TRUE(orig_page);
415 orig_bitmap = RenderLoadedPage(orig_page);
416 CompareBitmap(orig_bitmap.get(), 612, 792, kAllBlackChecksum);
417 UnloadPage(orig_page);
418 }
419
420 // Create a new document from |orig_bitmap| and save it.
421 {
422 ScopedFPDFDocument temp_doc(FPDF_CreateNewDocument());
423 ScopedFPDFPage temp_page(FPDFPage_New(temp_doc.get(), 0, 612, 792));
424
425 // Add the bitmap to an image object and add the image object to the output
426 // page.
427 ScopedFPDFPageObject temp_img(FPDFPageObj_NewImageObj(temp_doc.get()));
428 FPDF_PAGE pages_array[] = {temp_page.get()};
429 EXPECT_TRUE(FPDFImageObj_SetBitmap(pages_array, 1, temp_img.get(),
430 orig_bitmap.get()));
431 static constexpr FS_MATRIX kLetterScaleMatrix{612, 0, 0, 792, 0, 0};
432 EXPECT_TRUE(FPDFPageObj_SetMatrix(temp_img.get(), &kLetterScaleMatrix));
433 FPDFPage_InsertObject(temp_page.get(), temp_img.release());
434 EXPECT_TRUE(FPDFPage_GenerateContent(temp_page.get()));
435 EXPECT_TRUE(FPDF_SaveAsCopy(temp_doc.get(), this, 0));
436 }
437
438 // Get the generated content. Make sure it is at least as big as the original
439 // PDF.
440 EXPECT_GT(GetString().size(), 923u);
441 VerifySavedDocument(612, 792, kAllBlackChecksum);
442}
443
445 // Start with a blank page
446 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
447 ASSERT_TRUE(page);
448
449 // We will first add a red rectangle
450 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(10, 10, 20, 20);
451 ASSERT_TRUE(red_rect);
452 // Expect false when trying to set colors out of range
453 EXPECT_FALSE(FPDFPageObj_SetStrokeColor(red_rect, 100, 100, 100, 300));
454 EXPECT_FALSE(FPDFPageObj_SetFillColor(red_rect, 200, 256, 200, 0));
455
456 // Fill rectangle with red and insert to the page
457 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
459
460 int fillmode = FPDF_FILLMODE_NONE;
461 FPDF_BOOL stroke = true;
462 EXPECT_TRUE(FPDFPath_GetDrawMode(red_rect, &fillmode, &stroke));
463 EXPECT_EQ(FPDF_FILLMODE_ALTERNATE, fillmode);
464 EXPECT_FALSE(stroke);
465
466 static constexpr FS_MATRIX kMatrix = {1, 2, 3, 4, 5, 6};
467 EXPECT_TRUE(FPDFPageObj_SetMatrix(red_rect, &kMatrix));
468
469 FS_MATRIX matrix;
470 EXPECT_TRUE(FPDFPageObj_GetMatrix(red_rect, &matrix));
471 EXPECT_FLOAT_EQ(1.0f, matrix.a);
472 EXPECT_FLOAT_EQ(2.0f, matrix.b);
473 EXPECT_FLOAT_EQ(3.0f, matrix.c);
474 EXPECT_FLOAT_EQ(4.0f, matrix.d);
475 EXPECT_FLOAT_EQ(5.0f, matrix.e);
476 EXPECT_FLOAT_EQ(6.0f, matrix.f);
477
478 // Set back the identity matrix.
479 matrix = {1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f};
480 EXPECT_TRUE(FPDFPageObj_SetMatrix(red_rect, &matrix));
481
482 FPDFPage_InsertObject(page, red_rect);
483 {
484 ScopedFPDFBitmap page_bitmap = RenderPage(page);
485 CompareBitmap(page_bitmap.get(), 612, 792, kRedRectangleChecksum);
486 }
487
488 // Now add to that a green rectangle with some medium alpha
489 FPDF_PAGEOBJECT green_rect = FPDFPageObj_CreateNewRect(100, 100, 40, 40);
490 EXPECT_TRUE(FPDFPageObj_SetFillColor(green_rect, 0, 255, 0, 128));
491
492 // Make sure the type of the rectangle is a path.
493 EXPECT_EQ(FPDF_PAGEOBJ_PATH, FPDFPageObj_GetType(green_rect));
494
495 // Make sure we get back the same color we set previously.
496 unsigned int R;
497 unsigned int G;
498 unsigned int B;
499 unsigned int A;
500 EXPECT_TRUE(FPDFPageObj_GetFillColor(green_rect, &R, &G, &B, &A));
501 EXPECT_EQ(0u, R);
502 EXPECT_EQ(255u, G);
503 EXPECT_EQ(0u, B);
504 EXPECT_EQ(128u, A);
505
506 // Make sure the path has 5 points (1 CFX_Path::Point::Type::kMove and 4
507 // CFX_Path::Point::Type::kLine).
508 ASSERT_EQ(5, FPDFPath_CountSegments(green_rect));
509 // Verify actual coordinates.
510 FPDF_PATHSEGMENT segment = FPDFPath_GetPathSegment(green_rect, 0);
511 float x;
512 float y;
513 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
514 EXPECT_EQ(100, x);
515 EXPECT_EQ(100, y);
517 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
518 segment = FPDFPath_GetPathSegment(green_rect, 1);
519 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
520 EXPECT_EQ(100, x);
521 EXPECT_EQ(140, y);
523 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
524 segment = FPDFPath_GetPathSegment(green_rect, 2);
525 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
526 EXPECT_EQ(140, x);
527 EXPECT_EQ(140, y);
529 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
530 segment = FPDFPath_GetPathSegment(green_rect, 3);
531 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
532 EXPECT_EQ(140, x);
533 EXPECT_EQ(100, y);
535 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
536 segment = FPDFPath_GetPathSegment(green_rect, 4);
537 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
538 EXPECT_EQ(100, x);
539 EXPECT_EQ(100, y);
541 EXPECT_TRUE(FPDFPathSegment_GetClose(segment));
542
543 EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect, FPDF_FILLMODE_WINDING, 0));
544 FPDFPage_InsertObject(page, green_rect);
545 {
546 ScopedFPDFBitmap page_bitmap = RenderPage(page);
547 CompareBitmap(page_bitmap.get(), 612, 792,
548 "7b0b87604594e773add528fae567a558");
549 }
550
551 // Add a black triangle.
552 FPDF_PAGEOBJECT black_path = FPDFPageObj_CreateNewPath(400, 100);
553 EXPECT_TRUE(FPDFPageObj_SetFillColor(black_path, 0, 0, 0, 200));
554 EXPECT_TRUE(FPDFPath_SetDrawMode(black_path, FPDF_FILLMODE_ALTERNATE, 0));
555 EXPECT_TRUE(FPDFPath_LineTo(black_path, 400, 200));
556 EXPECT_TRUE(FPDFPath_LineTo(black_path, 300, 100));
557 EXPECT_TRUE(FPDFPath_Close(black_path));
558
559 // Make sure the path has 3 points (1 CFX_Path::Point::Type::kMove and 2
560 // CFX_Path::Point::Type::kLine).
561 ASSERT_EQ(3, FPDFPath_CountSegments(black_path));
562 // Verify actual coordinates.
563 segment = FPDFPath_GetPathSegment(black_path, 0);
564 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
565 EXPECT_EQ(400, x);
566 EXPECT_EQ(100, y);
568 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
569 segment = FPDFPath_GetPathSegment(black_path, 1);
570 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
571 EXPECT_EQ(400, x);
572 EXPECT_EQ(200, y);
574 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
575 segment = FPDFPath_GetPathSegment(black_path, 2);
576 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
577 EXPECT_EQ(300, x);
578 EXPECT_EQ(100, y);
580 EXPECT_TRUE(FPDFPathSegment_GetClose(segment));
581 // Make sure out of bounds index access fails properly.
582 EXPECT_FALSE(FPDFPath_GetPathSegment(black_path, 3));
583
584 FPDFPage_InsertObject(page, black_path);
585 {
586 ScopedFPDFBitmap page_bitmap = RenderPage(page);
587 CompareBitmap(page_bitmap.get(), 612, 792,
588 "eadc8020a14dfcf091da2688733d8806");
589 }
590
591 // Now add a more complex blue path.
592 FPDF_PAGEOBJECT blue_path = FPDFPageObj_CreateNewPath(200, 200);
593 EXPECT_TRUE(FPDFPageObj_SetFillColor(blue_path, 0, 0, 255, 255));
594 EXPECT_TRUE(FPDFPath_SetDrawMode(blue_path, FPDF_FILLMODE_WINDING, 0));
595 EXPECT_TRUE(FPDFPath_LineTo(blue_path, 230, 230));
596 EXPECT_TRUE(FPDFPath_BezierTo(blue_path, 250, 250, 280, 280, 300, 300));
597 EXPECT_TRUE(FPDFPath_LineTo(blue_path, 325, 325));
598 EXPECT_TRUE(FPDFPath_LineTo(blue_path, 350, 325));
599 EXPECT_TRUE(FPDFPath_BezierTo(blue_path, 375, 330, 390, 360, 400, 400));
600 EXPECT_TRUE(FPDFPath_Close(blue_path));
601 FPDFPage_InsertObject(page, blue_path);
602 const char* last_checksum = []() {
603 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
604 return "ed14c60702b1489c597c7d46ece7f86d";
605 }
606 return "9823e1a21bd9b72b6a442ba4f12af946";
607 }();
608 {
609 ScopedFPDFBitmap page_bitmap = RenderPage(page);
610 CompareBitmap(page_bitmap.get(), 612, 792, last_checksum);
611 }
612
613 // Now save the result, closing the page and document
614 EXPECT_TRUE(FPDFPage_GenerateContent(page));
615 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
617
618 // Render the saved result
619 VerifySavedDocument(612, 792, last_checksum);
620}
621
623 // Load document with a clipped rectangle.
624 ASSERT_TRUE(OpenDocument("clip_path.pdf"));
625 FPDF_PAGE page = LoadPage(0);
626 ASSERT_TRUE(page);
627
628 ASSERT_EQ(1, FPDFPage_CountObjects(page));
629
630 FPDF_PAGEOBJECT triangle = FPDFPage_GetObject(page, 0);
631 ASSERT_TRUE(triangle);
632
633 // Test that we got the expected triangle.
634 ASSERT_EQ(4, FPDFPath_CountSegments(triangle));
635
636 FPDF_PATHSEGMENT segment = FPDFPath_GetPathSegment(triangle, 0);
637 float x;
638 float y;
639 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
640 EXPECT_EQ(10, x);
641 EXPECT_EQ(10, y);
643 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
644
645 segment = FPDFPath_GetPathSegment(triangle, 1);
646 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
647 EXPECT_EQ(25, x);
648 EXPECT_EQ(40, y);
650 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
651
652 segment = FPDFPath_GetPathSegment(triangle, 2);
653 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
654 EXPECT_EQ(40, x);
655 EXPECT_EQ(10, y);
657 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
658
659 segment = FPDFPath_GetPathSegment(triangle, 3);
660 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
661 EXPECT_TRUE(FPDFPathSegment_GetClose(segment));
662
663 // Test FPDFPageObj_GetClipPath().
664 ASSERT_EQ(nullptr, FPDFPageObj_GetClipPath(nullptr));
665
666 FPDF_CLIPPATH clip_path = FPDFPageObj_GetClipPath(triangle);
667 ASSERT_TRUE(clip_path);
668
669 // Test FPDFClipPath_CountPaths().
670 ASSERT_EQ(-1, FPDFClipPath_CountPaths(nullptr));
671 ASSERT_EQ(1, FPDFClipPath_CountPaths(clip_path));
672
673 // Test FPDFClipPath_CountPathSegments().
674 ASSERT_EQ(-1, FPDFClipPath_CountPathSegments(nullptr, 0));
675 ASSERT_EQ(-1, FPDFClipPath_CountPathSegments(clip_path, -1));
676 ASSERT_EQ(-1, FPDFClipPath_CountPathSegments(clip_path, 1));
677 ASSERT_EQ(4, FPDFClipPath_CountPathSegments(clip_path, 0));
678
679 // FPDFClipPath_GetPathSegment() negative testing.
680 ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(nullptr, 0, 0));
681 ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(clip_path, -1, 0));
682 ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(clip_path, 1, 0));
683 ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(clip_path, 0, -1));
684 ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(clip_path, 0, 4));
685
686 // FPDFClipPath_GetPathSegment() positive testing.
687 segment = FPDFClipPath_GetPathSegment(clip_path, 0, 0);
688 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
689 EXPECT_EQ(10, x);
690 EXPECT_EQ(15, y);
692 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
693
694 segment = FPDFClipPath_GetPathSegment(clip_path, 0, 1);
695 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
696 EXPECT_EQ(40, x);
697 EXPECT_EQ(15, y);
699 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
700
701 segment = FPDFClipPath_GetPathSegment(clip_path, 0, 2);
702 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
703 EXPECT_EQ(40, x);
704 EXPECT_EQ(35, y);
706 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
707
708 segment = FPDFClipPath_GetPathSegment(clip_path, 0, 3);
709 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
710 EXPECT_EQ(10, x);
711 EXPECT_EQ(35, y);
713 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
714
715 UnloadPage(page);
716}
717
719 // Load document with a clipped rectangle.
720 ASSERT_TRUE(OpenDocument("bug_1399.pdf"));
721 FPDF_PAGE page = LoadPage(0);
722 ASSERT_TRUE(page);
723
724 ASSERT_EQ(7, FPDFPage_CountObjects(page));
725
726 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 0);
727 ASSERT_TRUE(obj);
728
729 ASSERT_EQ(2, FPDFPath_CountSegments(obj));
730
731 FPDF_PATHSEGMENT segment = FPDFPath_GetPathSegment(obj, 0);
732 float x;
733 float y;
734 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
735 EXPECT_FLOAT_EQ(107.718f, x);
736 EXPECT_FLOAT_EQ(719.922f, y);
738 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
739
740 segment = FPDFPath_GetPathSegment(obj, 1);
741 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
742 EXPECT_FLOAT_EQ(394.718f, x);
743 EXPECT_FLOAT_EQ(719.922f, y);
745 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
746
747 FPDF_CLIPPATH clip_path = FPDFPageObj_GetClipPath(obj);
748 ASSERT_TRUE(clip_path);
749
750 EXPECT_EQ(-1, FPDFClipPath_CountPaths(clip_path));
751 EXPECT_EQ(-1, FPDFClipPath_CountPathSegments(clip_path, 0));
752 EXPECT_FALSE(FPDFClipPath_GetPathSegment(clip_path, 0, 0));
753
754 UnloadPage(page);
755}
756
758 static const char kOriginalChecksum[] = "126366fb95e6caf8ea196780075b22b2";
759 static const char kRemovedChecksum[] = "6ec2f27531927882624b37bc7d8e12f4";
760
761 ASSERT_TRUE(OpenDocument("bug_1549.pdf"));
762 FPDF_PAGE page = LoadPage(0);
763
764 {
765 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
766 CompareBitmap(bitmap.get(), 100, 150, kOriginalChecksum);
767
768 ScopedFPDFPageObject obj(FPDFPage_GetObject(page, 0));
769 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj.get()));
770 ASSERT_TRUE(FPDFPage_RemoveObject(page, obj.get()));
771 }
772
773 ASSERT_TRUE(FPDFPage_GenerateContent(page));
774
775 {
776 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
777 CompareBitmap(bitmap.get(), 100, 150, kRemovedChecksum);
778 }
779
780 ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
781 UnloadPage(page);
782
783 // TODO(crbug.com/pdfium/1549): Should be `kRemovedChecksum`.
784 VerifySavedDocument(100, 150, "4f9889cd5993db20f1ab37d677ac8d26");
785}
786
788 // Load document with some text.
789 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
790 FPDF_PAGE page = LoadPage(0);
791 ASSERT_TRUE(page);
792
793 // Get the "Hello, world!" text object and change it.
794 ASSERT_EQ(2, FPDFPage_CountObjects(page));
795 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
796 ASSERT_TRUE(page_object);
797 ScopedFPDFWideString text1 = GetFPDFWideString(L"Changed for SetText test");
798 EXPECT_TRUE(FPDFText_SetText(page_object, text1.get()));
799
800 // Verify the "Hello, world!" text is gone and "Changed for SetText test" is
801 // now displayed.
802 ASSERT_EQ(2, FPDFPage_CountObjects(page));
803
804 const char* changed_checksum = []() {
805 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
806#if BUILDFLAG(IS_WIN)
807 return "e1c530ca0705424f19a1b7ff0bffdbaa";
808#elif BUILDFLAG(IS_APPLE)
809 return "c65881cb16125c23e5513a16dc68f3a2";
810#else
811 return "4a8345a139507932729e07d4831cbe2b";
812#endif
813 }
814#if BUILDFLAG(IS_APPLE)
815 return "b720e83476fd6819d47c533f1f43c728";
816#else
817 return "9a85b9354a69c61772ed24151c140f46";
818#endif
819 }();
820 {
821 ScopedFPDFBitmap page_bitmap = RenderPage(page);
822 CompareBitmap(page_bitmap.get(), 200, 200, changed_checksum);
823 }
824
825 // Now save the result.
826 EXPECT_TRUE(FPDFPage_GenerateContent(page));
827 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
828
829 UnloadPage(page);
830
831 // Re-open the file and check the changes were kept in the saved .pdf.
832 ASSERT_TRUE(OpenSavedDocument());
833 FPDF_PAGE saved_page = LoadSavedPage(0);
834 ASSERT_TRUE(saved_page);
835 EXPECT_EQ(2, FPDFPage_CountObjects(saved_page));
836 {
837 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
838 CompareBitmap(page_bitmap.get(), 200, 200, changed_checksum);
839 }
840
841 CloseSavedPage(saved_page);
842 CloseSavedDocument();
843}
844
846 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
847 FPDF_PAGE page = LoadPage(0);
848 ASSERT_TRUE(page);
849
850 ASSERT_EQ(2, FPDFPage_CountObjects(page));
851 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
852 ASSERT_TRUE(page_object);
853
854 const uint32_t kDummyValue = 42;
855 EXPECT_FALSE(FPDFText_SetCharcodes(nullptr, nullptr, 0));
856 EXPECT_FALSE(FPDFText_SetCharcodes(nullptr, nullptr, 1));
857 EXPECT_FALSE(FPDFText_SetCharcodes(nullptr, &kDummyValue, 0));
858 EXPECT_FALSE(FPDFText_SetCharcodes(nullptr, &kDummyValue, 1));
859 EXPECT_FALSE(FPDFText_SetCharcodes(page_object, nullptr, 1));
860
861 UnloadPage(page);
862}
863
865 // Load document with some text, with parts clipped.
866 ASSERT_TRUE(OpenDocument("bug_1558.pdf"));
867 FPDF_PAGE page = LoadPage(0);
868 ASSERT_TRUE(page);
869
870 const char* original_checksum = []() {
871 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
872#if BUILDFLAG(IS_WIN)
873 return "0822ec5d476e8371544ef4bb7a0596e1";
874#elif BUILDFLAG(IS_APPLE)
875 return "721dae4e2258a52a000af88d09ec75ca";
876#else
877 return "3c04e3acc732faaf39fb0c19efd056ac";
878#endif
879 }
880#if BUILDFLAG(IS_APPLE)
881 return "ae7a25c85e0e2dd0c5cb9dd5cd37f6df";
882#else
883 return "7af7fe5b281298261eb66ac2d22f5054";
884#endif
885 }();
886 {
887 // When opened before any editing and saving, the clipping path is rendered.
888 ScopedFPDFBitmap original_bitmap = RenderPage(page);
889 CompareBitmap(original_bitmap.get(), 200, 200, original_checksum);
890 }
891
892 // "Change" the text in the objects to their current values to force them to
893 // regenerate when saving.
894 {
895 ScopedFPDFTextPage text_page(FPDFText_LoadPage(page));
896 ASSERT_TRUE(text_page);
897 const int obj_count = FPDFPage_CountObjects(page);
898 ASSERT_EQ(2, obj_count);
899 for (int i = 0; i < obj_count; ++i) {
900 FPDF_PAGEOBJECT text_obj = FPDFPage_GetObject(page, i);
901 ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(text_obj));
902 unsigned long size =
903 FPDFTextObj_GetText(text_obj, text_page.get(),
904 /*buffer=*/nullptr, /*length=*/0);
905 ASSERT_GT(size, 0u);
906 std::vector<FPDF_WCHAR> buffer = GetFPDFWideStringBuffer(size);
907 ASSERT_EQ(size, FPDFTextObj_GetText(text_obj, text_page.get(),
908 buffer.data(), size));
909 EXPECT_TRUE(FPDFText_SetText(text_obj, buffer.data()));
910 }
911 }
912
913 {
914 // After editing but before saving, the clipping path is retained.
915 ScopedFPDFBitmap edited_bitmap = RenderPage(page);
916 CompareBitmap(edited_bitmap.get(), 200, 200, original_checksum);
917 }
918
919 // Save the file.
920 EXPECT_TRUE(FPDFPage_GenerateContent(page));
921 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
922 UnloadPage(page);
923
924 // Open the saved copy and render it.
925 ASSERT_TRUE(OpenSavedDocument());
926 FPDF_PAGE saved_page = LoadSavedPage(0);
927 ASSERT_TRUE(saved_page);
928
929 {
930 ScopedFPDFBitmap saved_bitmap = RenderSavedPage(saved_page);
931 CompareBitmap(saved_bitmap.get(), 200, 200, original_checksum);
932 }
933
934 CloseSavedPage(saved_page);
935 CloseSavedDocument();
936}
937
939 // Load document with some text within a clipping path.
940 ASSERT_TRUE(OpenDocument("bug_1574.pdf"));
941 FPDF_PAGE page = LoadPage(0);
942 ASSERT_TRUE(page);
943
944 const char* original_checksum = []() {
945 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
946#if BUILDFLAG(IS_WIN)
947 return "6f22adb3ba2a2c60a940bfb52e14dd58";
948#elif BUILDFLAG(IS_APPLE)
949 return "afa2260cbe84be78867940d72420d0b4";
950#else
951 return "d76a31d931a350f0809226a41029a9a4";
952#endif
953 }
954#if BUILDFLAG(IS_APPLE)
955 return "1226bc2b8072622eb28f52321876e814";
956#else
957 return "c5241eef60b9eac68ed1f2a5fd002703";
958#endif
959 }();
960 {
961 // When opened before any editing and saving, the text object is rendered.
962 ScopedFPDFBitmap original_bitmap = RenderPage(page);
963 CompareBitmap(original_bitmap.get(), 200, 300, original_checksum);
964 }
965
966 // "Change" the text in the objects to their current values to force them to
967 // regenerate when saving.
968 {
969 ScopedFPDFTextPage text_page(FPDFText_LoadPage(page));
970 ASSERT_TRUE(text_page);
971
972 ASSERT_EQ(2, FPDFPage_CountObjects(page));
973 FPDF_PAGEOBJECT text_obj = FPDFPage_GetObject(page, 1);
974 ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(text_obj));
975
976 unsigned long size = FPDFTextObj_GetText(text_obj, text_page.get(),
977 /*buffer=*/nullptr, /*length=*/0);
978 ASSERT_GT(size, 0u);
979 std::vector<FPDF_WCHAR> buffer = GetFPDFWideStringBuffer(size);
980 ASSERT_EQ(size, FPDFTextObj_GetText(text_obj, text_page.get(),
981 buffer.data(), size));
982 EXPECT_TRUE(FPDFText_SetText(text_obj, buffer.data()));
983 }
984
985 // Save the file.
986 EXPECT_TRUE(FPDFPage_GenerateContent(page));
987 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
988 UnloadPage(page);
989
990 // Open the saved copy and render it.
991 ASSERT_TRUE(OpenSavedDocument());
992 FPDF_PAGE saved_page = LoadSavedPage(0);
993 ASSERT_TRUE(saved_page);
994
995 {
996 ScopedFPDFBitmap saved_bitmap = RenderSavedPage(saved_page);
997 CompareBitmap(saved_bitmap.get(), 200, 300, original_checksum);
998 }
999
1000 CloseSavedPage(saved_page);
1001 CloseSavedDocument();
1002}
1003
1005 ASSERT_TRUE(OpenDocument("bug_1893.pdf"));
1006 FPDF_PAGE page = LoadPage(0);
1007 {
1008 const char* original_checksum = []() {
1009 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
1010#if BUILDFLAG(IS_WIN)
1011 return "10c8257bb54b4431196d963d68d45f12";
1012#elif BUILDFLAG(IS_APPLE)
1013 return "c42eef2028cb86a0a8601d61707b126f";
1014#else
1015 return "d8be4379e729242785945458924318a3";
1016#endif
1017 }
1018#if BUILDFLAG(IS_APPLE)
1019 return "0964322399241618539b474dbf9d40c6";
1020#else
1021 return "c3672f206e47d98677401f1617ad56eb";
1022#endif
1023 }();
1024
1025 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
1026 CompareBitmap(bitmap.get(), 200, 300, original_checksum);
1027 }
1028
1029 EXPECT_EQ(3, FPDFPage_CountObjects(page));
1030
1031 const char* removed_checksum = []() {
1032 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
1033#if BUILDFLAG(IS_WIN)
1034 return "95484d03b9da898617f297b1429f7f84";
1035#elif BUILDFLAG(IS_APPLE)
1036 return "7222709eca0e8f72a66ce06283f7c10f";
1037#else
1038 return "4a02191e033dddeb2110d55af3f14544";
1039#endif
1040 }
1041#if BUILDFLAG(IS_APPLE)
1042 return "d0837f2b8809a5902d3c4219441fbafe";
1043#else
1044 return "e9c0cbd6adcb2151b4e36a61ab26a20a";
1045#endif
1046 }();
1047
1048 // Remove the underline and regenerate the page content.
1049 {
1050 ScopedFPDFPageObject object(FPDFPage_GetObject(page, 0));
1051 ASSERT_TRUE(FPDFPage_RemoveObject(page, object.get()));
1052 ASSERT_TRUE(FPDFPage_GenerateContent(page));
1053
1054 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
1055 CompareBitmap(bitmap.get(), 200, 300, removed_checksum);
1056 }
1057
1058 ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1059 UnloadPage(page);
1060
1061 {
1062 // TODO(crbug.com/pdfium/1893): The saved result should match
1063 // `removed_checksum`. But in the actual saved result, the remaining text
1064 // objects were upside down. Remove `wrong_checksum` after fixing this
1065 // issue.
1066 const char* wrong_checksum = []() {
1067 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
1068#if BUILDFLAG(IS_WIN)
1069 return "441cada6218d4fd79dbe0ba95093524e";
1070#elif BUILDFLAG(IS_APPLE)
1071 return "627290533339e0ae493dc9385fac53e2";
1072#else
1073 return "57da26dcb24503403cadb27ed8bb46c6";
1074#endif
1075 }
1076#if BUILDFLAG(IS_APPLE)
1077 return "c3b6a8ecd863914044f5f79137c606b5";
1078#else
1079 return "cb19480a846e4efd36418cbd7412118e";
1080#endif
1081 }();
1082
1083 ASSERT_TRUE(OpenSavedDocument());
1084 FPDF_PAGE saved_page = LoadSavedPage(0);
1085 ScopedFPDFBitmap bitmap = RenderSavedPageWithFlags(saved_page, FPDF_ANNOT);
1086 CompareBitmap(bitmap.get(), 200, 300, wrong_checksum);
1087 CloseSavedPage(saved_page);
1088 CloseSavedDocument();
1089 }
1090}
1091
1093 // Load document with some text.
1094 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
1095 FPDF_PAGE page = LoadPage(0);
1096 ASSERT_TRUE(page);
1097
1098 // Show what the original file looks like.
1099 {
1100 ScopedFPDFBitmap page_bitmap = RenderPage(page);
1101 CompareBitmap(page_bitmap.get(), 200, 200, HelloWorldChecksum());
1102 }
1103
1104 // Get the "Hello, world!" text object and remove it.
1105 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1106 {
1107 ScopedFPDFPageObject page_object(FPDFPage_GetObject(page, 0));
1108 ASSERT_TRUE(page_object);
1109 ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(page_object.get()));
1110 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object.get()));
1111 }
1112 ASSERT_EQ(1, FPDFPage_CountObjects(page));
1113
1114 // Verify the "Hello, world!" text is gone.
1115 {
1116 ScopedFPDFBitmap page_bitmap = RenderPage(page);
1117 CompareBitmap(page_bitmap.get(), 200, 200, FirstRemovedChecksum());
1118 }
1119
1120 // Verify the rendering again after calling FPDFPage_GenerateContent().
1121 ASSERT_TRUE(FPDFPage_GenerateContent(page));
1122 {
1123 ScopedFPDFBitmap page_bitmap = RenderPage(page);
1124 CompareBitmap(page_bitmap.get(), 200, 200, FirstRemovedChecksum());
1125 }
1126
1127 // Save the document and verify it after reloading.
1128 ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1129 VerifySavedDocument(200, 200, FirstRemovedChecksum());
1130
1131 // Verify removed/renamed resources are no longer there.
1132 EXPECT_THAT(GetString(), Not(HasSubstr("/F1")));
1133 EXPECT_THAT(GetString(), Not(HasSubstr("/F2")));
1134 EXPECT_THAT(GetString(), Not(HasSubstr("/Times-Roman")));
1135
1136 UnloadPage(page);
1137}
1138
1141 // Load document with some text.
1142 ASSERT_TRUE(OpenDocument("hello_world_2_pages.pdf"));
1143 FPDF_PAGE page1 = LoadPage(0);
1144 ASSERT_TRUE(page1);
1145 FPDF_PAGE page2 = LoadPage(1);
1146 ASSERT_TRUE(page2);
1147
1148 // Show what the original file looks like.
1149 {
1150 ScopedFPDFBitmap page1_bitmap = RenderPage(page1);
1151 CompareBitmap(page1_bitmap.get(), 200, 200, HelloWorldChecksum());
1152 ScopedFPDFBitmap page2_bitmap = RenderPage(page2);
1153 CompareBitmap(page2_bitmap.get(), 200, 200, HelloWorldChecksum());
1154 }
1155
1156 // Get the "Hello, world!" text object from page 1 and remove it.
1157 ASSERT_EQ(2, FPDFPage_CountObjects(page1));
1158 {
1159 ScopedFPDFPageObject page_object(FPDFPage_GetObject(page1, 0));
1160 ASSERT_TRUE(page_object);
1161 ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(page_object.get()));
1162 EXPECT_TRUE(FPDFPage_RemoveObject(page1, page_object.get()));
1163 }
1164 ASSERT_EQ(1, FPDFPage_CountObjects(page1));
1165
1166 // Verify the "Hello, world!" text is gone from page 1.
1167 {
1168 ScopedFPDFBitmap page1_bitmap = RenderPage(page1);
1169 CompareBitmap(page1_bitmap.get(), 200, 200, FirstRemovedChecksum());
1170 ScopedFPDFBitmap page2_bitmap = RenderPage(page2);
1171 CompareBitmap(page2_bitmap.get(), 200, 200, HelloWorldChecksum());
1172 }
1173
1174 // Verify the rendering again after calling FPDFPage_GenerateContent().
1175 ASSERT_TRUE(FPDFPage_GenerateContent(page1));
1176 {
1177 ScopedFPDFBitmap page1_bitmap = RenderPage(page1);
1178 CompareBitmap(page1_bitmap.get(), 200, 200, FirstRemovedChecksum());
1179 ScopedFPDFBitmap page2_bitmap = RenderPage(page2);
1180 CompareBitmap(page2_bitmap.get(), 200, 200, HelloWorldChecksum());
1181 }
1182
1183 // Save the document and verify it after reloading.
1184 ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1185 ASSERT_TRUE(OpenSavedDocument());
1186 FPDF_PAGE saved_page1 = LoadSavedPage(0);
1187 VerifySavedRendering(saved_page1, 200, 200, FirstRemovedChecksum());
1188 CloseSavedPage(saved_page1);
1189 FPDF_PAGE saved_page2 = LoadSavedPage(1);
1190 VerifySavedRendering(saved_page2, 200, 200, HelloWorldChecksum());
1191 CloseSavedPage(saved_page2);
1192 CloseSavedDocument();
1193
1194 std::vector<std::string> split_saved_data = StringSplit(GetString(), '\n');
1195 // Verify removed/renamed resources are in the save PDF the correct number of
1196 // times.
1197 EXPECT_THAT(split_saved_data, Contains(HasSubstr("/F1")).Times(1));
1198 EXPECT_THAT(split_saved_data, Contains(HasSubstr("/F2")).Times(1));
1199 EXPECT_THAT(split_saved_data, Contains(HasSubstr("/Times-Roman")).Times(1));
1200
1201 UnloadPage(page1);
1202 UnloadPage(page2);
1203}
1204
1207 // Load document with some text.
1208 ASSERT_TRUE(OpenDocument("hello_world_2_pages_split_streams.pdf"));
1209 FPDF_PAGE page1 = LoadPage(0);
1210 ASSERT_TRUE(page1);
1211 FPDF_PAGE page2 = LoadPage(1);
1212 ASSERT_TRUE(page2);
1213
1214 // Show what the original file looks like.
1215 {
1216 ScopedFPDFBitmap page1_bitmap = RenderPage(page1);
1217 CompareBitmap(page1_bitmap.get(), 200, 200, HelloWorldChecksum());
1218 ScopedFPDFBitmap page2_bitmap = RenderPage(page2);
1219 CompareBitmap(page2_bitmap.get(), 200, 200, HelloWorldChecksum());
1220 }
1221
1222 // Get the "Hello, world!" text object from page 1 and remove it.
1223 ASSERT_EQ(2, FPDFPage_CountObjects(page1));
1224 {
1225 ScopedFPDFPageObject page_object(FPDFPage_GetObject(page1, 0));
1226 ASSERT_TRUE(page_object);
1227 ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(page_object.get()));
1228 EXPECT_TRUE(FPDFPage_RemoveObject(page1, page_object.get()));
1229 }
1230 ASSERT_EQ(1, FPDFPage_CountObjects(page1));
1231
1232 // Verify the "Hello, world!" text is gone from page 1.
1233 {
1234 ScopedFPDFBitmap page1_bitmap = RenderPage(page1);
1235 CompareBitmap(page1_bitmap.get(), 200, 200, FirstRemovedChecksum());
1236 ScopedFPDFBitmap page2_bitmap = RenderPage(page2);
1237 CompareBitmap(page2_bitmap.get(), 200, 200, HelloWorldChecksum());
1238 }
1239
1240 // Verify the rendering again after calling FPDFPage_GenerateContent().
1241 ASSERT_TRUE(FPDFPage_GenerateContent(page1));
1242 {
1243 ScopedFPDFBitmap page1_bitmap = RenderPage(page1);
1244 CompareBitmap(page1_bitmap.get(), 200, 200, FirstRemovedChecksum());
1245 ScopedFPDFBitmap page2_bitmap = RenderPage(page2);
1246 CompareBitmap(page2_bitmap.get(), 200, 200, HelloWorldChecksum());
1247 }
1248
1249 // Save the document and verify it after reloading.
1250 ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1251 ASSERT_TRUE(OpenSavedDocument());
1252 FPDF_PAGE saved_page1 = LoadSavedPage(0);
1253 VerifySavedRendering(saved_page1, 200, 200, FirstRemovedChecksum());
1254 CloseSavedPage(saved_page1);
1255 FPDF_PAGE saved_page2 = LoadSavedPage(1);
1256 VerifySavedRendering(saved_page2, 200, 200, HelloWorldChecksum());
1257 CloseSavedPage(saved_page2);
1258 CloseSavedDocument();
1259
1260 UnloadPage(page1);
1261 UnloadPage(page2);
1262}
1263
1265 // Load document with some text.
1266 ASSERT_TRUE(OpenDocument("hello_world_2_pages_shared_resources_dict.pdf"));
1267 FPDF_PAGE page1 = LoadPage(0);
1268 ASSERT_TRUE(page1);
1269 FPDF_PAGE page2 = LoadPage(1);
1270 ASSERT_TRUE(page2);
1271
1272 // Show what the original file looks like.
1273 {
1274 ScopedFPDFBitmap page1_bitmap = RenderPage(page1);
1275 CompareBitmap(page1_bitmap.get(), 200, 200, HelloWorldChecksum());
1276 ScopedFPDFBitmap page2_bitmap = RenderPage(page2);
1277 CompareBitmap(page2_bitmap.get(), 200, 200, HelloWorldChecksum());
1278 }
1279
1280 // Get the "Hello, world!" text object from page 1 and remove it.
1281 ASSERT_EQ(2, FPDFPage_CountObjects(page1));
1282 {
1283 ScopedFPDFPageObject page_object(FPDFPage_GetObject(page1, 0));
1284 ASSERT_TRUE(page_object);
1285 ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(page_object.get()));
1286 EXPECT_TRUE(FPDFPage_RemoveObject(page1, page_object.get()));
1287 }
1288 ASSERT_EQ(1, FPDFPage_CountObjects(page1));
1289
1290 // Verify the "Hello, world!" text is gone from page 1
1291 {
1292 ScopedFPDFBitmap page1_bitmap = RenderPage(page1);
1293 CompareBitmap(page1_bitmap.get(), 200, 200, FirstRemovedChecksum());
1294 ScopedFPDFBitmap page2_bitmap = RenderPage(page2);
1295 CompareBitmap(page2_bitmap.get(), 200, 200, HelloWorldChecksum());
1296 }
1297
1298 // Verify the rendering again after calling FPDFPage_GenerateContent().
1299 ASSERT_TRUE(FPDFPage_GenerateContent(page1));
1300 {
1301 ScopedFPDFBitmap page1_bitmap = RenderPage(page1);
1302 CompareBitmap(page1_bitmap.get(), 200, 200, FirstRemovedChecksum());
1303 ScopedFPDFBitmap page2_bitmap = RenderPage(page2);
1304 CompareBitmap(page2_bitmap.get(), 200, 200, HelloWorldChecksum());
1305 }
1306
1307 // Save the document and verify it after reloading.
1308 ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1309 ASSERT_TRUE(OpenSavedDocument());
1310 FPDF_PAGE saved_page1 = LoadSavedPage(0);
1311 VerifySavedRendering(saved_page1, 200, 200, FirstRemovedChecksum());
1312 CloseSavedPage(saved_page1);
1313 FPDF_PAGE saved_page2 = LoadSavedPage(1);
1314 VerifySavedRendering(saved_page2, 200, 200, HelloWorldChecksum());
1315 CloseSavedPage(saved_page2);
1316 CloseSavedDocument();
1317
1318 UnloadPage(page1);
1319 UnloadPage(page2);
1320}
1321
1322void CheckMarkCounts(FPDF_PAGE page,
1323 int start_from,
1324 int expected_object_count,
1325 size_t expected_prime_count,
1326 size_t expected_square_count,
1327 size_t expected_greater_than_ten_count,
1328 size_t expected_bounds_count) {
1329 int object_count = FPDFPage_CountObjects(page);
1330 ASSERT_EQ(expected_object_count, object_count);
1331
1332 size_t prime_count = 0;
1333 size_t square_count = 0;
1334 size_t greater_than_ten_count = 0;
1335 size_t bounds_count = 0;
1336 for (int i = 0; i < object_count; ++i) {
1337 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1338
1339 int mark_count = FPDFPageObj_CountMarks(page_object);
1340 for (int j = 0; j < mark_count; ++j) {
1341 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
1342
1343 char buffer[256];
1344 unsigned long name_len = 999u;
1345 ASSERT_TRUE(
1346 FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
1347 EXPECT_GT(name_len, 0u);
1348 EXPECT_NE(999u, name_len);
1349 std::wstring name =
1350 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1351 if (name == L"Prime") {
1352 prime_count++;
1353 } else if (name == L"Square") {
1354 square_count++;
1355 int expected_square = start_from + i;
1356 EXPECT_EQ(1, FPDFPageObjMark_CountParams(mark));
1357
1358 unsigned long get_param_key_return = 999u;
1359 ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark, 0, buffer, sizeof(buffer),
1360 &get_param_key_return));
1361 EXPECT_EQ((6u + 1u) * 2u, get_param_key_return);
1362 std::wstring key =
1363 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1364 EXPECT_EQ(L"Factor", key);
1365
1366 EXPECT_EQ(FPDF_OBJECT_NUMBER,
1368 int square_root;
1369 EXPECT_TRUE(
1370 FPDFPageObjMark_GetParamIntValue(mark, "Factor", &square_root));
1371 EXPECT_EQ(expected_square, square_root * square_root);
1372 } else if (name == L"GreaterThanTen") {
1373 greater_than_ten_count++;
1374 } else if (name == L"Bounds") {
1375 bounds_count++;
1376 EXPECT_EQ(1, FPDFPageObjMark_CountParams(mark));
1377
1378 unsigned long get_param_key_return = 999u;
1379 ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark, 0, buffer, sizeof(buffer),
1380 &get_param_key_return));
1381 EXPECT_EQ((8u + 1u) * 2u, get_param_key_return);
1382 std::wstring key =
1383 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1384 EXPECT_EQ(L"Position", key);
1385
1386 EXPECT_EQ(FPDF_OBJECT_STRING,
1388 unsigned long length;
1390 mark, "Position", buffer, sizeof(buffer), &length));
1391 ASSERT_GT(length, 0u);
1392 std::wstring value =
1393 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1394
1395 // "Position" can be "First", "Last", or "End".
1396 if (i == 0) {
1397 EXPECT_EQ((5u + 1u) * 2u, length);
1398 EXPECT_EQ(L"First", value);
1399 } else if (i == object_count - 1) {
1400 if (length == (4u + 1u) * 2u) {
1401 EXPECT_EQ(L"Last", value);
1402 } else if (length == (3u + 1u) * 2u) {
1403 EXPECT_EQ(L"End", value);
1404 } else {
1405 FAIL();
1406 }
1407 } else {
1408 FAIL();
1409 }
1410 } else {
1411 FAIL();
1412 }
1413 }
1414 }
1415
1416 // Expect certain number of tagged objects. The test file contains strings
1417 // from 1 to 19.
1418 EXPECT_EQ(expected_prime_count, prime_count);
1419 EXPECT_EQ(expected_square_count, square_count);
1420 EXPECT_EQ(expected_greater_than_ten_count, greater_than_ten_count);
1421 EXPECT_EQ(expected_bounds_count, bounds_count);
1422}
1423
1425 // Load document with some text marked with an indirect property.
1426 ASSERT_TRUE(OpenDocument("text_in_page_marked_indirect.pdf"));
1427 FPDF_PAGE page = LoadPage(0);
1428 ASSERT_TRUE(page);
1429
1430 CheckMarkCounts(page, 1, 19, 8, 4, 9, 1);
1431
1432 UnloadPage(page);
1433}
1434
1436 // Load document with some text.
1437 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
1438 FPDF_PAGE page = LoadPage(0);
1439 ASSERT_TRUE(page);
1440
1441 // Show what the original file looks like.
1442 {
1443 const char* original_checksum = []() {
1444 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
1445#if BUILDFLAG(IS_WIN)
1446 return "cefa45d13f92fb761251661a2c889157";
1447#elif BUILDFLAG(IS_APPLE)
1448 return "b2044dc5b49fdca723d74bd6277df689";
1449#else
1450 return "efc2206b313fff03be8e701907322b06";
1451#endif
1452 }
1453#if BUILDFLAG(IS_APPLE)
1454#ifdef ARCH_CPU_ARM64
1455 return "cdc8e22cf1e7e06999dc456288672a3b";
1456#else
1457 return "966579fb98206858ce2f0a1f94a74d05";
1458#endif // ARCH_CPU_ARM64
1459#else
1460 return "3d5a3de53d5866044c2b6bf339742c97";
1461#endif // BUILDFLAG(IS_APPLE)
1462 }();
1463 ScopedFPDFBitmap page_bitmap = RenderPage(page);
1464 CompareBitmap(page_bitmap.get(), 200, 200, original_checksum);
1465 }
1466
1467 constexpr int expected_object_count = 19;
1468 CheckMarkCounts(page, 1, expected_object_count, 8, 4, 9, 1);
1469
1470 // Get all objects marked with "Prime"
1471 std::vector<FPDF_PAGEOBJECT> primes;
1472 for (int i = 0; i < expected_object_count; ++i) {
1473 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1474
1475 int mark_count = FPDFPageObj_CountMarks(page_object);
1476 for (int j = 0; j < mark_count; ++j) {
1477 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
1478
1479 char buffer[256];
1480 unsigned long name_len = 999u;
1481 ASSERT_TRUE(
1482 FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
1483 EXPECT_GT(name_len, 0u);
1484 EXPECT_NE(999u, name_len);
1485 std::wstring name =
1486 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1487 if (name == L"Prime") {
1488 primes.push_back(page_object);
1489 }
1490 }
1491 }
1492
1493 // Remove all objects marked with "Prime".
1494 for (FPDF_PAGEOBJECT page_object : primes) {
1495 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1496 FPDFPageObj_Destroy(page_object);
1497 }
1498
1499 EXPECT_EQ(11, FPDFPage_CountObjects(page));
1500 const char* non_primes_checksum = []() {
1501 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
1502#if BUILDFLAG(IS_WIN)
1503 return "690c7d4c7850fbe726c2299208425f4f";
1504#elif BUILDFLAG(IS_APPLE)
1505 return "427228e73125ede1050a641cd9b9c8ec";
1506#else
1507 return "10a6558c9e40ea837922e6f2882a2d57";
1508#endif
1509 }
1510#if BUILDFLAG(IS_APPLE)
1511#ifdef ARCH_CPU_ARM64
1512 return "23c4aec321547f51591fe7363a9ea2d6";
1513#else
1514 return "6e19a4dd674b522cd39cf41956559bd6";
1515#endif // ARCH_CPU_ARM64
1516#else
1517 return "bc8623c052f12376c3d8dd09a6cd27df";
1518#endif // BUILDFLAG(IS_APPLE)
1519 }();
1520 const char* non_primes_after_save_checksum = []() {
1521 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
1522#if BUILDFLAG(IS_WIN)
1523 return "690c7d4c7850fbe726c2299208425f4f";
1524#elif BUILDFLAG(IS_APPLE)
1525 return "427228e73125ede1050a641cd9b9c8ec";
1526#else
1527 return "10a6558c9e40ea837922e6f2882a2d57";
1528#endif
1529 }
1530#if BUILDFLAG(IS_APPLE)
1531#ifdef ARCH_CPU_ARM64
1532 return "6bb1ea0d0a512f29edabda33064a0725";
1533#else
1534 return "3cb35c681f8fb5a43a49146ac7caa818";
1535#endif // ARCH_CPU_ARM64
1536#else
1537 return "bc8623c052f12376c3d8dd09a6cd27df";
1538#endif // BUILDFLAG(IS_APPLE)
1539 }();
1540 {
1541 ScopedFPDFBitmap page_bitmap = RenderPage(page);
1542 CompareBitmap(page_bitmap.get(), 200, 200, non_primes_checksum);
1543 }
1544
1545 // Save the file.
1546 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1547 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1548 UnloadPage(page);
1549
1550 // Re-open the file and check the prime marks are not there anymore.
1551 ASSERT_TRUE(OpenSavedDocument());
1552 FPDF_PAGE saved_page = LoadSavedPage(0);
1553 ASSERT_TRUE(saved_page);
1554 EXPECT_EQ(11, FPDFPage_CountObjects(saved_page));
1555
1556 {
1557 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
1558 CompareBitmap(page_bitmap.get(), 200, 200, non_primes_after_save_checksum);
1559 }
1560
1561 CloseSavedPage(saved_page);
1562 CloseSavedDocument();
1563}
1564
1566 // Load document with some text.
1567 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
1568 FPDF_PAGE page = LoadPage(0);
1569 ASSERT_TRUE(page);
1570
1571 constexpr int kExpectedObjectCount = 19;
1572 CheckMarkCounts(page, 1, kExpectedObjectCount, 8, 4, 9, 1);
1573
1574 // Remove all "Prime" content marks.
1575 for (int i = 0; i < kExpectedObjectCount; ++i) {
1576 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1577
1578 int mark_count = FPDFPageObj_CountMarks(page_object);
1579 for (int j = mark_count - 1; j >= 0; --j) {
1580 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
1581
1582 char buffer[256];
1583 unsigned long name_len = 999u;
1584 ASSERT_TRUE(
1585 FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
1586 EXPECT_GT(name_len, 0u);
1587 EXPECT_NE(999u, name_len);
1588 std::wstring name =
1589 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1590 if (name == L"Prime") {
1591 // Remove mark.
1592 EXPECT_TRUE(FPDFPageObj_RemoveMark(page_object, mark));
1593
1594 // Verify there is now one fewer mark in the page object.
1595 EXPECT_EQ(mark_count - 1, FPDFPageObj_CountMarks(page_object));
1596 }
1597 }
1598 }
1599
1600 // Verify there are 0 "Prime" content marks now.
1601 CheckMarkCounts(page, 1, kExpectedObjectCount, 0, 4, 9, 1);
1602
1603 // Save the file.
1604 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1605 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1606 UnloadPage(page);
1607
1608 // Re-open the file and check the prime marks are not there anymore.
1609 ASSERT_TRUE(OpenSavedDocument());
1610 FPDF_PAGE saved_page = LoadSavedPage(0);
1611 ASSERT_TRUE(saved_page);
1612
1613 CheckMarkCounts(saved_page, 1, kExpectedObjectCount, 0, 4, 9, 1);
1614
1615 CloseSavedPage(saved_page);
1616 CloseSavedDocument();
1617}
1618
1620 // Load document with some text.
1621 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
1622 FPDF_PAGE page = LoadPage(0);
1623 ASSERT_TRUE(page);
1624
1625 constexpr int kExpectedObjectCount = 19;
1626 CheckMarkCounts(page, 1, kExpectedObjectCount, 8, 4, 9, 1);
1627
1628 // Remove all "Square" content marks parameters.
1629 for (int i = 0; i < kExpectedObjectCount; ++i) {
1630 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1631
1632 int mark_count = FPDFPageObj_CountMarks(page_object);
1633 for (int j = 0; j < mark_count; ++j) {
1634 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
1635
1636 char buffer[256];
1637 unsigned long name_len = 999u;
1638 ASSERT_TRUE(
1639 FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
1640 EXPECT_GT(name_len, 0u);
1641 EXPECT_NE(999u, name_len);
1642 std::wstring name =
1643 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1644 if (name == L"Square") {
1645 // Show the mark has a "Factor" parameter.
1646 int out_value;
1647 EXPECT_TRUE(
1648 FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
1649
1650 // Remove parameter.
1651 EXPECT_TRUE(FPDFPageObjMark_RemoveParam(page_object, mark, "Factor"));
1652
1653 // Verify the "Factor" parameter is gone.
1654 EXPECT_FALSE(
1655 FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
1656 }
1657 }
1658 }
1659
1660 // Save the file.
1661 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1662 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1663 UnloadPage(page);
1664
1665 // Re-open the file and check the "Factor" parameters are still gone.
1666 ASSERT_TRUE(OpenSavedDocument());
1667 FPDF_PAGE saved_page = LoadSavedPage(0);
1668 ASSERT_TRUE(saved_page);
1669
1670 size_t square_count = 0;
1671 for (int i = 0; i < kExpectedObjectCount; ++i) {
1672 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(saved_page, i);
1673
1674 int mark_count = FPDFPageObj_CountMarks(page_object);
1675 for (int j = 0; j < mark_count; ++j) {
1676 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
1677
1678 char buffer[256];
1679 unsigned long name_len = 999u;
1680 ASSERT_TRUE(
1681 FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
1682 EXPECT_GT(name_len, 0u);
1683 EXPECT_NE(999u, name_len);
1684 std::wstring name =
1685 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1686 if (name == L"Square") {
1687 // Verify the "Factor" parameter is still gone.
1688 int out_value;
1689 EXPECT_FALSE(
1690 FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
1691
1692 ++square_count;
1693 }
1694 }
1695 }
1696
1697 // Verify the parameters are gone, but the marks are not.
1698 EXPECT_EQ(4u, square_count);
1699
1700 CloseSavedPage(saved_page);
1701 CloseSavedDocument();
1702}
1703
1705 // Load document with some text.
1706 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
1707 FPDF_PAGE page = LoadPage(0);
1708 ASSERT_TRUE(page);
1709
1710 // Iterate over all objects, counting the number of times each content mark
1711 // name appears.
1712 CheckMarkCounts(page, 1, 19, 8, 4, 9, 1);
1713
1714 // Remove first page object.
1715 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1716 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1717 FPDFPageObj_Destroy(page_object);
1718
1719 CheckMarkCounts(page, 2, 18, 8, 3, 9, 1);
1720
1721 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1722 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1723
1724 UnloadPage(page);
1725
1726 ASSERT_TRUE(OpenSavedDocument());
1727 FPDF_PAGE saved_page = LoadSavedPage(0);
1728 ASSERT_TRUE(saved_page);
1729
1730 CheckMarkCounts(saved_page, 2, 18, 8, 3, 9, 1);
1731
1732 CloseSavedPage(saved_page);
1733 CloseSavedDocument();
1734}
1735
1737 // Load document with some text.
1738 ASSERT_TRUE(OpenDocument("text_in_page_marked_indirect.pdf"));
1739 FPDF_PAGE page = LoadPage(0);
1740 ASSERT_TRUE(page);
1741
1742 // Iterate over all objects, counting the number of times each content mark
1743 // name appears.
1744 CheckMarkCounts(page, 1, 19, 8, 4, 9, 1);
1745
1746 // Remove first page object.
1747 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1748 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1749 FPDFPageObj_Destroy(page_object);
1750
1751 CheckMarkCounts(page, 2, 18, 8, 3, 9, 1);
1752
1753 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1754 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1755
1756 UnloadPage(page);
1757
1758 ASSERT_TRUE(OpenSavedDocument());
1759 FPDF_PAGE saved_page = LoadSavedPage(0);
1760 ASSERT_TRUE(saved_page);
1761
1762 CheckMarkCounts(saved_page, 2, 18, 8, 3, 9, 1);
1763
1764 CloseSavedPage(saved_page);
1765 CloseSavedDocument();
1766}
1767
1769 // Load document with some text.
1770 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
1771 FPDF_PAGE page = LoadPage(0);
1772 ASSERT_TRUE(page);
1773
1774 // Get the "Hello, world!" text object and remove it.
1775 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1776 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1777 ASSERT_TRUE(page_object);
1778 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1779
1780 // Verify the "Hello, world!" text is gone.
1781 ASSERT_EQ(1, FPDFPage_CountObjects(page));
1782
1783 // Save the file
1784 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1785 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1786 UnloadPage(page);
1787 FPDFPageObj_Destroy(page_object);
1788
1789 // Re-open the file and check the page object count is still 1.
1790 ASSERT_TRUE(OpenSavedDocument());
1791 FPDF_PAGE saved_page = LoadSavedPage(0);
1792 ASSERT_TRUE(saved_page);
1793 EXPECT_EQ(1, FPDFPage_CountObjects(saved_page));
1794 CloseSavedPage(saved_page);
1795 CloseSavedDocument();
1796}
1797
1799 // Load document with some text.
1800 ASSERT_TRUE(OpenDocument("hello_world_split_streams.pdf"));
1801 FPDF_PAGE page = LoadPage(0);
1802 ASSERT_TRUE(page);
1803
1804 // Get the "Hello, world!" text object and remove it. There is another object
1805 // in the same stream that says "Goodbye, world!"
1806 ASSERT_EQ(3, FPDFPage_CountObjects(page));
1807 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1808 ASSERT_TRUE(page_object);
1809 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1810
1811 // Verify the "Hello, world!" text is gone.
1812 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1813 const char* hello_removed_checksum = []() {
1814 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
1815#if BUILDFLAG(IS_WIN)
1816 return "48b5524e20e942d2a8f7e15611968cc7";
1817#elif BUILDFLAG(IS_APPLE)
1818 return "5b9d1dee233eb9d51e23a36c6c631443";
1819#else
1820 return "204c11472f5b93719487de7b9c1b1c93";
1821#endif
1822 }
1823#if BUILDFLAG(IS_APPLE)
1824 return "5508c2f06d104050f74f655693e38c2c";
1825#else
1826 return "a8cd82499cf744e0862ca468c9d4ceb8";
1827#endif
1828 }();
1829 {
1830 ScopedFPDFBitmap page_bitmap = RenderPage(page);
1831 CompareBitmap(page_bitmap.get(), 200, 200, hello_removed_checksum);
1832 }
1833
1834 // Save the file
1835 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1836 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1837 UnloadPage(page);
1838 FPDFPageObj_Destroy(page_object);
1839
1840 // Re-open the file and check the page object count is still 2.
1841 ASSERT_TRUE(OpenSavedDocument());
1842 FPDF_PAGE saved_page = LoadSavedPage(0);
1843 ASSERT_TRUE(saved_page);
1844
1845 EXPECT_EQ(2, FPDFPage_CountObjects(saved_page));
1846 {
1847 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
1848 CompareBitmap(page_bitmap.get(), 200, 200, hello_removed_checksum);
1849 }
1850
1851 CloseSavedPage(saved_page);
1852 CloseSavedDocument();
1853}
1854
1856 // Load document with some text.
1857 ASSERT_TRUE(OpenDocument("hello_world_split_streams.pdf"));
1858 FPDF_PAGE page = LoadPage(0);
1859 ASSERT_TRUE(page);
1860
1861 // Get the "Greetings, world!" text object and remove it. This is the only
1862 // object in the stream.
1863 ASSERT_EQ(3, FPDFPage_CountObjects(page));
1864 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 2);
1865 ASSERT_TRUE(page_object);
1866 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1867
1868 // Verify the "Greetings, world!" text is gone.
1869 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1870 {
1871 ScopedFPDFBitmap page_bitmap = RenderPage(page);
1872 CompareBitmap(page_bitmap.get(), 200, 200, HelloWorldChecksum());
1873 }
1874
1875 // Save the file
1876 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1877 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1878 UnloadPage(page);
1879 FPDFPageObj_Destroy(page_object);
1880
1881 // Re-open the file and check the page object count is still 2.
1882 ASSERT_TRUE(OpenSavedDocument());
1883 FPDF_PAGE saved_page = LoadSavedPage(0);
1884 ASSERT_TRUE(saved_page);
1885
1886 EXPECT_EQ(2, FPDFPage_CountObjects(saved_page));
1887 {
1888 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
1889 CompareBitmap(page_bitmap.get(), 200, 200, HelloWorldChecksum());
1890 }
1891
1892 CloseSavedPage(saved_page);
1893 CloseSavedDocument();
1894}
1895
1897 // Load document with some text split across streams.
1898 ASSERT_TRUE(OpenDocument("split_streams.pdf"));
1899 FPDF_PAGE page = LoadPage(0);
1900 ASSERT_TRUE(page);
1901
1902 // Content stream 0: page objects 0-14.
1903 // Content stream 1: page objects 15-17.
1904 // Content stream 2: page object 18.
1905 ASSERT_EQ(19, FPDFPage_CountObjects(page));
1906 for (int i = 0; i < 19; i++) {
1907 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1908 ASSERT_TRUE(page_object);
1909 CPDF_PageObject* cpdf_page_object =
1911 if (i < 15)
1912 EXPECT_EQ(0, cpdf_page_object->GetContentStream()) << i;
1913 else if (i < 18)
1914 EXPECT_EQ(1, cpdf_page_object->GetContentStream()) << i;
1915 else
1916 EXPECT_EQ(2, cpdf_page_object->GetContentStream()) << i;
1917 }
1918
1919 UnloadPage(page);
1920}
1921
1923 // Load document with some text split across streams.
1924 ASSERT_TRUE(OpenDocument("split_streams.pdf"));
1925 FPDF_PAGE page = LoadPage(0);
1926 ASSERT_TRUE(page);
1927
1928 // Content stream 0: page objects 0-14.
1929 // Content stream 1: page objects 15-17.
1930 // Content stream 2: page object 18.
1931 ASSERT_EQ(19, FPDFPage_CountObjects(page));
1932
1933 // Loop backwards because objects will being removed, which shifts the indexes
1934 // after the removed position.
1935 for (int i = 18; i >= 0; i--) {
1936 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1937 ASSERT_TRUE(page_object);
1938 CPDF_PageObject* cpdf_page_object =
1940
1941 // Empty content stream 1.
1942 if (cpdf_page_object->GetContentStream() == 1) {
1943 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1944 FPDFPageObj_Destroy(page_object);
1945 }
1946 }
1947
1948 // Content stream 0: page objects 0-14.
1949 // Content stream 2: page object 15.
1950 ASSERT_EQ(16, FPDFPage_CountObjects(page));
1951 for (int i = 0; i < 16; i++) {
1952 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1953 ASSERT_TRUE(page_object);
1954 CPDF_PageObject* cpdf_page_object =
1956 if (i < 15)
1957 EXPECT_EQ(0, cpdf_page_object->GetContentStream()) << i;
1958 else
1959 EXPECT_EQ(2, cpdf_page_object->GetContentStream()) << i;
1960 }
1961
1962 // Generate contents should remove the empty stream and update the page
1963 // objects' contents stream indexes.
1964 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1965
1966 // Content stream 0: page objects 0-14.
1967 // Content stream 1: page object 15.
1968 ASSERT_EQ(16, FPDFPage_CountObjects(page));
1969 for (int i = 0; i < 16; i++) {
1970 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1971 ASSERT_TRUE(page_object);
1972 CPDF_PageObject* cpdf_page_object =
1974 if (i < 15)
1975 EXPECT_EQ(0, cpdf_page_object->GetContentStream()) << i;
1976 else
1977 EXPECT_EQ(1, cpdf_page_object->GetContentStream()) << i;
1978 }
1979
1980 const char* stream1_removed_checksum = []() {
1981 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
1982#if BUILDFLAG(IS_WIN)
1983 return "d7e6debf2dc02de449860ee8012a18d2";
1984#elif BUILDFLAG(IS_APPLE)
1985 return "b26ac6d9bef9c756a19a9aafc60709bd";
1986#else
1987 return "0b3ef335b8d86a3f9d609368b9d075e0";
1988#endif
1989 }
1990#if BUILDFLAG(IS_APPLE)
1991#if ARCH_CPU_ARM64
1992 return "08505db7b598f7397a2260ecb1f6d86d";
1993#else
1994 return "3cdc75af44c15bed80998facd6e674c9";
1995#endif // ARCH_CPU_ARM64
1996#else
1997 return "b474826df1acedb05c7b82e1e49e64a6";
1998#endif // BUILDFLAG(IS_APPLE)
1999 }();
2000 {
2001 ScopedFPDFBitmap page_bitmap = RenderPage(page);
2002 CompareBitmap(page_bitmap.get(), 200, 200, stream1_removed_checksum);
2003 }
2004
2005 // Save the file
2006 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2007 UnloadPage(page);
2008
2009 // Re-open the file and check the page object count is still 16, and that
2010 // content stream 1 was removed.
2011 ASSERT_TRUE(OpenSavedDocument());
2012 FPDF_PAGE saved_page = LoadSavedPage(0);
2013 ASSERT_TRUE(saved_page);
2014
2015 // Content stream 0: page objects 0-14.
2016 // Content stream 1: page object 15.
2017 EXPECT_EQ(16, FPDFPage_CountObjects(saved_page));
2018 for (int i = 0; i < 16; i++) {
2019 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(saved_page, i);
2020 ASSERT_TRUE(page_object);
2021 CPDF_PageObject* cpdf_page_object =
2023 if (i < 15)
2024 EXPECT_EQ(0, cpdf_page_object->GetContentStream()) << i;
2025 else
2026 EXPECT_EQ(1, cpdf_page_object->GetContentStream()) << i;
2027 }
2028
2029 {
2030 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
2031 CompareBitmap(page_bitmap.get(), 200, 200, stream1_removed_checksum);
2032 }
2033
2034 CloseSavedPage(saved_page);
2035 CloseSavedDocument();
2036}
2037
2039 // Load document with a single stream.
2040 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
2041 FPDF_PAGE page = LoadPage(0);
2042 ASSERT_TRUE(page);
2043
2044 // Content stream 0: page objects 0-1.
2045 ASSERT_EQ(2, FPDFPage_CountObjects(page));
2046
2047 // Loop backwards because objects will being removed, which shifts the indexes
2048 // after the removed position.
2049 for (int i = 1; i >= 0; i--) {
2050 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
2051 ASSERT_TRUE(page_object);
2052 CPDF_PageObject* cpdf_page_object =
2054 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
2055 ASSERT_TRUE(FPDFPage_RemoveObject(page, page_object));
2056 FPDFPageObj_Destroy(page_object);
2057 }
2058
2059 // No more objects in the stream
2060 ASSERT_EQ(0, FPDFPage_CountObjects(page));
2061
2062 // Generate contents should remove the empty stream and update the page
2063 // objects' contents stream indexes.
2064 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2065
2066 ASSERT_EQ(0, FPDFPage_CountObjects(page));
2067
2068 {
2069 ScopedFPDFBitmap page_bitmap = RenderPage(page);
2070 CompareBitmap(page_bitmap.get(), 200, 200, kAllRemovedChecksum);
2071 }
2072
2073 // Save the file
2074 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2075 UnloadPage(page);
2076
2077 // Re-open the file and check the page object count is still 0.
2078 ASSERT_TRUE(OpenSavedDocument());
2079 FPDF_PAGE saved_page = LoadSavedPage(0);
2080 ASSERT_TRUE(saved_page);
2081
2082 EXPECT_EQ(0, FPDFPage_CountObjects(saved_page));
2083 {
2084 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
2085 CompareBitmap(page_bitmap.get(), 200, 200, kAllRemovedChecksum);
2086 }
2087
2088 CloseSavedPage(saved_page);
2089 CloseSavedDocument();
2090}
2091
2093 // Load document with a single stream.
2094 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
2095 FPDF_PAGE page = LoadPage(0);
2096 ASSERT_TRUE(page);
2097
2098 // Content stream 0: page objects 0-1.
2099 ASSERT_EQ(2, FPDFPage_CountObjects(page));
2100
2101 // Remove first object.
2102 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
2103 ASSERT_TRUE(page_object);
2104 CPDF_PageObject* cpdf_page_object =
2106 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
2107 ASSERT_TRUE(FPDFPage_RemoveObject(page, page_object));
2108 FPDFPageObj_Destroy(page_object);
2109
2110 // One object left in the stream.
2111 ASSERT_EQ(1, FPDFPage_CountObjects(page));
2112 page_object = FPDFPage_GetObject(page, 0);
2113 ASSERT_TRUE(page_object);
2114 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
2115 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
2116
2117 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2118
2119 // Still one object left in the stream.
2120 ASSERT_EQ(1, FPDFPage_CountObjects(page));
2121 page_object = FPDFPage_GetObject(page, 0);
2122 ASSERT_TRUE(page_object);
2123 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
2124 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
2125
2126 {
2127 ScopedFPDFBitmap page_bitmap = RenderPage(page);
2128 CompareBitmap(page_bitmap.get(), 200, 200, FirstRemovedChecksum());
2129 }
2130
2131 // Save the file
2132 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2133 UnloadPage(page);
2134
2135 // Re-open the file and check the page object count is still 0.
2136 ASSERT_TRUE(OpenSavedDocument());
2137 FPDF_PAGE saved_page = LoadSavedPage(0);
2138 ASSERT_TRUE(saved_page);
2139
2140 ASSERT_EQ(1, FPDFPage_CountObjects(saved_page));
2141 page_object = FPDFPage_GetObject(saved_page, 0);
2142 ASSERT_TRUE(page_object);
2143 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
2144 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
2145 {
2146 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
2147 CompareBitmap(page_bitmap.get(), 200, 200, FirstRemovedChecksum());
2148 }
2149
2150 CloseSavedPage(saved_page);
2151 CloseSavedDocument();
2152}
2153
2155 // Load document with a single stream.
2156 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
2157 FPDF_PAGE page = LoadPage(0);
2158 ASSERT_TRUE(page);
2159
2160 // Content stream 0: page objects 0-1.
2161 ASSERT_EQ(2, FPDFPage_CountObjects(page));
2162
2163 // Remove last object
2164 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 1);
2165 ASSERT_TRUE(page_object);
2166 CPDF_PageObject* cpdf_page_object =
2168 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
2169 ASSERT_TRUE(FPDFPage_RemoveObject(page, page_object));
2170 FPDFPageObj_Destroy(page_object);
2171
2172 // One object left in the stream.
2173 ASSERT_EQ(1, FPDFPage_CountObjects(page));
2174 page_object = FPDFPage_GetObject(page, 0);
2175 ASSERT_TRUE(page_object);
2176 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
2177 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
2178
2179 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2180
2181 // Still one object left in the stream.
2182 ASSERT_EQ(1, FPDFPage_CountObjects(page));
2183 page_object = FPDFPage_GetObject(page, 0);
2184 ASSERT_TRUE(page_object);
2185 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
2186 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
2187
2188 using pdfium::HelloWorldRemovedChecksum;
2189 {
2190 ScopedFPDFBitmap page_bitmap = RenderPage(page);
2191 CompareBitmap(page_bitmap.get(), 200, 200, HelloWorldRemovedChecksum());
2192 }
2193
2194 // Save the file
2195 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2196 UnloadPage(page);
2197
2198 // Re-open the file and check the page object count is still 0.
2199 ASSERT_TRUE(OpenSavedDocument());
2200 FPDF_PAGE saved_page = LoadSavedPage(0);
2201 ASSERT_TRUE(saved_page);
2202
2203 ASSERT_EQ(1, FPDFPage_CountObjects(saved_page));
2204 page_object = FPDFPage_GetObject(saved_page, 0);
2205 ASSERT_TRUE(page_object);
2206 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
2207 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
2208 {
2209 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
2210 CompareBitmap(page_bitmap.get(), 200, 200, HelloWorldRemovedChecksum());
2211 }
2212
2213 CloseSavedPage(saved_page);
2214 CloseSavedDocument();
2215}
2216
2218 // Load document with some text.
2219 ASSERT_TRUE(OpenDocument("hello_world_split_streams.pdf"));
2220 FPDF_PAGE page = LoadPage(0);
2221 ASSERT_TRUE(page);
2222
2223 // Content stream 0: page objects 0-1.
2224 // Content stream 1: page object 2.
2225 ASSERT_EQ(3, FPDFPage_CountObjects(page));
2226
2227 // Loop backwards because objects will being removed, which shifts the indexes
2228 // after the removed position.
2229 for (int i = 2; i >= 0; i--) {
2230 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
2231 ASSERT_TRUE(page_object);
2232 ASSERT_TRUE(FPDFPage_RemoveObject(page, page_object));
2233 FPDFPageObj_Destroy(page_object);
2234 }
2235
2236 // No more objects in the page.
2237 ASSERT_EQ(0, FPDFPage_CountObjects(page));
2238
2239 // Generate contents should remove the empty streams and update the page
2240 // objects' contents stream indexes.
2241 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2242
2243 ASSERT_EQ(0, FPDFPage_CountObjects(page));
2244
2245 {
2246 ScopedFPDFBitmap page_bitmap = RenderPage(page);
2247 CompareBitmap(page_bitmap.get(), 200, 200, kAllRemovedChecksum);
2248 }
2249
2250 // Save the file
2251 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2252 UnloadPage(page);
2253
2254 // Re-open the file and check the page object count is still 0.
2255 ASSERT_TRUE(OpenSavedDocument());
2256 FPDF_PAGE saved_page = LoadSavedPage(0);
2257 ASSERT_TRUE(saved_page);
2258
2259 EXPECT_EQ(0, FPDFPage_CountObjects(saved_page));
2260 {
2261 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
2262 CompareBitmap(page_bitmap.get(), 200, 200, kAllRemovedChecksum);
2263 }
2264
2265 CloseSavedPage(saved_page);
2266 CloseSavedDocument();
2267}
2268
2270 // Load document with some text.
2271 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
2272 FPDF_PAGE page = LoadPage(0);
2273 ASSERT_TRUE(page);
2274
2275 // Add a red rectangle.
2276 ASSERT_EQ(2, FPDFPage_CountObjects(page));
2277 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
2278 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
2280 FPDFPage_InsertObject(page, red_rect);
2281
2282 // Verify the red rectangle was added.
2283 ASSERT_EQ(3, FPDFPage_CountObjects(page));
2284
2285 // Save the file
2286 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2287 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2288 UnloadPage(page);
2289
2290 // Re-open the file and check the page object count is still 3.
2291 ASSERT_TRUE(OpenSavedDocument());
2292 FPDF_PAGE saved_page = LoadSavedPage(0);
2293 ASSERT_TRUE(saved_page);
2294 EXPECT_EQ(3, FPDFPage_CountObjects(saved_page));
2295 CloseSavedPage(saved_page);
2296 CloseSavedDocument();
2297}
2298
2300 // Load document with some text.
2301 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
2302 FPDF_PAGE page = LoadPage(0);
2303 ASSERT_TRUE(page);
2304
2305 // Add a red rectangle.
2306 ASSERT_EQ(2, FPDFPage_CountObjects(page));
2307 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
2308 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 100, 100, 255));
2310 FPDFPage_InsertObject(page, red_rect);
2311
2312 // Verify the red rectangle was added.
2313 ASSERT_EQ(3, FPDFPage_CountObjects(page));
2314
2315 // Generate content but change it again
2316 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2317 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
2318
2319 // Save the file
2320 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2321 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2322 UnloadPage(page);
2323
2324 // Re-open the file and check the page object count is still 3.
2325 ASSERT_TRUE(OpenSavedDocument());
2326 FPDF_PAGE saved_page = LoadSavedPage(0);
2327 ASSERT_TRUE(saved_page);
2328 EXPECT_EQ(3, FPDFPage_CountObjects(saved_page));
2329 CloseSavedPage(saved_page);
2330 CloseSavedDocument();
2331}
2332
2334 const int kOriginalObjectCount = 600;
2335
2336 // Load document with many objects.
2337 ASSERT_TRUE(OpenDocument("many_rectangles.pdf"));
2338 FPDF_PAGE page = LoadPage(0);
2339 ASSERT_TRUE(page);
2340
2341 using pdfium::ManyRectanglesChecksum;
2342 {
2343 ScopedFPDFBitmap page_bitmap = RenderPage(page);
2344 CompareBitmap(page_bitmap.get(), 200, 300, ManyRectanglesChecksum());
2345 }
2346
2347 // Add a black rectangle.
2348 ASSERT_EQ(kOriginalObjectCount, FPDFPage_CountObjects(page));
2349 FPDF_PAGEOBJECT black_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
2350 EXPECT_TRUE(FPDFPageObj_SetFillColor(black_rect, 0, 0, 0, 255));
2351 EXPECT_TRUE(FPDFPath_SetDrawMode(black_rect, FPDF_FILLMODE_ALTERNATE, 0));
2352 FPDFPage_InsertObject(page, black_rect);
2353
2354 // Verify the black rectangle was added.
2355 ASSERT_EQ(kOriginalObjectCount + 1, FPDFPage_CountObjects(page));
2356 const char* plus_rectangle_checksum = []() {
2357 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
2358 return "0d3715fcfb9bd0dd25dcce60800bff47";
2359 }
2360 return "6b9396ab570754b32b04ca629e902f77";
2361 }();
2362 {
2363 ScopedFPDFBitmap page_bitmap = RenderPage(page);
2364 CompareBitmap(page_bitmap.get(), 200, 300, plus_rectangle_checksum);
2365 }
2366
2367 // Save the file.
2368 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2369 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2370 UnloadPage(page);
2371
2372 // Re-open the file and check the rectangle added is still there.
2373 ASSERT_TRUE(OpenSavedDocument());
2374 FPDF_PAGE saved_page = LoadSavedPage(0);
2375 ASSERT_TRUE(saved_page);
2376 EXPECT_EQ(kOriginalObjectCount + 1, FPDFPage_CountObjects(saved_page));
2377 {
2378 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
2379 CompareBitmap(page_bitmap.get(), 200, 300, plus_rectangle_checksum);
2380 }
2381
2382 // Remove the added rectangle.
2383 FPDF_PAGEOBJECT added_object =
2384 FPDFPage_GetObject(saved_page, kOriginalObjectCount);
2385 EXPECT_TRUE(FPDFPage_RemoveObject(saved_page, added_object));
2386 FPDFPageObj_Destroy(added_object);
2387 {
2388 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
2389 CompareBitmap(page_bitmap.get(), 200, 300, ManyRectanglesChecksum());
2390 }
2391 EXPECT_EQ(kOriginalObjectCount, FPDFPage_CountObjects(saved_page));
2392
2393 // Save the file again.
2394 EXPECT_TRUE(FPDFPage_GenerateContent(saved_page));
2395 EXPECT_TRUE(FPDF_SaveAsCopy(saved_document(), this, 0));
2396
2397 CloseSavedPage(saved_page);
2398 CloseSavedDocument();
2399
2400 // Re-open the file (again) and check the black rectangle was removed and the
2401 // rest is intact.
2402 ASSERT_TRUE(OpenSavedDocument());
2403 saved_page = LoadSavedPage(0);
2404 ASSERT_TRUE(saved_page);
2405 EXPECT_EQ(kOriginalObjectCount, FPDFPage_CountObjects(saved_page));
2406 {
2407 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
2408 CompareBitmap(page_bitmap.get(), 200, 300, ManyRectanglesChecksum());
2409 }
2410
2411 CloseSavedPage(saved_page);
2412 CloseSavedDocument();
2413}
2414
2416 // Start with a blank page.
2417 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
2418 ASSERT_TRUE(page);
2419
2420 // Render the blank page and verify it's a blank bitmap.
2421 using pdfium::kBlankPage612By792Checksum;
2422 {
2423 ScopedFPDFBitmap page_bitmap = RenderPage(page);
2424 CompareBitmap(page_bitmap.get(), 612, 792, kBlankPage612By792Checksum);
2425 }
2426 ASSERT_EQ(0, FPDFPage_CountObjects(page));
2427
2428 // Add a red rectangle.
2429 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(10, 10, 20, 20);
2430 ASSERT_TRUE(red_rect);
2431 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
2433 FPDFPage_InsertObject(page, red_rect);
2434 {
2435 ScopedFPDFBitmap page_bitmap = RenderPage(page);
2436 CompareBitmap(page_bitmap.get(), 612, 792, kRedRectangleChecksum);
2437 }
2438 EXPECT_EQ(1, FPDFPage_CountObjects(page));
2439
2440 // Remove rectangle and verify it does not render anymore and the bitmap is
2441 // back to a blank one.
2442 EXPECT_TRUE(FPDFPage_RemoveObject(page, red_rect));
2443 {
2444 ScopedFPDFBitmap page_bitmap = RenderPage(page);
2445 CompareBitmap(page_bitmap.get(), 612, 792, kBlankPage612By792Checksum);
2446 }
2447 EXPECT_EQ(0, FPDFPage_CountObjects(page));
2448
2449 // Trying to remove an object not in the page should return false.
2450 EXPECT_FALSE(FPDFPage_RemoveObject(page, red_rect));
2451
2452 FPDF_ClosePage(page);
2453 FPDFPageObj_Destroy(red_rect);
2454}
2455
2457 CreateNewDocument();
2458 FPDF_PAGEOBJECT img = FPDFPageObj_NewImageObj(document());
2459 // This should fail gracefully, even if img is not a path.
2460 ASSERT_EQ(-1, FPDFPath_CountSegments(img));
2461
2462 // This should fail gracefully, even if path is NULL.
2463 ASSERT_EQ(-1, FPDFPath_CountSegments(nullptr));
2464
2465 // FPDFPath_GetPathSegment() with a non-path.
2466 ASSERT_EQ(nullptr, FPDFPath_GetPathSegment(img, 0));
2467 // FPDFPath_GetPathSegment() with a NULL path.
2468 ASSERT_EQ(nullptr, FPDFPath_GetPathSegment(nullptr, 0));
2469 float x;
2470 float y;
2471 // FPDFPathSegment_GetPoint() with a NULL segment.
2472 EXPECT_FALSE(FPDFPathSegment_GetPoint(nullptr, &x, &y));
2473
2474 // FPDFPathSegment_GetType() with a NULL segment.
2476
2477 // FPDFPathSegment_GetClose() with a NULL segment.
2478 EXPECT_FALSE(FPDFPathSegment_GetClose(nullptr));
2479
2481}
2482
2484 // Load document with some text
2485 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
2486 FPDF_PAGE page = LoadPage(0);
2487 ASSERT_TRUE(page);
2488
2489 // Add an opaque rectangle on top of some of the text.
2490 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
2491 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
2493 FPDFPage_InsertObject(page, red_rect);
2494
2495 // Add a transparent triangle on top of other part of the text.
2496 FPDF_PAGEOBJECT black_path = FPDFPageObj_CreateNewPath(20, 50);
2497 EXPECT_TRUE(FPDFPageObj_SetFillColor(black_path, 0, 0, 0, 100));
2498 EXPECT_TRUE(FPDFPath_SetDrawMode(black_path, FPDF_FILLMODE_ALTERNATE, 0));
2499 EXPECT_TRUE(FPDFPath_LineTo(black_path, 30, 80));
2500 EXPECT_TRUE(FPDFPath_LineTo(black_path, 40, 10));
2501 EXPECT_TRUE(FPDFPath_Close(black_path));
2502 FPDFPage_InsertObject(page, black_path);
2503
2504 // Render and check the result.
2505 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
2506 const char* checksum = []() {
2507 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
2508#if BUILDFLAG(IS_WIN)
2509 return "52c133b5b6bf76760c59cffc12c1131a";
2510#elif BUILDFLAG(IS_APPLE)
2511 return "9eba2a1a6599c2abcf002012217a6505";
2512#else
2513 return "72523cfac069f8a81057164682998961";
2514#endif
2515 }
2516#if BUILDFLAG(IS_APPLE)
2517 return "279693baca9f48da2d75a8e289aed58e";
2518#else
2519 return "fe415d47945c10b9cc8e9ca08887369e";
2520#endif
2521 }();
2522 CompareBitmap(bitmap.get(), 200, 200, checksum);
2523 UnloadPage(page);
2524}
2525
2527 // Load document with existing content
2528 ASSERT_TRUE(OpenDocument("bug_717.pdf"));
2529 FPDF_PAGE page = LoadPage(0);
2530 ASSERT_TRUE(page);
2531
2532 // Add a transparent rectangle on top of the existing content
2533 FPDF_PAGEOBJECT red_rect2 = FPDFPageObj_CreateNewRect(90, 700, 25, 50);
2534 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect2, 255, 0, 0, 100));
2535 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect2, FPDF_FILLMODE_ALTERNATE, 0));
2536 FPDFPage_InsertObject(page, red_rect2);
2537
2538 // Add an opaque rectangle on top of the existing content
2539 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(115, 700, 25, 50);
2540 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
2542 FPDFPage_InsertObject(page, red_rect);
2543
2544 const char* original_checksum = []() {
2545 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
2546 return "1e82fbdd21490cee9d3479fe6125af67";
2547 }
2548 return "ad04e5bd0f471a9a564fb034bd0fb073";
2549 }();
2550 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
2551 CompareBitmap(bitmap.get(), 612, 792, original_checksum);
2552 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2553
2554 // Now save the result, closing the page and document
2555 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2556 UnloadPage(page);
2557
2558 ASSERT_TRUE(OpenSavedDocument());
2559 FPDF_PAGE saved_page = LoadSavedPage(0);
2560 ASSERT_TRUE(saved_page);
2561 VerifySavedRendering(saved_page, 612, 792, original_checksum);
2562
2563 ClearString();
2564 // Add another opaque rectangle on top of the existing content
2565 FPDF_PAGEOBJECT green_rect = FPDFPageObj_CreateNewRect(150, 700, 25, 50);
2566 EXPECT_TRUE(FPDFPageObj_SetFillColor(green_rect, 0, 255, 0, 255));
2567 EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect, FPDF_FILLMODE_ALTERNATE, 0));
2568 FPDFPage_InsertObject(saved_page, green_rect);
2569
2570 // Add another transparent rectangle on top of existing content
2571 FPDF_PAGEOBJECT green_rect2 = FPDFPageObj_CreateNewRect(175, 700, 25, 50);
2572 EXPECT_TRUE(FPDFPageObj_SetFillColor(green_rect2, 0, 255, 0, 100));
2573 EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect2, FPDF_FILLMODE_ALTERNATE, 0));
2574 FPDFPage_InsertObject(saved_page, green_rect2);
2575 const char* last_checksum = []() {
2576 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
2577 return "8705d023e5fec3499d1e30cf2bcc5dc1";
2578 }
2579 return "4b5b00f824620f8c9b8801ebb98e1cdd";
2580 }();
2581 {
2582 ScopedFPDFBitmap new_bitmap = RenderSavedPage(saved_page);
2583 CompareBitmap(new_bitmap.get(), 612, 792, last_checksum);
2584 }
2585 EXPECT_TRUE(FPDFPage_GenerateContent(saved_page));
2586
2587 // Now save the result, closing the page and document
2588 EXPECT_TRUE(FPDF_SaveAsCopy(saved_document(), this, 0));
2589
2590 CloseSavedPage(saved_page);
2591 CloseSavedDocument();
2592
2593 // Render the saved result
2594 VerifySavedDocument(612, 792, last_checksum);
2595}
2596
2598 // Start with a blank page
2599 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
2600
2601 // Add a large stroked rectangle (fill color should not affect it).
2602 FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(20, 20, 200, 400);
2603 EXPECT_TRUE(FPDFPageObj_SetFillColor(rect, 255, 0, 0, 255));
2604 EXPECT_TRUE(FPDFPageObj_SetStrokeColor(rect, 0, 255, 0, 255));
2605 EXPECT_TRUE(FPDFPageObj_SetStrokeWidth(rect, 15.0f));
2606
2607 float width = 0;
2608 EXPECT_TRUE(FPDFPageObj_GetStrokeWidth(rect, &width));
2609 EXPECT_EQ(15.0f, width);
2610
2611 EXPECT_TRUE(FPDFPath_SetDrawMode(rect, 0, 1));
2612 FPDFPage_InsertObject(page, rect);
2613 {
2614 ScopedFPDFBitmap page_bitmap = RenderPage(page);
2615 const char* checksum_1 = []() {
2616 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
2617 return "1469acf60e7647ebeb8e1fb08c5d6c7a";
2618 }
2619 return "64bd31f862a89e0a9e505a5af6efd506";
2620 }();
2621 CompareBitmap(page_bitmap.get(), 612, 792, checksum_1);
2622 }
2623
2624 // Add crossed-checkmark
2625 FPDF_PAGEOBJECT check = FPDFPageObj_CreateNewPath(300, 500);
2626 EXPECT_TRUE(FPDFPath_LineTo(check, 400, 400));
2627 EXPECT_TRUE(FPDFPath_LineTo(check, 600, 600));
2628 EXPECT_TRUE(FPDFPath_MoveTo(check, 400, 600));
2629 EXPECT_TRUE(FPDFPath_LineTo(check, 600, 400));
2630 EXPECT_TRUE(FPDFPageObj_SetStrokeColor(check, 128, 128, 128, 180));
2631 EXPECT_TRUE(FPDFPageObj_SetStrokeWidth(check, 8.35f));
2632 EXPECT_TRUE(FPDFPath_SetDrawMode(check, 0, 1));
2633 FPDFPage_InsertObject(page, check);
2634 {
2635 ScopedFPDFBitmap page_bitmap = RenderPage(page);
2636 const char* checksum_2 = []() {
2637 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
2638 return "68b3194f74abd9d471695ce1415be43f";
2639 }
2640 return "4b6f3b9d25c4e194821217d5016c3724";
2641 }();
2642 CompareBitmap(page_bitmap.get(), 612, 792, checksum_2);
2643 }
2644
2645 // Add stroked and filled oval-ish path.
2646 FPDF_PAGEOBJECT path = FPDFPageObj_CreateNewPath(250, 100);
2647 EXPECT_TRUE(FPDFPath_BezierTo(path, 180, 166, 180, 233, 250, 300));
2648 EXPECT_TRUE(FPDFPath_LineTo(path, 255, 305));
2649 EXPECT_TRUE(FPDFPath_BezierTo(path, 325, 233, 325, 166, 255, 105));
2650 EXPECT_TRUE(FPDFPath_Close(path));
2651 EXPECT_TRUE(FPDFPageObj_SetFillColor(path, 200, 128, 128, 100));
2652 EXPECT_TRUE(FPDFPageObj_SetStrokeColor(path, 128, 200, 128, 150));
2653 EXPECT_TRUE(FPDFPageObj_SetStrokeWidth(path, 10.5f));
2655 FPDFPage_InsertObject(page, path);
2656 {
2657 ScopedFPDFBitmap page_bitmap = RenderPage(page);
2658 const char* checksum_3 = []() {
2659 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
2660 return "ea784068651df2b9ba132ce9215e6780";
2661 }
2662 return "ff3e6a22326754944cc6e56609acd73b";
2663 }();
2664 CompareBitmap(page_bitmap.get(), 612, 792, checksum_3);
2665 }
2666 FPDF_ClosePage(page);
2667}
2668
2669// Tests adding text from standard font using FPDFPageObj_NewTextObj.
2671 // Start with a blank page
2672 ScopedFPDFPage page(FPDFPage_New(CreateNewDocument(), 0, 612, 792));
2673
2674 // Add some text to the page
2675 FPDF_PAGEOBJECT text_object1 =
2676 FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
2677 EXPECT_TRUE(text_object1);
2678 ScopedFPDFWideString text1 = GetFPDFWideString(kBottomText);
2679 EXPECT_TRUE(FPDFText_SetText(text_object1, text1.get()));
2680 static constexpr FS_MATRIX kMatrix1{1, 0, 0, 1, 20, 20};
2681 EXPECT_TRUE(FPDFPageObj_SetMatrix(text_object1, &kMatrix1));
2682 FPDFPage_InsertObject(page.get(), text_object1);
2683 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
2684 {
2685 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
2686 CompareBitmap(page_bitmap.get(), 612, 792, BottomTextChecksum());
2687
2688 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2689 VerifySavedDocument(612, 792, BottomTextChecksum());
2690 }
2691
2692 // Try another font
2693 FPDF_PAGEOBJECT text_object2 =
2694 FPDFPageObj_NewTextObj(document(), "TimesNewRomanBold", 15.0f);
2695 EXPECT_TRUE(text_object2);
2696 ScopedFPDFWideString text2 =
2697 GetFPDFWideString(L"Hi, I'm Bold. Times New Roman Bold.");
2698 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
2699 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 100, 600);
2700 FPDFPage_InsertObject(page.get(), text_object2);
2701 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
2702 {
2703 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
2704 const char* checksum = []() {
2705 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
2706#if BUILDFLAG(IS_WIN)
2707 return "667f74c7cbf72c75bce303ca2de975a3";
2708#elif BUILDFLAG(IS_APPLE)
2709 return "86d51a764615b843465695786e92fec5";
2710#else
2711 return "3fa05f8935a43a38a8923e9d5fb94365";
2712#endif
2713 }
2714#if BUILDFLAG(IS_APPLE)
2715 return "983baaa1f688eff7a14b1bf91c171a1a";
2716#else
2717 return "161523e196eb5341604cd73e12c97922";
2718#endif
2719 }();
2720 CompareBitmap(page_bitmap.get(), 612, 792, checksum);
2721
2722 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2723 VerifySavedDocument(612, 792, checksum);
2724 }
2725
2726 // And some randomly transformed text
2727 FPDF_PAGEOBJECT text_object3 =
2728 FPDFPageObj_NewTextObj(document(), "Courier-Bold", 20.0f);
2729 EXPECT_TRUE(text_object3);
2730 ScopedFPDFWideString text3 = GetFPDFWideString(L"Can you read me? <:)>");
2731 EXPECT_TRUE(FPDFText_SetText(text_object3, text3.get()));
2732 FPDFPageObj_Transform(text_object3, 1, 1.5, 2, 0.5, 200, 200);
2733 FPDFPage_InsertObject(page.get(), text_object3);
2734 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
2735 {
2736 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
2737 const char* checksum = []() {
2738 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
2739#if BUILDFLAG(IS_WIN)
2740 return "4695b3de213d6795a591f27cd8d86e26";
2741#elif BUILDFLAG(IS_APPLE)
2742 return "422f1384c13e95c218498a8f18b9e5a7";
2743#else
2744 return "63385a217934d9ee9e17ef4d7f7b2128";
2745#endif
2746 }
2747#if BUILDFLAG(IS_APPLE)
2748 return "e0b3493c5c16e41d0d892ffb48e63fba";
2749#else
2750 return "1fbf772dca8d82b960631e6683934964";
2751#endif
2752 }();
2753 CompareBitmap(page_bitmap.get(), 612, 792, checksum);
2754
2755 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2756 VerifySavedDocument(612, 792, checksum);
2757 }
2758
2759 FS_MATRIX matrix;
2760 EXPECT_TRUE(FPDFPageObj_GetMatrix(text_object3, &matrix));
2761 EXPECT_FLOAT_EQ(1.0f, matrix.a);
2762 EXPECT_FLOAT_EQ(1.5f, matrix.b);
2763 EXPECT_FLOAT_EQ(2.0f, matrix.c);
2764 EXPECT_FLOAT_EQ(0.5f, matrix.d);
2765 EXPECT_FLOAT_EQ(200.0f, matrix.e);
2766 EXPECT_FLOAT_EQ(200.0f, matrix.f);
2767
2768 EXPECT_FALSE(FPDFTextObj_GetFontSize(nullptr, nullptr));
2769 float size = 55;
2770 EXPECT_FALSE(FPDFTextObj_GetFontSize(nullptr, &size));
2771 EXPECT_EQ(55, size);
2772 EXPECT_TRUE(FPDFTextObj_GetFontSize(text_object3, &size));
2773 EXPECT_EQ(20, size);
2774
2775 // TODO(npm): Why are there issues with text rotated by 90 degrees?
2776 // TODO(npm): FPDF_SaveAsCopy not giving the desired result after this.
2777}
2778
2780 // Start with a blank page
2781 ScopedFPDFPage page(FPDFPage_New(CreateNewDocument(), 0, 612, 792));
2782
2783 // Add some text of size 0 to the page.
2784 FPDF_PAGEOBJECT text_object =
2785 FPDFPageObj_NewTextObj(document(), "Arial", 0.0f);
2786 EXPECT_TRUE(text_object);
2787 ScopedFPDFWideString text = GetFPDFWideString(kBottomText);
2788 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
2789 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 20, 20);
2790
2791 float size = -1; // Make sure 'size' gets changed.
2792 EXPECT_TRUE(FPDFTextObj_GetFontSize(text_object, &size));
2793 EXPECT_EQ(0.0f, size);
2794
2795 FPDFPage_InsertObject(page.get(), text_object);
2796 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
2797 {
2798 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
2799 CompareBitmap(page_bitmap.get(), 612, 792,
2801
2802 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2803 VerifySavedDocument(612, 792, pdfium::kBlankPage612By792Checksum);
2804 }
2805}
2806
2808 ASSERT_TRUE(OpenDocument("text_render_mode.pdf"));
2809 FPDF_PAGE page = LoadPage(0);
2810 ASSERT_TRUE(page);
2811 ASSERT_EQ(2, FPDFPage_CountObjects(page));
2812
2813 EXPECT_EQ(FPDF_TEXTRENDERMODE_UNKNOWN,
2815
2816 FPDF_PAGEOBJECT fill = FPDFPage_GetObject(page, 0);
2817 EXPECT_EQ(FPDF_TEXTRENDERMODE_FILL, FPDFTextObj_GetTextRenderMode(fill));
2818
2819 FPDF_PAGEOBJECT stroke = FPDFPage_GetObject(page, 1);
2820 EXPECT_EQ(FPDF_TEXTRENDERMODE_STROKE, FPDFTextObj_GetTextRenderMode(stroke));
2821
2822 UnloadPage(page);
2823}
2824
2826 const char* original_checksum = []() {
2827 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
2828#if BUILDFLAG(IS_WIN)
2829 return "e17a6453cb48a600f180c5907c4ea02e";
2830#elif BUILDFLAG(IS_APPLE)
2831 return "e2d5c32499173c0ff939ad2e7fc01fd6";
2832#else
2833 return "48c7f21b2a1a1bbeab24cccccc131e47";
2834#endif
2835 }
2836#if BUILDFLAG(IS_APPLE)
2837 return "c488514ce0fc949069ff560407edacd2";
2838#else
2839 return "97a4fcf3c9581e19917895631af31d41";
2840#endif
2841 }();
2842 const char* stroke_checksum = []() {
2843 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
2844 return "d16eb1bb4748eeb5fb801594da70d519";
2845 }
2846 return "e06ee84aeebe926e8c980b7822027e8a";
2847 }();
2848
2849 {
2850 ASSERT_TRUE(OpenDocument("text_render_mode.pdf"));
2851 FPDF_PAGE page = LoadPage(0);
2852 ASSERT_TRUE(page);
2853 ASSERT_EQ(2, FPDFPage_CountObjects(page));
2854
2855 // Check the bitmap
2856 {
2857 ScopedFPDFBitmap page_bitmap = RenderPage(page);
2858 CompareBitmap(page_bitmap.get(), 612, 446, original_checksum);
2859 }
2860
2861 // Cannot set on a null object.
2862 EXPECT_FALSE(
2863 FPDFTextObj_SetTextRenderMode(nullptr, FPDF_TEXTRENDERMODE_UNKNOWN));
2864 EXPECT_FALSE(
2865 FPDFTextObj_SetTextRenderMode(nullptr, FPDF_TEXTRENDERMODE_INVISIBLE));
2866
2867 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
2868 ASSERT_TRUE(page_object);
2869 EXPECT_EQ(FPDF_TEXTRENDERMODE_FILL,
2871
2872 // Cannot set UNKNOWN as a render mode.
2873 EXPECT_FALSE(FPDFTextObj_SetTextRenderMode(page_object,
2874 FPDF_TEXTRENDERMODE_UNKNOWN));
2875
2876 EXPECT_TRUE(
2877 FPDFTextObj_SetTextRenderMode(page_object, FPDF_TEXTRENDERMODE_STROKE));
2878 EXPECT_EQ(FPDF_TEXTRENDERMODE_STROKE,
2880
2881 // Check that bitmap displays changed content
2882 {
2883 ScopedFPDFBitmap page_bitmap = RenderPage(page);
2884 CompareBitmap(page_bitmap.get(), 612, 446, stroke_checksum);
2885 }
2886
2887 // Save a copy.
2888 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2889 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2890
2891 UnloadPage(page);
2892 }
2893
2894 {
2895 // Open the saved copy and render it. Check that the changed text render
2896 // mode is kept in the saved copy.
2897 ASSERT_TRUE(OpenSavedDocument());
2898 FPDF_PAGE saved_page = LoadSavedPage(0);
2899 ASSERT_TRUE(saved_page);
2900
2901 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(saved_page, 0);
2902 EXPECT_TRUE(page_object);
2903 EXPECT_EQ(FPDF_TEXTRENDERMODE_STROKE,
2905
2906 ScopedFPDFBitmap bitmap = RenderSavedPage(saved_page);
2907 CompareBitmap(bitmap.get(), 612, 446, stroke_checksum);
2908
2909 CloseSavedPage(saved_page);
2910 CloseSavedDocument();
2911 }
2912}
2913
2915 // bad object tests
2916 EXPECT_FALSE(FPDFTextObj_GetFont(nullptr));
2917 EXPECT_EQ(0U, FPDFFont_GetFontName(nullptr, nullptr, 5));
2918 EXPECT_EQ(-1, FPDFFont_GetFlags(nullptr));
2919 EXPECT_EQ(-1, FPDFFont_GetWeight(nullptr));
2920 EXPECT_FALSE(FPDFFont_GetItalicAngle(nullptr, nullptr));
2921 EXPECT_FALSE(FPDFFont_GetAscent(nullptr, 12.f, nullptr));
2922 EXPECT_FALSE(FPDFFont_GetDescent(nullptr, 12.f, nullptr));
2923 EXPECT_FALSE(FPDFFont_GetGlyphWidth(nullptr, 's', 12.f, nullptr));
2924 EXPECT_FALSE(FPDFFont_GetGlyphPath(nullptr, 's', 12.f));
2925
2926 // good object tests
2927 ASSERT_TRUE(OpenDocument("text_font.pdf"));
2928 FPDF_PAGE page = LoadPage(0);
2929 ASSERT_TRUE(page);
2930 ASSERT_EQ(1, FPDFPage_CountObjects(page));
2931 FPDF_PAGEOBJECT text = FPDFPage_GetObject(page, 0);
2932 ASSERT_TRUE(text);
2933 float font_size;
2934 ASSERT_TRUE(FPDFTextObj_GetFontSize(text, &font_size));
2935 FPDF_FONT font = FPDFTextObj_GetFont(text);
2936 ASSERT_TRUE(font);
2937
2938 // null return pointer tests
2939 EXPECT_FALSE(FPDFFont_GetItalicAngle(font, nullptr));
2940 EXPECT_FALSE(FPDFFont_GetAscent(font, font_size, nullptr));
2941 EXPECT_FALSE(FPDFFont_GetDescent(font, font_size, nullptr));
2942 EXPECT_FALSE(FPDFFont_GetGlyphWidth(font, 's', font_size, nullptr));
2943
2944 // correct property tests
2945 {
2946 EXPECT_EQ(4, FPDFFont_GetFlags(font));
2947 EXPECT_EQ(400, FPDFFont_GetWeight(font));
2948
2949 int angle;
2950 EXPECT_TRUE(FPDFFont_GetItalicAngle(font, &angle));
2951 EXPECT_EQ(0, angle);
2952
2953 float ascent;
2954 EXPECT_TRUE(FPDFFont_GetAscent(font, font_size, &ascent));
2955 EXPECT_FLOAT_EQ(891 * font_size / 1000.0f, ascent);
2956
2957 float descent;
2958 EXPECT_TRUE(FPDFFont_GetDescent(font, font_size, &descent));
2959 EXPECT_FLOAT_EQ(-216 * font_size / 1000.0f, descent);
2960
2961 float a12;
2962 float a24;
2963 EXPECT_TRUE(FPDFFont_GetGlyphWidth(font, 'a', 12.0f, &a12));
2964 EXPECT_FLOAT_EQ(a12, 5.316f);
2965 EXPECT_TRUE(FPDFFont_GetGlyphWidth(font, 'a', 24.0f, &a24));
2966 EXPECT_FLOAT_EQ(a24, 10.632f);
2967 }
2968
2969 {
2970 // FPDFFont_GetFontName() positive testing.
2971 unsigned long size = FPDFFont_GetFontName(font, nullptr, 0);
2972 const char kExpectedFontName[] = "Liberation Serif";
2973 ASSERT_EQ(sizeof(kExpectedFontName), size);
2974 std::vector<char> font_name(size);
2975 ASSERT_EQ(size, FPDFFont_GetFontName(font, font_name.data(), size));
2976 ASSERT_STREQ(kExpectedFontName, font_name.data());
2977
2978 // FPDFFont_GetFontName() negative testing.
2979 ASSERT_EQ(0U, FPDFFont_GetFontName(nullptr, nullptr, 0));
2980
2981 font_name.resize(2);
2982 font_name[0] = 'x';
2983 font_name[1] = '\0';
2984 size = FPDFFont_GetFontName(font, font_name.data(), font_name.size());
2985 ASSERT_EQ(sizeof(kExpectedFontName), size);
2986 ASSERT_STREQ("x", font_name.data());
2987 }
2988
2989 {
2990 // FPDFFont_GetFontData() positive testing.
2991 constexpr size_t kExpectedSize = 8268;
2992 std::vector<uint8_t> buf;
2993 size_t buf_bytes_required = 123;
2994 ASSERT_TRUE(FPDFFont_GetFontData(font, nullptr, 0, &buf_bytes_required));
2995 ASSERT_EQ(kExpectedSize, buf_bytes_required);
2996
2997 buf.resize(kExpectedSize);
2998 EXPECT_EQ("495800b8e56e2d37f3bc48a1b52db952", GenerateMD5Base16(buf));
2999 buf_bytes_required = 234;
3000 // Test with buffer that is too small. Make sure `buf` is unchanged.
3001 EXPECT_TRUE(FPDFFont_GetFontData(font, buf.data(), buf.size() - 1,
3002 &buf_bytes_required));
3003 EXPECT_EQ("495800b8e56e2d37f3bc48a1b52db952", GenerateMD5Base16(buf));
3004 EXPECT_EQ(kExpectedSize, buf_bytes_required);
3005
3006 // Test with buffer of the correct size.
3007 buf_bytes_required = 234;
3008 EXPECT_TRUE(FPDFFont_GetFontData(font, buf.data(), buf.size(),
3009 &buf_bytes_required));
3010 EXPECT_EQ("1a67be75f719b6c476804d85bb9e4844", GenerateMD5Base16(buf));
3011 EXPECT_EQ(kExpectedSize, buf_bytes_required);
3012
3013 // FPDFFont_GetFontData() negative testing.
3014 EXPECT_FALSE(FPDFFont_GetFontData(nullptr, nullptr, 0, nullptr));
3015 EXPECT_FALSE(FPDFFont_GetFontData(font, nullptr, 0, nullptr));
3016
3017 buf_bytes_required = 345;
3018 EXPECT_FALSE(
3019 FPDFFont_GetFontData(nullptr, nullptr, 0, &buf_bytes_required));
3020 EXPECT_EQ(345u, buf_bytes_required);
3021
3022 EXPECT_FALSE(
3023 FPDFFont_GetFontData(nullptr, buf.data(), buf.size(), nullptr));
3024 EXPECT_FALSE(FPDFFont_GetFontData(font, buf.data(), buf.size(), nullptr));
3025
3026 buf_bytes_required = 345;
3027 EXPECT_FALSE(FPDFFont_GetFontData(nullptr, buf.data(), buf.size(),
3028 &buf_bytes_required));
3029 EXPECT_EQ(345u, buf_bytes_required);
3030 }
3031 {
3032 ASSERT_EQ(1, FPDFFont_GetIsEmbedded(font));
3033 ASSERT_EQ(-1, FPDFFont_GetIsEmbedded(nullptr));
3034 }
3035
3036 UnloadPage(page);
3037}
3038
3040 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
3041 FPDF_PAGE page = LoadPage(0);
3042 ASSERT_TRUE(page);
3043 ASSERT_EQ(2, FPDFPage_CountObjects(page));
3044
3045 // Since hello_world.pdf does not embed any font data, FPDFFont_GetFontData()
3046 // will return the substitution font data. Since pdfium_embeddertest is
3047 // hermetic, this first object consistently maps to Tinos-Regular.ttf.
3048 constexpr size_t kTinosRegularSize = 469968;
3049 FPDF_PAGEOBJECT text = FPDFPage_GetObject(page, 0);
3050 ASSERT_TRUE(text);
3051 FPDF_FONT font = FPDFTextObj_GetFont(text);
3052 ASSERT_TRUE(font);
3053 std::vector<uint8_t> buf;
3054 buf.resize(kTinosRegularSize);
3055 size_t buf_bytes_required;
3056 ASSERT_TRUE(
3057 FPDFFont_GetFontData(font, buf.data(), buf.size(), &buf_bytes_required));
3058 EXPECT_EQ(kTinosRegularSize, buf_bytes_required);
3059 EXPECT_EQ("2b019558f2c2de0b7cbc0a6e64b20599", GenerateMD5Base16(buf));
3060 EXPECT_EQ(0, FPDFFont_GetIsEmbedded(font));
3061
3062 // Similarly, the second object consistently maps to Arimo-Regular.ttf.
3063 constexpr size_t kArimoRegularSize = 436180;
3064 text = FPDFPage_GetObject(page, 1);
3065 ASSERT_TRUE(text);
3066 font = FPDFTextObj_GetFont(text);
3067 ASSERT_TRUE(font);
3068 buf.resize(kArimoRegularSize);
3069 ASSERT_TRUE(
3070 FPDFFont_GetFontData(font, buf.data(), buf.size(), &buf_bytes_required));
3071 EXPECT_EQ(kArimoRegularSize, buf_bytes_required);
3072 EXPECT_EQ("7ac02a544211773d9636e056e9da6c35", GenerateMD5Base16(buf));
3073 EXPECT_EQ(0, FPDFFont_GetIsEmbedded(font));
3074
3075 UnloadPage(page);
3076}
3077
3079 // bad glyphpath
3080 EXPECT_EQ(-1, FPDFGlyphPath_CountGlyphSegments(nullptr));
3081 EXPECT_FALSE(FPDFGlyphPath_GetGlyphPathSegment(nullptr, 1));
3082
3083 ASSERT_TRUE(OpenDocument("text_font.pdf"));
3084 FPDF_PAGE page = LoadPage(0);
3085 ASSERT_TRUE(page);
3086 ASSERT_EQ(1, FPDFPage_CountObjects(page));
3087 FPDF_PAGEOBJECT text = FPDFPage_GetObject(page, 0);
3088 ASSERT_TRUE(text);
3089 FPDF_FONT font = FPDFTextObj_GetFont(text);
3090 ASSERT_TRUE(font);
3091
3092 // bad glyph argument.
3093 ASSERT_FALSE(FPDFFont_GetGlyphPath(font, 1, 12.0f));
3094
3095 // good glyphpath
3096 FPDF_GLYPHPATH gpath = FPDFFont_GetGlyphPath(font, 's', 12.0f);
3097 ASSERT_TRUE(gpath);
3098
3099 int count = FPDFGlyphPath_CountGlyphSegments(gpath);
3100 ASSERT_GT(count, 0);
3101 EXPECT_FALSE(FPDFGlyphPath_GetGlyphPathSegment(gpath, -1));
3102 EXPECT_FALSE(FPDFGlyphPath_GetGlyphPathSegment(gpath, count));
3103
3104 FPDF_PATHSEGMENT segment = FPDFGlyphPath_GetGlyphPathSegment(gpath, 1);
3105 ASSERT_TRUE(segment);
3107
3108 UnloadPage(page);
3109}
3110
3112 ASSERT_TRUE(OpenDocument("form_object.pdf"));
3113 FPDF_PAGE page = LoadPage(0);
3114 ASSERT_TRUE(page);
3115 ASSERT_EQ(1, FPDFPage_CountObjects(page));
3116
3117 FPDF_PAGEOBJECT form = FPDFPage_GetObject(page, 0);
3119 ASSERT_EQ(-1, FPDFFormObj_CountObjects(nullptr));
3120 ASSERT_EQ(2, FPDFFormObj_CountObjects(form));
3121
3122 // FPDFFormObj_GetObject() positive testing.
3123 FPDF_PAGEOBJECT text1 = FPDFFormObj_GetObject(form, 0);
3124 ASSERT_TRUE(text1);
3125 float left = 0;
3126 float bottom = 0;
3127 float right = 0;
3128 float top = 0;
3129 ASSERT_TRUE(FPDFPageObj_GetBounds(text1, &left, &bottom, &right, &top));
3130 ASSERT_EQ(271, static_cast<int>(top));
3131
3132 FPDF_PAGEOBJECT text2 = FPDFFormObj_GetObject(form, 1);
3133 ASSERT_TRUE(text2);
3134 ASSERT_TRUE(FPDFPageObj_GetBounds(text2, &left, &bottom, &right, &top));
3135 ASSERT_EQ(221, static_cast<int>(top));
3136
3137 // FPDFFormObj_GetObject() negative testing.
3138 ASSERT_EQ(nullptr, FPDFFormObj_GetObject(nullptr, 0));
3139 ASSERT_EQ(nullptr, FPDFFormObj_GetObject(form, -1));
3140 ASSERT_EQ(nullptr, FPDFFormObj_GetObject(form, 2));
3141
3142 // FPDFPageObj_GetMatrix() positive testing for forms.
3143 static constexpr FS_MATRIX kMatrix = {1.0f, 1.5f, 2.0f, 2.5f, 100.0f, 200.0f};
3144 EXPECT_TRUE(FPDFPageObj_SetMatrix(form, &kMatrix));
3145
3146 FS_MATRIX matrix;
3147 EXPECT_TRUE(FPDFPageObj_GetMatrix(form, &matrix));
3148 EXPECT_FLOAT_EQ(kMatrix.a, matrix.a);
3149 EXPECT_FLOAT_EQ(kMatrix.b, matrix.b);
3150 EXPECT_FLOAT_EQ(kMatrix.c, matrix.c);
3151 EXPECT_FLOAT_EQ(kMatrix.d, matrix.d);
3152 EXPECT_FLOAT_EQ(kMatrix.e, matrix.e);
3153 EXPECT_FLOAT_EQ(kMatrix.f, matrix.f);
3154
3155 // FPDFPageObj_GetMatrix() negative testing for forms.
3156 EXPECT_FALSE(FPDFPageObj_GetMatrix(form, nullptr));
3157
3158 // Show that FPDFPage_RemoveObject() cannot remove page objects from within
3159 // `form`. This is working as intended, as FPDFPage_RemoveObject() only works
3160 // for page object within `page`.
3161 EXPECT_FALSE(FPDFPage_RemoveObject(page, text1));
3162 EXPECT_FALSE(FPDFPage_RemoveObject(page, text2));
3163
3164 UnloadPage(page);
3165}
3166
3168 const char* orig_checksum = []() {
3169 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
3170#if BUILDFLAG(IS_WIN)
3171 return "9d0ca0d471efc12950f337a867ab1694";
3172#elif BUILDFLAG(IS_APPLE)
3173 return "4cfff1919007a7faf099be5cc2cea00a";
3174#else
3175 return "1c6dae4b04fea7430a791135721eaba5";
3176#endif
3177 }
3178#if BUILDFLAG(IS_APPLE)
3179 return "a637057185f50aac1aa5490f726aef95";
3180#else
3181 return "34a9ec0a9581a7970e073c0bcc4ca676";
3182#endif
3183 }();
3184 const char* new_checksum = []() {
3185 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
3186#if BUILDFLAG(IS_WIN)
3187 return "dbebf244eb706dfebfd0594c23e993a9";
3188#elif BUILDFLAG(IS_APPLE)
3189 return "eb88a6842f5e12f5180385261db1f81d";
3190#else
3191 return "7282fe98693c0a7ad2c1b3f3f9563977";
3192#endif
3193 }
3194#if BUILDFLAG(IS_APPLE)
3195 return "8ad9d79b02b609ff734e2a2195c96e2d";
3196#else
3197 return "609b5632a21c886fa93182dbc290bf7a";
3198#endif
3199 }();
3200
3201 ASSERT_TRUE(OpenDocument("form_object.pdf"));
3202 FPDF_PAGE page = LoadPage(0);
3203 ASSERT_TRUE(page);
3204 ASSERT_EQ(1, FPDFPage_CountObjects(page));
3205
3206 {
3207 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
3208 CompareBitmap(bitmap.get(), 62, 69, orig_checksum);
3209 }
3210
3211 FPDF_PAGEOBJECT form = FPDFPage_GetObject(page, 0);
3213
3214 FPDFPageObj_Transform(form, 0.5, 0, 0, 0.5, 0, 0);
3215 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3216
3217 {
3218 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
3219 CompareBitmap(bitmap.get(), 62, 69, new_checksum);
3220 }
3221
3222 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3223 VerifySavedDocument(62, 69, new_checksum);
3224
3225 UnloadPage(page);
3226}
3227
3228// Tests adding text from standard font using FPDFText_LoadStandardFont.
3230 // Start with a blank page
3231 ScopedFPDFPage page(FPDFPage_New(CreateNewDocument(), 0, 612, 792));
3232
3233 // Load a standard font.
3234 ScopedFPDFFont font(FPDFText_LoadStandardFont(document(), "Helvetica"));
3235 ASSERT_TRUE(font);
3236
3237 // Add some text to the page.
3238 FPDF_PAGEOBJECT text_object =
3239 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
3240 EXPECT_TRUE(text_object);
3241 ScopedFPDFWideString text = GetFPDFWideString(kBottomText);
3242 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
3243 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 20, 20);
3244 FPDFPage_InsertObject(page.get(), text_object);
3245 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
3246 CompareBitmap(page_bitmap.get(), 612, 792, BottomTextChecksum());
3247}
3248
3250 CreateNewDocument();
3251 static constexpr const char* kStandardFontNames[] = {
3252 "Arial",
3253 "Arial-Bold",
3254 "Arial-BoldItalic",
3255 "Arial-Italic",
3256 "Courier",
3257 "Courier-BoldOblique",
3258 "Courier-Oblique",
3259 "Courier-Bold",
3260 "CourierNew",
3261 "CourierNew-Bold",
3262 "CourierNew-BoldItalic",
3263 "CourierNew-Italic",
3264 "Helvetica",
3265 "Helvetica-Bold",
3266 "Helvetica-BoldOblique",
3267 "Helvetica-Oblique",
3268 "Symbol",
3269 "TimesNewRoman",
3270 "TimesNewRoman-Bold",
3271 "TimesNewRoman-BoldItalic",
3272 "TimesNewRoman-Italic",
3273 "ZapfDingbats"};
3274 for (const char* font_name : kStandardFontNames) {
3275 ScopedFPDFFont font(FPDFText_LoadStandardFont(document(), font_name));
3276 EXPECT_TRUE(font) << font_name << " should be considered a standard font.";
3277 }
3278 static constexpr const char* kNotStandardFontNames[] = {
3279 "Abcdefg", "ArialB", "Arial-Style",
3280 "Font Name", "FontArial", "NotAStandardFontName",
3281 "TestFontName", "Quack", "Symbol-Italic",
3282 "Zapf"};
3283 for (const char* font_name : kNotStandardFontNames) {
3284 ScopedFPDFFont font(FPDFText_LoadStandardFont(document(), font_name));
3285 EXPECT_FALSE(font) << font_name
3286 << " should not be considered a standard font.";
3287 }
3288}
3289
3291 // New page
3292 ScopedFPDFPage page(FPDFPage_New(CreateNewDocument(), 0, 612, 792));
3293
3294 // Create a rect with nontrivial graphics
3295 FPDF_PAGEOBJECT rect1 = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
3296 FPDFPageObj_SetBlendMode(rect1, "Color");
3297 FPDFPage_InsertObject(page.get(), rect1);
3298 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
3299
3300 // Check that the ExtGState was created
3301 CPDF_Page* cpage = CPDFPageFromFPDFPage(page.get());
3302 RetainPtr<const CPDF_Dictionary> graphics_dict =
3303 cpage->GetResources()->GetDictFor("ExtGState");
3304 ASSERT_TRUE(graphics_dict);
3305 EXPECT_THAT(graphics_dict->GetKeys(),
3306 UnorderedElementsAreArray({"FXE1", "FXE2"}));
3307
3308 // Add a text object causing no change to the graphics dictionary
3309 FPDF_PAGEOBJECT text1 = FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
3310 // Only alpha, the last component, matters for the graphics dictionary. And
3311 // the default value is 255.
3312 EXPECT_TRUE(FPDFPageObj_SetFillColor(text1, 100, 100, 100, 255));
3313 FPDFPage_InsertObject(page.get(), text1);
3314 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
3315 EXPECT_THAT(graphics_dict->GetKeys(),
3316 UnorderedElementsAreArray({"FXE1", "FXE2"}));
3317
3318 // Add a text object increasing the size of the graphics dictionary
3319 FPDF_PAGEOBJECT text2 =
3320 FPDFPageObj_NewTextObj(document(), "Times-Roman", 12.0f);
3321 FPDFPage_InsertObject(page.get(), text2);
3322 FPDFPageObj_SetBlendMode(text2, "Darken");
3323 EXPECT_TRUE(FPDFPageObj_SetFillColor(text2, 0, 0, 255, 150));
3324 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
3325 EXPECT_THAT(graphics_dict->GetKeys(),
3326 UnorderedElementsAreArray({"FXE1", "FXE2", "FXE3"}));
3327
3328 // Add a path that should reuse graphics
3329 FPDF_PAGEOBJECT path = FPDFPageObj_CreateNewPath(400, 100);
3330 FPDFPageObj_SetBlendMode(path, "Darken");
3331 EXPECT_TRUE(FPDFPageObj_SetFillColor(path, 200, 200, 100, 150));
3332 FPDFPage_InsertObject(page.get(), path);
3333 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
3334 EXPECT_THAT(graphics_dict->GetKeys(),
3335 UnorderedElementsAreArray({"FXE1", "FXE2", "FXE3"}));
3336
3337 // Add a rect increasing the size of the graphics dictionary
3338 FPDF_PAGEOBJECT rect2 = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
3339 FPDFPageObj_SetBlendMode(rect2, "Darken");
3340 EXPECT_TRUE(FPDFPageObj_SetFillColor(rect2, 0, 0, 255, 150));
3341 EXPECT_TRUE(FPDFPageObj_SetStrokeColor(rect2, 0, 0, 0, 200));
3342 FPDFPage_InsertObject(page.get(), rect2);
3343 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
3344 EXPECT_THAT(graphics_dict->GetKeys(),
3345 UnorderedElementsAreArray({"FXE1", "FXE2", "FXE3", "FXE4"}));
3346}
3347
3349 // Start with a blank page
3350 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
3351
3352 // Add a red rectangle with some non-default alpha
3353 FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
3354 EXPECT_TRUE(FPDFPageObj_SetFillColor(rect, 255, 0, 0, 128));
3356 FPDFPage_InsertObject(page, rect);
3357 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3358
3359 // Check the ExtGState
3360 CPDF_Page* cpage = CPDFPageFromFPDFPage(page);
3361 RetainPtr<const CPDF_Dictionary> graphics_dict =
3362 cpage->GetResources()->GetDictFor("ExtGState");
3363 ASSERT_TRUE(graphics_dict);
3364 EXPECT_THAT(graphics_dict->GetKeys(),
3365 UnorderedElementsAreArray({"FXE1", "FXE2"}));
3366
3367 // Check the bitmap
3368 {
3369 ScopedFPDFBitmap page_bitmap = RenderPage(page);
3370 CompareBitmap(page_bitmap.get(), 612, 792,
3371 "5384da3406d62360ffb5cac4476fff1c");
3372 }
3373
3374 // Never mind, my new favorite color is blue, increase alpha.
3375 // The red graphics state goes away.
3376 EXPECT_TRUE(FPDFPageObj_SetFillColor(rect, 0, 0, 255, 180));
3377 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3378 EXPECT_THAT(graphics_dict->GetKeys(),
3379 UnorderedElementsAreArray({"FXE1", "FXE3"}));
3380
3381 // Check that bitmap displays changed content
3382 {
3383 ScopedFPDFBitmap page_bitmap = RenderPage(page);
3384 CompareBitmap(page_bitmap.get(), 612, 792,
3385 "2e51656f5073b0bee611d9cd086aa09c");
3386 }
3387
3388 // And now generate, without changes
3389 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3390 EXPECT_THAT(graphics_dict->GetKeys(),
3391 UnorderedElementsAreArray({"FXE1", "FXE3"}));
3392 {
3393 ScopedFPDFBitmap page_bitmap = RenderPage(page);
3394 CompareBitmap(page_bitmap.get(), 612, 792,
3395 "2e51656f5073b0bee611d9cd086aa09c");
3396 }
3397
3398 // Add some text to the page, which starts out with no fonts.
3399 RetainPtr<const CPDF_Dictionary> font_dict =
3400 cpage->GetResources()->GetDictFor("Font");
3401 EXPECT_FALSE(font_dict);
3402 FPDF_PAGEOBJECT text_object =
3403 FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
3404 ScopedFPDFWideString text =
3405 GetFPDFWideString(L"Something something #text# something");
3406 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
3407 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 300, 300);
3408 FPDFPage_InsertObject(page, text_object);
3409 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3410
3411 // After generating the content, there should now be a font resource.
3412 font_dict = cpage->GetResources()->GetDictFor("Font");
3413 ASSERT_TRUE(font_dict);
3414 EXPECT_THAT(graphics_dict->GetKeys(),
3415 UnorderedElementsAreArray({"FXE1", "FXE3"}));
3416 EXPECT_THAT(font_dict->GetKeys(), UnorderedElementsAreArray({"FXF1"}));
3417
3418 // Generate yet again, check dicts are reasonably sized
3419 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3420 EXPECT_THAT(graphics_dict->GetKeys(),
3421 UnorderedElementsAreArray({"FXE1", "FXE3"}));
3422 EXPECT_THAT(font_dict->GetKeys(), UnorderedElementsAreArray({"FXF1"}));
3423 FPDF_ClosePage(page);
3424}
3425
3427 CreateNewDocument();
3428 // TODO(npm): use other fonts after disallowing loading any font as any type
3429 RetainPtr<CPDF_Font> stock_font =
3430 CPDF_Font::GetStockFont(cpdf_doc(), "Times-Bold");
3431 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
3432 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
3433 FPDF_FONT_TYPE1, false));
3434 ASSERT_TRUE(font.get());
3435 CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
3436 EXPECT_TRUE(typed_font->IsType1Font());
3437
3438 RetainPtr<const CPDF_Dictionary> font_dict = typed_font->GetFontDict();
3439 EXPECT_EQ("Font", font_dict->GetNameFor("Type"));
3440 EXPECT_EQ("Type1", font_dict->GetNameFor("Subtype"));
3441 EXPECT_EQ("Tinos-Bold", font_dict->GetNameFor("BaseFont"));
3442 ASSERT_TRUE(font_dict->KeyExist("FirstChar"));
3443 ASSERT_TRUE(font_dict->KeyExist("LastChar"));
3444 EXPECT_EQ(32, font_dict->GetIntegerFor("FirstChar"));
3445 EXPECT_EQ(255, font_dict->GetIntegerFor("LastChar"));
3446
3447 RetainPtr<const CPDF_Array> widths_array = font_dict->GetArrayFor("Widths");
3448 ASSERT_TRUE(widths_array);
3449 ASSERT_EQ(224u, widths_array->size());
3450 EXPECT_EQ(250, widths_array->GetFloatAt(0));
3451 EXPECT_EQ(569, widths_array->GetFloatAt(11));
3452 EXPECT_EQ(500, widths_array->GetFloatAt(223));
3453 CheckFontDescriptor(font_dict, FPDF_FONT_TYPE1, true, false, span);
3454}
3455
3457 CreateNewDocument();
3458 RetainPtr<CPDF_Font> stock_font =
3459 CPDF_Font::GetStockFont(cpdf_doc(), "Courier");
3460 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
3461 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
3462 FPDF_FONT_TRUETYPE, false));
3463 ASSERT_TRUE(font.get());
3464 CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
3465 EXPECT_TRUE(typed_font->IsTrueTypeFont());
3466
3467 RetainPtr<const CPDF_Dictionary> font_dict = typed_font->GetFontDict();
3468 EXPECT_EQ("Font", font_dict->GetNameFor("Type"));
3469 EXPECT_EQ("TrueType", font_dict->GetNameFor("Subtype"));
3470 EXPECT_EQ("Cousine-Regular", font_dict->GetNameFor("BaseFont"));
3471 ASSERT_TRUE(font_dict->KeyExist("FirstChar"));
3472 ASSERT_TRUE(font_dict->KeyExist("LastChar"));
3473 EXPECT_EQ(32, font_dict->GetIntegerFor("FirstChar"));
3474 EXPECT_EQ(255, font_dict->GetIntegerFor("LastChar"));
3475
3476 RetainPtr<const CPDF_Array> widths_array = font_dict->GetArrayFor("Widths");
3477 ASSERT_TRUE(widths_array);
3478 ASSERT_EQ(224u, widths_array->size());
3479 EXPECT_EQ(600, widths_array->GetFloatAt(33));
3480 EXPECT_EQ(600, widths_array->GetFloatAt(74));
3481 EXPECT_EQ(600, widths_array->GetFloatAt(223));
3482 CheckFontDescriptor(font_dict, FPDF_FONT_TRUETYPE, false, false, span);
3483}
3484
3486 CreateNewDocument();
3487 RetainPtr<CPDF_Font> stock_font =
3488 CPDF_Font::GetStockFont(cpdf_doc(), "Times-Roman");
3489 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
3490 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
3491 FPDF_FONT_TYPE1, 1));
3492 ASSERT_TRUE(font.get());
3493 CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
3494 EXPECT_TRUE(typed_font->IsCIDFont());
3495
3496 // Check font dictionary entries
3497 RetainPtr<const CPDF_Dictionary> font_dict = typed_font->GetFontDict();
3498 EXPECT_EQ("Font", font_dict->GetNameFor("Type"));
3499 EXPECT_EQ("Type0", font_dict->GetNameFor("Subtype"));
3500 EXPECT_EQ("Tinos-Regular-Identity-H", font_dict->GetNameFor("BaseFont"));
3501 EXPECT_EQ("Identity-H", font_dict->GetNameFor("Encoding"));
3502 RetainPtr<const CPDF_Array> descendant_array =
3503 font_dict->GetArrayFor("DescendantFonts");
3504 ASSERT_TRUE(descendant_array);
3505 EXPECT_EQ(1u, descendant_array->size());
3506
3507 // Check the CIDFontDict
3508 RetainPtr<const CPDF_Dictionary> cidfont_dict =
3509 descendant_array->GetDictAt(0);
3510 EXPECT_EQ("Font", cidfont_dict->GetNameFor("Type"));
3511 EXPECT_EQ("CIDFontType0", cidfont_dict->GetNameFor("Subtype"));
3512 EXPECT_EQ("Tinos-Regular", cidfont_dict->GetNameFor("BaseFont"));
3513 RetainPtr<const CPDF_Dictionary> cidinfo_dict =
3514 cidfont_dict->GetDictFor("CIDSystemInfo");
3515 ASSERT_TRUE(cidinfo_dict);
3516 RetainPtr<const CPDF_Object> registry =
3517 cidinfo_dict->GetObjectFor("Registry");
3518 ASSERT_TRUE(registry);
3519 EXPECT_EQ(CPDF_Object::kString, registry->GetType());
3520 EXPECT_EQ("Adobe", registry->GetString());
3521 RetainPtr<const CPDF_Object> ordering =
3522 cidinfo_dict->GetObjectFor("Ordering");
3523 ASSERT_TRUE(ordering);
3524 EXPECT_EQ(CPDF_Object::kString, ordering->GetType());
3525 EXPECT_EQ("Identity", ordering->GetString());
3526 EXPECT_EQ(0, cidinfo_dict->GetFloatFor("Supplement"));
3527 CheckFontDescriptor(cidfont_dict.Get(), FPDF_FONT_TYPE1, false, false, span);
3528
3529 // Check widths
3530 RetainPtr<const CPDF_Array> widths_array = cidfont_dict->GetArrayFor("W");
3531 ASSERT_TRUE(widths_array);
3532 EXPECT_GT(widths_array->size(), 1u);
3533 CheckCompositeFontWidths(widths_array.Get(), typed_font);
3534}
3535
3537 CreateNewDocument();
3538 RetainPtr<CPDF_Font> stock_font =
3539 CPDF_Font::GetStockFont(cpdf_doc(), "Helvetica-Oblique");
3540 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
3541 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
3542 FPDF_FONT_TRUETYPE, 1));
3543 ASSERT_TRUE(font.get());
3544 CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
3545 EXPECT_TRUE(typed_font->IsCIDFont());
3546
3547 // Check font dictionary entries
3548 RetainPtr<const CPDF_Dictionary> font_dict = typed_font->GetFontDict();
3549 EXPECT_EQ("Font", font_dict->GetNameFor("Type"));
3550 EXPECT_EQ("Type0", font_dict->GetNameFor("Subtype"));
3551 EXPECT_EQ("Arimo-Italic", font_dict->GetNameFor("BaseFont"));
3552 EXPECT_EQ("Identity-H", font_dict->GetNameFor("Encoding"));
3553 RetainPtr<const CPDF_Array> descendant_array =
3554 font_dict->GetArrayFor("DescendantFonts");
3555 ASSERT_TRUE(descendant_array);
3556 EXPECT_EQ(1u, descendant_array->size());
3557
3558 // Check the CIDFontDict
3559 RetainPtr<const CPDF_Dictionary> cidfont_dict =
3560 descendant_array->GetDictAt(0);
3561 EXPECT_EQ("Font", cidfont_dict->GetNameFor("Type"));
3562 EXPECT_EQ("CIDFontType2", cidfont_dict->GetNameFor("Subtype"));
3563 EXPECT_EQ("Arimo-Italic", cidfont_dict->GetNameFor("BaseFont"));
3564 RetainPtr<const CPDF_Dictionary> cidinfo_dict =
3565 cidfont_dict->GetDictFor("CIDSystemInfo");
3566 ASSERT_TRUE(cidinfo_dict);
3567 EXPECT_EQ("Adobe", cidinfo_dict->GetByteStringFor("Registry"));
3568 EXPECT_EQ("Identity", cidinfo_dict->GetByteStringFor("Ordering"));
3569 EXPECT_EQ(0, cidinfo_dict->GetFloatFor("Supplement"));
3570 CheckFontDescriptor(cidfont_dict.Get(), FPDF_FONT_TRUETYPE, false, true,
3571 span);
3572
3573 // Check widths
3574 RetainPtr<const CPDF_Array> widths_array = cidfont_dict->GetArrayFor("W");
3575 ASSERT_TRUE(widths_array);
3576 CheckCompositeFontWidths(widths_array.Get(), typed_font);
3577}
3578
3580 // Load document with a -90 degree rotation
3581 ASSERT_TRUE(OpenDocument("bug_713197.pdf"));
3582 FPDF_PAGE page = LoadPage(0);
3583 EXPECT_TRUE(page);
3584
3585 EXPECT_EQ(3, FPDFPage_GetRotation(page));
3586 UnloadPage(page);
3587}
3588
3590 // Start with a blank page
3591 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
3592 {
3593 RetainPtr<CPDF_Font> stock_font =
3594 CPDF_Font::GetStockFont(cpdf_doc(), "Arial");
3595 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
3596 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
3597 FPDF_FONT_TRUETYPE, 0));
3598 ASSERT_TRUE(font.get());
3599
3600 // Add some text to the page
3601 FPDF_PAGEOBJECT text_object =
3602 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
3603 EXPECT_TRUE(text_object);
3604 ScopedFPDFWideString text = GetFPDFWideString(kLoadedFontText);
3605 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
3606 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 400, 400);
3607 FPDFPage_InsertObject(page, text_object);
3608 ScopedFPDFBitmap page_bitmap = RenderPage(page);
3609 CompareBitmap(page_bitmap.get(), 612, 792, LoadedFontTextChecksum());
3610
3611 // Add some more text, same font
3612 FPDF_PAGEOBJECT text_object2 =
3613 FPDFPageObj_CreateTextObj(document(), font.get(), 15.0f);
3614 ScopedFPDFWideString text2 = GetFPDFWideString(L"Bigger font size");
3615 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
3616 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 200, 200);
3617 FPDFPage_InsertObject(page, text_object2);
3618 }
3619 ScopedFPDFBitmap page_bitmap2 = RenderPage(page);
3620 const char* insert_true_type_checksum = []() {
3621 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
3622#if BUILDFLAG(IS_WIN)
3623 return "7e44d135666d8bfcef5cdb4c8161fd4b";
3624#elif BUILDFLAG(IS_APPLE)
3625 return "6bab7f663daca1aab63d787a0f5cb33b";
3626#else
3627 return "4f9a6c7752ac7d4e4c731260fdb5af15";
3628#endif
3629 }
3630#if BUILDFLAG(IS_APPLE)
3631 return "c7e2271a7f30e5b919a13ead47cea105";
3632#else
3633 return "683f4a385a891494100192cb338b11f0";
3634#endif
3635 }();
3636 CompareBitmap(page_bitmap2.get(), 612, 792, insert_true_type_checksum);
3637
3638 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3639 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3640 FPDF_ClosePage(page);
3641
3642 VerifySavedDocument(612, 792, insert_true_type_checksum);
3643}
3644
3646 // Open a file with one annotation and load its first page.
3647 ASSERT_TRUE(OpenDocument("annotation_highlight_long_content.pdf"));
3648 FPDF_PAGE page = LoadPage(0);
3649 ASSERT_TRUE(page);
3650
3651 {
3652 // Add an underline annotation to the page without specifying its rectangle.
3653 ScopedFPDFAnnotation annot(
3654 FPDFPage_CreateAnnot(page, FPDF_ANNOT_UNDERLINE));
3655 ASSERT_TRUE(annot);
3656
3657 // FPDFPage_TransformAnnots() should run without errors when modifying
3658 // annotation rectangles.
3659 FPDFPage_TransformAnnots(page, 1, 2, 3, 4, 5, 6);
3660 }
3661 UnloadPage(page);
3662}
3663
3664// TODO(npm): Add tests using Japanese fonts in other OS.
3665#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
3666TEST_F(FPDFEditEmbedderTest, AddCIDFontText) {
3667 // Start with a blank page
3668 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
3669 CFX_Font CIDfont;
3670 {
3671 // First, get the data from the font
3672 CIDfont.LoadSubst("Noto Sans CJK JP", true, 0, 400, 0,
3673 FX_CodePage::kShiftJIS, false);
3674 EXPECT_EQ("Noto Sans CJK JP", CIDfont.GetFaceName());
3675 pdfium::span<const uint8_t> span = CIDfont.GetFontSpan();
3676
3677 // Load the data into a FPDF_Font.
3678 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
3679 FPDF_FONT_TRUETYPE, 1));
3680 ASSERT_TRUE(font.get());
3681
3682 // Add some text to the page
3683 FPDF_PAGEOBJECT text_object =
3684 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
3685 ASSERT_TRUE(text_object);
3686 std::wstring wstr = L"ABCDEFGhijklmnop.";
3687 ScopedFPDFWideString text = GetFPDFWideString(wstr);
3688 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
3689 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 200, 200);
3690 FPDFPage_InsertObject(page, text_object);
3691
3692 // And add some Japanese characters
3693 FPDF_PAGEOBJECT text_object2 =
3694 FPDFPageObj_CreateTextObj(document(), font.get(), 18.0f);
3695 ASSERT_TRUE(text_object2);
3696 std::wstring wstr2 =
3697 L"\u3053\u3093\u306B\u3061\u306f\u4e16\u754C\u3002\u3053\u3053\u306B1"
3698 L"\u756A";
3699 ScopedFPDFWideString text2 = GetFPDFWideString(wstr2);
3700 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
3701 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 100, 500);
3702 FPDFPage_InsertObject(page, text_object2);
3703 }
3704
3705 // Check that the text renders properly.
3706 const char* checksum = []() {
3707 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
3708 return "2e174d17de96a760d42ca3a06acbf36a";
3709 }
3710 return "84d31d11b76845423a2cfc1879c0fbb9";
3711 }();
3712
3713 {
3714 ScopedFPDFBitmap page_bitmap = RenderPage(page);
3715 CompareBitmap(page_bitmap.get(), 612, 792, checksum);
3716 }
3717
3718 // Save the document, close the page.
3719 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3720 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3721 FPDF_ClosePage(page);
3722
3723 VerifySavedDocument(612, 792, checksum);
3724}
3725#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
3726
3728 const char* checksum = []() {
3729 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
3730 return "9a78649e85e69d220c22e0fc316da740";
3731 }
3732 return "3c20472b0552c0c22b88ab1ed8c6202b";
3733 }();
3734 {
3735 ASSERT_TRUE(OpenDocument("bug_779.pdf"));
3736 FPDF_PAGE page = LoadPage(0);
3737 ASSERT_NE(nullptr, page);
3738
3739 // Now add a more complex green path.
3740 FPDF_PAGEOBJECT green_path = FPDFPageObj_CreateNewPath(20, 20);
3741 EXPECT_TRUE(FPDFPageObj_SetFillColor(green_path, 0, 255, 0, 200));
3742 // TODO(npm): stroking will cause the checksums to differ.
3743 EXPECT_TRUE(FPDFPath_SetDrawMode(green_path, FPDF_FILLMODE_WINDING, 0));
3744 EXPECT_TRUE(FPDFPath_LineTo(green_path, 20, 63));
3745 EXPECT_TRUE(FPDFPath_BezierTo(green_path, 55, 55, 78, 78, 90, 90));
3746 EXPECT_TRUE(FPDFPath_LineTo(green_path, 133, 133));
3747 EXPECT_TRUE(FPDFPath_LineTo(green_path, 133, 33));
3748 EXPECT_TRUE(FPDFPath_BezierTo(green_path, 38, 33, 39, 36, 40, 40));
3749 EXPECT_TRUE(FPDFPath_Close(green_path));
3750 FPDFPage_InsertObject(page, green_path);
3751 ScopedFPDFBitmap page_bitmap = RenderLoadedPage(page);
3752 CompareBitmap(page_bitmap.get(), 612, 792, checksum);
3753
3754 // Now save the result, closing the page and document
3755 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3756 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3757 UnloadPage(page);
3758 }
3759
3760 VerifySavedDocument(612, 792, checksum);
3761}
3762
3764 // Load document with some text.
3765 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
3766 FPDF_PAGE page = LoadPage(0);
3767 ASSERT_TRUE(page);
3768
3769 CheckMarkCounts(page, 1, 19, 8, 4, 9, 1);
3770
3771 // Add to the first page object a "Bounds" mark with "Position": "First".
3772 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
3773 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_AddMark(page_object, "Bounds");
3774 EXPECT_TRUE(mark);
3775 EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), page_object, mark,
3776 "Position", "First"));
3777
3778 CheckMarkCounts(page, 1, 19, 8, 4, 9, 2);
3779
3780 // Save the file
3781 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3782 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3783 UnloadPage(page);
3784
3785 // Re-open the file and check the new mark is present.
3786 ASSERT_TRUE(OpenSavedDocument());
3787 FPDF_PAGE saved_page = LoadSavedPage(0);
3788 ASSERT_TRUE(saved_page);
3789
3790 CheckMarkCounts(saved_page, 1, 19, 8, 4, 9, 2);
3791
3792 CloseSavedPage(saved_page);
3793 CloseSavedDocument();
3794}
3795
3797 // Load document with some text in a compressed stream.
3798 ASSERT_TRUE(OpenDocument("hello_world_compressed_stream.pdf"));
3799 FPDF_PAGE page = LoadPage(0);
3800 ASSERT_TRUE(page);
3801
3802 // Render and check there are no marks.
3803 {
3804 ScopedFPDFBitmap page_bitmap = RenderPage(page);
3805 CompareBitmap(page_bitmap.get(), 200, 200, HelloWorldChecksum());
3806 }
3807 CheckMarkCounts(page, 0, 2, 0, 0, 0, 0);
3808
3809 // Add to the first page object a "Bounds" mark with "Position": "First".
3810 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
3811 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_AddMark(page_object, "Bounds");
3812 EXPECT_TRUE(mark);
3813 EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), page_object, mark,
3814 "Position", "First"));
3815
3816 // Render and check there is 1 mark.
3817 {
3818 ScopedFPDFBitmap page_bitmap = RenderPage(page);
3819 CompareBitmap(page_bitmap.get(), 200, 200, HelloWorldChecksum());
3820 }
3821 CheckMarkCounts(page, 0, 2, 0, 0, 0, 1);
3822
3823 // Save the file.
3824 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3825 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3826 UnloadPage(page);
3827
3828 // Re-open the file and check the new mark is present.
3829 ASSERT_TRUE(OpenSavedDocument());
3830 FPDF_PAGE saved_page = LoadSavedPage(0);
3831 ASSERT_TRUE(saved_page);
3832
3833 {
3834 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
3835 CompareBitmap(page_bitmap.get(), 200, 200, HelloWorldChecksum());
3836 }
3837 CheckMarkCounts(saved_page, 0, 2, 0, 0, 0, 1);
3838
3839 CloseSavedPage(saved_page);
3840 CloseSavedDocument();
3841}
3842
3844 // Load document with some text.
3845 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
3846 FPDF_PAGE page = LoadPage(0);
3847 ASSERT_TRUE(page);
3848
3849 constexpr int kExpectedObjectCount = 19;
3850 CheckMarkCounts(page, 1, kExpectedObjectCount, 8, 4, 9, 1);
3851
3852 // Check the "Bounds" mark's "Position" param is "Last".
3853 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
3854 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
3855 ASSERT_TRUE(mark);
3856 char buffer[256];
3857 unsigned long name_len = 999u;
3858 ASSERT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
3859 EXPECT_EQ((6u + 1u) * 2u, name_len);
3860 ASSERT_EQ(L"Bounds",
3861 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3862 unsigned long out_buffer_len;
3864 mark, "Position", buffer, sizeof(buffer), &out_buffer_len));
3865 ASSERT_EQ(L"Last",
3866 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3867
3868 // Set is to "End".
3869 EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), page_object, mark,
3870 "Position", "End"));
3871
3872 // Verify the object passed must correspond to the mark passed.
3873 FPDF_PAGEOBJECT another_page_object = FPDFPage_GetObject(page, 17);
3874 EXPECT_FALSE(FPDFPageObjMark_SetStringParam(document(), another_page_object,
3875 mark, "Position", "End"));
3876
3877 // Verify nothing else changed.
3878 CheckMarkCounts(page, 1, kExpectedObjectCount, 8, 4, 9, 1);
3879
3880 // Verify "Position" now maps to "End".
3882 mark, "Position", buffer, sizeof(buffer), &out_buffer_len));
3883 EXPECT_EQ(L"End",
3884 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3885
3886 // Save the file
3887 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3888 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3889 UnloadPage(page);
3890
3891 // Re-open the file and cerify "Position" still maps to "End".
3892 ASSERT_TRUE(OpenSavedDocument());
3893 FPDF_PAGE saved_page = LoadSavedPage(0);
3894 ASSERT_TRUE(saved_page);
3895
3896 CheckMarkCounts(saved_page, 1, kExpectedObjectCount, 8, 4, 9, 1);
3897 page_object = FPDFPage_GetObject(saved_page, 18);
3898 mark = FPDFPageObj_GetMark(page_object, 1);
3900 mark, "Position", buffer, sizeof(buffer), &out_buffer_len));
3901 EXPECT_EQ(L"End",
3902 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3903
3904 CloseSavedPage(saved_page);
3905 CloseSavedDocument();
3906}
3907
3909 // Start with a blank page.
3910 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
3911
3912 RetainPtr<CPDF_Font> stock_font =
3913 CPDF_Font::GetStockFont(cpdf_doc(), "Arial");
3914 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
3915 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
3916 FPDF_FONT_TRUETYPE, 0));
3917 ASSERT_TRUE(font.get());
3918
3919 // Add some text to the page.
3920 FPDF_PAGEOBJECT text_object =
3921 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
3922
3923 EXPECT_TRUE(text_object);
3924 ScopedFPDFWideString text1 = GetFPDFWideString(kLoadedFontText);
3925 EXPECT_TRUE(FPDFText_SetText(text_object, text1.get()));
3926 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 400, 400);
3927 FPDFPage_InsertObject(page, text_object);
3928
3929 // Add a mark with the tag "TestMarkName" to that text.
3930 EXPECT_EQ(0, FPDFPageObj_CountMarks(text_object));
3931 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_AddMark(text_object, "Test Mark Name");
3932 EXPECT_TRUE(mark);
3933 EXPECT_EQ(1, FPDFPageObj_CountMarks(text_object));
3934 EXPECT_EQ(mark, FPDFPageObj_GetMark(text_object, 0));
3935 char buffer[256];
3936 unsigned long name_len = 999u;
3937 ASSERT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
3938 EXPECT_EQ((14u + 1u) * 2, name_len);
3939 std::wstring name =
3940 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
3941 EXPECT_EQ(L"Test Mark Name", name);
3942
3943 // Add parameters:
3944 // - int "IntKey" : 42
3945 // - string "StringKey": "StringValue"
3946 // - blob "BlobKey": "\x01\x02\x03\0BlobValue1\0\0\0BlobValue2\0"
3947 constexpr size_t kBlobLen = 28;
3948 char block_value[kBlobLen];
3949 memcpy(block_value, "\x01\x02\x03\0BlobValue1\0\0\0BlobValue2\0", kBlobLen);
3950 EXPECT_EQ(0, FPDFPageObjMark_CountParams(mark));
3951 EXPECT_TRUE(
3952 FPDFPageObjMark_SetIntParam(document(), text_object, mark, "IntKey", 42));
3953 EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), text_object, mark,
3954 "StringKey", "StringValue"));
3955 EXPECT_TRUE(FPDFPageObjMark_SetBlobParam(document(), text_object, mark,
3956 "BlobKey", block_value, kBlobLen));
3957 EXPECT_EQ(3, FPDFPageObjMark_CountParams(mark));
3958
3959 // Check the two parameters can be retrieved.
3960 EXPECT_EQ(FPDF_OBJECT_NUMBER,
3962 int int_value;
3963 EXPECT_TRUE(FPDFPageObjMark_GetParamIntValue(mark, "IntKey", &int_value));
3964 EXPECT_EQ(42, int_value);
3965
3966 EXPECT_EQ(FPDF_OBJECT_STRING,
3967 FPDFPageObjMark_GetParamValueType(mark, "StringKey"));
3968 unsigned long out_buffer_len = 999u;
3970 mark, "StringKey", buffer, sizeof(buffer), &out_buffer_len));
3971 EXPECT_GT(out_buffer_len, 0u);
3972 EXPECT_NE(999u, out_buffer_len);
3973 name = GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
3974 EXPECT_EQ(L"StringValue", name);
3975
3976 EXPECT_EQ(FPDF_OBJECT_STRING,
3978 out_buffer_len = 0;
3980 mark, "BlobKey", buffer, sizeof(buffer), &out_buffer_len));
3981 EXPECT_EQ(kBlobLen, out_buffer_len);
3982 EXPECT_EQ(0, memcmp(block_value, buffer, kBlobLen));
3983
3984 // Render and check the bitmap is the expected one.
3985 {
3986 ScopedFPDFBitmap page_bitmap = RenderPage(page);
3987 CompareBitmap(page_bitmap.get(), 612, 792, LoadedFontTextChecksum());
3988 }
3989
3990 // Now save the result.
3991 EXPECT_EQ(1, FPDFPage_CountObjects(page));
3992 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3993 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3994
3995 FPDF_ClosePage(page);
3996
3997 // Re-open the file and check the changes were kept in the saved .pdf.
3998 ASSERT_TRUE(OpenSavedDocument());
3999 FPDF_PAGE saved_page = LoadSavedPage(0);
4000 ASSERT_TRUE(saved_page);
4001 EXPECT_EQ(1, FPDFPage_CountObjects(saved_page));
4002
4003 text_object = FPDFPage_GetObject(saved_page, 0);
4004 EXPECT_TRUE(text_object);
4005 EXPECT_EQ(1, FPDFPageObj_CountMarks(text_object));
4006 mark = FPDFPageObj_GetMark(text_object, 0);
4007 EXPECT_TRUE(mark);
4008
4009 name_len = 999u;
4010 ASSERT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
4011 EXPECT_EQ((14u + 1u) * 2, name_len);
4012 name = GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
4013 EXPECT_EQ(L"Test Mark Name", name);
4014
4015 CloseSavedPage(saved_page);
4016 CloseSavedDocument();
4017}
4018
4020 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
4021 FPDF_PAGE page = LoadPage(0);
4022 ASSERT_TRUE(page);
4023 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
4024 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
4025 ASSERT_TRUE(mark);
4026
4027 char buffer[256];
4028 unsigned long out_len;
4029
4030 // Show the positive cases of FPDFPageObjMark_GetName.
4031 out_len = 999u;
4032 EXPECT_TRUE(FPDFPageObjMark_GetName(mark, nullptr, 0, &out_len));
4033 EXPECT_EQ((6u + 1u) * 2u, out_len);
4034
4035 out_len = 999u;
4036 EXPECT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &out_len));
4037 EXPECT_EQ(L"Bounds",
4038 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
4039 EXPECT_EQ((6u + 1u) * 2u, out_len);
4040
4041 // Show the negative cases of FPDFPageObjMark_GetName.
4042 out_len = 999u;
4043 EXPECT_FALSE(
4044 FPDFPageObjMark_GetName(nullptr, buffer, sizeof(buffer), &out_len));
4045 EXPECT_EQ(999u, out_len);
4046
4047 EXPECT_FALSE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), nullptr));
4048
4049 UnloadPage(page);
4050}
4051
4053 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
4054 FPDF_PAGE page = LoadPage(0);
4055 ASSERT_TRUE(page);
4056 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
4057 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
4058 ASSERT_TRUE(mark);
4059
4060 char buffer[256];
4061 unsigned long out_len;
4062
4063 // Show the positive cases of FPDFPageObjMark_GetParamKey.
4064 out_len = 999u;
4065 EXPECT_TRUE(FPDFPageObjMark_GetParamKey(mark, 0, nullptr, 0, &out_len));
4066 EXPECT_EQ((8u + 1u) * 2u, out_len);
4067
4068 out_len = 999u;
4069 EXPECT_TRUE(
4070 FPDFPageObjMark_GetParamKey(mark, 0, buffer, sizeof(buffer), &out_len));
4071 EXPECT_EQ(L"Position",
4072 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
4073 EXPECT_EQ((8u + 1u) * 2u, out_len);
4074
4075 // Show the negative cases of FPDFPageObjMark_GetParamKey.
4076 out_len = 999u;
4077 EXPECT_FALSE(FPDFPageObjMark_GetParamKey(nullptr, 0, buffer, sizeof(buffer),
4078 &out_len));
4079 EXPECT_EQ(999u, out_len);
4080
4081 out_len = 999u;
4082 EXPECT_FALSE(
4083 FPDFPageObjMark_GetParamKey(mark, 1, buffer, sizeof(buffer), &out_len));
4084 EXPECT_EQ(999u, out_len);
4085
4086 EXPECT_FALSE(
4087 FPDFPageObjMark_GetParamKey(mark, 0, buffer, sizeof(buffer), nullptr));
4088
4089 UnloadPage(page);
4090}
4091
4093 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
4094 FPDF_PAGE page = LoadPage(0);
4095 ASSERT_TRUE(page);
4096 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 8);
4097 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 0);
4098 ASSERT_TRUE(mark);
4099
4100 int out_value;
4101
4102 // Show the positive cases of FPDFPageObjMark_GetParamIntValue.
4103 out_value = 999;
4104 EXPECT_TRUE(FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
4105 EXPECT_EQ(3, out_value);
4106
4107 // Show the negative cases of FPDFPageObjMark_GetParamIntValue.
4108 out_value = 999;
4109 EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(nullptr, "Factor", &out_value));
4110 EXPECT_EQ(999, out_value);
4111
4112 out_value = 999;
4113 EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(mark, "ParamThatDoesNotExist",
4114 &out_value));
4115 EXPECT_EQ(999, out_value);
4116
4117 EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(mark, "Factor", nullptr));
4118
4119 page_object = FPDFPage_GetObject(page, 18);
4120 mark = FPDFPageObj_GetMark(page_object, 1);
4121 out_value = 999;
4122 EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(mark, "Position", &out_value));
4123 EXPECT_EQ(999, out_value);
4124
4125 UnloadPage(page);
4126}
4127
4129 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
4130 FPDF_PAGE page = LoadPage(0);
4131 ASSERT_TRUE(page);
4132 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
4133 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
4134 ASSERT_TRUE(mark);
4135
4136 char buffer[256];
4137 unsigned long out_len;
4138
4139 // Show the positive cases of FPDFPageObjMark_GetParamStringValue.
4140 out_len = 999u;
4141 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(mark, "Position", nullptr, 0,
4142 &out_len));
4143 EXPECT_EQ((4u + 1u) * 2u, out_len);
4144
4145 out_len = 999u;
4146 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(mark, "Position", buffer,
4147 sizeof(buffer), &out_len));
4148 EXPECT_EQ(L"Last",
4149 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
4150 EXPECT_EQ((4u + 1u) * 2u, out_len);
4151
4152 // Show the negative cases of FPDFPageObjMark_GetParamStringValue.
4153 out_len = 999u;
4154 EXPECT_FALSE(FPDFPageObjMark_GetParamStringValue(nullptr, "Position", buffer,
4155 sizeof(buffer), &out_len));
4156 EXPECT_EQ(999u, out_len);
4157
4158 out_len = 999u;
4160 mark, "ParamThatDoesNotExist", buffer, sizeof(buffer), &out_len));
4161 EXPECT_EQ(999u, out_len);
4162
4163 EXPECT_FALSE(FPDFPageObjMark_GetParamStringValue(mark, "Position", buffer,
4164 sizeof(buffer), nullptr));
4165
4166 page_object = FPDFPage_GetObject(page, 8);
4167 mark = FPDFPageObj_GetMark(page_object, 0);
4168 out_len = 999u;
4169 EXPECT_FALSE(FPDFPageObjMark_GetParamStringValue(mark, "Factor", buffer,
4170 sizeof(buffer), &out_len));
4171 EXPECT_EQ(999u, out_len);
4172
4173 UnloadPage(page);
4174}
4175
4176// See also FPDFStructTreeEmbedderTest.GetMarkedContentID, which traverses the
4177// marked contents using FPDF_StructTree_GetForPage() and related API.
4179 ASSERT_TRUE(OpenDocument("marked_content_id.pdf"));
4180 FPDF_PAGE page = LoadPage(0);
4181 ASSERT_TRUE(page);
4182
4183 ASSERT_EQ(2, FPDFPage_CountObjects(page));
4184 FPDF_PAGEOBJECT object1 = FPDFPage_GetObject(page, 0);
4185 ASSERT_TRUE(object1);
4186 ASSERT_EQ(1, FPDFPageObj_CountMarks(object1));
4187
4188 FPDF_PAGEOBJECTMARK mark11 = FPDFPageObj_GetMark(object1, 0);
4189 ASSERT_TRUE(mark11);
4190 unsigned long len = 0;
4191 unsigned short buf[40];
4192 ASSERT_TRUE(FPDFPageObjMark_GetName(mark11, buf, sizeof(buf), &len));
4193 EXPECT_EQ(18u, len);
4194 EXPECT_EQ(L"Artifact", GetPlatformWString(buf));
4195 ASSERT_EQ(2, FPDFPageObjMark_CountParams(mark11));
4196 ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark11, 0, buf, sizeof(buf), &len));
4197 EXPECT_EQ(10u, len);
4198 EXPECT_EQ(L"BBox", GetPlatformWString(buf));
4199 EXPECT_EQ(FPDF_OBJECT_ARRAY,
4201 ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark11, 1, buf, sizeof(buf), &len));
4202 EXPECT_EQ(10u, len);
4203 EXPECT_EQ(L"Type", GetPlatformWString(buf));
4204 EXPECT_EQ(FPDF_OBJECT_NAME,
4206
4207 FPDF_PAGEOBJECT object2 = FPDFPage_GetObject(page, 1);
4208 ASSERT_TRUE(object2);
4209 ASSERT_EQ(2, FPDFPageObj_CountMarks(object2));
4210 EXPECT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(object2));
4211
4212 FPDF_PAGEOBJECTMARK mark21 = FPDFPageObj_GetMark(object2, 0);
4213 ASSERT_TRUE(mark21);
4214 ASSERT_TRUE(FPDFPageObjMark_GetName(mark21, buf, sizeof(buf), &len));
4215 EXPECT_EQ(14u, len);
4216 EXPECT_EQ(L"Figure", GetPlatformWString(buf));
4217 ASSERT_EQ(1, FPDFPageObjMark_CountParams(mark21));
4218 ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark21, 0, buf, sizeof(buf), &len));
4219 EXPECT_EQ(10u, len);
4220 EXPECT_EQ(L"MCID", GetPlatformWString(buf));
4221 ASSERT_EQ(FPDF_OBJECT_NUMBER,
4223 int mcid = -1;
4224 ASSERT_TRUE(FPDFPageObjMark_GetParamIntValue(mark21, "MCID", &mcid));
4225 EXPECT_EQ(0, mcid);
4226
4227 FPDF_PAGEOBJECTMARK mark22 = FPDFPageObj_GetMark(object2, 1);
4228 ASSERT_TRUE(mark22);
4229 ASSERT_TRUE(FPDFPageObjMark_GetName(mark22, buf, sizeof(buf), &len));
4230 EXPECT_EQ(18u, len);
4231 EXPECT_EQ(L"ClipSpan", GetPlatformWString(buf));
4232 EXPECT_EQ(0, FPDFPageObjMark_CountParams(mark22));
4233
4234 UnloadPage(page);
4235}
4236
4238 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
4239 FPDF_PAGE page = LoadPage(0);
4240 ASSERT_TRUE(page);
4241 ASSERT_EQ(39, FPDFPage_CountObjects(page));
4242
4243 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 32);
4245 EXPECT_FALSE(FPDFImageObj_GetBitmap(obj));
4246
4247 {
4248 obj = FPDFPage_GetObject(page, 33);
4250 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
4251 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
4252 CompareBitmap(bitmap.get(), 109, 88, kEmbeddedImage33Checksum);
4253 }
4254
4255 {
4256 obj = FPDFPage_GetObject(page, 34);
4258 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
4259 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
4260 CompareBitmap(bitmap.get(), 103, 75, "c8d51fa6821ceb2a67f08446ff236c40");
4261 }
4262
4263 {
4264 obj = FPDFPage_GetObject(page, 35);
4266 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
4267 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
4268 CompareBitmap(bitmap.get(), 92, 68, "7e34551035943e30a9f353db17de62ab");
4269 }
4270
4271 {
4272 obj = FPDFPage_GetObject(page, 36);
4274 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
4275 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
4276 CompareBitmap(bitmap.get(), 79, 60, "f4e72fb783a01c7b4614cdc25eaa98ac");
4277 }
4278
4279 {
4280 obj = FPDFPage_GetObject(page, 37);
4282 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
4283 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
4284 CompareBitmap(bitmap.get(), 126, 106, "2cf9e66414c72461f4ccbf9cdebdfa1b");
4285 }
4286
4287 {
4288 obj = FPDFPage_GetObject(page, 38);
4290 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
4291 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
4292 CompareBitmap(bitmap.get(), 194, 119, "a8f3a126cec274dab8242fd2ccdc1b8b");
4293 }
4294
4295 UnloadPage(page);
4296}
4297
4299 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
4300 FPDF_PAGE page = LoadPage(0);
4301 ASSERT_TRUE(page);
4302 ASSERT_EQ(39, FPDFPage_CountObjects(page));
4303
4304 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 33);
4306
4307 {
4308 // Render |obj| as is.
4309 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
4310 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
4311 CompareBitmap(bitmap.get(), 109, 88, kEmbeddedImage33Checksum);
4312 }
4313
4314 // Check the matrix for |obj|.
4315 FS_MATRIX matrix;
4316 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4317 EXPECT_FLOAT_EQ(53.0f, matrix.a);
4318 EXPECT_FLOAT_EQ(0.0f, matrix.b);
4319 EXPECT_FLOAT_EQ(0.0f, matrix.c);
4320 EXPECT_FLOAT_EQ(43.0f, matrix.d);
4321 EXPECT_FLOAT_EQ(72.0f, matrix.e);
4322 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
4323
4324 // Modify the matrix for |obj|.
4325 matrix.a = 120.0;
4326 EXPECT_TRUE(FPDFPageObj_SetMatrix(obj, &matrix));
4327
4328 // Make sure the matrix modification took place.
4329 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4330 EXPECT_FLOAT_EQ(120.0f, matrix.a);
4331 EXPECT_FLOAT_EQ(0.0f, matrix.b);
4332 EXPECT_FLOAT_EQ(0.0f, matrix.c);
4333 EXPECT_FLOAT_EQ(43.0f, matrix.d);
4334 EXPECT_FLOAT_EQ(72.0f, matrix.e);
4335 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
4336
4337 {
4338 // Render |obj| again. Note that the FPDFPageObj_SetMatrix() call has no
4339 // effect.
4340 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
4341 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
4342 CompareBitmap(bitmap.get(), 109, 88, kEmbeddedImage33Checksum);
4343 }
4344
4345 UnloadPage(page);
4346}
4347
4349 ASSERT_TRUE(OpenDocument("bug_631912.pdf"));
4350 FPDF_PAGE page = LoadPage(0);
4351 ASSERT_TRUE(page);
4352 ASSERT_EQ(1, FPDFPage_CountObjects(page));
4353
4354 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 0);
4356 {
4357 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
4358 ASSERT_TRUE(bitmap);
4359 EXPECT_EQ(FPDFBitmap_Gray, FPDFBitmap_GetFormat(bitmap.get()));
4360 CompareBitmap(bitmap.get(), 1152, 720, "3f6a48e2b3e91b799bf34567f55cb4de");
4361 }
4362
4363 UnloadPage(page);
4364}
4365
4367 ASSERT_TRUE(OpenDocument("matte.pdf"));
4368 FPDF_PAGE page = LoadPage(0);
4369 ASSERT_TRUE(page);
4370
4371 constexpr int kExpectedObjects = 4;
4372 ASSERT_EQ(kExpectedObjects, FPDFPage_CountObjects(page));
4373
4374 for (int i = 0; i < kExpectedObjects; ++i) {
4375 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, i);
4377 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
4378 ASSERT_TRUE(bitmap);
4379 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
4380 CompareBitmap(bitmap.get(), 50, 50, "46c9a1dbe0b44765ce46017ad629a2fe");
4381 }
4382
4383 UnloadPage(page);
4384}
4385
4387 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
4388 FPDF_PAGE page = LoadPage(0);
4389 ASSERT_TRUE(page);
4390 ASSERT_EQ(39, FPDFPage_CountObjects(page));
4391
4392 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 33);
4394
4395 {
4396 // Render `obj` as is.
4397 ScopedFPDFBitmap bitmap(
4398 FPDFImageObj_GetRenderedBitmap(document(), page, obj));
4399 EXPECT_EQ(FPDFBitmap_BGRA, FPDFBitmap_GetFormat(bitmap.get()));
4400 const char* checksum = []() {
4401 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
4402 return "3b51fc066ee18efbf70bab0501763603";
4403 }
4404 return "582ca300e003f512d7b552c7b5b45d2e";
4405 }();
4406 CompareBitmap(bitmap.get(), 53, 43, checksum);
4407 }
4408
4409 // Check the matrix for `obj`.
4410 FS_MATRIX matrix;
4411 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4412 EXPECT_FLOAT_EQ(53.0f, matrix.a);
4413 EXPECT_FLOAT_EQ(0.0f, matrix.b);
4414 EXPECT_FLOAT_EQ(0.0f, matrix.c);
4415 EXPECT_FLOAT_EQ(43.0f, matrix.d);
4416 EXPECT_FLOAT_EQ(72.0f, matrix.e);
4417 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
4418
4419 // Modify the matrix for `obj`.
4420 matrix.a = 120.0;
4421 EXPECT_TRUE(FPDFPageObj_SetMatrix(obj, &matrix));
4422
4423 // Make sure the matrix modification took place.
4424 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4425 EXPECT_FLOAT_EQ(120.0f, matrix.a);
4426 EXPECT_FLOAT_EQ(0.0f, matrix.b);
4427 EXPECT_FLOAT_EQ(0.0f, matrix.c);
4428 EXPECT_FLOAT_EQ(43.0f, matrix.d);
4429 EXPECT_FLOAT_EQ(72.0f, matrix.e);
4430 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
4431
4432 {
4433 // Render `obj` again. Note that the FPDFPageObj_SetMatrix() call has an
4434 // effect.
4435 ScopedFPDFBitmap bitmap(
4436 FPDFImageObj_GetRenderedBitmap(document(), page, obj));
4437 EXPECT_EQ(FPDFBitmap_BGRA, FPDFBitmap_GetFormat(bitmap.get()));
4438 const char* checksum = []() {
4439 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
4440 return "1003585870ad0fe37baf1c5bb3f5fd76";
4441 }
4442 return "0824c16dcf2dfcef44b45d88db1fddce";
4443 }();
4444 CompareBitmap(bitmap.get(), 120, 43, checksum);
4445 }
4446
4447 UnloadPage(page);
4448}
4449
4451 ASSERT_TRUE(OpenDocument("matte.pdf"));
4452 FPDF_PAGE page = LoadPage(0);
4453 ASSERT_TRUE(page);
4454
4455 constexpr int kExpectedObjects = 4;
4456 ASSERT_EQ(kExpectedObjects, FPDFPage_CountObjects(page));
4457
4458 const char* smask_checksum = []() {
4459 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
4460 return "0653a18f3bf9b4d8413a2aa10bc11c38";
4461 }
4462 return "5a3ae4a660ce919e29c42ec2258142f1";
4463 }();
4464 const char* no_smask_checksum = []() {
4465 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
4466 return "0da49e63e7d6337aca78b19938e3bf65";
4467 }
4468 return "67504e83f5d78214ea00efc19082c5c1";
4469 }();
4470
4471 for (int i = 0; i < kExpectedObjects; ++i) {
4472 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, i);
4474 ScopedFPDFBitmap bitmap(
4475 FPDFImageObj_GetRenderedBitmap(document(), page, obj));
4476 ASSERT_TRUE(bitmap);
4477 EXPECT_EQ(FPDFBitmap_BGRA, FPDFBitmap_GetFormat(bitmap.get()));
4478 if (i == 0)
4479 CompareBitmap(bitmap.get(), 40, 60, smask_checksum);
4480 else
4481 CompareBitmap(bitmap.get(), 40, 60, no_smask_checksum);
4482 }
4483
4484 UnloadPage(page);
4485}
4486
4488 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
4489 FPDF_PAGE page = LoadPage(0);
4490 ASSERT_TRUE(page);
4491
4492 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 33);
4494
4495 // Test various null parameters.
4496 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(nullptr, nullptr, nullptr));
4497 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(document(), nullptr, nullptr));
4498 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(nullptr, page, nullptr));
4499 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(nullptr, nullptr, obj));
4500 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(document(), page, nullptr));
4501 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(nullptr, page, obj));
4502
4503 // Test mismatch between document and page parameters.
4504 ScopedFPDFDocument new_document(FPDF_CreateNewDocument());
4505 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(new_document.get(), page, obj));
4506
4507 UnloadPage(page);
4508}
4509
4511 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
4512 FPDF_PAGE page = LoadPage(0);
4513 ASSERT_TRUE(page);
4514 ASSERT_EQ(39, FPDFPage_CountObjects(page));
4515
4516 // Retrieve an image object with flate-encoded data stream.
4517 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 33);
4519
4520 // Check that the raw image data has the correct length and hash value.
4521 unsigned long len = FPDFImageObj_GetImageDataRaw(obj, nullptr, 0);
4522 std::vector<uint8_t> buf(len);
4523 EXPECT_EQ(4091u, FPDFImageObj_GetImageDataRaw(obj, buf.data(), len));
4524 EXPECT_EQ("f73802327d2e88e890f653961bcda81a", GenerateMD5Base16(buf));
4525
4526 // Check that the decoded image data has the correct length and hash value.
4527 len = FPDFImageObj_GetImageDataDecoded(obj, nullptr, 0);
4528 buf.clear();
4529 buf.resize(len);
4530 EXPECT_EQ(28776u, FPDFImageObj_GetImageDataDecoded(obj, buf.data(), len));
4531 EXPECT_EQ(kEmbeddedImage33Checksum, GenerateMD5Base16(buf));
4532
4533 // Retrieve an image object with DCTDecode-encoded data stream.
4534 obj = FPDFPage_GetObject(page, 37);
4536
4537 // Check that the raw image data has the correct length and hash value.
4538 len = FPDFImageObj_GetImageDataRaw(obj, nullptr, 0);
4539 buf.clear();
4540 buf.resize(len);
4541 EXPECT_EQ(4370u, FPDFImageObj_GetImageDataRaw(obj, buf.data(), len));
4542 EXPECT_EQ("6aae1f3710335023a9e12191be66b64b", GenerateMD5Base16(buf));
4543
4544 // Check that the decoded image data has the correct length and hash value,
4545 // which should be the same as those of the raw data, since this image is
4546 // encoded by a single DCTDecode filter and decoding is a noop.
4547 len = FPDFImageObj_GetImageDataDecoded(obj, nullptr, 0);
4548 buf.clear();
4549 buf.resize(len);
4550 EXPECT_EQ(4370u, FPDFImageObj_GetImageDataDecoded(obj, buf.data(), len));
4551 EXPECT_EQ("6aae1f3710335023a9e12191be66b64b", GenerateMD5Base16(buf));
4552
4553 UnloadPage(page);
4554}
4555
4557 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
4558 FPDF_PAGE page = LoadPage(0);
4559 ASSERT_TRUE(page);
4560 ASSERT_EQ(39, FPDFPage_CountObjects(page));
4561
4562 FPDF_PAGEOBJECT obj;
4563 FS_MATRIX matrix;
4564
4565 obj = FPDFPage_GetObject(page, 33);
4567 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4568 EXPECT_FLOAT_EQ(53.0f, matrix.a);
4569 EXPECT_FLOAT_EQ(0.0f, matrix.b);
4570 EXPECT_FLOAT_EQ(0.0f, matrix.c);
4571 EXPECT_FLOAT_EQ(43.0f, matrix.d);
4572 EXPECT_FLOAT_EQ(72.0f, matrix.e);
4573 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
4574
4575 obj = FPDFPage_GetObject(page, 34);
4577 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4578 EXPECT_FLOAT_EQ(70.0f, matrix.a);
4579 EXPECT_FLOAT_EQ(0.0f, matrix.b);
4580 EXPECT_FLOAT_EQ(0.0f, matrix.c);
4581 EXPECT_FLOAT_EQ(51.0f, matrix.d);
4582 EXPECT_FLOAT_EQ(216.0f, matrix.e);
4583 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
4584
4585 obj = FPDFPage_GetObject(page, 35);
4587 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4588 EXPECT_FLOAT_EQ(69.0f, matrix.a);
4589 EXPECT_FLOAT_EQ(0.0f, matrix.b);
4590 EXPECT_FLOAT_EQ(0.0f, matrix.c);
4591 EXPECT_FLOAT_EQ(51.0f, matrix.d);
4592 EXPECT_FLOAT_EQ(360.0f, matrix.e);
4593 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
4594
4595 obj = FPDFPage_GetObject(page, 36);
4597 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4598 EXPECT_FLOAT_EQ(59.0f, matrix.a);
4599 EXPECT_FLOAT_EQ(0.0f, matrix.b);
4600 EXPECT_FLOAT_EQ(0.0f, matrix.c);
4601 EXPECT_FLOAT_EQ(45.0f, matrix.d);
4602 EXPECT_FLOAT_EQ(72.0f, matrix.e);
4603 EXPECT_FLOAT_EQ(553.510009765625f, matrix.f);
4604
4605 obj = FPDFPage_GetObject(page, 37);
4607 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4608 EXPECT_FLOAT_EQ(55.94000244140625f, matrix.a);
4609 EXPECT_FLOAT_EQ(0.0f, matrix.b);
4610 EXPECT_FLOAT_EQ(0.0f, matrix.c);
4611 EXPECT_FLOAT_EQ(46.950000762939453f, matrix.d);
4612 EXPECT_FLOAT_EQ(216.0f, matrix.e);
4613 EXPECT_FLOAT_EQ(552.510009765625f, matrix.f);
4614
4615 obj = FPDFPage_GetObject(page, 38);
4617 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4618 EXPECT_FLOAT_EQ(70.528999328613281f, matrix.a);
4619 EXPECT_FLOAT_EQ(0.0f, matrix.b);
4620 EXPECT_FLOAT_EQ(0.0f, matrix.c);
4621 EXPECT_FLOAT_EQ(43.149997711181641f, matrix.d);
4622 EXPECT_FLOAT_EQ(360.0f, matrix.e);
4623 EXPECT_FLOAT_EQ(553.3599853515625f, matrix.f);
4624
4625 UnloadPage(page);
4626}
4627
4629 FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(10, 10, 20, 20);
4630 ASSERT_TRUE(rect);
4631
4632 // There should be no memory leaks with a call to FPDFPageObj_Destroy().
4634}
4635
4637 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
4638 FPDF_PAGE page = LoadPage(0);
4639 ASSERT_TRUE(page);
4640
4641 // Verify that retrieving the filter of a non-image object would fail.
4642 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 32);
4644 ASSERT_EQ(0, FPDFImageObj_GetImageFilterCount(obj));
4645 EXPECT_EQ(0u, FPDFImageObj_GetImageFilter(obj, 0, nullptr, 0));
4646
4647 // Verify the returned filter string for an image object with a single filter.
4648 obj = FPDFPage_GetObject(page, 33);
4650 ASSERT_EQ(1, FPDFImageObj_GetImageFilterCount(obj));
4651 unsigned long len = FPDFImageObj_GetImageFilter(obj, 0, nullptr, 0);
4652 std::vector<char> buf(len);
4653 static constexpr char kFlateDecode[] = "FlateDecode";
4654 EXPECT_EQ(sizeof(kFlateDecode),
4655 FPDFImageObj_GetImageFilter(obj, 0, buf.data(), len));
4656 EXPECT_STREQ(kFlateDecode, buf.data());
4657 EXPECT_EQ(0u, FPDFImageObj_GetImageFilter(obj, 1, nullptr, 0));
4658
4659 // Verify all the filters for an image object with a list of filters.
4660 obj = FPDFPage_GetObject(page, 38);
4662 ASSERT_EQ(2, FPDFImageObj_GetImageFilterCount(obj));
4663 len = FPDFImageObj_GetImageFilter(obj, 0, nullptr, 0);
4664 buf.clear();
4665 buf.resize(len);
4666 static constexpr char kASCIIHexDecode[] = "ASCIIHexDecode";
4667 EXPECT_EQ(sizeof(kASCIIHexDecode),
4668 FPDFImageObj_GetImageFilter(obj, 0, buf.data(), len));
4669 EXPECT_STREQ(kASCIIHexDecode, buf.data());
4670
4671 len = FPDFImageObj_GetImageFilter(obj, 1, nullptr, 0);
4672 buf.clear();
4673 buf.resize(len);
4674 static constexpr char kDCTDecode[] = "DCTDecode";
4675 EXPECT_EQ(sizeof(kDCTDecode),
4676 FPDFImageObj_GetImageFilter(obj, 1, buf.data(), len));
4677 EXPECT_STREQ(kDCTDecode, buf.data());
4678
4679 UnloadPage(page);
4680}
4681
4683 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
4684 FPDF_PAGE page = LoadPage(0);
4685 ASSERT_TRUE(page);
4686
4687 // Check that getting the metadata of a null object would fail.
4688 FPDF_IMAGEOBJ_METADATA metadata;
4689 EXPECT_FALSE(FPDFImageObj_GetImageMetadata(nullptr, page, &metadata));
4690
4691 // Check that receiving the metadata with a null metadata object would fail.
4692 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 35);
4693 EXPECT_FALSE(FPDFImageObj_GetImageMetadata(obj, page, nullptr));
4694
4695 // Check that when retrieving an image object's metadata without passing in
4696 // |page|, all values are correct, with the last two being default values.
4698 ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, nullptr, &metadata));
4699 EXPECT_EQ(7, metadata.marked_content_id);
4700 EXPECT_EQ(92u, metadata.width);
4701 EXPECT_EQ(68u, metadata.height);
4702 EXPECT_FLOAT_EQ(96.0f, metadata.horizontal_dpi);
4703 EXPECT_FLOAT_EQ(96.0f, metadata.vertical_dpi);
4704 EXPECT_EQ(0u, metadata.bits_per_pixel);
4705 EXPECT_EQ(FPDF_COLORSPACE_UNKNOWN, metadata.colorspace);
4706
4707 // Verify the metadata of a bitmap image with indexed colorspace.
4708 ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, page, &metadata));
4709 EXPECT_EQ(7, metadata.marked_content_id);
4710 EXPECT_EQ(92u, metadata.width);
4711 EXPECT_EQ(68u, metadata.height);
4712 EXPECT_FLOAT_EQ(96.0f, metadata.horizontal_dpi);
4713 EXPECT_FLOAT_EQ(96.0f, metadata.vertical_dpi);
4714 EXPECT_EQ(1u, metadata.bits_per_pixel);
4715 EXPECT_EQ(FPDF_COLORSPACE_INDEXED, metadata.colorspace);
4716
4717 // Verify the metadata of an image with RGB colorspace.
4718 obj = FPDFPage_GetObject(page, 37);
4720 ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, page, &metadata));
4721 EXPECT_EQ(9, metadata.marked_content_id);
4722 EXPECT_EQ(126u, metadata.width);
4723 EXPECT_EQ(106u, metadata.height);
4724 EXPECT_FLOAT_EQ(162.173752f, metadata.horizontal_dpi);
4725 EXPECT_FLOAT_EQ(162.555878f, metadata.vertical_dpi);
4726 EXPECT_EQ(24u, metadata.bits_per_pixel);
4727 EXPECT_EQ(FPDF_COLORSPACE_DEVICERGB, metadata.colorspace);
4728
4729 UnloadPage(page);
4730}
4731
4733 ASSERT_TRUE(OpenDocument("jpx_lzw.pdf"));
4734 FPDF_PAGE page = LoadPage(0);
4735 ASSERT_TRUE(page);
4736
4737 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 0);
4739
4740 FPDF_IMAGEOBJ_METADATA metadata;
4741 ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, page, &metadata));
4742 EXPECT_EQ(-1, metadata.marked_content_id);
4743 EXPECT_EQ(612u, metadata.width);
4744 EXPECT_EQ(792u, metadata.height);
4745 EXPECT_FLOAT_EQ(72.0f, metadata.horizontal_dpi);
4746 EXPECT_FLOAT_EQ(72.0f, metadata.vertical_dpi);
4747 EXPECT_EQ(24u, metadata.bits_per_pixel);
4748 EXPECT_EQ(FPDF_COLORSPACE_UNKNOWN, metadata.colorspace);
4749
4750 UnloadPage(page);
4751}
4752
4754 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
4755 FPDF_PAGE page = LoadPage(0);
4756 ASSERT_TRUE(page);
4757
4758 // Check that getting the size of a null object would fail.
4759 unsigned int width = 0;
4760 unsigned int height = 0;
4761 EXPECT_FALSE(FPDFImageObj_GetImagePixelSize(nullptr, &width, &height));
4762
4763 // Check that receiving the size with a null width and height pointers would
4764 // fail.
4765 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 35);
4767 EXPECT_FALSE(FPDFImageObj_GetImagePixelSize(obj, nullptr, nullptr));
4768 EXPECT_FALSE(FPDFImageObj_GetImagePixelSize(obj, nullptr, &height));
4769 EXPECT_FALSE(FPDFImageObj_GetImagePixelSize(obj, &width, nullptr));
4770
4771 // Verify the pixel size of image.
4772 ASSERT_TRUE(FPDFImageObj_GetImagePixelSize(obj, &width, &height));
4773 EXPECT_EQ(92u, width);
4774 EXPECT_EQ(68u, height);
4775
4776 obj = FPDFPage_GetObject(page, 37);
4778 ASSERT_TRUE(FPDFImageObj_GetImagePixelSize(obj, &width, &height));
4779 EXPECT_EQ(126u, width);
4780 EXPECT_EQ(106u, height);
4781
4782 UnloadPage(page);
4783}
4784
4786 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
4787 FPDF_PAGE page = LoadPage(0);
4788 ASSERT_TRUE(page);
4789
4790 {
4791 FPDF_PAGEOBJECT text_object = FPDFPage_GetObject(page, 0);
4792 ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(text_object));
4793
4794 ScopedFPDFBitmap bitmap(
4795 FPDFTextObj_GetRenderedBitmap(document(), page, text_object, 1));
4796 ASSERT_TRUE(bitmap);
4797 const char* checksum = []() {
4798 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
4799#if BUILDFLAG(IS_WIN)
4800 return "5cef5b3e56e91e1a66b6780fb26bb5e3";
4801#elif BUILDFLAG(IS_APPLE)
4802 return "9e7774173acee966fcaa72e599eb9a93";
4803#else
4804 return "b17801afe8a36d6aad6c2239b88f2a73";
4805#endif
4806 }
4807 return "bb0abe1accca1cfeaaf78afa35762350";
4808 }();
4809 CompareBitmap(bitmap.get(), 64, 11, checksum);
4810
4811 ScopedFPDFBitmap x2_bitmap(
4812 FPDFTextObj_GetRenderedBitmap(document(), page, text_object, 2.4f));
4813 ASSERT_TRUE(x2_bitmap);
4814 const char* x2_checksum = []() {
4815 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
4816#if BUILDFLAG(IS_WIN)
4817 return "3cea4255285df04659e3c7477287bdb1";
4818#elif BUILDFLAG(IS_APPLE)
4819 return "2b34bddd2a1471e245cf72603c6799b4";
4820#else
4821 return "33af8b151ab26ebce5a71b39eedea6b1";
4822#endif
4823 }
4824 return "80db528ec7146d92247f2339a8f10ba5";
4825 }();
4826 CompareBitmap(x2_bitmap.get(), 153, 25, x2_checksum);
4827
4828 ScopedFPDFBitmap x10_bitmap(
4829 FPDFTextObj_GetRenderedBitmap(document(), page, text_object, 10));
4830 ASSERT_TRUE(x10_bitmap);
4831 const char* x10_checksum = []() {
4832 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
4833#if BUILDFLAG(IS_WIN)
4834 return "1cc617da9ed5922eeac2414108509ef5";
4835#elif BUILDFLAG(IS_APPLE)
4836 return "0450d576560274a7df31cb93d040e721";
4837#else
4838 return "93dd7ad07bdaaba9ecd268350cb91596";
4839#endif
4840 }
4841 return "149f63de758ab01d3b75605cdfd4c176";
4842 }();
4843 CompareBitmap(x10_bitmap.get(), 631, 103, x10_checksum);
4844 }
4845
4846 {
4847 FPDF_PAGEOBJECT text_object = FPDFPage_GetObject(page, 1);
4848 ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(text_object));
4849
4850 ScopedFPDFBitmap bitmap(
4851 FPDFTextObj_GetRenderedBitmap(document(), page, text_object, 1));
4852 ASSERT_TRUE(bitmap);
4853 const char* checksum = []() {
4854 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
4855#if BUILDFLAG(IS_WIN)
4856 return "336be21110c795cefcab9bbdbc3afcdd";
4857#elif BUILDFLAG(IS_APPLE)
4858 return "0b9efedcb8f5aa9246c52e90811cb046";
4859#else
4860 return "63fd059d984a5bea10f27ba026420202";
4861#endif
4862 }
4863 return "3fc1101b2408c5484adc24ba0a11ff3d";
4864 }();
4865 CompareBitmap(bitmap.get(), 116, 16, checksum);
4866
4867 ScopedFPDFBitmap x2_bitmap(
4868 FPDFTextObj_GetRenderedBitmap(document(), page, text_object, 2.4f));
4869 ASSERT_TRUE(x2_bitmap);
4870 const char* x2_checksum = []() {
4871 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
4872#if BUILDFLAG(IS_WIN)
4873 return "c5cecc5553843a4dd4fff3ceb4855a82";
4874#elif BUILDFLAG(IS_APPLE)
4875 return "10f4d9528a5471ab0b235984f0354dd4";
4876#else
4877 return "fc45021e3ea3ebd406fe6ffaa8c5c5b7";
4878#endif
4879 }
4880 return "429960ae7b822f0c630432535e637465";
4881 }();
4882 CompareBitmap(x2_bitmap.get(), 276, 36, x2_checksum);
4883
4884 ScopedFPDFBitmap x10_bitmap(
4885 FPDFTextObj_GetRenderedBitmap(document(), page, text_object, 10));
4886 ASSERT_TRUE(x10_bitmap);
4887 const char* x10_checksum = []() {
4888 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
4889#if BUILDFLAG(IS_WIN)
4890 return "cff29dcbe77092ec7f73e46766a289c7";
4891#elif BUILDFLAG(IS_APPLE)
4892 return "9e87791ffdf4cca0a0f118be245970c8";
4893#else
4894 return "61476636eaa0da0b93d8b1937cf22b75";
4895#endif
4896 }
4897 return "f5f93bf64de579b59e775d7076ca0a5a";
4898 }();
4899 CompareBitmap(x10_bitmap.get(), 1143, 150, x10_checksum);
4900 }
4901
4902 UnloadPage(page);
4903}
4904
4906 ASSERT_TRUE(OpenDocument("rotated_text.pdf"));
4907 FPDF_PAGE page = LoadPage(0);
4908 ASSERT_TRUE(page);
4909
4910 FPDF_PAGEOBJECT text_object = FPDFPage_GetObject(page, 0);
4911 ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(text_object));
4912
4913 ScopedFPDFBitmap bitmap(
4914 FPDFTextObj_GetRenderedBitmap(document(), page, text_object, 1));
4915 ASSERT_TRUE(bitmap);
4916 const char* checksum = []() {
4917 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
4918#if BUILDFLAG(IS_WIN)
4919 return "ba5322a4e6b0f79dca42be88f3007708";
4920#elif BUILDFLAG(IS_APPLE)
4921 return "22cf71716a7059f481a63e32b6088c8c";
4922#else
4923 return "f515a7209d7892065d3716ec462f5c10";
4924#endif
4925 }
4926 return "08ada0802f780d3fefb161dc6fb45977";
4927 }();
4928 CompareBitmap(bitmap.get(), 29, 28, checksum);
4929
4930 ScopedFPDFBitmap x2_bitmap(
4931 FPDFTextObj_GetRenderedBitmap(document(), page, text_object, 2.4f));
4932 ASSERT_TRUE(x2_bitmap);
4933 const char* x2_checksum = []() {
4934 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
4935#if BUILDFLAG(IS_WIN)
4936 return "e8fb0a707b2924726757a2ed32d6f28d";
4937#elif BUILDFLAG(IS_APPLE)
4938 return "5d4be6808bdcec3f6ee7352122dd986d";
4939#else
4940 return "c69bbe5318ec149f63228e276e708612";
4941#endif
4942 }
4943 return "09d7ddb647b8653cb59aede349a0c3e1";
4944 }();
4945 CompareBitmap(x2_bitmap.get(), 67, 67, x2_checksum);
4946
4947 ScopedFPDFBitmap x10_bitmap(
4948 FPDFTextObj_GetRenderedBitmap(document(), page, text_object, 10));
4949 ASSERT_TRUE(x10_bitmap);
4950 const char* x10_checksum = []() {
4951 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
4952#if BUILDFLAG(IS_WIN)
4953 return "eb0cbf56707d1c39ce0ab89a9b43d6a8";
4954#elif BUILDFLAG(IS_APPLE)
4955 return "98757f865abde60c7f7f60c74435cb85";
4956#else
4957 return "bb7c2ec575f27cf882dcd38f2563c00f";
4958#endif
4959 }
4960 return "bbd3842a4b50dbfcbce4eee2b067a297";
4961 }();
4962 CompareBitmap(x10_bitmap.get(), 275, 275, x10_checksum);
4963
4964 UnloadPage(page);
4965}
4966
4968 ASSERT_TRUE(OpenDocument("text_color.pdf"));
4969 FPDF_PAGE page = LoadPage(0);
4970 ASSERT_TRUE(page);
4971
4972 FPDF_PAGEOBJECT text_object = FPDFPage_GetObject(page, 0);
4973 ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(text_object));
4974
4975 ScopedFPDFBitmap bitmap(
4976 FPDFTextObj_GetRenderedBitmap(document(), page, text_object, 7.3f));
4977 ASSERT_TRUE(bitmap);
4978 const char* checksum = []() {
4979 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
4980 return "1d74731d23a056c0e3fb88f2f85b2581";
4981 }
4982 return "e8154fa8ededf4d9b8b35b5260897b6c";
4983 }();
4984 CompareBitmap(bitmap.get(), 120, 186, checksum);
4985
4986 UnloadPage(page);
4987}
4988
4990 // Start with a blank document.
4991 ASSERT_TRUE(CreateNewDocument());
4992
4993 // Create a new text object.
4994 ScopedFPDFPageObject text_object(
4995 FPDFPageObj_NewTextObj(document(), "Arial", 12.0f));
4996 ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(text_object.get()));
4997 ScopedFPDFWideString text = GetFPDFWideString(kBottomText);
4998 EXPECT_TRUE(FPDFText_SetText(text_object.get(), text.get()));
4999
5000 ScopedFPDFBitmap bitmap(
5001 FPDFTextObj_GetRenderedBitmap(document(), nullptr, text_object.get(), 1));
5002 ASSERT_TRUE(bitmap);
5003 const char* checksum = []() {
5004 if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
5005#if BUILDFLAG(IS_WIN)
5006 return "ef501232372617a545ae35d7664fd9ec";
5007#elif BUILDFLAG(IS_APPLE)
5008 return "a637d62f2e8ae10c3267b2ff5fcc2246";
5009#else
5010 return "574ae982d02e653ab6a8f23a6cdf4085";
5011#endif
5012 }
5013 return "fa947759dab76d68a07ccf6f97b2d9c2";
5014 }();
5015 CompareBitmap(bitmap.get(), 151, 12, checksum);
5016}
5017
5019 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
5020 FPDF_PAGE page = LoadPage(0);
5021 ASSERT_TRUE(page);
5022
5023 FPDF_PAGEOBJECT text_object = FPDFPage_GetObject(page, 0);
5024 ASSERT_TRUE(text_object);
5025
5026 // Simple bad parameters testing.
5027 EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(nullptr, nullptr, nullptr, 0));
5028 EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(document(), nullptr, nullptr, 0));
5029 EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(nullptr, page, nullptr, 0));
5030 EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(nullptr, nullptr, text_object, 0));
5031 EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(nullptr, nullptr, nullptr, 1));
5032 EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(document(), page, nullptr, 0));
5033 EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(document(), nullptr, nullptr, 1));
5034 EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(nullptr, page, text_object, 0));
5035 EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(nullptr, page, nullptr, 1));
5036 EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(nullptr, nullptr, text_object, 1));
5037 EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(document(), page, nullptr, 1));
5038 EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(nullptr, page, text_object, 1));
5039
5040 // Test bad scale values.
5041 EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(document(), page, text_object, 0));
5042 EXPECT_FALSE(
5043 FPDFTextObj_GetRenderedBitmap(document(), page, text_object, -1));
5044 EXPECT_FALSE(
5045 FPDFTextObj_GetRenderedBitmap(document(), page, text_object, 10000));
5046 EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(
5047 document(), page, text_object, std::numeric_limits<float>::max()));
5048 EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(
5049 document(), page, text_object, std::numeric_limits<float>::infinity()));
5050
5051 {
5052 // `text_object` will render without `page`, but may not render correctly
5053 // without the resources from `page`. Although it does in this simple case.
5054 ScopedFPDFBitmap bitmap(
5055 FPDFTextObj_GetRenderedBitmap(document(), nullptr, text_object, 1));
5056 EXPECT_TRUE(bitmap);
5057 }
5058
5059 // Mismatch between the document and the page fails too.
5060 ScopedFPDFDocument empty_document(FPDF_CreateNewDocument());
5061 EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(empty_document.get(), page,
5062 text_object, 1));
5063
5064 UnloadPage(page);
5065}
5066
5068 ASSERT_TRUE(OpenDocument("multiple_graphics_states.pdf"));
5069 FPDF_PAGE page = LoadPage(0);
5070 ASSERT_TRUE(page);
5071
5072 {
5073 ScopedFPDFPageObject path(FPDFPageObj_CreateNewPath(400, 100));
5074 EXPECT_TRUE(FPDFPageObj_SetFillColor(path.get(), 255, 0, 0, 255));
5075 EXPECT_TRUE(FPDFPath_SetDrawMode(path.get(), FPDF_FILLMODE_ALTERNATE, 0));
5076 EXPECT_TRUE(FPDFPath_MoveTo(path.get(), 100, 100));
5077 EXPECT_TRUE(FPDFPath_LineTo(path.get(), 100, 125));
5078 EXPECT_TRUE(FPDFPath_Close(path.get()));
5079
5080 FPDFPage_InsertObject(page, path.release());
5081 EXPECT_TRUE(FPDFPage_GenerateContent(page));
5082 }
5083
5084 const char* checksum = CFX_DefaultRenderDevice::UseSkiaRenderer()
5085 ? "7ebec75d95c64b522999a710de76c52c"
5086 : "f4b36616a7fea81a4f06cc7b01a55ac1";
5087
5088 ScopedFPDFBitmap bitmap = RenderPage(page);
5089 CompareBitmap(bitmap.get(), 200, 300, checksum);
5090
5091 ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
5092 VerifySavedDocument(200, 300, checksum);
5093
5094 UnloadPage(page);
5095}
5096
5098 protected:
5100 std::vector<std::string> hashes;
5101 hashes.reserve(page_count);
5102 for (int i = 0; i < page_count; ++i) {
5103 hashes.push_back(HashForPage(i));
5104 }
5105 return hashes;
5106 }
5107
5108 private:
5109 std::string HashForPage(int page_index) {
5110 FPDF_PAGE page = LoadPage(page_index);
5111 EXPECT_TRUE(page);
5112 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
5113 std::string hash = HashBitmap(bitmap.get());
5114 UnloadPage(page);
5115 return hash;
5116 }
5117};
5118
5120 static const FPDFEditMoveEmbedderTestCase kTestCases[] = {
5121 {{0, 1, 2, 3, 4}, 5, 0, true, {0, 1, 2, 3, 4}, "no change"},
5122 {{0, 4, 2, 1, 3}, 5, 0, true, {0, 4, 2, 1, 3}, "reorder all pages"},
5123 {{0, 2, 4, 3}, 4, 1, true, {1, 0, 2, 4, 3}, "reorder 4 pages"},
5124 {{1, 4, 2}, 3, 2, true, {0, 3, 1, 4, 2}, "reorder 3 pages"},
5125 {{3, 2}, 2, 3, true, {0, 1, 4, 3, 2}, "reorder 2 pages"},
5126 {{3}, 1, 4, true, {0, 1, 2, 4, 3}, "reorder 1 page"},
5127 {{1, 1}, 2, 2, false, {}, "duplicate index"},
5128 {{5, 3, 2}, 3, 0, false, {}, "out of range index"},
5129 {{3}, 0, 0, false, {}, "page_indices_len needs to be in range [1, 5]"},
5130 {{4, 3, 2, 1, 0}, 6, 0, false, {}, "page_indices_len is too big"},
5131 {{3}, 0, 5, false, {}, "dest_page_index is out of range"},
5132 {{3, 1, 4}, 0, -1, false, {}, "dest_page_index is out of range"},
5133 };
5134
5135 // Try all test cases with a freshly opened document that has 5 pages.
5136 for (const FPDFEditMoveEmbedderTestCase& tc : kTestCases) {
5137 ASSERT_TRUE(OpenDocument("rectangles_multi_pages.pdf"));
5138 const int page_count = GetPageCount();
5139 ASSERT_EQ(page_count, 5);
5140 // Check that the test case has correctly formed expected result.
5141 if (tc.expected_result) {
5142 ASSERT_THAT(tc.expected_order, testing::SizeIs(page_count));
5143 } else {
5144 ASSERT_THAT(tc.expected_order, testing::SizeIs(0));
5145 }
5146
5147 // Cache the original pages' hashes.
5148 std::vector<std::string> orig_hashes = HashesForDocument(page_count);
5149 ASSERT_THAT(orig_hashes, testing::SizeIs(page_count));
5150
5151 EXPECT_EQ(FPDF_MovePages(document(), &tc.page_indices[0],
5152 tc.page_indices_len, tc.dest_page_index),
5153 tc.expected_result)
5154 << tc;
5155
5156 if (tc.expected_result) {
5157 // Check for updated page order.
5158 std::vector<std::string> new_hashes = HashesForDocument(page_count);
5159 std::vector<std::string> expected_hashes;
5160 expected_hashes.reserve(page_count);
5161 for (int i = 0; i < page_count; ++i) {
5162 expected_hashes.push_back(orig_hashes[tc.expected_order[i]]);
5163 }
5164 EXPECT_THAT(new_hashes, testing::ContainerEq(expected_hashes)) << tc;
5165 } else {
5166 // Check that pages are unchanged.
5167 EXPECT_THAT(HashesForDocument(page_count),
5168 testing::ContainerEq(orig_hashes))
5169 << tc;
5170 }
5171
5172 CloseDocument();
5173 }
5174}
ByteString GetNameFor(const ByteString &key) const
virtual bool IsTrueTypeFont() const
Definition cpdf_font.cpp:67
virtual int GetCharWidthF(uint32_t charcode)=0
virtual bool IsType1Font() const
Definition cpdf_font.cpp:63
virtual bool IsCIDFont() const
Definition cpdf_font.cpp:75
int32_t GetContentStream() const
void UnloadPage(FPDF_PAGE page)
FPDF_DOCUMENT document() const
FPDF_PAGE LoadPage(int page_number)
void CreateEmptyDocumentWithoutFormFillEnvironment()
void CheckCompositeFontWidths(const CPDF_Array *widths_array, CPDF_Font *typed_font)
void CheckFontDescriptor(const CPDF_Dictionary *font_dict, int font_type, bool bold, bool italic, pdfium::span< const uint8_t > span)
std::vector< std::string > HashesForDocument(int page_count)
ByteString(const char *ptr)
bool IsEmpty() const
Definition bytestring.h:119
CPDF_Page * CPDFPageFromFPDFPage(FPDF_PAGE page)
CPDF_PageObject * CPDFPageObjectFromFPDFPageObject(FPDF_PAGEOBJECT page_object)
#define FPDF_ANNOT_UNDERLINE
Definition fpdf_annot.h:30
FPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV FPDFPath_GetPathSegment(FPDF_PAGEOBJECT path, int index)
FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFFont_GetFontName(FPDF_FONT font, char *buffer, unsigned long length)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetGlyphWidth(FPDF_FONT font, uint32_t glyph, float font_size, float *width)
#define FPDF_FILLMODE_ALTERNATE
Definition fpdf_edit.h:52
FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetRotation(FPDF_PAGE page)
FPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetWeight(FPDF_FONT font)
#define FPDF_COLORSPACE_UNKNOWN
Definition fpdf_edit.h:24
FPDF_EXPORT int FPDF_CALLCONV FPDFFormObj_CountObjects(FPDF_PAGEOBJECT form_object)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetStrokeColor(FPDF_PAGEOBJECT page_object, unsigned int R, unsigned int G, unsigned int B, unsigned int A)
FPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetIsEmbedded(FPDF_FONT font)
FPDF_EXPORT int FPDF_CALLCONV FPDFPathSegment_GetType(FPDF_PATHSEGMENT segment)
#define FPDF_FONT_TRUETYPE
Definition fpdf_edit.h:56
FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateNewPath(float x, float y)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_SetDrawMode(FPDF_PAGEOBJECT path, int fillmode, FPDF_BOOL stroke)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetParamKey(FPDF_PAGEOBJECTMARK mark, unsigned long index, void *buffer, unsigned long buflen, unsigned long *out_buflen)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_GetImageMetadata(FPDF_PAGEOBJECT image_object, FPDF_PAGE page, FPDF_IMAGEOBJ_METADATA *metadata)
FPDF_EXPORT void FPDF_CALLCONV FPDFPage_InsertObject(FPDF_PAGE page, FPDF_PAGEOBJECT page_object)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPathSegment_GetPoint(FPDF_PATHSEGMENT segment, float *x, float *y)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetDescent(FPDF_FONT font, float font_size, float *descent)
FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFImageObj_GetRenderedBitmap(FPDF_DOCUMENT document, FPDF_PAGE page, FPDF_PAGEOBJECT image_object)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_Close(FPDF_PAGEOBJECT path)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetFillColor(FPDF_PAGEOBJECT page_object, unsigned int R, unsigned int G, unsigned int B, unsigned int A)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFTextObj_SetTextRenderMode(FPDF_PAGEOBJECT text, FPDF_TEXT_RENDERMODE render_mode)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_GetDrawMode(FPDF_PAGEOBJECT path, int *fillmode, FPDF_BOOL *stroke)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetItalicAngle(FPDF_FONT font, int *angle)
FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFImageObj_GetImageDataRaw(FPDF_PAGEOBJECT image_object, void *buffer, unsigned long buflen)
#define FPDF_FILLMODE_NONE
Definition fpdf_edit.h:51
FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFImageObj_GetImageFilter(FPDF_PAGEOBJECT image_object, int index, void *buffer, unsigned long buflen)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetFillColor(FPDF_PAGEOBJECT page_object, unsigned int *R, unsigned int *G, unsigned int *B, unsigned int *A)
FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFImageObj_GetBitmap(FPDF_PAGEOBJECT image_object)
FPDF_EXPORT int FPDF_CALLCONV FPDFPageObjMark_CountParams(FPDF_PAGEOBJECTMARK mark)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_RemoveMark(FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark)
FPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetFlags(FPDF_FONT font)
#define FPDF_SEGMENT_MOVETO
Definition fpdf_edit.h:49
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetParamStringValue(FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, void *buffer, unsigned long buflen, unsigned long *out_buflen)
FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_CountMarks(FPDF_PAGEOBJECT page_object)
FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateNewRect(float x, float y, float w, float h)
#define FPDF_SEGMENT_UNKNOWN
Definition fpdf_edit.h:46
FPDF_EXPORT void FPDF_CALLCONV FPDFPage_TransformAnnots(FPDF_PAGE page, double a, double b, double c, double d, double e, double f)
#define FPDF_FONT_TYPE1
Definition fpdf_edit.h:55
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_RemoveObject(FPDF_PAGE page, FPDF_PAGEOBJECT page_object)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_LineTo(FPDF_PAGEOBJECT path, float x, float y)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetParamBlobValue(FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, void *buffer, unsigned long buflen, unsigned long *out_buflen)
#define FPDF_SEGMENT_BEZIERTO
Definition fpdf_edit.h:48
FPDF_EXPORT int FPDF_CALLCONV FPDFImageObj_GetImageFilterCount(FPDF_PAGEOBJECT image_object)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_RemoveParam(FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key)
FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPage_GetObject(FPDF_PAGE page, int index)
FPDF_EXPORT FPDF_TEXT_RENDERMODE FPDF_CALLCONV FPDFTextObj_GetTextRenderMode(FPDF_PAGEOBJECT text)
FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV FPDFPageObjMark_GetParamValueType(FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetParamIntValue(FPDF_PAGEOBJECTMARK mark, FPDF_BYTESTRING key, int *out_value)
FPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFTextObj_GetFont(FPDF_PAGEOBJECT text)
FPDF_EXPORT FPDF_GLYPHPATH FPDF_CALLCONV FPDFFont_GetGlyphPath(FPDF_FONT font, uint32_t glyph, float font_size)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_BezierTo(FPDF_PAGEOBJECT path, float x1, float y1, float x2, float y2, float x3, float y3)
FPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetType(FPDF_PAGEOBJECT page_object)
#define FPDF_PAGEOBJ_PATH
Definition fpdf_edit.h:40
FPDF_EXPORT int FPDF_CALLCONV FPDFPath_CountSegments(FPDF_PAGEOBJECT path)
#define FPDF_PAGEOBJ_TEXT
Definition fpdf_edit.h:39
#define FPDF_PAGEOBJ_IMAGE
Definition fpdf_edit.h:41
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_MoveTo(FPDF_PAGEOBJECT path, float x, float y)
#define FPDF_COLORSPACE_INDEXED
Definition fpdf_edit.h:34
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetBounds(FPDF_PAGEOBJECT page_object, float *left, float *bottom, float *right, float *top)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFTextObj_GetFontSize(FPDF_PAGEOBJECT text, float *size)
FPDF_EXPORT FPDF_PAGEOBJECTMARK FPDF_CALLCONV FPDFPageObj_GetMark(FPDF_PAGEOBJECT page_object, unsigned long index)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetStrokeWidth(FPDF_PAGEOBJECT page_object, float *width)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetMatrix(FPDF_PAGEOBJECT page_object, const FS_MATRIX *matrix)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_SetStrokeWidth(FPDF_PAGEOBJECT page_object, float width)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFImageObj_GetImagePixelSize(FPDF_PAGEOBJECT image_object, unsigned int *width, unsigned int *height)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetAscent(FPDF_FONT font, float font_size, float *ascent)
#define FPDF_PAGEOBJ_FORM
Definition fpdf_edit.h:43
FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFImageObj_GetImageDataDecoded(FPDF_PAGEOBJECT image_object, void *buffer, unsigned long buflen)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GenerateContent(FPDF_PAGE page)
FPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV FPDFGlyphPath_GetGlyphPathSegment(FPDF_GLYPHPATH glyphpath, int index)
#define FPDF_COLORSPACE_DEVICERGB
Definition fpdf_edit.h:26
FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFTextObj_GetRenderedBitmap(FPDF_DOCUMENT document, FPDF_PAGE page, FPDF_PAGEOBJECT text_object, float scale)
FPDF_EXPORT int FPDF_CALLCONV FPDFPage_CountObjects(FPDF_PAGE page)
FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFFormObj_GetObject(FPDF_PAGEOBJECT form_object, unsigned long index)
FPDF_EXPORT FPDF_PAGEOBJECTMARK FPDF_CALLCONV FPDFPageObj_AddMark(FPDF_PAGEOBJECT page_object, FPDF_BYTESTRING name)
#define FPDF_SEGMENT_LINETO
Definition fpdf_edit.h:47
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObjMark_GetName(FPDF_PAGEOBJECTMARK mark, void *buffer, unsigned long buflen, unsigned long *out_buflen)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPageObj_GetMatrix(FPDF_PAGEOBJECT page_object, FS_MATRIX *matrix)
FPDF_EXPORT int FPDF_CALLCONV FPDFGlyphPath_CountGlyphSegments(FPDF_GLYPHPATH glyphpath)
FPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_SetBlendMode(FPDF_PAGEOBJECT page_object, FPDF_BYTESTRING blend_mode)
FPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_Transform(FPDF_PAGEOBJECT page_object, double a, double b, double c, double d, double e, double f)
FPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_Destroy(FPDF_PAGEOBJECT page_object)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPathSegment_GetClose(FPDF_PATHSEGMENT segment)
#define FPDF_FILLMODE_WINDING
Definition fpdf_edit.h:53
TEST_F(FPDFEditEmbedderTest, EmbedNotoSansSCFont)
TEST_F(FPDFEditEmbedderTest, GraphicsData)
void CheckMarkCounts(FPDF_PAGE page, int start_from, int expected_object_count, size_t expected_prime_count, size_t expected_square_count, size_t expected_greater_than_ten_count, size_t expected_bounds_count)
TEST_F(FPDFEditMoveEmbedderTest, MovePagesTest)
FPDF_EXPORT int FPDF_CALLCONV FPDFClipPath_CountPaths(FPDF_CLIPPATH clip_path)
FPDF_EXPORT FPDF_CLIPPATH FPDF_CALLCONV FPDFPageObj_GetClipPath(FPDF_PAGEOBJECT page_object)
FPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV FPDFClipPath_GetPathSegment(FPDF_CLIPPATH clip_path, int path_index, int segment_index)
FPDF_EXPORT int FPDF_CALLCONV FPDFClipPath_CountPathSegments(FPDF_CLIPPATH clip_path, int path_index)
FPDF_EXPORT void FPDF_CALLCONV FPDF_ClosePage(FPDF_PAGE page)
#define FPDF_OBJECT_NUMBER
Definition fpdfview.h:38
#define FPDFBitmap_BGR
Definition fpdfview.h:1100
#define FPDF_OBJECT_NAME
Definition fpdfview.h:40
#define FPDFBitmap_BGRA
Definition fpdfview.h:1104
#define FPDF_OBJECT_STRING
Definition fpdfview.h:39
#define FPDFBitmap_Gray
Definition fpdfview.h:1098
#define FPDF_OBJECT_ARRAY
Definition fpdfview.h:41
#define FPDF_ANNOT
Definition fpdfview.h:804
bool FontStyleIsNonSymbolic(uint32_t style)
Definition fx_font.h:71
bool FontStyleIsItalic(uint32_t style)
Definition fx_font.h:62
bool FontStyleIsForceBold(uint32_t style)
Definition fx_font.h:59
const char kBlankPage612By792Checksum[]
const char * HelloWorldChecksum()
const char * HelloWorldRemovedChecksum()
const char * ManyRectanglesChecksum()
unsigned int bits_per_pixel
Definition fpdf_edit.h:87
unsigned int height
Definition fpdf_edit.h:81
unsigned int width
Definition fpdf_edit.h:79