1 // Copyright 2016 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <memory>
6 #include <string>
7 #include <utility>
8 #include <vector>
9
10 #include "build/build_config.h"
11 #include "core/fpdfapi/font/cpdf_font.h"
12 #include "core/fpdfapi/page/cpdf_formobject.h"
13 #include "core/fpdfapi/page/cpdf_page.h"
14 #include "core/fpdfapi/page/cpdf_pageobject.h"
15 #include "core/fpdfapi/parser/cpdf_array.h"
16 #include "core/fpdfapi/parser/cpdf_dictionary.h"
17 #include "core/fpdfapi/parser/cpdf_number.h"
18 #include "core/fpdfapi/parser/cpdf_stream.h"
19 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
20 #include "core/fxcrt/fx_system.h"
21 #include "core/fxge/fx_font.h"
22 #include "fpdfsdk/cpdfsdk_helpers.h"
23 #include "public/cpp/fpdf_scopers.h"
24 #include "public/fpdf_annot.h"
25 #include "public/fpdf_edit.h"
26 #include "public/fpdfview.h"
27 #include "testing/embedder_test.h"
28 #include "testing/fx_string_testhelpers.h"
29 #include "testing/gmock/include/gmock/gmock-matchers.h"
30 #include "testing/gtest/include/gtest/gtest.h"
31 #include "testing/utils/hash.h"
32
33 class FPDFEditEmbedderTest : public EmbedderTest {
34 protected:
CreateNewDocument()35 FPDF_DOCUMENT CreateNewDocument() {
36 document_ = FPDF_CreateNewDocument();
37 cpdf_doc_ = CPDFDocumentFromFPDFDocument(document_);
38 return document_;
39 }
40
CheckFontDescriptor(const CPDF_Dictionary * font_dict,int font_type,bool bold,bool italic,pdfium::span<const uint8_t> span)41 void CheckFontDescriptor(const CPDF_Dictionary* font_dict,
42 int font_type,
43 bool bold,
44 bool italic,
45 pdfium::span<const uint8_t> span) {
46 const CPDF_Dictionary* font_desc = font_dict->GetDictFor("FontDescriptor");
47 ASSERT_TRUE(font_desc);
48 EXPECT_EQ("FontDescriptor", font_desc->GetStringFor("Type"));
49 EXPECT_EQ(font_dict->GetStringFor("BaseFont"),
50 font_desc->GetStringFor("FontName"));
51
52 // Check that the font descriptor has the required keys according to spec
53 // 1.7 Table 5.19
54 ASSERT_TRUE(font_desc->KeyExist("Flags"));
55
56 int font_flags = font_desc->GetIntegerFor("Flags");
57 EXPECT_EQ(bold, FontStyleIsForceBold(font_flags));
58 EXPECT_EQ(italic, FontStyleIsItalic(font_flags));
59 EXPECT_TRUE(FontStyleIsNonSymbolic(font_flags));
60 ASSERT_TRUE(font_desc->KeyExist("FontBBox"));
61
62 const CPDF_Array* fontBBox = font_desc->GetArrayFor("FontBBox");
63 ASSERT_TRUE(fontBBox);
64 EXPECT_EQ(4u, fontBBox->size());
65 // Check that the coordinates are in the preferred order according to spec
66 // 1.7 Section 3.8.4
67 EXPECT_TRUE(fontBBox->GetIntegerAt(0) < fontBBox->GetIntegerAt(2));
68 EXPECT_TRUE(fontBBox->GetIntegerAt(1) < fontBBox->GetIntegerAt(3));
69
70 EXPECT_TRUE(font_desc->KeyExist("ItalicAngle"));
71 EXPECT_TRUE(font_desc->KeyExist("Ascent"));
72 EXPECT_TRUE(font_desc->KeyExist("Descent"));
73 EXPECT_TRUE(font_desc->KeyExist("CapHeight"));
74 EXPECT_TRUE(font_desc->KeyExist("StemV"));
75 ByteString present("FontFile");
76 ByteString absent("FontFile2");
77 if (font_type == FPDF_FONT_TRUETYPE)
78 std::swap(present, absent);
79 EXPECT_TRUE(font_desc->KeyExist(present));
80 EXPECT_FALSE(font_desc->KeyExist(absent));
81
82 auto streamAcc =
83 pdfium::MakeRetain<CPDF_StreamAcc>(font_desc->GetStreamFor(present));
84 streamAcc->LoadAllDataRaw();
85
86 // Check that the font stream is the one that was provided
87 ASSERT_EQ(span.size(), streamAcc->GetSize());
88 if (font_type == FPDF_FONT_TRUETYPE) {
89 ASSERT_EQ(static_cast<int>(span.size()),
90 streamAcc->GetDict()->GetIntegerFor("Length1"));
91 }
92
93 const uint8_t* stream_data = streamAcc->GetData();
94 for (size_t j = 0; j < span.size(); j++)
95 EXPECT_EQ(span[j], stream_data[j]) << " at byte " << j;
96 }
97
CheckCompositeFontWidths(const CPDF_Array * widths_array,CPDF_Font * typed_font)98 void CheckCompositeFontWidths(const CPDF_Array* widths_array,
99 CPDF_Font* typed_font) {
100 // Check that W array is in a format that conforms to PDF spec 1.7 section
101 // "Glyph Metrics in CIDFonts" (these checks are not
102 // implementation-specific).
103 EXPECT_GT(widths_array->size(), 1u);
104 int num_cids_checked = 0;
105 int cur_cid = 0;
106 for (size_t idx = 0; idx < widths_array->size(); idx++) {
107 int cid = widths_array->GetNumberAt(idx);
108 EXPECT_GE(cid, cur_cid);
109 ASSERT_FALSE(++idx == widths_array->size());
110 const CPDF_Object* next = widths_array->GetObjectAt(idx);
111 if (next->IsArray()) {
112 // We are in the c [w1 w2 ...] case
113 const CPDF_Array* arr = next->AsArray();
114 int cnt = static_cast<int>(arr->size());
115 size_t inner_idx = 0;
116 for (cur_cid = cid; cur_cid < cid + cnt; cur_cid++) {
117 uint32_t width = arr->GetNumberAt(inner_idx++);
118 EXPECT_EQ(width, typed_font->GetCharWidthF(cur_cid))
119 << " at cid " << cur_cid;
120 }
121 num_cids_checked += cnt;
122 continue;
123 }
124 // Otherwise, are in the c_first c_last w case.
125 ASSERT_TRUE(next->IsNumber());
126 int last_cid = next->AsNumber()->GetInteger();
127 ASSERT_FALSE(++idx == widths_array->size());
128 uint32_t width = widths_array->GetNumberAt(idx);
129 for (cur_cid = cid; cur_cid <= last_cid; cur_cid++) {
130 EXPECT_EQ(width, typed_font->GetCharWidthF(cur_cid))
131 << " at cid " << cur_cid;
132 }
133 num_cids_checked += last_cid - cid + 1;
134 }
135 // Make sure we have a good amount of cids described
136 EXPECT_GT(num_cids_checked, 900);
137 }
cpdf_doc()138 CPDF_Document* cpdf_doc() { return cpdf_doc_; }
139
140 private:
141 CPDF_Document* cpdf_doc_;
142 };
143
144 namespace {
145
146 const char kExpectedPDF[] =
147 "%PDF-1.7\r\n"
148 "%\xA1\xB3\xC5\xD7\r\n"
149 "1 0 obj\r\n"
150 "<</Pages 2 0 R /Type/Catalog>>\r\n"
151 "endobj\r\n"
152 "2 0 obj\r\n"
153 "<</Count 1/Kids\\[ 4 0 R \\]/Type/Pages>>\r\n"
154 "endobj\r\n"
155 "3 0 obj\r\n"
156 "<</CreationDate\\(D:.*\\)/Creator\\(PDFium\\)>>\r\n"
157 "endobj\r\n"
158 "4 0 obj\r\n"
159 "<</MediaBox\\[ 0 0 640 480\\]/Parent 2 0 R "
160 "/Resources<</ExtGState<</FXE1 5 0 R >>>>"
161 "/Rotate 0/Type/Page"
162 ">>\r\n"
163 "endobj\r\n"
164 "5 0 obj\r\n"
165 "<</BM/Normal/CA 1/ca 1>>\r\n"
166 "endobj\r\n"
167 "xref\r\n"
168 "0 6\r\n"
169 "0000000000 65535 f\r\n"
170 "0000000017 00000 n\r\n"
171 "0000000066 00000 n\r\n"
172 "0000000122 00000 n\r\n"
173 "0000000192 00000 n\r\n"
174 "0000000311 00000 n\r\n"
175 "trailer\r\n"
176 "<<\r\n"
177 "/Root 1 0 R\r\n"
178 "/Info 3 0 R\r\n"
179 "/Size 6/ID\\[<.*><.*>\\]>>\r\n"
180 "startxref\r\n"
181 "354\r\n"
182 "%%EOF\r\n";
183
184 } // namespace
185
TEST_F(FPDFEditEmbedderTest,EmptyCreation)186 TEST_F(FPDFEditEmbedderTest, EmptyCreation) {
187 EXPECT_TRUE(CreateEmptyDocument());
188 FPDF_PAGE page = FPDFPage_New(document(), 0, 640.0, 480.0);
189 EXPECT_NE(nullptr, page);
190 // The FPDFPage_GenerateContent call should do nothing.
191 EXPECT_TRUE(FPDFPage_GenerateContent(page));
192 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
193
194 EXPECT_THAT(GetString(), testing::MatchesRegex(std::string(
195 kExpectedPDF, sizeof(kExpectedPDF))));
196 FPDF_ClosePage(page);
197 }
198
199 // Regression test for https://crbug.com/667012
TEST_F(FPDFEditEmbedderTest,RasterizePDF)200 TEST_F(FPDFEditEmbedderTest, RasterizePDF) {
201 const char kAllBlackMd5sum[] = "5708fc5c4a8bd0abde99c8e8f0390615";
202
203 // Get the bitmap for the original document.
204 ScopedFPDFBitmap orig_bitmap;
205 {
206 EXPECT_TRUE(OpenDocument("black.pdf"));
207 FPDF_PAGE orig_page = LoadPage(0);
208 ASSERT_TRUE(orig_page);
209 orig_bitmap = RenderLoadedPage(orig_page);
210 CompareBitmap(orig_bitmap.get(), 612, 792, kAllBlackMd5sum);
211 UnloadPage(orig_page);
212 }
213
214 // Create a new document from |orig_bitmap| and save it.
215 {
216 FPDF_DOCUMENT temp_doc = FPDF_CreateNewDocument();
217 FPDF_PAGE temp_page = FPDFPage_New(temp_doc, 0, 612, 792);
218
219 // Add the bitmap to an image object and add the image object to the output
220 // page.
221 FPDF_PAGEOBJECT temp_img = FPDFPageObj_NewImageObj(temp_doc);
222 EXPECT_TRUE(
223 FPDFImageObj_SetBitmap(&temp_page, 1, temp_img, orig_bitmap.get()));
224 EXPECT_TRUE(FPDFImageObj_SetMatrix(temp_img, 612, 0, 0, 792, 0, 0));
225 FPDFPage_InsertObject(temp_page, temp_img);
226 EXPECT_TRUE(FPDFPage_GenerateContent(temp_page));
227 EXPECT_TRUE(FPDF_SaveAsCopy(temp_doc, this, 0));
228 FPDF_ClosePage(temp_page);
229 FPDF_CloseDocument(temp_doc);
230 }
231
232 // Get the generated content. Make sure it is at least as big as the original
233 // PDF.
234 EXPECT_GT(GetString().size(), 923u);
235 VerifySavedDocument(612, 792, kAllBlackMd5sum);
236 }
237
238 // TODO(crbug.com/pdfium/11): Fix this test and enable.
239 #if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
240 #define MAYBE_AddPaths DISABLED_AddPaths
241 #else
242 #define MAYBE_AddPaths AddPaths
243 #endif
TEST_F(FPDFEditEmbedderTest,MAYBE_AddPaths)244 TEST_F(FPDFEditEmbedderTest, MAYBE_AddPaths) {
245 // Start with a blank page
246 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
247 ASSERT_TRUE(page);
248
249 // We will first add a red rectangle
250 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(10, 10, 20, 20);
251 ASSERT_TRUE(red_rect);
252 // Expect false when trying to set colors out of range
253 EXPECT_FALSE(FPDFPageObj_SetStrokeColor(red_rect, 100, 100, 100, 300));
254 EXPECT_FALSE(FPDFPageObj_SetFillColor(red_rect, 200, 256, 200, 0));
255
256 // Fill rectangle with red and insert to the page
257 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
258 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
259
260 int fillmode = FPDF_FILLMODE_NONE;
261 FPDF_BOOL stroke = true;
262 EXPECT_TRUE(FPDFPath_GetDrawMode(red_rect, &fillmode, &stroke));
263 EXPECT_EQ(FPDF_FILLMODE_ALTERNATE, fillmode);
264 EXPECT_FALSE(stroke);
265
266 static const FS_MATRIX kMatrix = {1, 2, 3, 4, 5, 6};
267 EXPECT_FALSE(FPDFPath_SetMatrix(nullptr, &kMatrix));
268 EXPECT_TRUE(FPDFPath_SetMatrix(red_rect, &kMatrix));
269
270 FS_MATRIX matrix;
271 EXPECT_FALSE(FPDFPath_GetMatrix(nullptr, &matrix));
272 EXPECT_TRUE(FPDFPath_GetMatrix(red_rect, &matrix));
273 EXPECT_FLOAT_EQ(1.0f, matrix.a);
274 EXPECT_FLOAT_EQ(2.0f, matrix.b);
275 EXPECT_FLOAT_EQ(3.0f, matrix.c);
276 EXPECT_FLOAT_EQ(4.0f, matrix.d);
277 EXPECT_FLOAT_EQ(5.0f, matrix.e);
278 EXPECT_FLOAT_EQ(6.0f, matrix.f);
279
280 // Set back the identity matrix.
281 matrix = {1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f};
282 EXPECT_TRUE(FPDFPath_SetMatrix(red_rect, &matrix));
283
284 FPDFPage_InsertObject(page, red_rect);
285 {
286 ScopedFPDFBitmap page_bitmap = RenderPage(page);
287 CompareBitmap(page_bitmap.get(), 612, 792,
288 "66d02eaa6181e2c069ce2ea99beda497");
289 }
290
291 // Now add to that a green rectangle with some medium alpha
292 FPDF_PAGEOBJECT green_rect = FPDFPageObj_CreateNewRect(100, 100, 40, 40);
293 EXPECT_TRUE(FPDFPageObj_SetFillColor(green_rect, 0, 255, 0, 128));
294
295 // Make sure the type of the rectangle is a path.
296 EXPECT_EQ(FPDF_PAGEOBJ_PATH, FPDFPageObj_GetType(green_rect));
297
298 // Make sure we get back the same color we set previously.
299 unsigned int R;
300 unsigned int G;
301 unsigned int B;
302 unsigned int A;
303 EXPECT_TRUE(FPDFPageObj_GetFillColor(green_rect, &R, &G, &B, &A));
304 EXPECT_EQ(0u, R);
305 EXPECT_EQ(255u, G);
306 EXPECT_EQ(0u, B);
307 EXPECT_EQ(128u, A);
308
309 // Make sure the path has 5 points (1 FXPT_TYPE::MoveTo and 4
310 // FXPT_TYPE::LineTo).
311 ASSERT_EQ(5, FPDFPath_CountSegments(green_rect));
312 // Verify actual coordinates.
313 FPDF_PATHSEGMENT segment = FPDFPath_GetPathSegment(green_rect, 0);
314 float x;
315 float y;
316 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
317 EXPECT_EQ(100, x);
318 EXPECT_EQ(100, y);
319 EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment));
320 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
321 segment = FPDFPath_GetPathSegment(green_rect, 1);
322 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
323 EXPECT_EQ(100, x);
324 EXPECT_EQ(140, y);
325 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
326 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
327 segment = FPDFPath_GetPathSegment(green_rect, 2);
328 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
329 EXPECT_EQ(140, x);
330 EXPECT_EQ(140, y);
331 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
332 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
333 segment = FPDFPath_GetPathSegment(green_rect, 3);
334 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
335 EXPECT_EQ(140, x);
336 EXPECT_EQ(100, y);
337 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
338 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
339 segment = FPDFPath_GetPathSegment(green_rect, 4);
340 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
341 EXPECT_EQ(100, x);
342 EXPECT_EQ(100, y);
343 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
344 EXPECT_TRUE(FPDFPathSegment_GetClose(segment));
345
346 EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect, FPDF_FILLMODE_WINDING, 0));
347 FPDFPage_InsertObject(page, green_rect);
348 {
349 ScopedFPDFBitmap page_bitmap = RenderPage(page);
350 CompareBitmap(page_bitmap.get(), 612, 792,
351 "7b0b87604594e773add528fae567a558");
352 }
353
354 // Add a black triangle.
355 FPDF_PAGEOBJECT black_path = FPDFPageObj_CreateNewPath(400, 100);
356 EXPECT_TRUE(FPDFPageObj_SetFillColor(black_path, 0, 0, 0, 200));
357 EXPECT_TRUE(FPDFPath_SetDrawMode(black_path, FPDF_FILLMODE_ALTERNATE, 0));
358 EXPECT_TRUE(FPDFPath_LineTo(black_path, 400, 200));
359 EXPECT_TRUE(FPDFPath_LineTo(black_path, 300, 100));
360 EXPECT_TRUE(FPDFPath_Close(black_path));
361
362 // Make sure the path has 3 points (1 FXPT_TYPE::MoveTo and 2
363 // FXPT_TYPE::LineTo).
364 ASSERT_EQ(3, FPDFPath_CountSegments(black_path));
365 // Verify actual coordinates.
366 segment = FPDFPath_GetPathSegment(black_path, 0);
367 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
368 EXPECT_EQ(400, x);
369 EXPECT_EQ(100, y);
370 EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment));
371 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
372 segment = FPDFPath_GetPathSegment(black_path, 1);
373 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
374 EXPECT_EQ(400, x);
375 EXPECT_EQ(200, y);
376 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
377 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
378 segment = FPDFPath_GetPathSegment(black_path, 2);
379 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
380 EXPECT_EQ(300, x);
381 EXPECT_EQ(100, y);
382 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
383 EXPECT_TRUE(FPDFPathSegment_GetClose(segment));
384 // Make sure out of bounds index access fails properly.
385 EXPECT_EQ(nullptr, FPDFPath_GetPathSegment(black_path, 3));
386
387 FPDFPage_InsertObject(page, black_path);
388 {
389 ScopedFPDFBitmap page_bitmap = RenderPage(page);
390 CompareBitmap(page_bitmap.get(), 612, 792,
391 "eadc8020a14dfcf091da2688733d8806");
392 }
393
394 // Now add a more complex blue path.
395 FPDF_PAGEOBJECT blue_path = FPDFPageObj_CreateNewPath(200, 200);
396 EXPECT_TRUE(FPDFPageObj_SetFillColor(blue_path, 0, 0, 255, 255));
397 EXPECT_TRUE(FPDFPath_SetDrawMode(blue_path, FPDF_FILLMODE_WINDING, 0));
398 EXPECT_TRUE(FPDFPath_LineTo(blue_path, 230, 230));
399 EXPECT_TRUE(FPDFPath_BezierTo(blue_path, 250, 250, 280, 280, 300, 300));
400 EXPECT_TRUE(FPDFPath_LineTo(blue_path, 325, 325));
401 EXPECT_TRUE(FPDFPath_LineTo(blue_path, 350, 325));
402 EXPECT_TRUE(FPDFPath_BezierTo(blue_path, 375, 330, 390, 360, 400, 400));
403 EXPECT_TRUE(FPDFPath_Close(blue_path));
404 FPDFPage_InsertObject(page, blue_path);
405 const char kLastMD5[] = "9823e1a21bd9b72b6a442ba4f12af946";
406 {
407 ScopedFPDFBitmap page_bitmap = RenderPage(page);
408 CompareBitmap(page_bitmap.get(), 612, 792, kLastMD5);
409 }
410
411 // Now save the result, closing the page and document
412 EXPECT_TRUE(FPDFPage_GenerateContent(page));
413 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
414 FPDF_ClosePage(page);
415
416 // Render the saved result
417 VerifySavedDocument(612, 792, kLastMD5);
418 }
419
TEST_F(FPDFEditEmbedderTest,ClipPath)420 TEST_F(FPDFEditEmbedderTest, ClipPath) {
421 // Load document with a clipped rectangle.
422 EXPECT_TRUE(OpenDocument("clip_path.pdf"));
423 FPDF_PAGE page = LoadPage(0);
424 ASSERT_TRUE(page);
425
426 ASSERT_EQ(1, FPDFPage_CountObjects(page));
427
428 FPDF_PAGEOBJECT triangle = FPDFPage_GetObject(page, 0);
429 ASSERT_TRUE(triangle);
430
431 // Test that we got the expected triangle.
432 ASSERT_EQ(4, FPDFPath_CountSegments(triangle));
433
434 FPDF_PATHSEGMENT segment = FPDFPath_GetPathSegment(triangle, 0);
435 float x;
436 float y;
437 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
438 EXPECT_EQ(10, x);
439 EXPECT_EQ(10, y);
440 EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment));
441 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
442
443 segment = FPDFPath_GetPathSegment(triangle, 1);
444 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
445 EXPECT_EQ(25, x);
446 EXPECT_EQ(40, y);
447 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
448 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
449
450 segment = FPDFPath_GetPathSegment(triangle, 2);
451 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
452 EXPECT_EQ(40, x);
453 EXPECT_EQ(10, y);
454 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
455 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
456
457 segment = FPDFPath_GetPathSegment(triangle, 3);
458 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
459 EXPECT_TRUE(FPDFPathSegment_GetClose(segment));
460
461 // Test FPDFPageObj_GetClipPath().
462 ASSERT_EQ(nullptr, FPDFPageObj_GetClipPath(nullptr));
463
464 FPDF_CLIPPATH clip_path = FPDFPageObj_GetClipPath(triangle);
465 ASSERT_TRUE(clip_path);
466
467 // Test FPDFClipPath_CountPaths().
468 ASSERT_EQ(-1, FPDFClipPath_CountPaths(nullptr));
469 ASSERT_EQ(1, FPDFClipPath_CountPaths(clip_path));
470
471 // Test FPDFClipPath_CountPathSegments().
472 ASSERT_EQ(-1, FPDFClipPath_CountPathSegments(nullptr, 0));
473 ASSERT_EQ(-1, FPDFClipPath_CountPathSegments(clip_path, -1));
474 ASSERT_EQ(-1, FPDFClipPath_CountPathSegments(clip_path, 1));
475 ASSERT_EQ(4, FPDFClipPath_CountPathSegments(clip_path, 0));
476
477 // FPDFClipPath_GetPathSegment() negative testing.
478 ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(nullptr, 0, 0));
479 ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(clip_path, -1, 0));
480 ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(clip_path, 1, 0));
481 ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(clip_path, 0, -1));
482 ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(clip_path, 0, 4));
483
484 // FPDFClipPath_GetPathSegment() positive testing.
485 segment = FPDFClipPath_GetPathSegment(clip_path, 0, 0);
486 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
487 EXPECT_EQ(10, x);
488 EXPECT_EQ(15, y);
489 EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment));
490 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
491
492 segment = FPDFClipPath_GetPathSegment(clip_path, 0, 1);
493 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
494 EXPECT_EQ(40, x);
495 EXPECT_EQ(15, y);
496 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
497 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
498
499 segment = FPDFClipPath_GetPathSegment(clip_path, 0, 2);
500 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
501 EXPECT_EQ(40, x);
502 EXPECT_EQ(35, y);
503 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
504 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
505
506 segment = FPDFClipPath_GetPathSegment(clip_path, 0, 3);
507 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
508 EXPECT_EQ(10, x);
509 EXPECT_EQ(35, y);
510 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
511 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
512
513 UnloadPage(page);
514 }
515
TEST_F(FPDFEditEmbedderTest,BUG_1399)516 TEST_F(FPDFEditEmbedderTest, BUG_1399) {
517 // Load document with a clipped rectangle.
518 EXPECT_TRUE(OpenDocument("bug_1399.pdf"));
519 FPDF_PAGE page = LoadPage(0);
520 ASSERT_TRUE(page);
521
522 ASSERT_EQ(7, FPDFPage_CountObjects(page));
523
524 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 0);
525 ASSERT_TRUE(obj);
526
527 ASSERT_EQ(2, FPDFPath_CountSegments(obj));
528
529 FPDF_PATHSEGMENT segment = FPDFPath_GetPathSegment(obj, 0);
530 float x;
531 float y;
532 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
533 EXPECT_FLOAT_EQ(107.718f, x);
534 EXPECT_FLOAT_EQ(719.922f, y);
535 EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment));
536 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
537
538 segment = FPDFPath_GetPathSegment(obj, 1);
539 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
540 EXPECT_FLOAT_EQ(394.718f, x);
541 EXPECT_FLOAT_EQ(719.922f, y);
542 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
543 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
544
545 FPDF_CLIPPATH clip_path = FPDFPageObj_GetClipPath(obj);
546 ASSERT_TRUE(clip_path);
547
548 EXPECT_EQ(-1, FPDFClipPath_CountPaths(clip_path));
549 EXPECT_EQ(-1, FPDFClipPath_CountPathSegments(clip_path, 0));
550 EXPECT_FALSE(FPDFClipPath_GetPathSegment(clip_path, 0, 0));
551
552 UnloadPage(page);
553 }
554
555 // TODO(crbug.com/pdfium/11): Fix this test and enable.
556 #if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
557 #define MAYBE_SetText DISABLED_SetText
558 #else
559 #define MAYBE_SetText SetText
560 #endif
TEST_F(FPDFEditEmbedderTest,MAYBE_SetText)561 TEST_F(FPDFEditEmbedderTest, MAYBE_SetText) {
562 // Load document with some text.
563 EXPECT_TRUE(OpenDocument("hello_world.pdf"));
564 FPDF_PAGE page = LoadPage(0);
565 ASSERT_TRUE(page);
566
567 // Get the "Hello, world!" text object and change it.
568 ASSERT_EQ(2, FPDFPage_CountObjects(page));
569 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
570 ASSERT_TRUE(page_object);
571 ScopedFPDFWideString text1 = GetFPDFWideString(L"Changed for SetText test");
572 EXPECT_TRUE(FPDFText_SetText(page_object, text1.get()));
573
574 // Verify the "Hello, world!" text is gone and "Changed for SetText test" is
575 // now displayed.
576 ASSERT_EQ(2, FPDFPage_CountObjects(page));
577 #if defined(OS_MACOSX)
578 const char kChangedMD5[] = "94c1e7a5af7dd9d77dc2223b1091acb7";
579 #elif defined(OS_WIN)
580 const char kChangedMD5[] = "3137fdb27962671f5c3963a5e965eff5";
581 #else
582 const char kChangedMD5[] = "a0c4ea6620772991f66bf7130379b08a";
583 #endif
584 {
585 ScopedFPDFBitmap page_bitmap = RenderPage(page);
586 CompareBitmap(page_bitmap.get(), 200, 200, kChangedMD5);
587 }
588
589 // Now save the result.
590 EXPECT_TRUE(FPDFPage_GenerateContent(page));
591 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
592
593 UnloadPage(page);
594
595 // Re-open the file and check the changes were kept in the saved .pdf.
596 ASSERT_TRUE(OpenSavedDocument());
597 FPDF_PAGE saved_page = LoadSavedPage(0);
598 EXPECT_EQ(2, FPDFPage_CountObjects(saved_page));
599 {
600 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
601 CompareBitmap(page_bitmap.get(), 200, 200, kChangedMD5);
602 }
603
604 CloseSavedPage(saved_page);
605 CloseSavedDocument();
606 }
607
608 // TODO(crbug.com/pdfium/11): Fix this test and enable.
609 #if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
610 #define MAYBE_RemovePageObject DISABLED_RemovePageObject
611 #else
612 #define MAYBE_RemovePageObject RemovePageObject
613 #endif
TEST_F(FPDFEditEmbedderTest,MAYBE_RemovePageObject)614 TEST_F(FPDFEditEmbedderTest, MAYBE_RemovePageObject) {
615 // Load document with some text.
616 EXPECT_TRUE(OpenDocument("hello_world.pdf"));
617 FPDF_PAGE page = LoadPage(0);
618 ASSERT_TRUE(page);
619
620 // Show what the original file looks like.
621 {
622 #if defined(OS_MACOSX)
623 const char kOriginalMD5[] = "b90475ca64d1348c3bf5e2b77ad9187a";
624 #elif defined(OS_WIN)
625 const char kOriginalMD5[] = "795b7ce1626931aa06af0fa23b7d80bb";
626 #else
627 const char kOriginalMD5[] = "2baa4c0e1758deba1b9c908e1fbd04ed";
628 #endif
629 ScopedFPDFBitmap page_bitmap = RenderPage(page);
630 CompareBitmap(page_bitmap.get(), 200, 200, kOriginalMD5);
631 }
632
633 // Get the "Hello, world!" text object and remove it.
634 ASSERT_EQ(2, FPDFPage_CountObjects(page));
635 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
636 ASSERT_TRUE(page_object);
637 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
638
639 // Verify the "Hello, world!" text is gone.
640 {
641 #if defined(OS_MACOSX)
642 const char kRemovedMD5[] = "af760c4702467cb1492a57fb8215efaa";
643 #elif defined(OS_WIN)
644 const char kRemovedMD5[] = "aae6c5334721f90ec30d3d59f4ef7deb";
645 #else
646 const char kRemovedMD5[] = "b76df015fe88009c3c342395df96abf1";
647 #endif
648 ScopedFPDFBitmap page_bitmap = RenderPage(page);
649 CompareBitmap(page_bitmap.get(), 200, 200, kRemovedMD5);
650 }
651 ASSERT_EQ(1, FPDFPage_CountObjects(page));
652
653 UnloadPage(page);
654 FPDFPageObj_Destroy(page_object);
655 }
656
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)657 void CheckMarkCounts(FPDF_PAGE page,
658 int start_from,
659 int expected_object_count,
660 size_t expected_prime_count,
661 size_t expected_square_count,
662 size_t expected_greater_than_ten_count,
663 size_t expected_bounds_count) {
664 int object_count = FPDFPage_CountObjects(page);
665 ASSERT_EQ(expected_object_count, object_count);
666
667 size_t prime_count = 0;
668 size_t square_count = 0;
669 size_t greater_than_ten_count = 0;
670 size_t bounds_count = 0;
671 for (int i = 0; i < object_count; ++i) {
672 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
673
674 int mark_count = FPDFPageObj_CountMarks(page_object);
675 for (int j = 0; j < mark_count; ++j) {
676 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
677
678 char buffer[256];
679 unsigned long name_len = 999u;
680 ASSERT_TRUE(
681 FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
682 EXPECT_GT(name_len, 0u);
683 EXPECT_NE(999u, name_len);
684 std::wstring name =
685 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
686 if (name == L"Prime") {
687 prime_count++;
688 } else if (name == L"Square") {
689 square_count++;
690 int expected_square = start_from + i;
691 EXPECT_EQ(1, FPDFPageObjMark_CountParams(mark));
692
693 unsigned long get_param_key_return = 999u;
694 ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark, 0, buffer, sizeof(buffer),
695 &get_param_key_return));
696 EXPECT_EQ((6u + 1u) * 2u, get_param_key_return);
697 std::wstring key =
698 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
699 EXPECT_EQ(L"Factor", key);
700
701 EXPECT_EQ(FPDF_OBJECT_NUMBER,
702 FPDFPageObjMark_GetParamValueType(mark, "Factor"));
703 int square_root;
704 EXPECT_TRUE(
705 FPDFPageObjMark_GetParamIntValue(mark, "Factor", &square_root));
706 EXPECT_EQ(expected_square, square_root * square_root);
707 } else if (name == L"GreaterThanTen") {
708 greater_than_ten_count++;
709 } else if (name == L"Bounds") {
710 bounds_count++;
711 EXPECT_EQ(1, FPDFPageObjMark_CountParams(mark));
712
713 unsigned long get_param_key_return = 999u;
714 ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark, 0, buffer, sizeof(buffer),
715 &get_param_key_return));
716 EXPECT_EQ((8u + 1u) * 2u, get_param_key_return);
717 std::wstring key =
718 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
719 EXPECT_EQ(L"Position", key);
720
721 EXPECT_EQ(FPDF_OBJECT_STRING,
722 FPDFPageObjMark_GetParamValueType(mark, "Position"));
723 unsigned long length;
724 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(
725 mark, "Position", buffer, sizeof(buffer), &length));
726 ASSERT_GT(length, 0u);
727 std::wstring value =
728 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
729
730 // "Position" can be "First", "Last", or "End".
731 if (i == 0) {
732 EXPECT_EQ((5u + 1u) * 2u, length);
733 EXPECT_EQ(L"First", value);
734 } else if (i == object_count - 1) {
735 if (length == (4u + 1u) * 2u) {
736 EXPECT_EQ(L"Last", value);
737 } else if (length == (3u + 1u) * 2u) {
738 EXPECT_EQ(L"End", value);
739 } else {
740 FAIL();
741 }
742 } else {
743 FAIL();
744 }
745 } else {
746 FAIL();
747 }
748 }
749 }
750
751 // Expect certain number of tagged objects. The test file contains strings
752 // from 1 to 19.
753 EXPECT_EQ(expected_prime_count, prime_count);
754 EXPECT_EQ(expected_square_count, square_count);
755 EXPECT_EQ(expected_greater_than_ten_count, greater_than_ten_count);
756 EXPECT_EQ(expected_bounds_count, bounds_count);
757 }
758
TEST_F(FPDFEditEmbedderTest,ReadMarkedObjectsIndirectDict)759 TEST_F(FPDFEditEmbedderTest, ReadMarkedObjectsIndirectDict) {
760 // Load document with some text marked with an indirect property.
761 EXPECT_TRUE(OpenDocument("text_in_page_marked_indirect.pdf"));
762 FPDF_PAGE page = LoadPage(0);
763 ASSERT_TRUE(page);
764
765 CheckMarkCounts(page, 1, 19, 8, 4, 9, 1);
766
767 UnloadPage(page);
768 }
769
770 // TODO(crbug.com/pdfium/11): Fix this test and enable.
771 #if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
772 #define MAYBE_RemoveMarkedObjectsPrime DISABLED_RemoveMarkedObjectsPrime
773 #else
774 #define MAYBE_RemoveMarkedObjectsPrime RemoveMarkedObjectsPrime
775 #endif
TEST_F(FPDFEditEmbedderTest,MAYBE_RemoveMarkedObjectsPrime)776 TEST_F(FPDFEditEmbedderTest, MAYBE_RemoveMarkedObjectsPrime) {
777 // Load document with some text.
778 EXPECT_TRUE(OpenDocument("text_in_page_marked.pdf"));
779 FPDF_PAGE page = LoadPage(0);
780 ASSERT_TRUE(page);
781
782 // Show what the original file looks like.
783 {
784 #if defined(OS_MACOSX)
785 const char kOriginalMD5[] = "5a5eb63cb21cc15084fea1f14284b8df";
786 #elif defined(OS_WIN)
787 const char kOriginalMD5[] = "00542ee435b37749c4453be63bf7bdb6";
788 #else
789 const char kOriginalMD5[] = "41647268d5911d049801803b15c2dfb0";
790 #endif
791 ScopedFPDFBitmap page_bitmap = RenderPage(page);
792 CompareBitmap(page_bitmap.get(), 200, 200, kOriginalMD5);
793 }
794
795 constexpr int expected_object_count = 19;
796 CheckMarkCounts(page, 1, expected_object_count, 8, 4, 9, 1);
797
798 // Get all objects marked with "Prime"
799 std::vector<FPDF_PAGEOBJECT> primes;
800 for (int i = 0; i < expected_object_count; ++i) {
801 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
802
803 int mark_count = FPDFPageObj_CountMarks(page_object);
804 for (int j = 0; j < mark_count; ++j) {
805 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
806
807 char buffer[256];
808 unsigned long name_len = 999u;
809 ASSERT_TRUE(
810 FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
811 EXPECT_GT(name_len, 0u);
812 EXPECT_NE(999u, name_len);
813 std::wstring name =
814 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
815 if (name == L"Prime") {
816 primes.push_back(page_object);
817 }
818 }
819 }
820
821 // Remove all objects marked with "Prime".
822 for (FPDF_PAGEOBJECT page_object : primes) {
823 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
824 FPDFPageObj_Destroy(page_object);
825 }
826
827 EXPECT_EQ(11, FPDFPage_CountObjects(page));
828
829 #if defined(OS_MACOSX)
830 const char kNonPrimesMD5[] = "57e76dc7375d896704f0fd6d6d1b9e65";
831 const char kNonPrimesAfterSaveMD5[] = "6304512d0150bbd5578e8e22d3121103";
832 #elif defined(OS_WIN)
833 const char kNonPrimesMD5[] = "86e371fdae30c2471f476631f3f93413";
834 const char kNonPrimesAfterSaveMD5[] = "86e371fdae30c2471f476631f3f93413";
835 #else
836 const char kNonPrimesMD5[] = "67ab13115d0cc34e99a1003c28047b40";
837 const char kNonPrimesAfterSaveMD5[] = "67ab13115d0cc34e99a1003c28047b40";
838 #endif
839 {
840 ScopedFPDFBitmap page_bitmap = RenderPage(page);
841 CompareBitmap(page_bitmap.get(), 200, 200, kNonPrimesMD5);
842 }
843
844 // Save the file.
845 EXPECT_TRUE(FPDFPage_GenerateContent(page));
846 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
847 UnloadPage(page);
848
849 // Re-open the file and check the prime marks are not there anymore.
850 ASSERT_TRUE(OpenSavedDocument());
851 FPDF_PAGE saved_page = LoadSavedPage(0);
852 EXPECT_EQ(11, FPDFPage_CountObjects(saved_page));
853
854 {
855 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
856 CompareBitmap(page_bitmap.get(), 200, 200, kNonPrimesAfterSaveMD5);
857 }
858
859 CloseSavedPage(saved_page);
860 CloseSavedDocument();
861 }
862
TEST_F(FPDFEditEmbedderTest,RemoveMarks)863 TEST_F(FPDFEditEmbedderTest, RemoveMarks) {
864 // Load document with some text.
865 EXPECT_TRUE(OpenDocument("text_in_page_marked.pdf"));
866 FPDF_PAGE page = LoadPage(0);
867 ASSERT_TRUE(page);
868
869 constexpr int kExpectedObjectCount = 19;
870 CheckMarkCounts(page, 1, kExpectedObjectCount, 8, 4, 9, 1);
871
872 // Remove all "Prime" content marks.
873 for (int i = 0; i < kExpectedObjectCount; ++i) {
874 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
875
876 int mark_count = FPDFPageObj_CountMarks(page_object);
877 for (int j = mark_count - 1; j >= 0; --j) {
878 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
879
880 char buffer[256];
881 unsigned long name_len = 999u;
882 ASSERT_TRUE(
883 FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
884 EXPECT_GT(name_len, 0u);
885 EXPECT_NE(999u, name_len);
886 std::wstring name =
887 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
888 if (name == L"Prime") {
889 // Remove mark.
890 EXPECT_TRUE(FPDFPageObj_RemoveMark(page_object, mark));
891
892 // Verify there is now one fewer mark in the page object.
893 EXPECT_EQ(mark_count - 1, FPDFPageObj_CountMarks(page_object));
894 }
895 }
896 }
897
898 // Verify there are 0 "Prime" content marks now.
899 CheckMarkCounts(page, 1, kExpectedObjectCount, 0, 4, 9, 1);
900
901 // Save the file.
902 EXPECT_TRUE(FPDFPage_GenerateContent(page));
903 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
904 UnloadPage(page);
905
906 // Re-open the file and check the prime marks are not there anymore.
907 ASSERT_TRUE(OpenSavedDocument());
908 FPDF_PAGE saved_page = LoadSavedPage(0);
909
910 CheckMarkCounts(saved_page, 1, kExpectedObjectCount, 0, 4, 9, 1);
911
912 CloseSavedPage(saved_page);
913 CloseSavedDocument();
914 }
915
TEST_F(FPDFEditEmbedderTest,RemoveMarkParam)916 TEST_F(FPDFEditEmbedderTest, RemoveMarkParam) {
917 // Load document with some text.
918 EXPECT_TRUE(OpenDocument("text_in_page_marked.pdf"));
919 FPDF_PAGE page = LoadPage(0);
920 ASSERT_TRUE(page);
921
922 constexpr int kExpectedObjectCount = 19;
923 CheckMarkCounts(page, 1, kExpectedObjectCount, 8, 4, 9, 1);
924
925 // Remove all "Square" content marks parameters.
926 for (int i = 0; i < kExpectedObjectCount; ++i) {
927 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
928
929 int mark_count = FPDFPageObj_CountMarks(page_object);
930 for (int j = 0; j < mark_count; ++j) {
931 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
932
933 char buffer[256];
934 unsigned long name_len = 999u;
935 ASSERT_TRUE(
936 FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
937 EXPECT_GT(name_len, 0u);
938 EXPECT_NE(999u, name_len);
939 std::wstring name =
940 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
941 if (name == L"Square") {
942 // Show the mark has a "Factor" parameter.
943 int out_value;
944 EXPECT_TRUE(
945 FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
946
947 // Remove parameter.
948 EXPECT_TRUE(FPDFPageObjMark_RemoveParam(page_object, mark, "Factor"));
949
950 // Verify the "Factor" parameter is gone.
951 EXPECT_FALSE(
952 FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
953 }
954 }
955 }
956
957 // Save the file.
958 EXPECT_TRUE(FPDFPage_GenerateContent(page));
959 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
960 UnloadPage(page);
961
962 // Re-open the file and check the "Factor" parameters are still gone.
963 ASSERT_TRUE(OpenSavedDocument());
964 FPDF_PAGE saved_page = LoadSavedPage(0);
965
966 size_t square_count = 0;
967 for (int i = 0; i < kExpectedObjectCount; ++i) {
968 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(saved_page, i);
969
970 int mark_count = FPDFPageObj_CountMarks(page_object);
971 for (int j = 0; j < mark_count; ++j) {
972 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
973
974 char buffer[256];
975 unsigned long name_len = 999u;
976 ASSERT_TRUE(
977 FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
978 EXPECT_GT(name_len, 0u);
979 EXPECT_NE(999u, name_len);
980 std::wstring name =
981 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
982 if (name == L"Square") {
983 // Verify the "Factor" parameter is still gone.
984 int out_value;
985 EXPECT_FALSE(
986 FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
987
988 ++square_count;
989 }
990 }
991 }
992
993 // Verify the parameters are gone, but the marks are not.
994 EXPECT_EQ(4u, square_count);
995
996 CloseSavedPage(saved_page);
997 CloseSavedDocument();
998 }
999
TEST_F(FPDFEditEmbedderTest,MaintainMarkedObjects)1000 TEST_F(FPDFEditEmbedderTest, MaintainMarkedObjects) {
1001 // Load document with some text.
1002 EXPECT_TRUE(OpenDocument("text_in_page_marked.pdf"));
1003 FPDF_PAGE page = LoadPage(0);
1004 ASSERT_TRUE(page);
1005
1006 // Iterate over all objects, counting the number of times each content mark
1007 // name appears.
1008 CheckMarkCounts(page, 1, 19, 8, 4, 9, 1);
1009
1010 // Remove first page object.
1011 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1012 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1013 FPDFPageObj_Destroy(page_object);
1014
1015 CheckMarkCounts(page, 2, 18, 8, 3, 9, 1);
1016
1017 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1018 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1019
1020 UnloadPage(page);
1021
1022 ASSERT_TRUE(OpenSavedDocument());
1023 FPDF_PAGE saved_page = LoadSavedPage(0);
1024
1025 CheckMarkCounts(saved_page, 2, 18, 8, 3, 9, 1);
1026
1027 CloseSavedPage(saved_page);
1028 CloseSavedDocument();
1029 }
1030
TEST_F(FPDFEditEmbedderTest,MaintainIndirectMarkedObjects)1031 TEST_F(FPDFEditEmbedderTest, MaintainIndirectMarkedObjects) {
1032 // Load document with some text.
1033 EXPECT_TRUE(OpenDocument("text_in_page_marked_indirect.pdf"));
1034 FPDF_PAGE page = LoadPage(0);
1035 ASSERT_TRUE(page);
1036
1037 // Iterate over all objects, counting the number of times each content mark
1038 // name appears.
1039 CheckMarkCounts(page, 1, 19, 8, 4, 9, 1);
1040
1041 // Remove first page object.
1042 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1043 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1044 FPDFPageObj_Destroy(page_object);
1045
1046 CheckMarkCounts(page, 2, 18, 8, 3, 9, 1);
1047
1048 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1049 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1050
1051 UnloadPage(page);
1052
1053 ASSERT_TRUE(OpenSavedDocument());
1054 FPDF_PAGE saved_page = LoadSavedPage(0);
1055
1056 CheckMarkCounts(saved_page, 2, 18, 8, 3, 9, 1);
1057
1058 CloseSavedPage(saved_page);
1059 CloseSavedDocument();
1060 }
1061
TEST_F(FPDFEditEmbedderTest,RemoveExistingPageObject)1062 TEST_F(FPDFEditEmbedderTest, RemoveExistingPageObject) {
1063 // Load document with some text.
1064 EXPECT_TRUE(OpenDocument("hello_world.pdf"));
1065 FPDF_PAGE page = LoadPage(0);
1066 ASSERT_TRUE(page);
1067
1068 // Get the "Hello, world!" text object and remove it.
1069 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1070 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1071 ASSERT_TRUE(page_object);
1072 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1073
1074 // Verify the "Hello, world!" text is gone.
1075 ASSERT_EQ(1, FPDFPage_CountObjects(page));
1076
1077 // Save the file
1078 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1079 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1080 UnloadPage(page);
1081 FPDFPageObj_Destroy(page_object);
1082
1083 // Re-open the file and check the page object count is still 1.
1084 ASSERT_TRUE(OpenSavedDocument());
1085 FPDF_PAGE saved_page = LoadSavedPage(0);
1086 EXPECT_EQ(1, FPDFPage_CountObjects(saved_page));
1087 CloseSavedPage(saved_page);
1088 CloseSavedDocument();
1089 }
1090
1091 // TODO(crbug.com/pdfium/11): Fix this test and enable.
1092 #if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
1093 #define MAYBE_RemoveExistingPageObjectSplitStreamsNotLonely \
1094 DISABLED_RemoveExistingPageObjectSplitStreamsNotLonely
1095 #else
1096 #define MAYBE_RemoveExistingPageObjectSplitStreamsNotLonely \
1097 RemoveExistingPageObjectSplitStreamsNotLonely
1098 #endif
TEST_F(FPDFEditEmbedderTest,MAYBE_RemoveExistingPageObjectSplitStreamsNotLonely)1099 TEST_F(FPDFEditEmbedderTest,
1100 MAYBE_RemoveExistingPageObjectSplitStreamsNotLonely) {
1101 // Load document with some text.
1102 EXPECT_TRUE(OpenDocument("hello_world_split_streams.pdf"));
1103 FPDF_PAGE page = LoadPage(0);
1104 ASSERT_TRUE(page);
1105
1106 // Get the "Hello, world!" text object and remove it. There is another object
1107 // in the same stream that says "Goodbye, world!"
1108 ASSERT_EQ(3, FPDFPage_CountObjects(page));
1109 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1110 ASSERT_TRUE(page_object);
1111 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1112
1113 // Verify the "Hello, world!" text is gone.
1114 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1115 #if defined(OS_MACOSX)
1116 const char kHelloRemovedMD5[] = "e07a62d412728fc4d6e3ff42f2dd0e11";
1117 #elif defined(OS_WIN)
1118 const char kHelloRemovedMD5[] = "a97d4c72c969ba373c2dce675d277e65";
1119 #else
1120 const char kHelloRemovedMD5[] = "95b92950647a2190e1230911e7a1a0e9";
1121 #endif
1122 {
1123 ScopedFPDFBitmap page_bitmap = RenderPage(page);
1124 CompareBitmap(page_bitmap.get(), 200, 200, kHelloRemovedMD5);
1125 }
1126
1127 // Save the file
1128 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1129 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1130 UnloadPage(page);
1131 FPDFPageObj_Destroy(page_object);
1132
1133 // Re-open the file and check the page object count is still 2.
1134 ASSERT_TRUE(OpenSavedDocument());
1135 FPDF_PAGE saved_page = LoadSavedPage(0);
1136
1137 EXPECT_EQ(2, FPDFPage_CountObjects(saved_page));
1138 {
1139 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
1140 CompareBitmap(page_bitmap.get(), 200, 200, kHelloRemovedMD5);
1141 }
1142
1143 CloseSavedPage(saved_page);
1144 CloseSavedDocument();
1145 }
1146
1147 // TODO(crbug.com/pdfium/11): Fix this test and enable.
1148 #if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
1149 #define MAYBE_RemoveExistingPageObjectSplitStreamsLonely \
1150 DISABLED_RemoveExistingPageObjectSplitStreamsLonely
1151 #else
1152 #define MAYBE_RemoveExistingPageObjectSplitStreamsLonely \
1153 RemoveExistingPageObjectSplitStreamsLonely
1154 #endif
TEST_F(FPDFEditEmbedderTest,MAYBE_RemoveExistingPageObjectSplitStreamsLonely)1155 TEST_F(FPDFEditEmbedderTest, MAYBE_RemoveExistingPageObjectSplitStreamsLonely) {
1156 // Load document with some text.
1157 EXPECT_TRUE(OpenDocument("hello_world_split_streams.pdf"));
1158 FPDF_PAGE page = LoadPage(0);
1159 ASSERT_TRUE(page);
1160
1161 // Get the "Greetings, world!" text object and remove it. This is the only
1162 // object in the stream.
1163 ASSERT_EQ(3, FPDFPage_CountObjects(page));
1164 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 2);
1165 ASSERT_TRUE(page_object);
1166 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1167
1168 // Verify the "Greetings, world!" text is gone.
1169 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1170 #if defined(OS_MACOSX)
1171 const char kGreetingsRemovedMD5[] = "b90475ca64d1348c3bf5e2b77ad9187a";
1172 #elif defined(OS_WIN)
1173 const char kGreetingsRemovedMD5[] = "795b7ce1626931aa06af0fa23b7d80bb";
1174 #else
1175 const char kGreetingsRemovedMD5[] = "2baa4c0e1758deba1b9c908e1fbd04ed";
1176 #endif
1177 {
1178 ScopedFPDFBitmap page_bitmap = RenderPage(page);
1179 CompareBitmap(page_bitmap.get(), 200, 200, kGreetingsRemovedMD5);
1180 }
1181
1182 // Save the file
1183 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1184 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1185 UnloadPage(page);
1186 FPDFPageObj_Destroy(page_object);
1187
1188 // Re-open the file and check the page object count is still 2.
1189 ASSERT_TRUE(OpenSavedDocument());
1190 FPDF_PAGE saved_page = LoadSavedPage(0);
1191
1192 EXPECT_EQ(2, FPDFPage_CountObjects(saved_page));
1193 {
1194 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
1195 CompareBitmap(page_bitmap.get(), 200, 200, kGreetingsRemovedMD5);
1196 }
1197
1198 CloseSavedPage(saved_page);
1199 CloseSavedDocument();
1200 }
1201
TEST_F(FPDFEditEmbedderTest,GetContentStream)1202 TEST_F(FPDFEditEmbedderTest, GetContentStream) {
1203 // Load document with some text split across streams.
1204 EXPECT_TRUE(OpenDocument("split_streams.pdf"));
1205 FPDF_PAGE page = LoadPage(0);
1206 ASSERT_TRUE(page);
1207
1208 // Content stream 0: page objects 0-14.
1209 // Content stream 1: page objects 15-17.
1210 // Content stream 2: page object 18.
1211 ASSERT_EQ(19, FPDFPage_CountObjects(page));
1212 for (int i = 0; i < 19; i++) {
1213 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1214 ASSERT_TRUE(page_object);
1215 CPDF_PageObject* cpdf_page_object =
1216 CPDFPageObjectFromFPDFPageObject(page_object);
1217 if (i < 15)
1218 EXPECT_EQ(0, cpdf_page_object->GetContentStream()) << i;
1219 else if (i < 18)
1220 EXPECT_EQ(1, cpdf_page_object->GetContentStream()) << i;
1221 else
1222 EXPECT_EQ(2, cpdf_page_object->GetContentStream()) << i;
1223 }
1224
1225 UnloadPage(page);
1226 }
1227
1228 // TODO(crbug.com/pdfium/11): Fix this test and enable.
1229 #if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
1230 #define MAYBE_RemoveAllFromStream DISABLED_RemoveAllFromStream
1231 #else
1232 #define MAYBE_RemoveAllFromStream RemoveAllFromStream
1233 #endif
TEST_F(FPDFEditEmbedderTest,MAYBE_RemoveAllFromStream)1234 TEST_F(FPDFEditEmbedderTest, MAYBE_RemoveAllFromStream) {
1235 // Load document with some text split across streams.
1236 EXPECT_TRUE(OpenDocument("split_streams.pdf"));
1237 FPDF_PAGE page = LoadPage(0);
1238 ASSERT_TRUE(page);
1239
1240 // Content stream 0: page objects 0-14.
1241 // Content stream 1: page objects 15-17.
1242 // Content stream 2: page object 18.
1243 ASSERT_EQ(19, FPDFPage_CountObjects(page));
1244
1245 // Loop backwards because objects will being removed, which shifts the indexes
1246 // after the removed position.
1247 for (int i = 18; i >= 0; i--) {
1248 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1249 ASSERT_TRUE(page_object);
1250 CPDF_PageObject* cpdf_page_object =
1251 CPDFPageObjectFromFPDFPageObject(page_object);
1252
1253 // Empty content stream 1.
1254 if (cpdf_page_object->GetContentStream() == 1) {
1255 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1256 FPDFPageObj_Destroy(page_object);
1257 }
1258 }
1259
1260 // Content stream 0: page objects 0-14.
1261 // Content stream 2: page object 15.
1262 ASSERT_EQ(16, FPDFPage_CountObjects(page));
1263 for (int i = 0; i < 16; i++) {
1264 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1265 ASSERT_TRUE(page_object);
1266 CPDF_PageObject* cpdf_page_object =
1267 CPDFPageObjectFromFPDFPageObject(page_object);
1268 if (i < 15)
1269 EXPECT_EQ(0, cpdf_page_object->GetContentStream()) << i;
1270 else
1271 EXPECT_EQ(2, cpdf_page_object->GetContentStream()) << i;
1272 }
1273
1274 // Generate contents should remove the empty stream and update the page
1275 // objects' contents stream indexes.
1276 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1277
1278 // Content stream 0: page objects 0-14.
1279 // Content stream 1: page object 15.
1280 ASSERT_EQ(16, FPDFPage_CountObjects(page));
1281 for (int i = 0; i < 16; i++) {
1282 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1283 ASSERT_TRUE(page_object);
1284 CPDF_PageObject* cpdf_page_object =
1285 CPDFPageObjectFromFPDFPageObject(page_object);
1286 if (i < 15)
1287 EXPECT_EQ(0, cpdf_page_object->GetContentStream()) << i;
1288 else
1289 EXPECT_EQ(1, cpdf_page_object->GetContentStream()) << i;
1290 }
1291
1292 #if defined(OS_MACOSX)
1293 const char kStream1RemovedMD5[] = "d2e21fbd5a6de563f619feeeb6163331";
1294 #elif defined(OS_WIN)
1295 const char kStream1RemovedMD5[] = "b4140f203523e38793283a5943d8075b";
1296 #else
1297 const char kStream1RemovedMD5[] = "e86a3efc160ede6cfcb1f59bcacf1105";
1298 #endif
1299 {
1300 ScopedFPDFBitmap page_bitmap = RenderPage(page);
1301 CompareBitmap(page_bitmap.get(), 200, 200, kStream1RemovedMD5);
1302 }
1303
1304 // Save the file
1305 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1306 UnloadPage(page);
1307
1308 // Re-open the file and check the page object count is still 16, and that
1309 // content stream 1 was removed.
1310 ASSERT_TRUE(OpenSavedDocument());
1311 FPDF_PAGE saved_page = LoadSavedPage(0);
1312
1313 // Content stream 0: page objects 0-14.
1314 // Content stream 1: page object 15.
1315 EXPECT_EQ(16, FPDFPage_CountObjects(saved_page));
1316 for (int i = 0; i < 16; i++) {
1317 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(saved_page, i);
1318 ASSERT_TRUE(page_object);
1319 CPDF_PageObject* cpdf_page_object =
1320 CPDFPageObjectFromFPDFPageObject(page_object);
1321 if (i < 15)
1322 EXPECT_EQ(0, cpdf_page_object->GetContentStream()) << i;
1323 else
1324 EXPECT_EQ(1, cpdf_page_object->GetContentStream()) << i;
1325 }
1326
1327 {
1328 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
1329 CompareBitmap(page_bitmap.get(), 200, 200, kStream1RemovedMD5);
1330 }
1331
1332 CloseSavedPage(saved_page);
1333 CloseSavedDocument();
1334 }
1335
TEST_F(FPDFEditEmbedderTest,RemoveAllFromSingleStream)1336 TEST_F(FPDFEditEmbedderTest, RemoveAllFromSingleStream) {
1337 // Load document with a single stream.
1338 EXPECT_TRUE(OpenDocument("hello_world.pdf"));
1339 FPDF_PAGE page = LoadPage(0);
1340 ASSERT_TRUE(page);
1341
1342 // Content stream 0: page objects 0-1.
1343 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1344
1345 // Loop backwards because objects will being removed, which shifts the indexes
1346 // after the removed position.
1347 for (int i = 1; i >= 0; i--) {
1348 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1349 ASSERT_TRUE(page_object);
1350 CPDF_PageObject* cpdf_page_object =
1351 CPDFPageObjectFromFPDFPageObject(page_object);
1352 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1353 ASSERT_TRUE(FPDFPage_RemoveObject(page, page_object));
1354 FPDFPageObj_Destroy(page_object);
1355 }
1356
1357 // No more objects in the stream
1358 ASSERT_EQ(0, FPDFPage_CountObjects(page));
1359
1360 // Generate contents should remove the empty stream and update the page
1361 // objects' contents stream indexes.
1362 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1363
1364 ASSERT_EQ(0, FPDFPage_CountObjects(page));
1365
1366 const char kAllRemovedMD5[] = "eee4600ac08b458ac7ac2320e225674c";
1367 {
1368 ScopedFPDFBitmap page_bitmap = RenderPage(page);
1369 CompareBitmap(page_bitmap.get(), 200, 200, kAllRemovedMD5);
1370 }
1371
1372 // Save the file
1373 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1374 UnloadPage(page);
1375
1376 // Re-open the file and check the page object count is still 0.
1377 ASSERT_TRUE(OpenSavedDocument());
1378 FPDF_PAGE saved_page = LoadSavedPage(0);
1379
1380 EXPECT_EQ(0, FPDFPage_CountObjects(saved_page));
1381 {
1382 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
1383 CompareBitmap(page_bitmap.get(), 200, 200, kAllRemovedMD5);
1384 }
1385
1386 CloseSavedPage(saved_page);
1387 CloseSavedDocument();
1388 }
1389
1390 // TODO(crbug.com/pdfium/11): Fix this test and enable.
1391 #if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
1392 #define MAYBE_RemoveFirstFromSingleStream DISABLED_RemoveFirstFromSingleStream
1393 #else
1394 #define MAYBE_RemoveFirstFromSingleStream RemoveFirstFromSingleStream
1395 #endif
TEST_F(FPDFEditEmbedderTest,MAYBE_RemoveFirstFromSingleStream)1396 TEST_F(FPDFEditEmbedderTest, MAYBE_RemoveFirstFromSingleStream) {
1397 // Load document with a single stream.
1398 EXPECT_TRUE(OpenDocument("hello_world.pdf"));
1399 FPDF_PAGE page = LoadPage(0);
1400 ASSERT_TRUE(page);
1401
1402 // Content stream 0: page objects 0-1.
1403 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1404
1405 // Remove first object.
1406 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1407 ASSERT_TRUE(page_object);
1408 CPDF_PageObject* cpdf_page_object =
1409 CPDFPageObjectFromFPDFPageObject(page_object);
1410 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1411 ASSERT_TRUE(FPDFPage_RemoveObject(page, page_object));
1412 FPDFPageObj_Destroy(page_object);
1413
1414 // One object left in the stream.
1415 ASSERT_EQ(1, FPDFPage_CountObjects(page));
1416 page_object = FPDFPage_GetObject(page, 0);
1417 ASSERT_TRUE(page_object);
1418 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1419 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1420
1421 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1422
1423 // Still one object left in the stream.
1424 ASSERT_EQ(1, FPDFPage_CountObjects(page));
1425 page_object = FPDFPage_GetObject(page, 0);
1426 ASSERT_TRUE(page_object);
1427 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1428 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1429
1430 #if defined(OS_MACOSX)
1431 const char kFirstRemovedMD5[] = "af760c4702467cb1492a57fb8215efaa";
1432 #elif defined(OS_WIN)
1433 const char kFirstRemovedMD5[] = "aae6c5334721f90ec30d3d59f4ef7deb";
1434 #else
1435 const char kFirstRemovedMD5[] = "b76df015fe88009c3c342395df96abf1";
1436 #endif
1437 {
1438 ScopedFPDFBitmap page_bitmap = RenderPage(page);
1439 CompareBitmap(page_bitmap.get(), 200, 200, kFirstRemovedMD5);
1440 }
1441
1442 // Save the file
1443 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1444 UnloadPage(page);
1445
1446 // Re-open the file and check the page object count is still 0.
1447 ASSERT_TRUE(OpenSavedDocument());
1448 FPDF_PAGE saved_page = LoadSavedPage(0);
1449
1450 ASSERT_EQ(1, FPDFPage_CountObjects(saved_page));
1451 page_object = FPDFPage_GetObject(saved_page, 0);
1452 ASSERT_TRUE(page_object);
1453 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1454 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1455 {
1456 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
1457 CompareBitmap(page_bitmap.get(), 200, 200, kFirstRemovedMD5);
1458 }
1459
1460 CloseSavedPage(saved_page);
1461 CloseSavedDocument();
1462 }
1463
1464 // TODO(crbug.com/pdfium/11): Fix this test and enable.
1465 #if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
1466 #define MAYBE_RemoveLastFromSingleStream DISABLED_RemoveLastFromSingleStream
1467 #else
1468 #define MAYBE_RemoveLastFromSingleStream RemoveLastFromSingleStream
1469 #endif
TEST_F(FPDFEditEmbedderTest,MAYBE_RemoveLastFromSingleStream)1470 TEST_F(FPDFEditEmbedderTest, MAYBE_RemoveLastFromSingleStream) {
1471 // Load document with a single stream.
1472 EXPECT_TRUE(OpenDocument("hello_world.pdf"));
1473 FPDF_PAGE page = LoadPage(0);
1474 ASSERT_TRUE(page);
1475
1476 // Content stream 0: page objects 0-1.
1477 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1478
1479 // Remove last object
1480 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 1);
1481 ASSERT_TRUE(page_object);
1482 CPDF_PageObject* cpdf_page_object =
1483 CPDFPageObjectFromFPDFPageObject(page_object);
1484 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1485 ASSERT_TRUE(FPDFPage_RemoveObject(page, page_object));
1486 FPDFPageObj_Destroy(page_object);
1487
1488 // One object left in the stream.
1489 ASSERT_EQ(1, FPDFPage_CountObjects(page));
1490 page_object = FPDFPage_GetObject(page, 0);
1491 ASSERT_TRUE(page_object);
1492 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1493 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1494
1495 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1496
1497 // Still one object left in the stream.
1498 ASSERT_EQ(1, FPDFPage_CountObjects(page));
1499 page_object = FPDFPage_GetObject(page, 0);
1500 ASSERT_TRUE(page_object);
1501 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1502 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1503
1504 #if defined(OS_MACOSX)
1505 const char kLastRemovedMD5[] = "f8fbd14a048b9e2ea8e5f059f22a910e";
1506 #elif defined(OS_WIN)
1507 const char kLastRemovedMD5[] = "93db13099042bafefb3c22a165bad684";
1508 #else
1509 const char kLastRemovedMD5[] = "93dcc09055f87a2792c8e3065af99a1b";
1510 #endif
1511 {
1512 ScopedFPDFBitmap page_bitmap = RenderPage(page);
1513 CompareBitmap(page_bitmap.get(), 200, 200, kLastRemovedMD5);
1514 }
1515
1516 // Save the file
1517 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1518 UnloadPage(page);
1519
1520 // Re-open the file and check the page object count is still 0.
1521 ASSERT_TRUE(OpenSavedDocument());
1522 FPDF_PAGE saved_page = LoadSavedPage(0);
1523
1524 ASSERT_EQ(1, FPDFPage_CountObjects(saved_page));
1525 page_object = FPDFPage_GetObject(saved_page, 0);
1526 ASSERT_TRUE(page_object);
1527 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1528 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1529 {
1530 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
1531 CompareBitmap(page_bitmap.get(), 200, 200, kLastRemovedMD5);
1532 }
1533
1534 CloseSavedPage(saved_page);
1535 CloseSavedDocument();
1536 }
1537
TEST_F(FPDFEditEmbedderTest,RemoveAllFromMultipleStreams)1538 TEST_F(FPDFEditEmbedderTest, RemoveAllFromMultipleStreams) {
1539 // Load document with some text.
1540 EXPECT_TRUE(OpenDocument("hello_world_split_streams.pdf"));
1541 FPDF_PAGE page = LoadPage(0);
1542 ASSERT_TRUE(page);
1543
1544 // Content stream 0: page objects 0-1.
1545 // Content stream 1: page object 2.
1546 ASSERT_EQ(3, FPDFPage_CountObjects(page));
1547
1548 // Loop backwards because objects will being removed, which shifts the indexes
1549 // after the removed position.
1550 for (int i = 2; i >= 0; i--) {
1551 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1552 ASSERT_TRUE(page_object);
1553 ASSERT_TRUE(FPDFPage_RemoveObject(page, page_object));
1554 FPDFPageObj_Destroy(page_object);
1555 }
1556
1557 // No more objects in the page.
1558 ASSERT_EQ(0, FPDFPage_CountObjects(page));
1559
1560 // Generate contents should remove the empty streams and update the page
1561 // objects' contents stream indexes.
1562 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1563
1564 ASSERT_EQ(0, FPDFPage_CountObjects(page));
1565
1566 const char kAllRemovedMD5[] = "eee4600ac08b458ac7ac2320e225674c";
1567 {
1568 ScopedFPDFBitmap page_bitmap = RenderPage(page);
1569 CompareBitmap(page_bitmap.get(), 200, 200, kAllRemovedMD5);
1570 }
1571
1572 // Save the file
1573 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1574 UnloadPage(page);
1575
1576 // Re-open the file and check the page object count is still 0.
1577 ASSERT_TRUE(OpenSavedDocument());
1578 FPDF_PAGE saved_page = LoadSavedPage(0);
1579
1580 EXPECT_EQ(0, FPDFPage_CountObjects(saved_page));
1581 {
1582 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
1583 CompareBitmap(page_bitmap.get(), 200, 200, kAllRemovedMD5);
1584 }
1585
1586 CloseSavedPage(saved_page);
1587 CloseSavedDocument();
1588 }
1589
TEST_F(FPDFEditEmbedderTest,InsertPageObjectAndSave)1590 TEST_F(FPDFEditEmbedderTest, InsertPageObjectAndSave) {
1591 // Load document with some text.
1592 EXPECT_TRUE(OpenDocument("hello_world.pdf"));
1593 FPDF_PAGE page = LoadPage(0);
1594 ASSERT_TRUE(page);
1595
1596 // Add a red rectangle.
1597 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1598 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
1599 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
1600 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
1601 FPDFPage_InsertObject(page, red_rect);
1602
1603 // Verify the red rectangle was added.
1604 ASSERT_EQ(3, FPDFPage_CountObjects(page));
1605
1606 // Save the file
1607 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1608 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1609 UnloadPage(page);
1610
1611 // Re-open the file and check the page object count is still 3.
1612 ASSERT_TRUE(OpenSavedDocument());
1613 FPDF_PAGE saved_page = LoadSavedPage(0);
1614 EXPECT_EQ(3, FPDFPage_CountObjects(saved_page));
1615 CloseSavedPage(saved_page);
1616 CloseSavedDocument();
1617 }
1618
TEST_F(FPDFEditEmbedderTest,InsertPageObjectEditAndSave)1619 TEST_F(FPDFEditEmbedderTest, InsertPageObjectEditAndSave) {
1620 // Load document with some text.
1621 EXPECT_TRUE(OpenDocument("hello_world.pdf"));
1622 FPDF_PAGE page = LoadPage(0);
1623 ASSERT_TRUE(page);
1624
1625 // Add a red rectangle.
1626 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1627 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
1628 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 100, 100, 255));
1629 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
1630 FPDFPage_InsertObject(page, red_rect);
1631
1632 // Verify the red rectangle was added.
1633 ASSERT_EQ(3, FPDFPage_CountObjects(page));
1634
1635 // Generate content but change it again
1636 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1637 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
1638
1639 // Save the file
1640 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1641 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1642 UnloadPage(page);
1643
1644 // Re-open the file and check the page object count is still 3.
1645 ASSERT_TRUE(OpenSavedDocument());
1646 FPDF_PAGE saved_page = LoadSavedPage(0);
1647 EXPECT_EQ(3, FPDFPage_CountObjects(saved_page));
1648 CloseSavedPage(saved_page);
1649 CloseSavedDocument();
1650 }
1651
1652 // TODO(crbug.com/pdfium/11): Fix this test and enable.
1653 #if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
1654 #define MAYBE_InsertAndRemoveLargeFile DISABLED_InsertAndRemoveLargeFile
1655 #else
1656 #define MAYBE_InsertAndRemoveLargeFile InsertAndRemoveLargeFile
1657 #endif
TEST_F(FPDFEditEmbedderTest,MAYBE_InsertAndRemoveLargeFile)1658 TEST_F(FPDFEditEmbedderTest, MAYBE_InsertAndRemoveLargeFile) {
1659 const int kOriginalObjectCount = 600;
1660
1661 // Load document with many objects.
1662 EXPECT_TRUE(OpenDocument("many_rectangles.pdf"));
1663 FPDF_PAGE page = LoadPage(0);
1664 ASSERT_TRUE(page);
1665 const char kOriginalMD5[] = "b0170c575b65ecb93ebafada0ff0f038";
1666 {
1667 ScopedFPDFBitmap page_bitmap = RenderPage(page);
1668 CompareBitmap(page_bitmap.get(), 200, 300, kOriginalMD5);
1669 }
1670
1671 // Add a black rectangle.
1672 ASSERT_EQ(kOriginalObjectCount, FPDFPage_CountObjects(page));
1673 FPDF_PAGEOBJECT black_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
1674 EXPECT_TRUE(FPDFPageObj_SetFillColor(black_rect, 0, 0, 0, 255));
1675 EXPECT_TRUE(FPDFPath_SetDrawMode(black_rect, FPDF_FILLMODE_ALTERNATE, 0));
1676 FPDFPage_InsertObject(page, black_rect);
1677
1678 // Verify the black rectangle was added.
1679 ASSERT_EQ(kOriginalObjectCount + 1, FPDFPage_CountObjects(page));
1680 const char kPlusRectangleMD5[] = "6b9396ab570754b32b04ca629e902f77";
1681 {
1682 ScopedFPDFBitmap page_bitmap = RenderPage(page);
1683 CompareBitmap(page_bitmap.get(), 200, 300, kPlusRectangleMD5);
1684 }
1685
1686 // Save the file.
1687 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1688 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1689 UnloadPage(page);
1690
1691 // Re-open the file and check the rectangle added is still there.
1692 ASSERT_TRUE(OpenSavedDocument());
1693 FPDF_PAGE saved_page = LoadSavedPage(0);
1694 EXPECT_EQ(kOriginalObjectCount + 1, FPDFPage_CountObjects(saved_page));
1695 {
1696 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
1697 CompareBitmap(page_bitmap.get(), 200, 300, kPlusRectangleMD5);
1698 }
1699
1700 // Remove the added rectangle.
1701 FPDF_PAGEOBJECT added_object =
1702 FPDFPage_GetObject(saved_page, kOriginalObjectCount);
1703 EXPECT_TRUE(FPDFPage_RemoveObject(saved_page, added_object));
1704 FPDFPageObj_Destroy(added_object);
1705 {
1706 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
1707 CompareBitmap(page_bitmap.get(), 200, 300, kOriginalMD5);
1708 }
1709 EXPECT_EQ(kOriginalObjectCount, FPDFPage_CountObjects(saved_page));
1710
1711 // Save the file again.
1712 EXPECT_TRUE(FPDFPage_GenerateContent(saved_page));
1713 EXPECT_TRUE(FPDF_SaveAsCopy(saved_document_, this, 0));
1714
1715 CloseSavedPage(saved_page);
1716 CloseSavedDocument();
1717
1718 // Re-open the file (again) and check the black rectangle was removed and the
1719 // rest is intact.
1720 ASSERT_TRUE(OpenSavedDocument());
1721 saved_page = LoadSavedPage(0);
1722 EXPECT_EQ(kOriginalObjectCount, FPDFPage_CountObjects(saved_page));
1723 {
1724 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
1725 CompareBitmap(page_bitmap.get(), 200, 300, kOriginalMD5);
1726 }
1727
1728 CloseSavedPage(saved_page);
1729 CloseSavedDocument();
1730 }
1731
TEST_F(FPDFEditEmbedderTest,AddAndRemovePaths)1732 TEST_F(FPDFEditEmbedderTest, AddAndRemovePaths) {
1733 // Start with a blank page.
1734 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
1735 ASSERT_TRUE(page);
1736
1737 // Render the blank page and verify it's a blank bitmap.
1738 const char kBlankMD5[] = "1940568c9ba33bac5d0b1ee9558c76b3";
1739 {
1740 ScopedFPDFBitmap page_bitmap = RenderPage(page);
1741 CompareBitmap(page_bitmap.get(), 612, 792, kBlankMD5);
1742 }
1743 ASSERT_EQ(0, FPDFPage_CountObjects(page));
1744
1745 // Add a red rectangle.
1746 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(10, 10, 20, 20);
1747 ASSERT_TRUE(red_rect);
1748 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
1749 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
1750 FPDFPage_InsertObject(page, red_rect);
1751 const char kRedRectangleMD5[] = "66d02eaa6181e2c069ce2ea99beda497";
1752 {
1753 ScopedFPDFBitmap page_bitmap = RenderPage(page);
1754 CompareBitmap(page_bitmap.get(), 612, 792, kRedRectangleMD5);
1755 }
1756 EXPECT_EQ(1, FPDFPage_CountObjects(page));
1757
1758 // Remove rectangle and verify it does not render anymore and the bitmap is
1759 // back to a blank one.
1760 EXPECT_TRUE(FPDFPage_RemoveObject(page, red_rect));
1761 {
1762 ScopedFPDFBitmap page_bitmap = RenderPage(page);
1763 CompareBitmap(page_bitmap.get(), 612, 792, kBlankMD5);
1764 }
1765 EXPECT_EQ(0, FPDFPage_CountObjects(page));
1766
1767 // Trying to remove an object not in the page should return false.
1768 EXPECT_FALSE(FPDFPage_RemoveObject(page, red_rect));
1769
1770 FPDF_ClosePage(page);
1771 FPDFPageObj_Destroy(red_rect);
1772 }
1773
TEST_F(FPDFEditEmbedderTest,PathsPoints)1774 TEST_F(FPDFEditEmbedderTest, PathsPoints) {
1775 CreateNewDocument();
1776 FPDF_PAGEOBJECT img = FPDFPageObj_NewImageObj(document_);
1777 // This should fail gracefully, even if img is not a path.
1778 ASSERT_EQ(-1, FPDFPath_CountSegments(img));
1779
1780 // This should fail gracefully, even if path is NULL.
1781 ASSERT_EQ(-1, FPDFPath_CountSegments(nullptr));
1782
1783 // FPDFPath_GetPathSegment() with a non-path.
1784 ASSERT_EQ(nullptr, FPDFPath_GetPathSegment(img, 0));
1785 // FPDFPath_GetPathSegment() with a NULL path.
1786 ASSERT_EQ(nullptr, FPDFPath_GetPathSegment(nullptr, 0));
1787 float x;
1788 float y;
1789 // FPDFPathSegment_GetPoint() with a NULL segment.
1790 EXPECT_FALSE(FPDFPathSegment_GetPoint(nullptr, &x, &y));
1791
1792 // FPDFPathSegment_GetType() with a NULL segment.
1793 ASSERT_EQ(FPDF_SEGMENT_UNKNOWN, FPDFPathSegment_GetType(nullptr));
1794
1795 // FPDFPathSegment_GetClose() with a NULL segment.
1796 EXPECT_FALSE(FPDFPathSegment_GetClose(nullptr));
1797
1798 FPDFPageObj_Destroy(img);
1799 }
1800
1801 // TODO(crbug.com/pdfium/11): Fix this test and enable.
1802 #if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
1803 #define MAYBE_PathOnTopOfText DISABLED_PathOnTopOfText
1804 #else
1805 #define MAYBE_PathOnTopOfText PathOnTopOfText
1806 #endif
TEST_F(FPDFEditEmbedderTest,MAYBE_PathOnTopOfText)1807 TEST_F(FPDFEditEmbedderTest, MAYBE_PathOnTopOfText) {
1808 // Load document with some text
1809 EXPECT_TRUE(OpenDocument("hello_world.pdf"));
1810 FPDF_PAGE page = LoadPage(0);
1811 ASSERT_TRUE(page);
1812
1813 // Add an opaque rectangle on top of some of the text.
1814 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
1815 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
1816 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
1817 FPDFPage_InsertObject(page, red_rect);
1818
1819 // Add a transparent triangle on top of other part of the text.
1820 FPDF_PAGEOBJECT black_path = FPDFPageObj_CreateNewPath(20, 50);
1821 EXPECT_TRUE(FPDFPageObj_SetFillColor(black_path, 0, 0, 0, 100));
1822 EXPECT_TRUE(FPDFPath_SetDrawMode(black_path, FPDF_FILLMODE_ALTERNATE, 0));
1823 EXPECT_TRUE(FPDFPath_LineTo(black_path, 30, 80));
1824 EXPECT_TRUE(FPDFPath_LineTo(black_path, 40, 10));
1825 EXPECT_TRUE(FPDFPath_Close(black_path));
1826 FPDFPage_InsertObject(page, black_path);
1827
1828 // Render and check the result. Text is slightly different on Mac.
1829 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
1830 #if defined(OS_MACOSX)
1831 const char md5[] = "f9e6fa74230f234286bfcada9f7606d8";
1832 #elif defined(OS_WIN)
1833 const char md5[] = "74dd9c393b8b2578d2b7feb032b7daad";
1834 #else
1835 const char md5[] = "aa71b09b93b55f467f1290e5111babee";
1836 #endif
1837 CompareBitmap(bitmap.get(), 200, 200, md5);
1838 UnloadPage(page);
1839 }
1840
1841 // TODO(crbug.com/pdfium/11): Fix this test and enable.
1842 #if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
1843 #define MAYBE_EditOverExistingContent DISABLED_EditOverExistingContent
1844 #else
1845 #define MAYBE_EditOverExistingContent EditOverExistingContent
1846 #endif
TEST_F(FPDFEditEmbedderTest,MAYBE_EditOverExistingContent)1847 TEST_F(FPDFEditEmbedderTest, MAYBE_EditOverExistingContent) {
1848 // Load document with existing content
1849 EXPECT_TRUE(OpenDocument("bug_717.pdf"));
1850 FPDF_PAGE page = LoadPage(0);
1851 ASSERT_TRUE(page);
1852
1853 // Add a transparent rectangle on top of the existing content
1854 FPDF_PAGEOBJECT red_rect2 = FPDFPageObj_CreateNewRect(90, 700, 25, 50);
1855 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect2, 255, 0, 0, 100));
1856 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect2, FPDF_FILLMODE_ALTERNATE, 0));
1857 FPDFPage_InsertObject(page, red_rect2);
1858
1859 // Add an opaque rectangle on top of the existing content
1860 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(115, 700, 25, 50);
1861 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
1862 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
1863 FPDFPage_InsertObject(page, red_rect);
1864
1865 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
1866 CompareBitmap(bitmap.get(), 612, 792, "ad04e5bd0f471a9a564fb034bd0fb073");
1867 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1868
1869 // Now save the result, closing the page and document
1870 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1871 UnloadPage(page);
1872
1873 ASSERT_TRUE(OpenSavedDocument());
1874 FPDF_PAGE saved_page = LoadSavedPage(0);
1875 VerifySavedRendering(saved_page, 612, 792,
1876 "ad04e5bd0f471a9a564fb034bd0fb073");
1877
1878 ClearString();
1879 // Add another opaque rectangle on top of the existing content
1880 FPDF_PAGEOBJECT green_rect = FPDFPageObj_CreateNewRect(150, 700, 25, 50);
1881 EXPECT_TRUE(FPDFPageObj_SetFillColor(green_rect, 0, 255, 0, 255));
1882 EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect, FPDF_FILLMODE_ALTERNATE, 0));
1883 FPDFPage_InsertObject(saved_page, green_rect);
1884
1885 // Add another transparent rectangle on top of existing content
1886 FPDF_PAGEOBJECT green_rect2 = FPDFPageObj_CreateNewRect(175, 700, 25, 50);
1887 EXPECT_TRUE(FPDFPageObj_SetFillColor(green_rect2, 0, 255, 0, 100));
1888 EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect2, FPDF_FILLMODE_ALTERNATE, 0));
1889 FPDFPage_InsertObject(saved_page, green_rect2);
1890 const char kLastMD5[] = "4b5b00f824620f8c9b8801ebb98e1cdd";
1891 {
1892 ScopedFPDFBitmap new_bitmap = RenderSavedPage(saved_page);
1893 CompareBitmap(new_bitmap.get(), 612, 792, kLastMD5);
1894 }
1895 EXPECT_TRUE(FPDFPage_GenerateContent(saved_page));
1896
1897 // Now save the result, closing the page and document
1898 EXPECT_TRUE(FPDF_SaveAsCopy(saved_document_, this, 0));
1899
1900 CloseSavedPage(saved_page);
1901 CloseSavedDocument();
1902
1903 // Render the saved result
1904 VerifySavedDocument(612, 792, kLastMD5);
1905 }
1906
1907 // TODO(crbug.com/pdfium/11): Fix this test and enable.
1908 #if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
1909 #define MAYBE_AddStrokedPaths DISABLED_AddStrokedPaths
1910 #else
1911 #define MAYBE_AddStrokedPaths AddStrokedPaths
1912 #endif
TEST_F(FPDFEditEmbedderTest,MAYBE_AddStrokedPaths)1913 TEST_F(FPDFEditEmbedderTest, MAYBE_AddStrokedPaths) {
1914 // Start with a blank page
1915 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
1916
1917 // Add a large stroked rectangle (fill color should not affect it).
1918 FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(20, 20, 200, 400);
1919 EXPECT_TRUE(FPDFPageObj_SetFillColor(rect, 255, 0, 0, 255));
1920 EXPECT_TRUE(FPDFPageObj_SetStrokeColor(rect, 0, 255, 0, 255));
1921 EXPECT_TRUE(FPDFPageObj_SetStrokeWidth(rect, 15.0f));
1922
1923 float width = 0;
1924 EXPECT_TRUE(FPDFPageObj_GetStrokeWidth(rect, &width));
1925 EXPECT_EQ(15.0f, width);
1926
1927 EXPECT_TRUE(FPDFPath_SetDrawMode(rect, 0, 1));
1928 FPDFPage_InsertObject(page, rect);
1929 {
1930 ScopedFPDFBitmap page_bitmap = RenderPage(page);
1931 CompareBitmap(page_bitmap.get(), 612, 792,
1932 "64bd31f862a89e0a9e505a5af6efd506");
1933 }
1934
1935 // Add crossed-checkmark
1936 FPDF_PAGEOBJECT check = FPDFPageObj_CreateNewPath(300, 500);
1937 EXPECT_TRUE(FPDFPath_LineTo(check, 400, 400));
1938 EXPECT_TRUE(FPDFPath_LineTo(check, 600, 600));
1939 EXPECT_TRUE(FPDFPath_MoveTo(check, 400, 600));
1940 EXPECT_TRUE(FPDFPath_LineTo(check, 600, 400));
1941 EXPECT_TRUE(FPDFPageObj_SetStrokeColor(check, 128, 128, 128, 180));
1942 EXPECT_TRUE(FPDFPageObj_SetStrokeWidth(check, 8.35f));
1943 EXPECT_TRUE(FPDFPath_SetDrawMode(check, 0, 1));
1944 FPDFPage_InsertObject(page, check);
1945 {
1946 ScopedFPDFBitmap page_bitmap = RenderPage(page);
1947 CompareBitmap(page_bitmap.get(), 612, 792,
1948 "4b6f3b9d25c4e194821217d5016c3724");
1949 }
1950
1951 // Add stroked and filled oval-ish path.
1952 FPDF_PAGEOBJECT path = FPDFPageObj_CreateNewPath(250, 100);
1953 EXPECT_TRUE(FPDFPath_BezierTo(path, 180, 166, 180, 233, 250, 300));
1954 EXPECT_TRUE(FPDFPath_LineTo(path, 255, 305));
1955 EXPECT_TRUE(FPDFPath_BezierTo(path, 325, 233, 325, 166, 255, 105));
1956 EXPECT_TRUE(FPDFPath_Close(path));
1957 EXPECT_TRUE(FPDFPageObj_SetFillColor(path, 200, 128, 128, 100));
1958 EXPECT_TRUE(FPDFPageObj_SetStrokeColor(path, 128, 200, 128, 150));
1959 EXPECT_TRUE(FPDFPageObj_SetStrokeWidth(path, 10.5f));
1960 EXPECT_TRUE(FPDFPath_SetDrawMode(path, FPDF_FILLMODE_ALTERNATE, 1));
1961 FPDFPage_InsertObject(page, path);
1962 {
1963 ScopedFPDFBitmap page_bitmap = RenderPage(page);
1964 CompareBitmap(page_bitmap.get(), 612, 792,
1965 "ff3e6a22326754944cc6e56609acd73b");
1966 }
1967 FPDF_ClosePage(page);
1968 }
1969
1970 // Tests adding text from standard font using FPDFPageObj_NewTextObj.
1971 // TODO(crbug.com/pdfium/11): Fix this test and enable.
1972 #if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
1973 #define MAYBE_AddStandardFontText DISABLED_AddStandardFontText
1974 #else
1975 #define MAYBE_AddStandardFontText AddStandardFontText
1976 #endif
TEST_F(FPDFEditEmbedderTest,MAYBE_AddStandardFontText)1977 TEST_F(FPDFEditEmbedderTest, MAYBE_AddStandardFontText) {
1978 // Start with a blank page
1979 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
1980
1981 // Add some text to the page
1982 FPDF_PAGEOBJECT text_object1 =
1983 FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
1984 EXPECT_TRUE(text_object1);
1985 ScopedFPDFWideString text1 =
1986 GetFPDFWideString(L"I'm at the bottom of the page");
1987 EXPECT_TRUE(FPDFText_SetText(text_object1, text1.get()));
1988 FPDFPageObj_Transform(text_object1, 1, 0, 0, 1, 20, 20);
1989 FPDFPage_InsertObject(page, text_object1);
1990 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1991 {
1992 ScopedFPDFBitmap page_bitmap = RenderPage(page);
1993 #if defined(OS_MACOSX)
1994 const char md5[] = "a4dddc1a3930fa694bbff9789dab4161";
1995 #elif defined(OS_WIN)
1996 const char md5[] = "08d1ff3e5a42801bee6077fd366bef00";
1997 #else
1998 const char md5[] = "eacaa24573b8ce997b3882595f096f00";
1999 #endif
2000 CompareBitmap(page_bitmap.get(), 612, 792, md5);
2001
2002 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2003 VerifySavedDocument(612, 792, md5);
2004 }
2005
2006 // Try another font
2007 FPDF_PAGEOBJECT text_object2 =
2008 FPDFPageObj_NewTextObj(document(), "TimesNewRomanBold", 15.0f);
2009 EXPECT_TRUE(text_object2);
2010 ScopedFPDFWideString text2 =
2011 GetFPDFWideString(L"Hi, I'm Bold. Times New Roman Bold.");
2012 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
2013 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 100, 600);
2014 FPDFPage_InsertObject(page, text_object2);
2015 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2016 {
2017 ScopedFPDFBitmap page_bitmap = RenderPage(page);
2018 #if defined(OS_MACOSX)
2019 const char md5[] = "a5c4ace4c6f27644094813fe1441a21c";
2020 #elif defined(OS_WIN)
2021 const char md5[] = "3755dd35abd4c605755369401ee85b2d";
2022 #else
2023 const char md5[] = "76fcc7d08aa15445efd2e2ceb7c6cc3b";
2024 #endif
2025 CompareBitmap(page_bitmap.get(), 612, 792, md5);
2026
2027 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2028 VerifySavedDocument(612, 792, md5);
2029 }
2030
2031 // And some randomly transformed text
2032 FPDF_PAGEOBJECT text_object3 =
2033 FPDFPageObj_NewTextObj(document(), "Courier-Bold", 20.0f);
2034 EXPECT_TRUE(text_object3);
2035 ScopedFPDFWideString text3 = GetFPDFWideString(L"Can you read me? <:)>");
2036 EXPECT_TRUE(FPDFText_SetText(text_object3, text3.get()));
2037 FPDFPageObj_Transform(text_object3, 1, 1.5, 2, 0.5, 200, 200);
2038 FPDFPage_InsertObject(page, text_object3);
2039 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2040 {
2041 ScopedFPDFBitmap page_bitmap = RenderPage(page);
2042 #if defined(OS_MACOSX)
2043 const char md5[] = "40b3ef04f915ff4c4208948001763544";
2044 #elif defined(OS_WIN)
2045 const char md5[] = "5ded49fe157f89627903553771431e3d";
2046 #else
2047 const char md5[] = "344534539aa7c5cc78404cfff4bde7fb";
2048 #endif
2049 CompareBitmap(page_bitmap.get(), 612, 792, md5);
2050
2051 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2052 VerifySavedDocument(612, 792, md5);
2053 }
2054
2055 FS_MATRIX matrix;
2056 EXPECT_FALSE(FPDFTextObj_GetMatrix(nullptr, &matrix));
2057 EXPECT_TRUE(FPDFTextObj_GetMatrix(text_object3, &matrix));
2058 EXPECT_FLOAT_EQ(1.0f, matrix.a);
2059 EXPECT_FLOAT_EQ(1.5f, matrix.b);
2060 EXPECT_FLOAT_EQ(2.0f, matrix.c);
2061 EXPECT_FLOAT_EQ(0.5f, matrix.d);
2062 EXPECT_FLOAT_EQ(200.0f, matrix.e);
2063 EXPECT_FLOAT_EQ(200.0f, matrix.f);
2064
2065 EXPECT_EQ(0, FPDFTextObj_GetFontSize(nullptr));
2066 EXPECT_EQ(20, FPDFTextObj_GetFontSize(text_object3));
2067
2068 // TODO(npm): Why are there issues with text rotated by 90 degrees?
2069 // TODO(npm): FPDF_SaveAsCopy not giving the desired result after this.
2070 FPDF_ClosePage(page);
2071 }
2072
TEST_F(FPDFEditEmbedderTest,GetTextRenderMode)2073 TEST_F(FPDFEditEmbedderTest, GetTextRenderMode) {
2074 EXPECT_TRUE(OpenDocument("text_render_mode.pdf"));
2075 FPDF_PAGE page = LoadPage(0);
2076 ASSERT_TRUE(page);
2077 ASSERT_EQ(2, FPDFPage_CountObjects(page));
2078
2079 EXPECT_EQ(FPDF_TEXTRENDERMODE_UNKNOWN,
2080 FPDFTextObj_GetTextRenderMode(nullptr));
2081
2082 FPDF_PAGEOBJECT fill = FPDFPage_GetObject(page, 0);
2083 EXPECT_EQ(FPDF_TEXTRENDERMODE_FILL, FPDFTextObj_GetTextRenderMode(fill));
2084
2085 FPDF_PAGEOBJECT stroke = FPDFPage_GetObject(page, 1);
2086 EXPECT_EQ(FPDF_TEXTRENDERMODE_STROKE, FPDFTextObj_GetTextRenderMode(stroke));
2087
2088 UnloadPage(page);
2089 }
2090
TEST_F(FPDFEditEmbedderTest,SetTextRenderMode)2091 TEST_F(FPDFEditEmbedderTest, SetTextRenderMode) {
2092 EXPECT_TRUE(OpenDocument("text_render_mode.pdf"));
2093 FPDF_PAGE page = LoadPage(0);
2094 ASSERT_TRUE(page);
2095 ASSERT_EQ(2, FPDFPage_CountObjects(page));
2096
2097 // Check the bitmap
2098 {
2099 #if defined(OS_MACOSX)
2100 const char md5[] = "139846b4ffbd34b1fd67e3b82cf33b7e";
2101 #elif defined(OS_WIN)
2102 const char md5[] = "de6e86bad3e9fda753a8471a45cfbb58";
2103 #else
2104 const char md5[] = "5a012d2920ac075c39ffa9437ea42faa";
2105 #endif
2106 ScopedFPDFBitmap page_bitmap = RenderPage(page);
2107 CompareBitmap(page_bitmap.get(), 612, 446, md5);
2108 }
2109
2110 // Cannot set on a null object.
2111 EXPECT_FALSE(
2112 FPDFTextObj_SetTextRenderMode(nullptr, FPDF_TEXTRENDERMODE_UNKNOWN));
2113 EXPECT_FALSE(
2114 FPDFTextObj_SetTextRenderMode(nullptr, FPDF_TEXTRENDERMODE_INVISIBLE));
2115
2116 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
2117 ASSERT_TRUE(page_object);
2118 EXPECT_EQ(FPDF_TEXTRENDERMODE_FILL,
2119 FPDFTextObj_GetTextRenderMode(page_object));
2120
2121 // Cannot set UNKNOWN as a render mode.
2122 EXPECT_FALSE(
2123 FPDFTextObj_SetTextRenderMode(page_object, FPDF_TEXTRENDERMODE_UNKNOWN));
2124
2125 EXPECT_TRUE(
2126 FPDFTextObj_SetTextRenderMode(page_object, FPDF_TEXTRENDERMODE_STROKE));
2127 EXPECT_EQ(FPDF_TEXTRENDERMODE_STROKE,
2128 FPDFTextObj_GetTextRenderMode(page_object));
2129
2130 // Check that bitmap displays changed content
2131 {
2132 const char md5[] = "412e52e621b46bd77baf2162e1fb1a1d";
2133 ScopedFPDFBitmap page_bitmap = RenderPage(page);
2134 CompareBitmap(page_bitmap.get(), 612, 446, md5);
2135 }
2136
2137 UnloadPage(page);
2138 }
2139
TEST_F(FPDFEditEmbedderTest,TestGetTextFontName)2140 TEST_F(FPDFEditEmbedderTest, TestGetTextFontName) {
2141 EXPECT_TRUE(OpenDocument("text_font.pdf"));
2142 FPDF_PAGE page = LoadPage(0);
2143 ASSERT_TRUE(page);
2144 ASSERT_EQ(1, FPDFPage_CountObjects(page));
2145
2146 // FPDFTextObj_GetFontName() positive testing.
2147 FPDF_PAGEOBJECT text = FPDFPage_GetObject(page, 0);
2148 unsigned long size = FPDFTextObj_GetFontName(text, nullptr, 0);
2149 const char kExpectedFontName[] = "Liberation Serif";
2150 ASSERT_EQ(sizeof(kExpectedFontName), size);
2151 std::vector<char> font_name(size);
2152 ASSERT_EQ(size, FPDFTextObj_GetFontName(text, font_name.data(), size));
2153 ASSERT_STREQ(kExpectedFontName, font_name.data());
2154
2155 // FPDFTextObj_GetFontName() negative testing.
2156 ASSERT_EQ(0U, FPDFTextObj_GetFontName(nullptr, nullptr, 0));
2157
2158 font_name.resize(2);
2159 font_name[0] = 'x';
2160 font_name[1] = '\0';
2161 size = FPDFTextObj_GetFontName(text, font_name.data(), font_name.size());
2162 ASSERT_EQ(sizeof(kExpectedFontName), size);
2163 ASSERT_EQ(std::string("x"), std::string(font_name.data()));
2164
2165 UnloadPage(page);
2166 }
2167
TEST_F(FPDFEditEmbedderTest,TestFormGetObjects)2168 TEST_F(FPDFEditEmbedderTest, TestFormGetObjects) {
2169 EXPECT_TRUE(OpenDocument("form_object.pdf"));
2170 FPDF_PAGE page = LoadPage(0);
2171 ASSERT_TRUE(page);
2172 ASSERT_EQ(1, FPDFPage_CountObjects(page));
2173
2174 FPDF_PAGEOBJECT form = FPDFPage_GetObject(page, 0);
2175 EXPECT_EQ(FPDF_PAGEOBJ_FORM, FPDFPageObj_GetType(form));
2176 ASSERT_EQ(-1, FPDFFormObj_CountObjects(nullptr));
2177 ASSERT_EQ(2, FPDFFormObj_CountObjects(form));
2178
2179 // FPDFFormObj_GetObject() positive testing.
2180 FPDF_PAGEOBJECT text1 = FPDFFormObj_GetObject(form, 0);
2181 ASSERT_TRUE(text1);
2182 float left = 0;
2183 float bottom = 0;
2184 float right = 0;
2185 float top = 0;
2186 ASSERT_TRUE(FPDFPageObj_GetBounds(text1, &left, &bottom, &right, &top));
2187 ASSERT_EQ(271, static_cast<int>(top));
2188
2189 FPDF_PAGEOBJECT text2 = FPDFFormObj_GetObject(form, 1);
2190 ASSERT_TRUE(text2);
2191 ASSERT_TRUE(FPDFPageObj_GetBounds(text2, &left, &bottom, &right, &top));
2192 ASSERT_EQ(221, static_cast<int>(top));
2193
2194 // FPDFFormObj_GetObject() negative testing.
2195 ASSERT_EQ(nullptr, FPDFFormObj_GetObject(nullptr, 0));
2196 ASSERT_EQ(nullptr, FPDFFormObj_GetObject(form, -1));
2197 ASSERT_EQ(nullptr, FPDFFormObj_GetObject(form, 2));
2198
2199 // Reset the form object matrix to identity.
2200 auto* pPageObj = CPDFPageObjectFromFPDFPageObject(form);
2201 CPDF_FormObject* pFormObj = pPageObj->AsForm();
2202 pFormObj->Transform(pFormObj->form_matrix().GetInverse());
2203
2204 // FPDFFormObj_GetMatrix() positive testing.
2205 static constexpr FS_MATRIX kMatrix = {1.0f, 1.5f, 2.0f, 2.5f, 100.0f, 200.0f};
2206 pFormObj->Transform(CFXMatrixFromFSMatrix(kMatrix));
2207
2208 FS_MATRIX matrix;
2209 EXPECT_TRUE(FPDFFormObj_GetMatrix(form, &matrix));
2210 EXPECT_FLOAT_EQ(kMatrix.a, matrix.a);
2211 EXPECT_FLOAT_EQ(kMatrix.b, matrix.b);
2212 EXPECT_FLOAT_EQ(kMatrix.c, matrix.c);
2213 EXPECT_FLOAT_EQ(kMatrix.d, matrix.d);
2214 EXPECT_FLOAT_EQ(kMatrix.e, matrix.e);
2215 EXPECT_FLOAT_EQ(kMatrix.f, matrix.f);
2216
2217 // FPDFFormObj_GetMatrix() negative testing.
2218 EXPECT_FALSE(FPDFFormObj_GetMatrix(nullptr, &matrix));
2219 EXPECT_FALSE(FPDFFormObj_GetMatrix(form, nullptr));
2220 EXPECT_FALSE(FPDFFormObj_GetMatrix(nullptr, nullptr));
2221
2222 UnloadPage(page);
2223 }
2224
2225 // Tests adding text from standard font using FPDFText_LoadStandardFont.
2226 // TODO(crbug.com/pdfium/11): Fix this test and enable.
2227 #if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
2228 #define MAYBE_AddStandardFontText2 DISABLED_AddStandardFontText2
2229 #else
2230 #define MAYBE_AddStandardFontText2 AddStandardFontText2
2231 #endif
TEST_F(FPDFEditEmbedderTest,MAYBE_AddStandardFontText2)2232 TEST_F(FPDFEditEmbedderTest, MAYBE_AddStandardFontText2) {
2233 // Start with a blank page
2234 ScopedFPDFPage page(FPDFPage_New(CreateNewDocument(), 0, 612, 792));
2235
2236 // Load a standard font.
2237 ScopedFPDFFont font(FPDFText_LoadStandardFont(document(), "Helvetica"));
2238 ASSERT_TRUE(font);
2239
2240 // Add some text to the page.
2241 FPDF_PAGEOBJECT text_object =
2242 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
2243 EXPECT_TRUE(text_object);
2244 ScopedFPDFWideString text =
2245 GetFPDFWideString(L"I'm at the bottom of the page");
2246 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
2247 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 20, 20);
2248 FPDFPage_InsertObject(page.get(), text_object);
2249 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
2250 #if defined(OS_MACOSX)
2251 const char md5[] = "a4dddc1a3930fa694bbff9789dab4161";
2252 #elif defined(OS_WIN)
2253 const char md5[] = "08d1ff3e5a42801bee6077fd366bef00";
2254 #else
2255 const char md5[] = "eacaa24573b8ce997b3882595f096f00";
2256 #endif
2257 CompareBitmap(page_bitmap.get(), 612, 792, md5);
2258 }
2259
TEST_F(FPDFEditEmbedderTest,LoadStandardFonts)2260 TEST_F(FPDFEditEmbedderTest, LoadStandardFonts) {
2261 CreateNewDocument();
2262 static constexpr const char* kStandardFontNames[] = {
2263 "Arial",
2264 "Arial-Bold",
2265 "Arial-BoldItalic",
2266 "Arial-Italic",
2267 "Courier",
2268 "Courier-BoldOblique",
2269 "Courier-Oblique",
2270 "Courier-Bold",
2271 "CourierNew",
2272 "CourierNew-Bold",
2273 "CourierNew-BoldItalic",
2274 "CourierNew-Italic",
2275 "Helvetica",
2276 "Helvetica-Bold",
2277 "Helvetica-BoldOblique",
2278 "Helvetica-Oblique",
2279 "Symbol",
2280 "TimesNewRoman",
2281 "TimesNewRoman-Bold",
2282 "TimesNewRoman-BoldItalic",
2283 "TimesNewRoman-Italic",
2284 "ZapfDingbats"};
2285 for (const char* font_name : kStandardFontNames) {
2286 ScopedFPDFFont font(FPDFText_LoadStandardFont(document(), font_name));
2287 EXPECT_TRUE(font) << font_name << " should be considered a standard font.";
2288 }
2289 static constexpr const char* kNotStandardFontNames[] = {
2290 "Abcdefg", "ArialB", "Arial-Style",
2291 "Font Name", "FontArial", "NotAStandardFontName",
2292 "TestFontName", "Quack", "Symbol-Italic",
2293 "Zapf"};
2294 for (const char* font_name : kNotStandardFontNames) {
2295 ScopedFPDFFont font(FPDFText_LoadStandardFont(document(), font_name));
2296 EXPECT_FALSE(font) << font_name
2297 << " should not be considered a standard font.";
2298 }
2299 }
2300
TEST_F(FPDFEditEmbedderTest,GraphicsData)2301 TEST_F(FPDFEditEmbedderTest, GraphicsData) {
2302 // New page
2303 ScopedFPDFPage page(FPDFPage_New(CreateNewDocument(), 0, 612, 792));
2304
2305 // Create a rect with nontrivial graphics
2306 FPDF_PAGEOBJECT rect1 = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
2307 FPDFPageObj_SetBlendMode(rect1, "Color");
2308 FPDFPage_InsertObject(page.get(), rect1);
2309 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
2310
2311 // Check that the ExtGState was created
2312 CPDF_Page* cpage = CPDFPageFromFPDFPage(page.get());
2313 CPDF_Dictionary* graphics_dict = cpage->m_pResources->GetDictFor("ExtGState");
2314 ASSERT_TRUE(graphics_dict);
2315 EXPECT_EQ(2u, graphics_dict->size());
2316
2317 // Add a text object causing no change to the graphics dictionary
2318 FPDF_PAGEOBJECT text1 = FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
2319 // Only alpha, the last component, matters for the graphics dictionary. And
2320 // the default value is 255.
2321 EXPECT_TRUE(FPDFPageObj_SetFillColor(text1, 100, 100, 100, 255));
2322 FPDFPage_InsertObject(page.get(), text1);
2323 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
2324 EXPECT_EQ(2u, graphics_dict->size());
2325
2326 // Add a text object increasing the size of the graphics dictionary
2327 FPDF_PAGEOBJECT text2 =
2328 FPDFPageObj_NewTextObj(document(), "Times-Roman", 12.0f);
2329 FPDFPage_InsertObject(page.get(), text2);
2330 FPDFPageObj_SetBlendMode(text2, "Darken");
2331 EXPECT_TRUE(FPDFPageObj_SetFillColor(text2, 0, 0, 255, 150));
2332 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
2333 EXPECT_EQ(3u, graphics_dict->size());
2334
2335 // Add a path that should reuse graphics
2336 FPDF_PAGEOBJECT path = FPDFPageObj_CreateNewPath(400, 100);
2337 FPDFPageObj_SetBlendMode(path, "Darken");
2338 EXPECT_TRUE(FPDFPageObj_SetFillColor(path, 200, 200, 100, 150));
2339 FPDFPage_InsertObject(page.get(), path);
2340 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
2341 EXPECT_EQ(3u, graphics_dict->size());
2342
2343 // Add a rect increasing the size of the graphics dictionary
2344 FPDF_PAGEOBJECT rect2 = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
2345 FPDFPageObj_SetBlendMode(rect2, "Darken");
2346 EXPECT_TRUE(FPDFPageObj_SetFillColor(rect2, 0, 0, 255, 150));
2347 EXPECT_TRUE(FPDFPageObj_SetStrokeColor(rect2, 0, 0, 0, 200));
2348 FPDFPage_InsertObject(page.get(), rect2);
2349 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
2350 EXPECT_EQ(4u, graphics_dict->size());
2351 }
2352
TEST_F(FPDFEditEmbedderTest,DoubleGenerating)2353 TEST_F(FPDFEditEmbedderTest, DoubleGenerating) {
2354 // Start with a blank page
2355 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
2356
2357 // Add a red rectangle with some non-default alpha
2358 FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
2359 EXPECT_TRUE(FPDFPageObj_SetFillColor(rect, 255, 0, 0, 128));
2360 EXPECT_TRUE(FPDFPath_SetDrawMode(rect, FPDF_FILLMODE_WINDING, 0));
2361 FPDFPage_InsertObject(page, rect);
2362 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2363
2364 // Check the ExtGState
2365 CPDF_Page* cpage = CPDFPageFromFPDFPage(page);
2366 CPDF_Dictionary* graphics_dict = cpage->m_pResources->GetDictFor("ExtGState");
2367 ASSERT_TRUE(graphics_dict);
2368 EXPECT_EQ(2u, graphics_dict->size());
2369
2370 // Check the bitmap
2371 {
2372 ScopedFPDFBitmap page_bitmap = RenderPage(page);
2373 CompareBitmap(page_bitmap.get(), 612, 792,
2374 "5384da3406d62360ffb5cac4476fff1c");
2375 }
2376
2377 // Never mind, my new favorite color is blue, increase alpha
2378 EXPECT_TRUE(FPDFPageObj_SetFillColor(rect, 0, 0, 255, 180));
2379 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2380 EXPECT_EQ(3u, graphics_dict->size());
2381
2382 // Check that bitmap displays changed content
2383 {
2384 ScopedFPDFBitmap page_bitmap = RenderPage(page);
2385 CompareBitmap(page_bitmap.get(), 612, 792,
2386 "2e51656f5073b0bee611d9cd086aa09c");
2387 }
2388
2389 // And now generate, without changes
2390 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2391 EXPECT_EQ(3u, graphics_dict->size());
2392 {
2393 ScopedFPDFBitmap page_bitmap = RenderPage(page);
2394 CompareBitmap(page_bitmap.get(), 612, 792,
2395 "2e51656f5073b0bee611d9cd086aa09c");
2396 }
2397
2398 // Add some text to the page
2399 FPDF_PAGEOBJECT text_object =
2400 FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
2401 ScopedFPDFWideString text =
2402 GetFPDFWideString(L"Something something #text# something");
2403 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
2404 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 300, 300);
2405 FPDFPage_InsertObject(page, text_object);
2406 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2407 CPDF_Dictionary* font_dict = cpage->m_pResources->GetDictFor("Font");
2408 ASSERT_TRUE(font_dict);
2409 EXPECT_EQ(1u, font_dict->size());
2410
2411 // Generate yet again, check dicts are reasonably sized
2412 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2413 EXPECT_EQ(3u, graphics_dict->size());
2414 EXPECT_EQ(1u, font_dict->size());
2415 FPDF_ClosePage(page);
2416 }
2417
TEST_F(FPDFEditEmbedderTest,LoadSimpleType1Font)2418 TEST_F(FPDFEditEmbedderTest, LoadSimpleType1Font) {
2419 CreateNewDocument();
2420 // TODO(npm): use other fonts after disallowing loading any font as any type
2421 RetainPtr<CPDF_Font> stock_font =
2422 CPDF_Font::GetStockFont(cpdf_doc(), "Times-Bold");
2423 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
2424 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
2425 FPDF_FONT_TYPE1, false));
2426 ASSERT_TRUE(font.get());
2427 CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
2428 EXPECT_TRUE(typed_font->IsType1Font());
2429
2430 const CPDF_Dictionary* font_dict = typed_font->GetFontDict();
2431 EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
2432 EXPECT_EQ("Type1", font_dict->GetStringFor("Subtype"));
2433 EXPECT_EQ("TimesNewRomanPS-BoldMT", font_dict->GetStringFor("BaseFont"));
2434 ASSERT_TRUE(font_dict->KeyExist("FirstChar"));
2435 ASSERT_TRUE(font_dict->KeyExist("LastChar"));
2436 EXPECT_EQ(32, font_dict->GetIntegerFor("FirstChar"));
2437 EXPECT_EQ(255, font_dict->GetIntegerFor("LastChar"));
2438
2439 const CPDF_Array* widths_array = font_dict->GetArrayFor("Widths");
2440 ASSERT_TRUE(widths_array);
2441 ASSERT_EQ(224u, widths_array->size());
2442 EXPECT_EQ(250, widths_array->GetNumberAt(0));
2443 EXPECT_EQ(569, widths_array->GetNumberAt(11));
2444 EXPECT_EQ(500, widths_array->GetNumberAt(223));
2445 CheckFontDescriptor(font_dict, FPDF_FONT_TYPE1, true, false, span);
2446 }
2447
TEST_F(FPDFEditEmbedderTest,LoadSimpleTrueTypeFont)2448 TEST_F(FPDFEditEmbedderTest, LoadSimpleTrueTypeFont) {
2449 CreateNewDocument();
2450 RetainPtr<CPDF_Font> stock_font =
2451 CPDF_Font::GetStockFont(cpdf_doc(), "Courier");
2452 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
2453 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
2454 FPDF_FONT_TRUETYPE, false));
2455 ASSERT_TRUE(font.get());
2456 CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
2457 EXPECT_TRUE(typed_font->IsTrueTypeFont());
2458
2459 const CPDF_Dictionary* font_dict = typed_font->GetFontDict();
2460 EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
2461 EXPECT_EQ("TrueType", font_dict->GetStringFor("Subtype"));
2462 EXPECT_EQ("CourierNewPSMT", font_dict->GetStringFor("BaseFont"));
2463 ASSERT_TRUE(font_dict->KeyExist("FirstChar"));
2464 ASSERT_TRUE(font_dict->KeyExist("LastChar"));
2465 EXPECT_EQ(32, font_dict->GetIntegerFor("FirstChar"));
2466 EXPECT_EQ(255, font_dict->GetIntegerFor("LastChar"));
2467
2468 const CPDF_Array* widths_array = font_dict->GetArrayFor("Widths");
2469 ASSERT_TRUE(widths_array);
2470 ASSERT_EQ(224u, widths_array->size());
2471 EXPECT_EQ(600, widths_array->GetNumberAt(33));
2472 EXPECT_EQ(600, widths_array->GetNumberAt(74));
2473 EXPECT_EQ(600, widths_array->GetNumberAt(223));
2474 CheckFontDescriptor(font_dict, FPDF_FONT_TRUETYPE, false, false, span);
2475 }
2476
TEST_F(FPDFEditEmbedderTest,LoadCIDType0Font)2477 TEST_F(FPDFEditEmbedderTest, LoadCIDType0Font) {
2478 CreateNewDocument();
2479 RetainPtr<CPDF_Font> stock_font =
2480 CPDF_Font::GetStockFont(cpdf_doc(), "Times-Roman");
2481 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
2482 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
2483 FPDF_FONT_TYPE1, 1));
2484 ASSERT_TRUE(font.get());
2485 CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
2486 EXPECT_TRUE(typed_font->IsCIDFont());
2487
2488 // Check font dictionary entries
2489 const CPDF_Dictionary* font_dict = typed_font->GetFontDict();
2490 EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
2491 EXPECT_EQ("Type0", font_dict->GetStringFor("Subtype"));
2492 EXPECT_EQ("TimesNewRomanPSMT-Identity-H",
2493 font_dict->GetStringFor("BaseFont"));
2494 EXPECT_EQ("Identity-H", font_dict->GetStringFor("Encoding"));
2495 const CPDF_Array* descendant_array =
2496 font_dict->GetArrayFor("DescendantFonts");
2497 ASSERT_TRUE(descendant_array);
2498 EXPECT_EQ(1u, descendant_array->size());
2499
2500 // Check the CIDFontDict
2501 const CPDF_Dictionary* cidfont_dict = descendant_array->GetDictAt(0);
2502 EXPECT_EQ("Font", cidfont_dict->GetStringFor("Type"));
2503 EXPECT_EQ("CIDFontType0", cidfont_dict->GetStringFor("Subtype"));
2504 EXPECT_EQ("TimesNewRomanPSMT", cidfont_dict->GetStringFor("BaseFont"));
2505 const CPDF_Dictionary* cidinfo_dict =
2506 cidfont_dict->GetDictFor("CIDSystemInfo");
2507 ASSERT_TRUE(cidinfo_dict);
2508 const CPDF_Object* registry = cidinfo_dict->GetObjectFor("Registry");
2509 ASSERT_TRUE(registry);
2510 EXPECT_EQ(CPDF_Object::kString, registry->GetType());
2511 EXPECT_EQ("Adobe", registry->GetString());
2512 const CPDF_Object* ordering = cidinfo_dict->GetObjectFor("Ordering");
2513 ASSERT_TRUE(ordering);
2514 EXPECT_EQ(CPDF_Object::kString, ordering->GetType());
2515 EXPECT_EQ("Identity", ordering->GetString());
2516 EXPECT_EQ(0, cidinfo_dict->GetNumberFor("Supplement"));
2517 CheckFontDescriptor(cidfont_dict, FPDF_FONT_TYPE1, false, false, span);
2518
2519 // Check widths
2520 const CPDF_Array* widths_array = cidfont_dict->GetArrayFor("W");
2521 ASSERT_TRUE(widths_array);
2522 EXPECT_GT(widths_array->size(), 1u);
2523 CheckCompositeFontWidths(widths_array, typed_font);
2524 }
2525
TEST_F(FPDFEditEmbedderTest,LoadCIDType2Font)2526 TEST_F(FPDFEditEmbedderTest, LoadCIDType2Font) {
2527 CreateNewDocument();
2528 RetainPtr<CPDF_Font> stock_font =
2529 CPDF_Font::GetStockFont(cpdf_doc(), "Helvetica-Oblique");
2530 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
2531 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
2532 FPDF_FONT_TRUETYPE, 1));
2533 ASSERT_TRUE(font.get());
2534 CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
2535 EXPECT_TRUE(typed_font->IsCIDFont());
2536
2537 // Check font dictionary entries
2538 const CPDF_Dictionary* font_dict = typed_font->GetFontDict();
2539 EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
2540 EXPECT_EQ("Type0", font_dict->GetStringFor("Subtype"));
2541 EXPECT_EQ("Arial-ItalicMT", font_dict->GetStringFor("BaseFont"));
2542 EXPECT_EQ("Identity-H", font_dict->GetStringFor("Encoding"));
2543 const CPDF_Array* descendant_array =
2544 font_dict->GetArrayFor("DescendantFonts");
2545 ASSERT_TRUE(descendant_array);
2546 EXPECT_EQ(1u, descendant_array->size());
2547
2548 // Check the CIDFontDict
2549 const CPDF_Dictionary* cidfont_dict = descendant_array->GetDictAt(0);
2550 EXPECT_EQ("Font", cidfont_dict->GetStringFor("Type"));
2551 EXPECT_EQ("CIDFontType2", cidfont_dict->GetStringFor("Subtype"));
2552 EXPECT_EQ("Arial-ItalicMT", cidfont_dict->GetStringFor("BaseFont"));
2553 const CPDF_Dictionary* cidinfo_dict =
2554 cidfont_dict->GetDictFor("CIDSystemInfo");
2555 ASSERT_TRUE(cidinfo_dict);
2556 EXPECT_EQ("Adobe", cidinfo_dict->GetStringFor("Registry"));
2557 EXPECT_EQ("Identity", cidinfo_dict->GetStringFor("Ordering"));
2558 EXPECT_EQ(0, cidinfo_dict->GetNumberFor("Supplement"));
2559 CheckFontDescriptor(cidfont_dict, FPDF_FONT_TRUETYPE, false, true, span);
2560
2561 // Check widths
2562 const CPDF_Array* widths_array = cidfont_dict->GetArrayFor("W");
2563 ASSERT_TRUE(widths_array);
2564 CheckCompositeFontWidths(widths_array, typed_font);
2565 }
2566
TEST_F(FPDFEditEmbedderTest,NormalizeNegativeRotation)2567 TEST_F(FPDFEditEmbedderTest, NormalizeNegativeRotation) {
2568 // Load document with a -90 degree rotation
2569 EXPECT_TRUE(OpenDocument("bug_713197.pdf"));
2570 FPDF_PAGE page = LoadPage(0);
2571 EXPECT_NE(nullptr, page);
2572
2573 EXPECT_EQ(3, FPDFPage_GetRotation(page));
2574 UnloadPage(page);
2575 }
2576
2577 // TODO(crbug.com/pdfium/11): Fix this test and enable.
2578 #if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
2579 #define MAYBE_AddTrueTypeFontText DISABLED_AddTrueTypeFontText
2580 #else
2581 #define MAYBE_AddTrueTypeFontText AddTrueTypeFontText
2582 #endif
TEST_F(FPDFEditEmbedderTest,MAYBE_AddTrueTypeFontText)2583 TEST_F(FPDFEditEmbedderTest, MAYBE_AddTrueTypeFontText) {
2584 // Start with a blank page
2585 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
2586 {
2587 RetainPtr<CPDF_Font> stock_font =
2588 CPDF_Font::GetStockFont(cpdf_doc(), "Arial");
2589 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
2590 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
2591 FPDF_FONT_TRUETYPE, 0));
2592 ASSERT_TRUE(font.get());
2593
2594 // Add some text to the page
2595 FPDF_PAGEOBJECT text_object =
2596 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
2597 EXPECT_TRUE(text_object);
2598 ScopedFPDFWideString text =
2599 GetFPDFWideString(L"I am testing my loaded font, WEE.");
2600 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
2601 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 400, 400);
2602 FPDFPage_InsertObject(page, text_object);
2603 ScopedFPDFBitmap page_bitmap = RenderPage(page);
2604 #if defined(OS_MACOSX)
2605 const char md5[] = "17d2b6cd574cf66170b09c8927529a94";
2606 #elif defined(OS_WIN)
2607 const char md5[] = "d60ba39f9698e32360d99e727dd93165";
2608 #else
2609 const char md5[] = "70592859010ffbf532a2237b8118bcc4";
2610 #endif
2611 CompareBitmap(page_bitmap.get(), 612, 792, md5);
2612
2613 // Add some more text, same font
2614 FPDF_PAGEOBJECT text_object2 =
2615 FPDFPageObj_CreateTextObj(document(), font.get(), 15.0f);
2616 ScopedFPDFWideString text2 = GetFPDFWideString(L"Bigger font size");
2617 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
2618 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 200, 200);
2619 FPDFPage_InsertObject(page, text_object2);
2620 }
2621 ScopedFPDFBitmap page_bitmap2 = RenderPage(page);
2622 #if defined(OS_MACOSX)
2623 const char md5_2[] = "8eded4193ff1f0f77b8b600a825e97ea";
2624 #elif defined(OS_WIN)
2625 const char md5_2[] = "2199b579c49ab5f80c246a586a80ee90";
2626 #else
2627 const char md5_2[] = "c1d10cce1761c4a998a16b2562030568";
2628 #endif
2629 CompareBitmap(page_bitmap2.get(), 612, 792, md5_2);
2630
2631 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2632 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2633 FPDF_ClosePage(page);
2634
2635 VerifySavedDocument(612, 792, md5_2);
2636 }
2637
TEST_F(FPDFEditEmbedderTest,TransformAnnot)2638 TEST_F(FPDFEditEmbedderTest, TransformAnnot) {
2639 // Open a file with one annotation and load its first page.
2640 ASSERT_TRUE(OpenDocument("annotation_highlight_long_content.pdf"));
2641 FPDF_PAGE page = LoadPage(0);
2642 ASSERT_TRUE(page);
2643
2644 {
2645 // Add an underline annotation to the page without specifying its rectangle.
2646 ScopedFPDFAnnotation annot(
2647 FPDFPage_CreateAnnot(page, FPDF_ANNOT_UNDERLINE));
2648 ASSERT_TRUE(annot);
2649
2650 // FPDFPage_TransformAnnots() should run without errors when modifying
2651 // annotation rectangles.
2652 FPDFPage_TransformAnnots(page, 1, 2, 3, 4, 5, 6);
2653 }
2654 UnloadPage(page);
2655 }
2656
2657 // TODO(npm): Add tests using Japanese fonts in other OS.
2658 #if _FX_PLATFORM_ == _FX_PLATFORM_LINUX_
2659 // TODO(crbug.com/pdfium/11): Fix this test and enable.
2660 #if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
2661 #define MAYBE_AddCIDFontText DISABLED_AddCIDFontText
2662 #else
2663 #define MAYBE_AddCIDFontText AddCIDFontText
2664 #endif
TEST_F(FPDFEditEmbedderTest,MAYBE_AddCIDFontText)2665 TEST_F(FPDFEditEmbedderTest, MAYBE_AddCIDFontText) {
2666 // Start with a blank page
2667 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
2668 CFX_Font CIDfont;
2669 {
2670 // First, get the data from the font
2671 CIDfont.LoadSubst("IPAGothic", 1, 0, 400, 0, 932, 0);
2672 EXPECT_EQ("IPAGothic", CIDfont.GetFaceName());
2673 pdfium::span<const uint8_t> span = CIDfont.GetFontSpan();
2674
2675 // Load the data into a FPDF_Font.
2676 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
2677 FPDF_FONT_TRUETYPE, 1));
2678 ASSERT_TRUE(font.get());
2679
2680 // Add some text to the page
2681 FPDF_PAGEOBJECT text_object =
2682 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
2683 ASSERT_TRUE(text_object);
2684 std::wstring wstr = L"ABCDEFGhijklmnop.";
2685 ScopedFPDFWideString text = GetFPDFWideString(wstr);
2686 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
2687 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 200, 200);
2688 FPDFPage_InsertObject(page, text_object);
2689
2690 // And add some Japanese characters
2691 FPDF_PAGEOBJECT text_object2 =
2692 FPDFPageObj_CreateTextObj(document(), font.get(), 18.0f);
2693 ASSERT_TRUE(text_object2);
2694 std::wstring wstr2 =
2695 L"\u3053\u3093\u306B\u3061\u306f\u4e16\u754C\u3002\u3053\u3053\u306B1"
2696 L"\u756A";
2697 ScopedFPDFWideString text2 = GetFPDFWideString(wstr2);
2698 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
2699 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 100, 500);
2700 FPDFPage_InsertObject(page, text_object2);
2701 }
2702
2703 // Check that the text renders properly.
2704 const char md5[] = "5159a72903fe57bf0cf645c894de8a74";
2705 {
2706 ScopedFPDFBitmap page_bitmap = RenderPage(page);
2707 CompareBitmap(page_bitmap.get(), 612, 792, md5);
2708 }
2709
2710 // Save the document, close the page.
2711 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2712 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2713 FPDF_ClosePage(page);
2714
2715 VerifySavedDocument(612, 792, md5);
2716 }
2717 #endif // _FX_PLATFORM_ == _FX_PLATFORM_LINUX_
2718
2719 // TODO(crbug.com/pdfium/11): Fix this test and enable.
2720 #if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
2721 #define MAYBE_SaveAndRender DISABLED_SaveAndRender
2722 #else
2723 #define MAYBE_SaveAndRender SaveAndRender
2724 #endif
TEST_F(FPDFEditEmbedderTest,MAYBE_SaveAndRender)2725 TEST_F(FPDFEditEmbedderTest, MAYBE_SaveAndRender) {
2726 const char md5[] = "3c20472b0552c0c22b88ab1ed8c6202b";
2727 {
2728 EXPECT_TRUE(OpenDocument("bug_779.pdf"));
2729 FPDF_PAGE page = LoadPage(0);
2730 ASSERT_NE(nullptr, page);
2731
2732 // Now add a more complex blue path.
2733 FPDF_PAGEOBJECT green_path = FPDFPageObj_CreateNewPath(20, 20);
2734 EXPECT_TRUE(FPDFPageObj_SetFillColor(green_path, 0, 255, 0, 200));
2735 // TODO(npm): stroking will cause the MD5s to differ.
2736 EXPECT_TRUE(FPDFPath_SetDrawMode(green_path, FPDF_FILLMODE_WINDING, 0));
2737 EXPECT_TRUE(FPDFPath_LineTo(green_path, 20, 63));
2738 EXPECT_TRUE(FPDFPath_BezierTo(green_path, 55, 55, 78, 78, 90, 90));
2739 EXPECT_TRUE(FPDFPath_LineTo(green_path, 133, 133));
2740 EXPECT_TRUE(FPDFPath_LineTo(green_path, 133, 33));
2741 EXPECT_TRUE(FPDFPath_BezierTo(green_path, 38, 33, 39, 36, 40, 40));
2742 EXPECT_TRUE(FPDFPath_Close(green_path));
2743 FPDFPage_InsertObject(page, green_path);
2744 ScopedFPDFBitmap page_bitmap = RenderLoadedPage(page);
2745 CompareBitmap(page_bitmap.get(), 612, 792, md5);
2746
2747 // Now save the result, closing the page and document
2748 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2749 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2750 UnloadPage(page);
2751 }
2752
2753 VerifySavedDocument(612, 792, md5);
2754 }
2755
TEST_F(FPDFEditEmbedderTest,AddMark)2756 TEST_F(FPDFEditEmbedderTest, AddMark) {
2757 // Load document with some text.
2758 EXPECT_TRUE(OpenDocument("text_in_page_marked.pdf"));
2759 FPDF_PAGE page = LoadPage(0);
2760 ASSERT_TRUE(page);
2761
2762 CheckMarkCounts(page, 1, 19, 8, 4, 9, 1);
2763
2764 // Add to the first page object a "Bounds" mark with "Position": "First".
2765 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
2766 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_AddMark(page_object, "Bounds");
2767 EXPECT_TRUE(mark);
2768 EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), page_object, mark,
2769 "Position", "First"));
2770
2771 CheckMarkCounts(page, 1, 19, 8, 4, 9, 2);
2772
2773 // Save the file
2774 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2775 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2776 UnloadPage(page);
2777
2778 // Re-open the file and check the new mark is present.
2779 ASSERT_TRUE(OpenSavedDocument());
2780 FPDF_PAGE saved_page = LoadSavedPage(0);
2781
2782 CheckMarkCounts(saved_page, 1, 19, 8, 4, 9, 2);
2783
2784 CloseSavedPage(saved_page);
2785 CloseSavedDocument();
2786 }
2787
2788 // TODO(crbug.com/pdfium/11): Fix this test and enable.
2789 #if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
2790 #define MAYBE_AddMarkCompressedStream DISABLED_AddMarkCompressedStream
2791 #else
2792 #define MAYBE_AddMarkCompressedStream AddMarkCompressedStream
2793 #endif
TEST_F(FPDFEditEmbedderTest,MAYBE_AddMarkCompressedStream)2794 TEST_F(FPDFEditEmbedderTest, MAYBE_AddMarkCompressedStream) {
2795 #if defined(OS_MACOSX)
2796 const char kOriginalMD5[] = "b90475ca64d1348c3bf5e2b77ad9187a";
2797 #elif defined(OS_WIN)
2798 const char kOriginalMD5[] = "795b7ce1626931aa06af0fa23b7d80bb";
2799 #else
2800 const char kOriginalMD5[] = "2baa4c0e1758deba1b9c908e1fbd04ed";
2801 #endif
2802
2803 // Load document with some text in a compressed stream.
2804 EXPECT_TRUE(OpenDocument("hello_world_compressed_stream.pdf"));
2805 FPDF_PAGE page = LoadPage(0);
2806 ASSERT_TRUE(page);
2807
2808 // Render and check there are no marks.
2809 {
2810 ScopedFPDFBitmap page_bitmap = RenderPage(page);
2811 CompareBitmap(page_bitmap.get(), 200, 200, kOriginalMD5);
2812 }
2813 CheckMarkCounts(page, 0, 2, 0, 0, 0, 0);
2814
2815 // Add to the first page object a "Bounds" mark with "Position": "First".
2816 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
2817 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_AddMark(page_object, "Bounds");
2818 EXPECT_TRUE(mark);
2819 EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), page_object, mark,
2820 "Position", "First"));
2821
2822 // Render and check there is 1 mark.
2823 {
2824 ScopedFPDFBitmap page_bitmap = RenderPage(page);
2825 CompareBitmap(page_bitmap.get(), 200, 200, kOriginalMD5);
2826 }
2827 CheckMarkCounts(page, 0, 2, 0, 0, 0, 1);
2828
2829 // Save the file.
2830 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2831 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2832 UnloadPage(page);
2833
2834 // Re-open the file and check the new mark is present.
2835 ASSERT_TRUE(OpenSavedDocument());
2836 FPDF_PAGE saved_page = LoadSavedPage(0);
2837
2838 {
2839 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
2840 CompareBitmap(page_bitmap.get(), 200, 200, kOriginalMD5);
2841 }
2842 CheckMarkCounts(saved_page, 0, 2, 0, 0, 0, 1);
2843
2844 CloseSavedPage(saved_page);
2845 CloseSavedDocument();
2846 }
2847
TEST_F(FPDFEditEmbedderTest,SetMarkParam)2848 TEST_F(FPDFEditEmbedderTest, SetMarkParam) {
2849 // Load document with some text.
2850 EXPECT_TRUE(OpenDocument("text_in_page_marked.pdf"));
2851 FPDF_PAGE page = LoadPage(0);
2852 ASSERT_TRUE(page);
2853
2854 constexpr int kExpectedObjectCount = 19;
2855 CheckMarkCounts(page, 1, kExpectedObjectCount, 8, 4, 9, 1);
2856
2857 // Check the "Bounds" mark's "Position" param is "Last".
2858 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
2859 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
2860 ASSERT_TRUE(mark);
2861 char buffer[256];
2862 unsigned long name_len = 999u;
2863 ASSERT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
2864 EXPECT_EQ((6u + 1u) * 2u, name_len);
2865 ASSERT_EQ(L"Bounds",
2866 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
2867 unsigned long out_buffer_len;
2868 ASSERT_TRUE(FPDFPageObjMark_GetParamStringValue(
2869 mark, "Position", buffer, sizeof(buffer), &out_buffer_len));
2870 ASSERT_EQ(L"Last",
2871 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
2872
2873 // Set is to "End".
2874 EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), page_object, mark,
2875 "Position", "End"));
2876
2877 // Verify the object passed must correspond to the mark passed.
2878 FPDF_PAGEOBJECT another_page_object = FPDFPage_GetObject(page, 17);
2879 EXPECT_FALSE(FPDFPageObjMark_SetStringParam(document(), another_page_object,
2880 mark, "Position", "End"));
2881
2882 // Verify nothing else changed.
2883 CheckMarkCounts(page, 1, kExpectedObjectCount, 8, 4, 9, 1);
2884
2885 // Verify "Position" now maps to "End".
2886 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(
2887 mark, "Position", buffer, sizeof(buffer), &out_buffer_len));
2888 EXPECT_EQ(L"End",
2889 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
2890
2891 // Save the file
2892 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2893 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2894 UnloadPage(page);
2895
2896 // Re-open the file and cerify "Position" still maps to "End".
2897 ASSERT_TRUE(OpenSavedDocument());
2898 FPDF_PAGE saved_page = LoadSavedPage(0);
2899
2900 CheckMarkCounts(saved_page, 1, kExpectedObjectCount, 8, 4, 9, 1);
2901 page_object = FPDFPage_GetObject(saved_page, 18);
2902 mark = FPDFPageObj_GetMark(page_object, 1);
2903 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(
2904 mark, "Position", buffer, sizeof(buffer), &out_buffer_len));
2905 EXPECT_EQ(L"End",
2906 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
2907
2908 CloseSavedPage(saved_page);
2909 CloseSavedDocument();
2910 }
2911
2912 // TODO(crbug.com/pdfium/11): Fix this test and enable.
2913 #if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
2914 #define MAYBE_AddMarkedText DISABLED_AddMarkedText
2915 #else
2916 #define MAYBE_AddMarkedText AddMarkedText
2917 #endif
TEST_F(FPDFEditEmbedderTest,MAYBE_AddMarkedText)2918 TEST_F(FPDFEditEmbedderTest, MAYBE_AddMarkedText) {
2919 // Start with a blank page.
2920 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
2921
2922 RetainPtr<CPDF_Font> stock_font =
2923 CPDF_Font::GetStockFont(cpdf_doc(), "Arial");
2924 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
2925 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
2926 FPDF_FONT_TRUETYPE, 0));
2927 ASSERT_TRUE(font.get());
2928
2929 // Add some text to the page.
2930 FPDF_PAGEOBJECT text_object =
2931 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
2932
2933 EXPECT_TRUE(text_object);
2934 ScopedFPDFWideString text1 =
2935 GetFPDFWideString(L"I am testing my loaded font, WEE.");
2936 EXPECT_TRUE(FPDFText_SetText(text_object, text1.get()));
2937 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 400, 400);
2938 FPDFPage_InsertObject(page, text_object);
2939
2940 // Add a mark with the tag "TestMarkName" to that text.
2941 EXPECT_EQ(0, FPDFPageObj_CountMarks(text_object));
2942 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_AddMark(text_object, "Test Mark Name");
2943 EXPECT_TRUE(mark);
2944 EXPECT_EQ(1, FPDFPageObj_CountMarks(text_object));
2945 EXPECT_EQ(mark, FPDFPageObj_GetMark(text_object, 0));
2946 char buffer[256];
2947 unsigned long name_len = 999u;
2948 ASSERT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
2949 EXPECT_EQ((14u + 1u) * 2, name_len);
2950 std::wstring name =
2951 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
2952 EXPECT_EQ(L"Test Mark Name", name);
2953
2954 // Add parameters:
2955 // - int "IntKey" : 42
2956 // - string "StringKey": "StringValue"
2957 // - blob "BlobKey": "\x01\x02\x03\0BlobValue1\0\0\0BlobValue2\0"
2958 constexpr size_t kBlobLen = 28;
2959 char block_value[kBlobLen];
2960 memcpy(block_value, "\x01\x02\x03\0BlobValue1\0\0\0BlobValue2\0", kBlobLen);
2961 EXPECT_EQ(0, FPDFPageObjMark_CountParams(mark));
2962 EXPECT_TRUE(
2963 FPDFPageObjMark_SetIntParam(document(), text_object, mark, "IntKey", 42));
2964 EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), text_object, mark,
2965 "StringKey", "StringValue"));
2966 EXPECT_TRUE(FPDFPageObjMark_SetBlobParam(document(), text_object, mark,
2967 "BlobKey", block_value, kBlobLen));
2968 EXPECT_EQ(3, FPDFPageObjMark_CountParams(mark));
2969
2970 // Check the two parameters can be retrieved.
2971 EXPECT_EQ(FPDF_OBJECT_NUMBER,
2972 FPDFPageObjMark_GetParamValueType(mark, "IntKey"));
2973 int int_value;
2974 EXPECT_TRUE(FPDFPageObjMark_GetParamIntValue(mark, "IntKey", &int_value));
2975 EXPECT_EQ(42, int_value);
2976
2977 EXPECT_EQ(FPDF_OBJECT_STRING,
2978 FPDFPageObjMark_GetParamValueType(mark, "StringKey"));
2979 unsigned long out_buffer_len = 999u;
2980 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(
2981 mark, "StringKey", buffer, sizeof(buffer), &out_buffer_len));
2982 EXPECT_GT(out_buffer_len, 0u);
2983 EXPECT_NE(999u, out_buffer_len);
2984 name = GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
2985 EXPECT_EQ(L"StringValue", name);
2986
2987 EXPECT_EQ(FPDF_OBJECT_STRING,
2988 FPDFPageObjMark_GetParamValueType(mark, "BlobKey"));
2989 out_buffer_len = 0;
2990 EXPECT_TRUE(FPDFPageObjMark_GetParamBlobValue(
2991 mark, "BlobKey", buffer, sizeof(buffer), &out_buffer_len));
2992 EXPECT_EQ(kBlobLen, out_buffer_len);
2993 EXPECT_EQ(0, memcmp(block_value, buffer, kBlobLen));
2994
2995 // Render and check the bitmap is the expected one.
2996 #if defined(OS_MACOSX)
2997 const char md5[] = "17d2b6cd574cf66170b09c8927529a94";
2998 #elif defined(OS_WIN)
2999 const char md5[] = "d60ba39f9698e32360d99e727dd93165";
3000 #else
3001 const char md5[] = "70592859010ffbf532a2237b8118bcc4";
3002 #endif
3003 {
3004 ScopedFPDFBitmap page_bitmap = RenderPage(page);
3005 CompareBitmap(page_bitmap.get(), 612, 792, md5);
3006 }
3007
3008 // Now save the result.
3009 EXPECT_EQ(1, FPDFPage_CountObjects(page));
3010 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3011 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3012
3013 FPDF_ClosePage(page);
3014
3015 // Re-open the file and check the changes were kept in the saved .pdf.
3016 ASSERT_TRUE(OpenSavedDocument());
3017 FPDF_PAGE saved_page = LoadSavedPage(0);
3018 EXPECT_EQ(1, FPDFPage_CountObjects(saved_page));
3019
3020 text_object = FPDFPage_GetObject(saved_page, 0);
3021 EXPECT_TRUE(text_object);
3022 EXPECT_EQ(1, FPDFPageObj_CountMarks(text_object));
3023 mark = FPDFPageObj_GetMark(text_object, 0);
3024 EXPECT_TRUE(mark);
3025
3026 name_len = 999u;
3027 ASSERT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
3028 EXPECT_EQ((14u + 1u) * 2, name_len);
3029 name = GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
3030 EXPECT_EQ(L"Test Mark Name", name);
3031
3032 CloseSavedPage(saved_page);
3033 CloseSavedDocument();
3034 }
3035
TEST_F(FPDFEditEmbedderTest,MarkGetName)3036 TEST_F(FPDFEditEmbedderTest, MarkGetName) {
3037 EXPECT_TRUE(OpenDocument("text_in_page_marked.pdf"));
3038 FPDF_PAGE page = LoadPage(0);
3039 ASSERT_TRUE(page);
3040 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
3041 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
3042 ASSERT_TRUE(mark);
3043
3044 char buffer[256];
3045 unsigned long out_len;
3046
3047 // Show the positive cases of FPDFPageObjMark_GetName.
3048 out_len = 999u;
3049 EXPECT_TRUE(FPDFPageObjMark_GetName(mark, nullptr, 0, &out_len));
3050 EXPECT_EQ((6u + 1u) * 2u, out_len);
3051
3052 out_len = 999u;
3053 EXPECT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &out_len));
3054 EXPECT_EQ(L"Bounds",
3055 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3056 EXPECT_EQ((6u + 1u) * 2u, out_len);
3057
3058 // Show the negative cases of FPDFPageObjMark_GetName.
3059 out_len = 999u;
3060 EXPECT_FALSE(
3061 FPDFPageObjMark_GetName(nullptr, buffer, sizeof(buffer), &out_len));
3062 EXPECT_EQ(999u, out_len);
3063
3064 EXPECT_FALSE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), nullptr));
3065
3066 UnloadPage(page);
3067 }
3068
TEST_F(FPDFEditEmbedderTest,MarkGetParamKey)3069 TEST_F(FPDFEditEmbedderTest, MarkGetParamKey) {
3070 EXPECT_TRUE(OpenDocument("text_in_page_marked.pdf"));
3071 FPDF_PAGE page = LoadPage(0);
3072 ASSERT_TRUE(page);
3073 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
3074 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
3075 ASSERT_TRUE(mark);
3076
3077 char buffer[256];
3078 unsigned long out_len;
3079
3080 // Show the positive cases of FPDFPageObjMark_GetParamKey.
3081 out_len = 999u;
3082 EXPECT_TRUE(FPDFPageObjMark_GetParamKey(mark, 0, nullptr, 0, &out_len));
3083 EXPECT_EQ((8u + 1u) * 2u, out_len);
3084
3085 out_len = 999u;
3086 EXPECT_TRUE(
3087 FPDFPageObjMark_GetParamKey(mark, 0, buffer, sizeof(buffer), &out_len));
3088 EXPECT_EQ(L"Position",
3089 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3090 EXPECT_EQ((8u + 1u) * 2u, out_len);
3091
3092 // Show the negative cases of FPDFPageObjMark_GetParamKey.
3093 out_len = 999u;
3094 EXPECT_FALSE(FPDFPageObjMark_GetParamKey(nullptr, 0, buffer, sizeof(buffer),
3095 &out_len));
3096 EXPECT_EQ(999u, out_len);
3097
3098 out_len = 999u;
3099 EXPECT_FALSE(
3100 FPDFPageObjMark_GetParamKey(mark, 1, buffer, sizeof(buffer), &out_len));
3101 EXPECT_EQ(999u, out_len);
3102
3103 EXPECT_FALSE(
3104 FPDFPageObjMark_GetParamKey(mark, 0, buffer, sizeof(buffer), nullptr));
3105
3106 UnloadPage(page);
3107 }
3108
TEST_F(FPDFEditEmbedderTest,MarkGetIntParam)3109 TEST_F(FPDFEditEmbedderTest, MarkGetIntParam) {
3110 EXPECT_TRUE(OpenDocument("text_in_page_marked.pdf"));
3111 FPDF_PAGE page = LoadPage(0);
3112 ASSERT_TRUE(page);
3113 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 8);
3114 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 0);
3115 ASSERT_TRUE(mark);
3116
3117 int out_value;
3118
3119 // Show the positive cases of FPDFPageObjMark_GetParamIntValue.
3120 out_value = 999;
3121 EXPECT_TRUE(FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
3122 EXPECT_EQ(3, out_value);
3123
3124 // Show the negative cases of FPDFPageObjMark_GetParamIntValue.
3125 out_value = 999;
3126 EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(nullptr, "Factor", &out_value));
3127 EXPECT_EQ(999, out_value);
3128
3129 out_value = 999;
3130 EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(mark, "ParamThatDoesNotExist",
3131 &out_value));
3132 EXPECT_EQ(999, out_value);
3133
3134 EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(mark, "Factor", nullptr));
3135
3136 page_object = FPDFPage_GetObject(page, 18);
3137 mark = FPDFPageObj_GetMark(page_object, 1);
3138 out_value = 999;
3139 EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(mark, "Position", &out_value));
3140 EXPECT_EQ(999, out_value);
3141
3142 UnloadPage(page);
3143 }
3144
TEST_F(FPDFEditEmbedderTest,MarkGetStringParam)3145 TEST_F(FPDFEditEmbedderTest, MarkGetStringParam) {
3146 EXPECT_TRUE(OpenDocument("text_in_page_marked.pdf"));
3147 FPDF_PAGE page = LoadPage(0);
3148 ASSERT_TRUE(page);
3149 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
3150 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
3151 ASSERT_TRUE(mark);
3152
3153 char buffer[256];
3154 unsigned long out_len;
3155
3156 // Show the positive cases of FPDFPageObjMark_GetParamStringValue.
3157 out_len = 999u;
3158 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(mark, "Position", nullptr, 0,
3159 &out_len));
3160 EXPECT_EQ((4u + 1u) * 2u, out_len);
3161
3162 out_len = 999u;
3163 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(mark, "Position", buffer,
3164 sizeof(buffer), &out_len));
3165 EXPECT_EQ(L"Last",
3166 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3167 EXPECT_EQ((4u + 1u) * 2u, out_len);
3168
3169 // Show the negative cases of FPDFPageObjMark_GetParamStringValue.
3170 out_len = 999u;
3171 EXPECT_FALSE(FPDFPageObjMark_GetParamStringValue(nullptr, "Position", buffer,
3172 sizeof(buffer), &out_len));
3173 EXPECT_EQ(999u, out_len);
3174
3175 out_len = 999u;
3176 EXPECT_FALSE(FPDFPageObjMark_GetParamStringValue(
3177 mark, "ParamThatDoesNotExist", buffer, sizeof(buffer), &out_len));
3178 EXPECT_EQ(999u, out_len);
3179
3180 EXPECT_FALSE(FPDFPageObjMark_GetParamStringValue(mark, "Position", buffer,
3181 sizeof(buffer), nullptr));
3182
3183 page_object = FPDFPage_GetObject(page, 8);
3184 mark = FPDFPageObj_GetMark(page_object, 0);
3185 out_len = 999u;
3186 EXPECT_FALSE(FPDFPageObjMark_GetParamStringValue(mark, "Factor", buffer,
3187 sizeof(buffer), &out_len));
3188 EXPECT_EQ(999u, out_len);
3189
3190 UnloadPage(page);
3191 }
3192
TEST_F(FPDFEditEmbedderTest,ExtractImageBitmap)3193 TEST_F(FPDFEditEmbedderTest, ExtractImageBitmap) {
3194 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
3195 FPDF_PAGE page = LoadPage(0);
3196 ASSERT_TRUE(page);
3197 ASSERT_EQ(39, FPDFPage_CountObjects(page));
3198
3199 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 32);
3200 EXPECT_NE(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3201 EXPECT_FALSE(FPDFImageObj_GetBitmap(obj));
3202
3203 obj = FPDFPage_GetObject(page, 33);
3204 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3205 FPDF_BITMAP bitmap = FPDFImageObj_GetBitmap(obj);
3206 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap));
3207 CompareBitmap(bitmap, 109, 88, "cb3637934bb3b95a6e4ae1ea9eb9e56e");
3208 FPDFBitmap_Destroy(bitmap);
3209
3210 obj = FPDFPage_GetObject(page, 34);
3211 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3212 bitmap = FPDFImageObj_GetBitmap(obj);
3213 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap));
3214 CompareBitmap(bitmap, 103, 75, "c8d51fa6821ceb2a67f08446ff236c40");
3215 FPDFBitmap_Destroy(bitmap);
3216
3217 obj = FPDFPage_GetObject(page, 35);
3218 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3219 bitmap = FPDFImageObj_GetBitmap(obj);
3220 EXPECT_EQ(FPDFBitmap_Gray, FPDFBitmap_GetFormat(bitmap));
3221 CompareBitmap(bitmap, 92, 68, "9c6d76cb1e37ef8514f9455d759391f3");
3222 FPDFBitmap_Destroy(bitmap);
3223
3224 obj = FPDFPage_GetObject(page, 36);
3225 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3226 bitmap = FPDFImageObj_GetBitmap(obj);
3227 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap));
3228 CompareBitmap(bitmap, 79, 60, "f4e72fb783a01c7b4614cdc25eaa98ac");
3229 FPDFBitmap_Destroy(bitmap);
3230
3231 obj = FPDFPage_GetObject(page, 37);
3232 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3233 bitmap = FPDFImageObj_GetBitmap(obj);
3234 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap));
3235 CompareBitmap(bitmap, 126, 106, "2cf9e66414c72461f4ccbf9cdebdfa1b");
3236 FPDFBitmap_Destroy(bitmap);
3237
3238 obj = FPDFPage_GetObject(page, 38);
3239 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3240 bitmap = FPDFImageObj_GetBitmap(obj);
3241 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap));
3242 CompareBitmap(bitmap, 194, 119, "a8f3a126cec274dab8242fd2ccdc1b8b");
3243 FPDFBitmap_Destroy(bitmap);
3244 UnloadPage(page);
3245 }
3246
TEST_F(FPDFEditEmbedderTest,ExtractJBigImageBitmap)3247 TEST_F(FPDFEditEmbedderTest, ExtractJBigImageBitmap) {
3248 ASSERT_TRUE(OpenDocument("bug_631912.pdf"));
3249 FPDF_PAGE page = LoadPage(0);
3250 ASSERT_TRUE(page);
3251 ASSERT_EQ(1, FPDFPage_CountObjects(page));
3252
3253 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 0);
3254 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3255 {
3256 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3257 ASSERT_TRUE(bitmap);
3258 EXPECT_EQ(FPDFBitmap_Gray, FPDFBitmap_GetFormat(bitmap.get()));
3259 CompareBitmap(bitmap.get(), 1152, 720, "3f6a48e2b3e91b799bf34567f55cb4de");
3260 }
3261
3262 UnloadPage(page);
3263 }
3264
TEST_F(FPDFEditEmbedderTest,GetImageData)3265 TEST_F(FPDFEditEmbedderTest, GetImageData) {
3266 EXPECT_TRUE(OpenDocument("embedded_images.pdf"));
3267 FPDF_PAGE page = LoadPage(0);
3268 ASSERT_TRUE(page);
3269 ASSERT_EQ(39, FPDFPage_CountObjects(page));
3270
3271 // Retrieve an image object with flate-encoded data stream.
3272 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 33);
3273 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3274
3275 // Check that the raw image data has the correct length and hash value.
3276 unsigned long len = FPDFImageObj_GetImageDataRaw(obj, nullptr, 0);
3277 std::vector<char> buf(len);
3278 EXPECT_EQ(4091u, FPDFImageObj_GetImageDataRaw(obj, buf.data(), len));
3279 EXPECT_EQ("f73802327d2e88e890f653961bcda81a",
3280 GenerateMD5Base16(reinterpret_cast<uint8_t*>(buf.data()), len));
3281
3282 // Check that the decoded image data has the correct length and hash value.
3283 len = FPDFImageObj_GetImageDataDecoded(obj, nullptr, 0);
3284 buf.clear();
3285 buf.resize(len);
3286 EXPECT_EQ(28776u, FPDFImageObj_GetImageDataDecoded(obj, buf.data(), len));
3287 EXPECT_EQ("cb3637934bb3b95a6e4ae1ea9eb9e56e",
3288 GenerateMD5Base16(reinterpret_cast<uint8_t*>(buf.data()), len));
3289
3290 // Retrieve an image object with DCTDecode-encoded data stream.
3291 obj = FPDFPage_GetObject(page, 37);
3292 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3293
3294 // Check that the raw image data has the correct length and hash value.
3295 len = FPDFImageObj_GetImageDataRaw(obj, nullptr, 0);
3296 buf.clear();
3297 buf.resize(len);
3298 EXPECT_EQ(4370u, FPDFImageObj_GetImageDataRaw(obj, buf.data(), len));
3299 EXPECT_EQ("6aae1f3710335023a9e12191be66b64b",
3300 GenerateMD5Base16(reinterpret_cast<uint8_t*>(buf.data()), len));
3301
3302 // Check that the decoded image data has the correct length and hash value,
3303 // which should be the same as those of the raw data, since this image is
3304 // encoded by a single DCTDecode filter and decoding is a noop.
3305 len = FPDFImageObj_GetImageDataDecoded(obj, nullptr, 0);
3306 buf.clear();
3307 buf.resize(len);
3308 EXPECT_EQ(4370u, FPDFImageObj_GetImageDataDecoded(obj, buf.data(), len));
3309 EXPECT_EQ("6aae1f3710335023a9e12191be66b64b",
3310 GenerateMD5Base16(reinterpret_cast<uint8_t*>(buf.data()), len));
3311
3312 UnloadPage(page);
3313 }
3314
TEST_F(FPDFEditEmbedderTest,GetImageMatrix)3315 TEST_F(FPDFEditEmbedderTest, GetImageMatrix) {
3316 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
3317 FPDF_PAGE page = LoadPage(0);
3318 ASSERT_TRUE(page);
3319 ASSERT_EQ(39, FPDFPage_CountObjects(page));
3320
3321 FPDF_PAGEOBJECT obj;
3322 double a;
3323 double b;
3324 double c;
3325 double d;
3326 double e;
3327 double f;
3328
3329 obj = FPDFPage_GetObject(page, 33);
3330 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3331 EXPECT_TRUE(FPDFImageObj_GetMatrix(obj, &a, &b, &c, &d, &e, &f));
3332 EXPECT_DOUBLE_EQ(53.0, a);
3333 EXPECT_DOUBLE_EQ(0.0, b);
3334 EXPECT_DOUBLE_EQ(0.0, c);
3335 EXPECT_DOUBLE_EQ(43.0, d);
3336 EXPECT_DOUBLE_EQ(72.0, e);
3337 EXPECT_DOUBLE_EQ(646.510009765625, f);
3338
3339 obj = FPDFPage_GetObject(page, 34);
3340 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3341 EXPECT_TRUE(FPDFImageObj_GetMatrix(obj, &a, &b, &c, &d, &e, &f));
3342 EXPECT_DOUBLE_EQ(70.0, a);
3343 EXPECT_DOUBLE_EQ(0.0, b);
3344 EXPECT_DOUBLE_EQ(0.0, c);
3345 EXPECT_DOUBLE_EQ(51.0, d);
3346 EXPECT_DOUBLE_EQ(216.0, e);
3347 EXPECT_DOUBLE_EQ(646.510009765625, f);
3348
3349 obj = FPDFPage_GetObject(page, 35);
3350 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3351 EXPECT_TRUE(FPDFImageObj_GetMatrix(obj, &a, &b, &c, &d, &e, &f));
3352 EXPECT_DOUBLE_EQ(69.0, a);
3353 EXPECT_DOUBLE_EQ(0.0, b);
3354 EXPECT_DOUBLE_EQ(0.0, c);
3355 EXPECT_DOUBLE_EQ(51.0, d);
3356 EXPECT_DOUBLE_EQ(360.0, e);
3357 EXPECT_DOUBLE_EQ(646.510009765625, f);
3358
3359 obj = FPDFPage_GetObject(page, 36);
3360 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3361 EXPECT_TRUE(FPDFImageObj_GetMatrix(obj, &a, &b, &c, &d, &e, &f));
3362 EXPECT_DOUBLE_EQ(59.0, a);
3363 EXPECT_DOUBLE_EQ(0.0, b);
3364 EXPECT_DOUBLE_EQ(0.0, c);
3365 EXPECT_DOUBLE_EQ(45.0, d);
3366 EXPECT_DOUBLE_EQ(72.0, e);
3367 EXPECT_DOUBLE_EQ(553.510009765625, f);
3368
3369 obj = FPDFPage_GetObject(page, 37);
3370 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3371 EXPECT_TRUE(FPDFImageObj_GetMatrix(obj, &a, &b, &c, &d, &e, &f));
3372 EXPECT_DOUBLE_EQ(55.94000244140625, a);
3373 EXPECT_DOUBLE_EQ(0.0, b);
3374 EXPECT_DOUBLE_EQ(0.0, c);
3375 EXPECT_DOUBLE_EQ(46.950000762939453, d);
3376 EXPECT_DOUBLE_EQ(216.0, e);
3377 EXPECT_DOUBLE_EQ(552.510009765625, f);
3378
3379 obj = FPDFPage_GetObject(page, 38);
3380 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3381 EXPECT_TRUE(FPDFImageObj_GetMatrix(obj, &a, &b, &c, &d, &e, &f));
3382 EXPECT_DOUBLE_EQ(70.528999328613281, a);
3383 EXPECT_DOUBLE_EQ(0.0, b);
3384 EXPECT_DOUBLE_EQ(0.0, c);
3385 EXPECT_DOUBLE_EQ(43.149997711181641, d);
3386 EXPECT_DOUBLE_EQ(360.0, e);
3387 EXPECT_DOUBLE_EQ(553.3599853515625, f);
3388
3389 UnloadPage(page);
3390 }
3391
TEST_F(FPDFEditEmbedderTest,DestroyPageObject)3392 TEST_F(FPDFEditEmbedderTest, DestroyPageObject) {
3393 FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(10, 10, 20, 20);
3394 ASSERT_TRUE(rect);
3395
3396 // There should be no memory leaks with a call to FPDFPageObj_Destroy().
3397 FPDFPageObj_Destroy(rect);
3398 }
3399
TEST_F(FPDFEditEmbedderTest,GetImageFilters)3400 TEST_F(FPDFEditEmbedderTest, GetImageFilters) {
3401 EXPECT_TRUE(OpenDocument("embedded_images.pdf"));
3402 FPDF_PAGE page = LoadPage(0);
3403 ASSERT_TRUE(page);
3404
3405 // Verify that retrieving the filter of a non-image object would fail.
3406 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 32);
3407 ASSERT_NE(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3408 ASSERT_EQ(0, FPDFImageObj_GetImageFilterCount(obj));
3409 EXPECT_EQ(0u, FPDFImageObj_GetImageFilter(obj, 0, nullptr, 0));
3410
3411 // Verify the returned filter string for an image object with a single filter.
3412 obj = FPDFPage_GetObject(page, 33);
3413 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3414 ASSERT_EQ(1, FPDFImageObj_GetImageFilterCount(obj));
3415 unsigned long len = FPDFImageObj_GetImageFilter(obj, 0, nullptr, 0);
3416 std::vector<char> buf(len);
3417 static constexpr char kFlateDecode[] = "FlateDecode";
3418 EXPECT_EQ(sizeof(kFlateDecode),
3419 FPDFImageObj_GetImageFilter(obj, 0, buf.data(), len));
3420 EXPECT_STREQ(kFlateDecode, buf.data());
3421 EXPECT_EQ(0u, FPDFImageObj_GetImageFilter(obj, 1, nullptr, 0));
3422
3423 // Verify all the filters for an image object with a list of filters.
3424 obj = FPDFPage_GetObject(page, 38);
3425 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3426 ASSERT_EQ(2, FPDFImageObj_GetImageFilterCount(obj));
3427 len = FPDFImageObj_GetImageFilter(obj, 0, nullptr, 0);
3428 buf.clear();
3429 buf.resize(len);
3430 static constexpr char kASCIIHexDecode[] = "ASCIIHexDecode";
3431 EXPECT_EQ(sizeof(kASCIIHexDecode),
3432 FPDFImageObj_GetImageFilter(obj, 0, buf.data(), len));
3433 EXPECT_STREQ(kASCIIHexDecode, buf.data());
3434
3435 len = FPDFImageObj_GetImageFilter(obj, 1, nullptr, 0);
3436 buf.clear();
3437 buf.resize(len);
3438 static constexpr char kDCTDecode[] = "DCTDecode";
3439 EXPECT_EQ(sizeof(kDCTDecode),
3440 FPDFImageObj_GetImageFilter(obj, 1, buf.data(), len));
3441 EXPECT_STREQ(kDCTDecode, buf.data());
3442
3443 UnloadPage(page);
3444 }
3445
TEST_F(FPDFEditEmbedderTest,GetImageMetadata)3446 TEST_F(FPDFEditEmbedderTest, GetImageMetadata) {
3447 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
3448 FPDF_PAGE page = LoadPage(0);
3449 ASSERT_TRUE(page);
3450
3451 // Check that getting the metadata of a null object would fail.
3452 FPDF_IMAGEOBJ_METADATA metadata;
3453 EXPECT_FALSE(FPDFImageObj_GetImageMetadata(nullptr, page, &metadata));
3454
3455 // Check that receiving the metadata with a null metadata object would fail.
3456 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 35);
3457 EXPECT_FALSE(FPDFImageObj_GetImageMetadata(obj, page, nullptr));
3458
3459 // Check that when retrieving an image object's metadata without passing in
3460 // |page|, all values are correct, with the last two being default values.
3461 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3462 ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, nullptr, &metadata));
3463 EXPECT_EQ(7, metadata.marked_content_id);
3464 EXPECT_EQ(92u, metadata.width);
3465 EXPECT_EQ(68u, metadata.height);
3466 EXPECT_FLOAT_EQ(96.0f, metadata.horizontal_dpi);
3467 EXPECT_FLOAT_EQ(96.0f, metadata.vertical_dpi);
3468 EXPECT_EQ(0u, metadata.bits_per_pixel);
3469 EXPECT_EQ(FPDF_COLORSPACE_UNKNOWN, metadata.colorspace);
3470
3471 // Verify the metadata of a bitmap image with indexed colorspace.
3472 ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, page, &metadata));
3473 EXPECT_EQ(7, metadata.marked_content_id);
3474 EXPECT_EQ(92u, metadata.width);
3475 EXPECT_EQ(68u, metadata.height);
3476 EXPECT_FLOAT_EQ(96.0f, metadata.horizontal_dpi);
3477 EXPECT_FLOAT_EQ(96.0f, metadata.vertical_dpi);
3478 EXPECT_EQ(1u, metadata.bits_per_pixel);
3479 EXPECT_EQ(FPDF_COLORSPACE_INDEXED, metadata.colorspace);
3480
3481 // Verify the metadata of an image with RGB colorspace.
3482 obj = FPDFPage_GetObject(page, 37);
3483 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3484 ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, page, &metadata));
3485 EXPECT_EQ(9, metadata.marked_content_id);
3486 EXPECT_EQ(126u, metadata.width);
3487 EXPECT_EQ(106u, metadata.height);
3488 EXPECT_FLOAT_EQ(162.173752f, metadata.horizontal_dpi);
3489 EXPECT_FLOAT_EQ(162.555878f, metadata.vertical_dpi);
3490 EXPECT_EQ(24u, metadata.bits_per_pixel);
3491 EXPECT_EQ(FPDF_COLORSPACE_DEVICERGB, metadata.colorspace);
3492
3493 UnloadPage(page);
3494 }
3495