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