1 // Copyright 2017 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "public/fpdf_annot.h"
6
7 #include <limits.h>
8
9 #include <algorithm>
10 #include <string>
11 #include <vector>
12
13 #include "build/build_config.h"
14 #include "constants/annotation_common.h"
15 #include "core/fpdfapi/page/cpdf_annotcontext.h"
16 #include "core/fpdfapi/parser/cpdf_array.h"
17 #include "core/fpdfapi/parser/cpdf_dictionary.h"
18 #include "core/fxcrt/fx_system.h"
19 #include "core/fxge/cfx_defaultrenderdevice.h"
20 #include "fpdfsdk/cpdfsdk_helpers.h"
21 #include "public/cpp/fpdf_scopers.h"
22 #include "public/fpdf_edit.h"
23 #include "public/fpdf_formfill.h"
24 #include "public/fpdfview.h"
25 #include "testing/embedder_test.h"
26 #include "testing/embedder_test_constants.h"
27 #include "testing/fx_string_testhelpers.h"
28 #include "testing/gmock/include/gmock/gmock-matchers.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30 #include "testing/utils/hash.h"
31 #include "third_party/base/containers/contains.h"
32 #include "third_party/base/containers/span.h"
33
34 using pdfium::AnnotationStampWithApChecksum;
35
36 namespace {
37
38 const wchar_t kStreamData[] =
39 L"/GS gs 0.0 0.0 0.0 RG 4 w 211.8 747.6 m 211.8 744.8 "
40 L"212.6 743.0 214.2 740.8 "
41 L"c 215.4 739.0 216.8 737.1 218.9 736.1 c 220.8 735.1 221.4 733.0 "
42 L"223.7 732.4 c 232.6 729.9 242.0 730.8 251.2 730.8 c 257.5 730.8 "
43 L"263.0 732.9 269.0 734.4 c S";
44
VerifyFocusableAnnotSubtypes(FPDF_FORMHANDLE form_handle,pdfium::span<const FPDF_ANNOTATION_SUBTYPE> expected_subtypes)45 void VerifyFocusableAnnotSubtypes(
46 FPDF_FORMHANDLE form_handle,
47 pdfium::span<const FPDF_ANNOTATION_SUBTYPE> expected_subtypes) {
48 ASSERT_EQ(static_cast<int>(expected_subtypes.size()),
49 FPDFAnnot_GetFocusableSubtypesCount(form_handle));
50
51 std::vector<FPDF_ANNOTATION_SUBTYPE> actual_subtypes(
52 expected_subtypes.size());
53 ASSERT_TRUE(FPDFAnnot_GetFocusableSubtypes(
54 form_handle, actual_subtypes.data(), actual_subtypes.size()));
55 for (size_t i = 0; i < expected_subtypes.size(); ++i)
56 ASSERT_EQ(expected_subtypes[i], actual_subtypes[i]);
57 }
58
SetAndVerifyFocusableAnnotSubtypes(FPDF_FORMHANDLE form_handle,pdfium::span<const FPDF_ANNOTATION_SUBTYPE> subtypes)59 void SetAndVerifyFocusableAnnotSubtypes(
60 FPDF_FORMHANDLE form_handle,
61 pdfium::span<const FPDF_ANNOTATION_SUBTYPE> subtypes) {
62 ASSERT_TRUE(FPDFAnnot_SetFocusableSubtypes(form_handle, subtypes.data(),
63 subtypes.size()));
64 VerifyFocusableAnnotSubtypes(form_handle, subtypes);
65 }
66
VerifyAnnotationSubtypesAndFocusability(FPDF_FORMHANDLE form_handle,FPDF_PAGE page,pdfium::span<const FPDF_ANNOTATION_SUBTYPE> expected_subtypes,pdfium::span<const FPDF_ANNOTATION_SUBTYPE> expected_focusable_subtypes)67 void VerifyAnnotationSubtypesAndFocusability(
68 FPDF_FORMHANDLE form_handle,
69 FPDF_PAGE page,
70 pdfium::span<const FPDF_ANNOTATION_SUBTYPE> expected_subtypes,
71 pdfium::span<const FPDF_ANNOTATION_SUBTYPE> expected_focusable_subtypes) {
72 ASSERT_EQ(static_cast<int>(expected_subtypes.size()),
73 FPDFPage_GetAnnotCount(page));
74 for (size_t i = 0; i < expected_subtypes.size(); ++i) {
75 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, i));
76 ASSERT_TRUE(annot);
77 EXPECT_EQ(expected_subtypes[i], FPDFAnnot_GetSubtype(annot.get()));
78
79 bool expected_focusable =
80 pdfium::Contains(expected_focusable_subtypes, expected_subtypes[i]);
81 EXPECT_EQ(expected_focusable,
82 FORM_SetFocusedAnnot(form_handle, annot.get()));
83
84 // Kill the focus so the next test starts in an unfocused state.
85 FORM_ForceToKillFocus(form_handle);
86 }
87 }
88
VerifyUriActionInLink(FPDF_DOCUMENT doc,FPDF_LINK link,const std::string & expected_uri)89 void VerifyUriActionInLink(FPDF_DOCUMENT doc,
90 FPDF_LINK link,
91 const std::string& expected_uri) {
92 ASSERT_TRUE(link);
93
94 FPDF_ACTION action = FPDFLink_GetAction(link);
95 ASSERT_TRUE(action);
96 EXPECT_EQ(static_cast<unsigned long>(PDFACTION_URI),
97 FPDFAction_GetType(action));
98
99 unsigned long bufsize = FPDFAction_GetURIPath(doc, action, nullptr, 0);
100 ASSERT_EQ(expected_uri.size() + 1, bufsize);
101
102 std::vector<char> buffer(bufsize);
103 EXPECT_EQ(bufsize,
104 FPDFAction_GetURIPath(doc, action, buffer.data(), bufsize));
105 EXPECT_STREQ(expected_uri.c_str(), buffer.data());
106 }
107
108 } // namespace
109
110 class FPDFAnnotEmbedderTest : public EmbedderTest {};
111
TEST_F(FPDFAnnotEmbedderTest,SetAP)112 TEST_F(FPDFAnnotEmbedderTest, SetAP) {
113 ScopedFPDFDocument doc(FPDF_CreateNewDocument());
114 ASSERT_TRUE(doc);
115 ScopedFPDFPage page(FPDFPage_New(doc.get(), 0, 100, 100));
116 ASSERT_TRUE(page);
117 ScopedFPDFWideString ap_stream = GetFPDFWideString(kStreamData);
118 ASSERT_TRUE(ap_stream);
119
120 ScopedFPDFAnnotation annot(FPDFPage_CreateAnnot(page.get(), FPDF_ANNOT_INK));
121 ASSERT_TRUE(annot);
122
123 // Negative case: FPDFAnnot_SetAP() should fail if bounding rect is not yet
124 // set on the annotation.
125 EXPECT_FALSE(FPDFAnnot_SetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_NORMAL,
126 ap_stream.get()));
127
128 const FS_RECTF bounding_rect{206.0f, 753.0f, 339.0f, 709.0f};
129 EXPECT_TRUE(FPDFAnnot_SetRect(annot.get(), &bounding_rect));
130
131 ASSERT_TRUE(FPDFAnnot_SetColor(annot.get(), FPDFANNOT_COLORTYPE_Color,
132 /*R=*/255, /*G=*/0, /*B=*/0, /*A=*/255));
133
134 EXPECT_TRUE(FPDFAnnot_SetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_NORMAL,
135 ap_stream.get()));
136
137 // Verify that appearance stream is created as form XObject
138 CPDF_AnnotContext* context = CPDFAnnotContextFromFPDFAnnotation(annot.get());
139 ASSERT_TRUE(context);
140 const CPDF_Dictionary* annot_dict = context->GetAnnotDict();
141 ASSERT_TRUE(annot_dict);
142 RetainPtr<const CPDF_Dictionary> ap_dict =
143 annot_dict->GetDictFor(pdfium::annotation::kAP);
144 ASSERT_TRUE(ap_dict);
145 RetainPtr<const CPDF_Dictionary> stream_dict = ap_dict->GetDictFor("N");
146 ASSERT_TRUE(stream_dict);
147 // Check for non-existence of resources dictionary in case of opaque color
148 RetainPtr<const CPDF_Dictionary> resources_dict =
149 stream_dict->GetDictFor("Resources");
150 ASSERT_FALSE(resources_dict);
151 ByteString type = stream_dict->GetByteStringFor(pdfium::annotation::kType);
152 EXPECT_EQ("XObject", type);
153 ByteString sub_type =
154 stream_dict->GetByteStringFor(pdfium::annotation::kSubtype);
155 EXPECT_EQ("Form", sub_type);
156
157 // Check that the appearance stream is same as we just set.
158 const uint32_t kStreamDataSize = std::size(kStreamData) * sizeof(FPDF_WCHAR);
159 unsigned long normal_length_bytes = FPDFAnnot_GetAP(
160 annot.get(), FPDF_ANNOT_APPEARANCEMODE_NORMAL, nullptr, 0);
161 ASSERT_EQ(kStreamDataSize, normal_length_bytes);
162 std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(normal_length_bytes);
163 EXPECT_EQ(kStreamDataSize,
164 FPDFAnnot_GetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_NORMAL,
165 buf.data(), normal_length_bytes));
166 EXPECT_EQ(kStreamData, GetPlatformWString(buf.data()));
167 }
168
TEST_F(FPDFAnnotEmbedderTest,SetAPWithOpacity)169 TEST_F(FPDFAnnotEmbedderTest, SetAPWithOpacity) {
170 ScopedFPDFDocument doc(FPDF_CreateNewDocument());
171 ASSERT_TRUE(doc);
172 ScopedFPDFPage page(FPDFPage_New(doc.get(), 0, 100, 100));
173 ASSERT_TRUE(page);
174 ScopedFPDFWideString ap_stream = GetFPDFWideString(kStreamData);
175 ASSERT_TRUE(ap_stream);
176
177 ScopedFPDFAnnotation annot(FPDFPage_CreateAnnot(page.get(), FPDF_ANNOT_INK));
178 ASSERT_TRUE(annot);
179
180 ASSERT_TRUE(FPDFAnnot_SetColor(annot.get(), FPDFANNOT_COLORTYPE_Color,
181 /*R=*/255, /*G=*/0, /*B=*/0, /*A=*/102));
182
183 const FS_RECTF bounding_rect{206.0f, 753.0f, 339.0f, 709.0f};
184 EXPECT_TRUE(FPDFAnnot_SetRect(annot.get(), &bounding_rect));
185
186 EXPECT_TRUE(FPDFAnnot_SetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_NORMAL,
187 ap_stream.get()));
188
189 CPDF_AnnotContext* context = CPDFAnnotContextFromFPDFAnnotation(annot.get());
190 ASSERT_TRUE(context);
191 const CPDF_Dictionary* annot_dict = context->GetAnnotDict();
192 ASSERT_TRUE(annot_dict);
193 RetainPtr<const CPDF_Dictionary> ap_dict =
194 annot_dict->GetDictFor(pdfium::annotation::kAP);
195 ASSERT_TRUE(ap_dict);
196 RetainPtr<const CPDF_Dictionary> stream_dict = ap_dict->GetDictFor("N");
197 ASSERT_TRUE(stream_dict);
198 RetainPtr<const CPDF_Dictionary> resources_dict =
199 stream_dict->GetDictFor("Resources");
200 ASSERT_TRUE(stream_dict);
201 RetainPtr<const CPDF_Dictionary> extGState_dict =
202 resources_dict->GetDictFor("ExtGState");
203 ASSERT_TRUE(extGState_dict);
204 RetainPtr<const CPDF_Dictionary> gs_dict = extGState_dict->GetDictFor("GS");
205 ASSERT_TRUE(gs_dict);
206 ByteString type = gs_dict->GetByteStringFor(pdfium::annotation::kType);
207 EXPECT_EQ("ExtGState", type);
208 float opacity = gs_dict->GetFloatFor("CA");
209 // Opacity value of 102 is represented as 0.4f (=104/255) in /CA entry.
210 EXPECT_FLOAT_EQ(0.4f, opacity);
211 ByteString blend_mode = gs_dict->GetByteStringFor("BM");
212 EXPECT_EQ("Normal", blend_mode);
213 bool alpha_source_flag = gs_dict->GetBooleanFor("AIS", true);
214 EXPECT_FALSE(alpha_source_flag);
215 }
216
TEST_F(FPDFAnnotEmbedderTest,InkListAPIValidations)217 TEST_F(FPDFAnnotEmbedderTest, InkListAPIValidations) {
218 ScopedFPDFDocument doc(FPDF_CreateNewDocument());
219 ASSERT_TRUE(doc);
220 ScopedFPDFPage page(FPDFPage_New(doc.get(), 0, 100, 100));
221 ASSERT_TRUE(page);
222
223 // Create a new ink annotation.
224 ScopedFPDFAnnotation ink_annot(
225 FPDFPage_CreateAnnot(page.get(), FPDF_ANNOT_INK));
226 ASSERT_TRUE(ink_annot);
227 CPDF_AnnotContext* context =
228 CPDFAnnotContextFromFPDFAnnotation(ink_annot.get());
229 ASSERT_TRUE(context);
230 const CPDF_Dictionary* annot_dict = context->GetAnnotDict();
231 ASSERT_TRUE(annot_dict);
232
233 static constexpr FS_POINTF kFirstInkStroke[] = {
234 {80.0f, 90.0f}, {81.0f, 91.0f}, {82.0f, 92.0f},
235 {83.0f, 93.0f}, {84.0f, 94.0f}, {85.0f, 95.0f}};
236 static constexpr size_t kFirstStrokePointCount = std::size(kFirstInkStroke);
237
238 static constexpr FS_POINTF kSecondInkStroke[] = {
239 {70.0f, 90.0f}, {71.0f, 91.0f}, {72.0f, 92.0f}};
240 static constexpr size_t kSecondStrokePointCount = std::size(kSecondInkStroke);
241
242 static constexpr FS_POINTF kThirdInkStroke[] = {{60.0f, 90.0f},
243 {61.0f, 91.0f},
244 {62.0f, 92.0f},
245 {63.0f, 93.0f},
246 {64.0f, 94.0f}};
247 static constexpr size_t kThirdStrokePointCount = std::size(kThirdInkStroke);
248
249 // Negative test: |annot| is passed as nullptr.
250 EXPECT_EQ(-1, FPDFAnnot_AddInkStroke(nullptr, kFirstInkStroke,
251 kFirstStrokePointCount));
252
253 // Negative test: |annot| is not ink annotation.
254 // Create a new highlight annotation.
255 ScopedFPDFAnnotation highlight_annot(
256 FPDFPage_CreateAnnot(page.get(), FPDF_ANNOT_HIGHLIGHT));
257 ASSERT_TRUE(highlight_annot);
258 EXPECT_EQ(-1, FPDFAnnot_AddInkStroke(highlight_annot.get(), kFirstInkStroke,
259 kFirstStrokePointCount));
260
261 // Negative test: passing |point_count| as 0.
262 EXPECT_EQ(-1, FPDFAnnot_AddInkStroke(ink_annot.get(), kFirstInkStroke, 0));
263
264 // Negative test: passing |points| array as nullptr.
265 EXPECT_EQ(-1, FPDFAnnot_AddInkStroke(ink_annot.get(), nullptr,
266 kFirstStrokePointCount));
267
268 // Negative test: passing |point_count| more than ULONG_MAX/2.
269 EXPECT_EQ(-1, FPDFAnnot_AddInkStroke(ink_annot.get(), kSecondInkStroke,
270 ULONG_MAX / 2 + 1));
271
272 // InkStroke should get added to ink annotation. Also inklist should get
273 // created.
274 EXPECT_EQ(0, FPDFAnnot_AddInkStroke(ink_annot.get(), kFirstInkStroke,
275 kFirstStrokePointCount));
276
277 RetainPtr<const CPDF_Array> inklist = annot_dict->GetArrayFor("InkList");
278 ASSERT_TRUE(inklist);
279 EXPECT_EQ(1u, inklist->size());
280 EXPECT_EQ(kFirstStrokePointCount * 2, inklist->GetArrayAt(0)->size());
281
282 // Adding another inkStroke to ink annotation with all valid paremeters.
283 // InkList already exists in ink_annot.
284 EXPECT_EQ(1, FPDFAnnot_AddInkStroke(ink_annot.get(), kSecondInkStroke,
285 kSecondStrokePointCount));
286 EXPECT_EQ(2u, inklist->size());
287 EXPECT_EQ(kSecondStrokePointCount * 2, inklist->GetArrayAt(1)->size());
288
289 // Adding one more InkStroke to the ink annotation. |point_count| passed is
290 // less than the data available in |buffer|.
291 EXPECT_EQ(2, FPDFAnnot_AddInkStroke(ink_annot.get(), kThirdInkStroke,
292 kThirdStrokePointCount - 1));
293 EXPECT_EQ(3u, inklist->size());
294 EXPECT_EQ((kThirdStrokePointCount - 1) * 2, inklist->GetArrayAt(2)->size());
295 }
296
TEST_F(FPDFAnnotEmbedderTest,RemoveInkList)297 TEST_F(FPDFAnnotEmbedderTest, RemoveInkList) {
298 ScopedFPDFDocument doc(FPDF_CreateNewDocument());
299 ASSERT_TRUE(doc);
300 ScopedFPDFPage page(FPDFPage_New(doc.get(), 0, 100, 100));
301 ASSERT_TRUE(page);
302
303 // Negative test: |annot| is passed as nullptr.
304 EXPECT_FALSE(FPDFAnnot_RemoveInkList(nullptr));
305
306 // Negative test: |annot| is not ink annotation.
307 // Create a new highlight annotation.
308 ScopedFPDFAnnotation highlight_annot(
309 FPDFPage_CreateAnnot(page.get(), FPDF_ANNOT_HIGHLIGHT));
310 ASSERT_TRUE(highlight_annot);
311 EXPECT_FALSE(FPDFAnnot_RemoveInkList(highlight_annot.get()));
312
313 // Create a new ink annotation.
314 ScopedFPDFAnnotation ink_annot(
315 FPDFPage_CreateAnnot(page.get(), FPDF_ANNOT_INK));
316 ASSERT_TRUE(ink_annot);
317 CPDF_AnnotContext* context =
318 CPDFAnnotContextFromFPDFAnnotation(ink_annot.get());
319 ASSERT_TRUE(context);
320 const CPDF_Dictionary* annot_dict = context->GetAnnotDict();
321 ASSERT_TRUE(annot_dict);
322
323 static constexpr FS_POINTF kInkStroke[] = {{80.0f, 90.0f}, {81.0f, 91.0f},
324 {82.0f, 92.0f}, {83.0f, 93.0f},
325 {84.0f, 94.0f}, {85.0f, 95.0f}};
326 static constexpr size_t kPointCount = std::size(kInkStroke);
327
328 // InkStroke should get added to ink annotation. Also inklist should get
329 // created.
330 EXPECT_EQ(0,
331 FPDFAnnot_AddInkStroke(ink_annot.get(), kInkStroke, kPointCount));
332
333 RetainPtr<const CPDF_Array> inklist = annot_dict->GetArrayFor("InkList");
334 ASSERT_TRUE(inklist);
335 ASSERT_EQ(1u, inklist->size());
336 EXPECT_EQ(kPointCount * 2, inklist->GetArrayAt(0)->size());
337
338 // Remove inklist.
339 EXPECT_TRUE(FPDFAnnot_RemoveInkList(ink_annot.get()));
340 EXPECT_FALSE(annot_dict->KeyExist("InkList"));
341 }
342
TEST_F(FPDFAnnotEmbedderTest,BadParams)343 TEST_F(FPDFAnnotEmbedderTest, BadParams) {
344 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
345 FPDF_PAGE page = LoadPage(0);
346 ASSERT_TRUE(page);
347
348 EXPECT_EQ(0, FPDFPage_GetAnnotCount(nullptr));
349
350 EXPECT_FALSE(FPDFPage_GetAnnot(nullptr, 0));
351 EXPECT_FALSE(FPDFPage_GetAnnot(nullptr, -1));
352 EXPECT_FALSE(FPDFPage_GetAnnot(nullptr, 1));
353 EXPECT_FALSE(FPDFPage_GetAnnot(page, -1));
354 EXPECT_FALSE(FPDFPage_GetAnnot(page, 1));
355
356 EXPECT_EQ(FPDF_ANNOT_UNKNOWN, FPDFAnnot_GetSubtype(nullptr));
357
358 EXPECT_EQ(0, FPDFAnnot_GetObjectCount(nullptr));
359
360 EXPECT_FALSE(FPDFAnnot_GetObject(nullptr, 0));
361 EXPECT_FALSE(FPDFAnnot_GetObject(nullptr, -1));
362 EXPECT_FALSE(FPDFAnnot_GetObject(nullptr, 1));
363
364 EXPECT_FALSE(FPDFAnnot_HasKey(nullptr, "foo"));
365
366 static const wchar_t kContents[] = L"Bar";
367 ScopedFPDFWideString text = GetFPDFWideString(kContents);
368 EXPECT_FALSE(FPDFAnnot_SetStringValue(nullptr, "foo", text.get()));
369
370 FPDF_WCHAR buffer[64];
371 EXPECT_EQ(0u, FPDFAnnot_GetStringValue(nullptr, "foo", nullptr, 0));
372 EXPECT_EQ(0u, FPDFAnnot_GetStringValue(nullptr, "foo", buffer, 0));
373 EXPECT_EQ(0u,
374 FPDFAnnot_GetStringValue(nullptr, "foo", buffer, sizeof(buffer)));
375
376 UnloadPage(page);
377 }
378
TEST_F(FPDFAnnotEmbedderTest,BadAnnotsEntry)379 TEST_F(FPDFAnnotEmbedderTest, BadAnnotsEntry) {
380 ASSERT_TRUE(OpenDocument("bad_annots_entry.pdf"));
381 FPDF_PAGE page = LoadPage(0);
382 ASSERT_TRUE(page);
383
384 EXPECT_EQ(1, FPDFPage_GetAnnotCount(page));
385 EXPECT_FALSE(FPDFPage_GetAnnot(page, 0));
386
387 UnloadPage(page);
388 }
389
TEST_F(FPDFAnnotEmbedderTest,RenderAnnotWithOnlyRolloverAP)390 TEST_F(FPDFAnnotEmbedderTest, RenderAnnotWithOnlyRolloverAP) {
391 // Open a file with one annotation and load its first page.
392 ASSERT_TRUE(OpenDocument("annotation_highlight_rollover_ap.pdf"));
393 FPDF_PAGE page = LoadPage(0);
394 ASSERT_TRUE(page);
395
396 // This annotation has a malformed appearance stream, which does not have its
397 // normal appearance defined, only its rollover appearance. In this case, its
398 // normal appearance should be generated, allowing the highlight annotation to
399 // still display.
400 ScopedFPDFBitmap bitmap = RenderLoadedPageWithFlags(page, FPDF_ANNOT);
401 CompareBitmap(bitmap.get(), 612, 792, "dc98f06da047bd8aabfa99562d2cbd1e");
402
403 UnloadPage(page);
404 }
405
TEST_F(FPDFAnnotEmbedderTest,RenderMultilineMarkupAnnotWithoutAP)406 TEST_F(FPDFAnnotEmbedderTest, RenderMultilineMarkupAnnotWithoutAP) {
407 const char* checksum = []() {
408 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
409 return "ec1f4ccbd0aecfdea6d53893387a0101";
410 return "76512832d88017668d9acc7aacd13dae";
411 }();
412
413 // Open a file with multiline markup annotations.
414 ASSERT_TRUE(OpenDocument("annotation_markup_multiline_no_ap.pdf"));
415 FPDF_PAGE page = LoadPage(0);
416 ASSERT_TRUE(page);
417
418 ScopedFPDFBitmap bitmap = RenderLoadedPageWithFlags(page, FPDF_ANNOT);
419 CompareBitmap(bitmap.get(), 595, 842, checksum);
420
421 UnloadPage(page);
422 }
423
TEST_F(FPDFAnnotEmbedderTest,ExtractHighlightLongContent)424 TEST_F(FPDFAnnotEmbedderTest, ExtractHighlightLongContent) {
425 // Open a file with one annotation and load its first page.
426 ASSERT_TRUE(OpenDocument("annotation_highlight_long_content.pdf"));
427 FPDF_PAGE page = LoadPageNoEvents(0);
428 ASSERT_TRUE(page);
429
430 // Check that there is a total of 1 annotation on its first page.
431 EXPECT_EQ(1, FPDFPage_GetAnnotCount(page));
432
433 // Check that the annotation is of type "highlight".
434 {
435 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
436 ASSERT_TRUE(annot);
437 EXPECT_EQ(FPDF_ANNOT_HIGHLIGHT, FPDFAnnot_GetSubtype(annot.get()));
438
439 // Check that the annotation color is yellow.
440 unsigned int R;
441 unsigned int G;
442 unsigned int B;
443 unsigned int A;
444 ASSERT_TRUE(FPDFAnnot_GetColor(annot.get(), FPDFANNOT_COLORTYPE_Color, &R,
445 &G, &B, &A));
446 EXPECT_EQ(255u, R);
447 EXPECT_EQ(255u, G);
448 EXPECT_EQ(0u, B);
449 EXPECT_EQ(255u, A);
450
451 // Check that the author is correct.
452 static const char kAuthorKey[] = "T";
453 EXPECT_EQ(FPDF_OBJECT_STRING,
454 FPDFAnnot_GetValueType(annot.get(), kAuthorKey));
455 unsigned long length_bytes =
456 FPDFAnnot_GetStringValue(annot.get(), kAuthorKey, nullptr, 0);
457 ASSERT_EQ(28u, length_bytes);
458 std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(length_bytes);
459 EXPECT_EQ(28u, FPDFAnnot_GetStringValue(annot.get(), kAuthorKey, buf.data(),
460 length_bytes));
461 EXPECT_EQ(L"Jae Hyun Park", GetPlatformWString(buf.data()));
462
463 // Check that the content is correct.
464 EXPECT_EQ(
465 FPDF_OBJECT_STRING,
466 FPDFAnnot_GetValueType(annot.get(), pdfium::annotation::kContents));
467 length_bytes = FPDFAnnot_GetStringValue(
468 annot.get(), pdfium::annotation::kContents, nullptr, 0);
469 ASSERT_EQ(2690u, length_bytes);
470 buf = GetFPDFWideStringBuffer(length_bytes);
471 EXPECT_EQ(2690u, FPDFAnnot_GetStringValue(annot.get(),
472 pdfium::annotation::kContents,
473 buf.data(), length_bytes));
474 static const wchar_t kContents[] =
475 L"This is a note for that highlight annotation. Very long highlight "
476 "annotation. Long long long Long long longLong long longLong long "
477 "longLong long longLong long longLong long longLong long longLong long "
478 "longLong long longLong long longLong long longLong long longLong long "
479 "longLong long longLong long longLong long longLong long longLong long "
480 "longLong long longLong long longLong long longLong long longLong long "
481 "longLong long longLong long longLong long longLong long longLong long "
482 "longLong long longLong long longLong long longLong long longLong long "
483 "longLong long longLong long longLong long longLong long longLong long "
484 "longLong long longLong long longLong long longLong long longLong long "
485 "longLong long longLong long longLong long longLong long longLong long "
486 "longLong long longLong long longLong long longLong long longLong long "
487 "longLong long longLong long longLong long longLong long longLong long "
488 "longLong long longLong long longLong long longLong long longLong long "
489 "longLong long longLong long longLong long longLong long longLong long "
490 "longLong long longLong long longLong long longLong long longLong long "
491 "longLong long longLong long longLong long longLong long longLong long "
492 "longLong long longLong long longLong long longLong long longLong long "
493 "longLong long longLong long longLong long longLong long longLong long "
494 "longLong long long. END";
495 EXPECT_EQ(kContents, GetPlatformWString(buf.data()));
496
497 // Check that the quadpoints are correct.
498 FS_QUADPOINTSF quadpoints;
499 ASSERT_TRUE(FPDFAnnot_GetAttachmentPoints(annot.get(), 0, &quadpoints));
500 EXPECT_EQ(115.802643f, quadpoints.x1);
501 EXPECT_EQ(718.913940f, quadpoints.y1);
502 EXPECT_EQ(157.211182f, quadpoints.x4);
503 EXPECT_EQ(706.264465f, quadpoints.y4);
504 }
505 UnloadPageNoEvents(page);
506 }
507
TEST_F(FPDFAnnotEmbedderTest,ExtractInkMultiple)508 TEST_F(FPDFAnnotEmbedderTest, ExtractInkMultiple) {
509 // Open a file with three annotations and load its first page.
510 ASSERT_TRUE(OpenDocument("annotation_ink_multiple.pdf"));
511 FPDF_PAGE page = LoadPageNoEvents(0);
512 ASSERT_TRUE(page);
513
514 // Check that there is a total of 3 annotation on its first page.
515 EXPECT_EQ(3, FPDFPage_GetAnnotCount(page));
516
517 {
518 // Check that the third annotation is of type "ink".
519 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 2));
520 ASSERT_TRUE(annot);
521 EXPECT_EQ(FPDF_ANNOT_INK, FPDFAnnot_GetSubtype(annot.get()));
522
523 // Check that the annotation color is blue with opacity.
524 unsigned int R;
525 unsigned int G;
526 unsigned int B;
527 unsigned int A;
528 ASSERT_TRUE(FPDFAnnot_GetColor(annot.get(), FPDFANNOT_COLORTYPE_Color, &R,
529 &G, &B, &A));
530 EXPECT_EQ(0u, R);
531 EXPECT_EQ(0u, G);
532 EXPECT_EQ(255u, B);
533 EXPECT_EQ(76u, A);
534
535 // Check that there is no content.
536 EXPECT_EQ(2u, FPDFAnnot_GetStringValue(
537 annot.get(), pdfium::annotation::kContents, nullptr, 0));
538
539 // Check that the rectangle coordinates are correct.
540 // Note that upon rendering, the rectangle coordinates will be adjusted.
541 FS_RECTF rect;
542 ASSERT_TRUE(FPDFAnnot_GetRect(annot.get(), &rect));
543 EXPECT_EQ(351.820404f, rect.left);
544 EXPECT_EQ(583.830688f, rect.bottom);
545 EXPECT_EQ(475.336090f, rect.right);
546 EXPECT_EQ(681.535034f, rect.top);
547 }
548 {
549 const char* expected_hash = []() {
550 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
551 #if BUILDFLAG(IS_APPLE)
552 return "6e00cc75639c5314c8273072915d8f92";
553 #else
554 return "1fb0dd8dd5f0b9bb8d076e48eb59296d";
555 #endif
556 }
557 return "354002e1c4386d38fdde29ef8d61074a";
558 }();
559 ScopedFPDFBitmap bitmap = RenderLoadedPageWithFlags(page, FPDF_ANNOT);
560 CompareBitmap(bitmap.get(), 612, 792, expected_hash);
561 }
562 UnloadPageNoEvents(page);
563 }
564
TEST_F(FPDFAnnotEmbedderTest,AddIllegalSubtypeAnnotation)565 TEST_F(FPDFAnnotEmbedderTest, AddIllegalSubtypeAnnotation) {
566 // Open a file with one annotation and load its first page.
567 ASSERT_TRUE(OpenDocument("annotation_highlight_long_content.pdf"));
568 FPDF_PAGE page = LoadPage(0);
569 ASSERT_TRUE(page);
570
571 // Add an annotation with an illegal subtype.
572 ASSERT_FALSE(FPDFPage_CreateAnnot(page, -1));
573
574 UnloadPage(page);
575 }
576
TEST_F(FPDFAnnotEmbedderTest,AddFirstTextAnnotation)577 TEST_F(FPDFAnnotEmbedderTest, AddFirstTextAnnotation) {
578 // Open a file with no annotation and load its first page.
579 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
580 FPDF_PAGE page = LoadPage(0);
581 ASSERT_TRUE(page);
582 EXPECT_EQ(0, FPDFPage_GetAnnotCount(page));
583
584 {
585 // Add a text annotation to the page.
586 ScopedFPDFAnnotation annot(FPDFPage_CreateAnnot(page, FPDF_ANNOT_TEXT));
587 ASSERT_TRUE(annot);
588
589 // Check that there is now 1 annotations on this page.
590 EXPECT_EQ(1, FPDFPage_GetAnnotCount(page));
591
592 // Check that the subtype of the annotation is correct.
593 EXPECT_EQ(FPDF_ANNOT_TEXT, FPDFAnnot_GetSubtype(annot.get()));
594 }
595
596 {
597 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
598 ASSERT_TRUE(annot);
599 EXPECT_EQ(FPDF_ANNOT_TEXT, FPDFAnnot_GetSubtype(annot.get()));
600
601 // Set the color of the annotation.
602 ASSERT_TRUE(FPDFAnnot_SetColor(annot.get(), FPDFANNOT_COLORTYPE_Color, 51,
603 102, 153, 204));
604 // Check that the color has been set correctly.
605 unsigned int R;
606 unsigned int G;
607 unsigned int B;
608 unsigned int A;
609 ASSERT_TRUE(FPDFAnnot_GetColor(annot.get(), FPDFANNOT_COLORTYPE_Color, &R,
610 &G, &B, &A));
611 EXPECT_EQ(51u, R);
612 EXPECT_EQ(102u, G);
613 EXPECT_EQ(153u, B);
614 EXPECT_EQ(204u, A);
615
616 // Change the color of the annotation.
617 ASSERT_TRUE(FPDFAnnot_SetColor(annot.get(), FPDFANNOT_COLORTYPE_Color, 204,
618 153, 102, 51));
619 // Check that the color has been set correctly.
620 ASSERT_TRUE(FPDFAnnot_GetColor(annot.get(), FPDFANNOT_COLORTYPE_Color, &R,
621 &G, &B, &A));
622 EXPECT_EQ(204u, R);
623 EXPECT_EQ(153u, G);
624 EXPECT_EQ(102u, B);
625 EXPECT_EQ(51u, A);
626
627 // Set the annotation rectangle.
628 FS_RECTF rect;
629 ASSERT_TRUE(FPDFAnnot_GetRect(annot.get(), &rect));
630 EXPECT_EQ(0.f, rect.left);
631 EXPECT_EQ(0.f, rect.right);
632 rect.left = 35;
633 rect.bottom = 150;
634 rect.right = 53;
635 rect.top = 165;
636 ASSERT_TRUE(FPDFAnnot_SetRect(annot.get(), &rect));
637 // Check that the annotation rectangle has been set correctly.
638 ASSERT_TRUE(FPDFAnnot_GetRect(annot.get(), &rect));
639 EXPECT_EQ(35.f, rect.left);
640 EXPECT_EQ(150.f, rect.bottom);
641 EXPECT_EQ(53.f, rect.right);
642 EXPECT_EQ(165.f, rect.top);
643
644 // Set the content of the annotation.
645 static const wchar_t kContents[] = L"Hello! This is a customized content.";
646 ScopedFPDFWideString text = GetFPDFWideString(kContents);
647 ASSERT_TRUE(FPDFAnnot_SetStringValue(
648 annot.get(), pdfium::annotation::kContents, text.get()));
649 // Check that the content has been set correctly.
650 unsigned long length_bytes = FPDFAnnot_GetStringValue(
651 annot.get(), pdfium::annotation::kContents, nullptr, 0);
652 ASSERT_EQ(74u, length_bytes);
653 std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(length_bytes);
654 EXPECT_EQ(74u, FPDFAnnot_GetStringValue(annot.get(),
655 pdfium::annotation::kContents,
656 buf.data(), length_bytes));
657 EXPECT_EQ(kContents, GetPlatformWString(buf.data()));
658 }
659 UnloadPage(page);
660 }
661
TEST_F(FPDFAnnotEmbedderTest,AddAndSaveLinkAnnotation)662 TEST_F(FPDFAnnotEmbedderTest, AddAndSaveLinkAnnotation) {
663 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
664 FPDF_PAGE page = LoadPage(0);
665 ASSERT_TRUE(page);
666 {
667 ScopedFPDFBitmap bitmap = RenderLoadedPageWithFlags(page, FPDF_ANNOT);
668 CompareBitmap(bitmap.get(), 200, 200, pdfium::HelloWorldChecksum());
669 }
670 EXPECT_EQ(0, FPDFPage_GetAnnotCount(page));
671
672 constexpr char kUri[] = "https://pdfium.org/";
673
674 {
675 // Add a link annotation to the page and set its URI.
676 ScopedFPDFAnnotation annot(FPDFPage_CreateAnnot(page, FPDF_ANNOT_LINK));
677 ASSERT_TRUE(annot);
678 EXPECT_EQ(1, FPDFPage_GetAnnotCount(page));
679 EXPECT_EQ(FPDF_ANNOT_LINK, FPDFAnnot_GetSubtype(annot.get()));
680 EXPECT_TRUE(FPDFAnnot_SetURI(annot.get(), kUri));
681 VerifyUriActionInLink(document(), FPDFAnnot_GetLink(annot.get()), kUri);
682
683 // Negative tests:
684 EXPECT_FALSE(FPDFAnnot_SetURI(nullptr, nullptr));
685 VerifyUriActionInLink(document(), FPDFAnnot_GetLink(annot.get()), kUri);
686 EXPECT_FALSE(FPDFAnnot_SetURI(annot.get(), nullptr));
687 VerifyUriActionInLink(document(), FPDFAnnot_GetLink(annot.get()), kUri);
688 EXPECT_FALSE(FPDFAnnot_SetURI(nullptr, kUri));
689 VerifyUriActionInLink(document(), FPDFAnnot_GetLink(annot.get()), kUri);
690
691 // Position the link on top of "Hello, world!" without a border.
692 const FS_RECTF kRect = {19.0f, 48.0f, 85.0f, 60.0f};
693 EXPECT_TRUE(FPDFAnnot_SetRect(annot.get(), &kRect));
694 EXPECT_TRUE(FPDFAnnot_SetBorder(annot.get(), /*horizontal_radius=*/0.0f,
695 /*vertical_radius=*/0.0f,
696 /*border_width=*/0.0f));
697
698 VerifyUriActionInLink(document(), FPDFLink_GetLinkAtPoint(page, 40.0, 50.0),
699 kUri);
700 }
701
702 {
703 // Add an ink annotation to the page. Trying to add a link to it fails.
704 ScopedFPDFAnnotation annot(FPDFPage_CreateAnnot(page, FPDF_ANNOT_INK));
705 ASSERT_TRUE(annot);
706 EXPECT_EQ(2, FPDFPage_GetAnnotCount(page));
707 EXPECT_EQ(FPDF_ANNOT_INK, FPDFAnnot_GetSubtype(annot.get()));
708 EXPECT_FALSE(FPDFAnnot_SetURI(annot.get(), kUri));
709 }
710
711 // Remove the ink annotation added above for negative testing.
712 EXPECT_TRUE(FPDFPage_RemoveAnnot(page, 1));
713 EXPECT_EQ(1, FPDFPage_GetAnnotCount(page));
714
715 // Save the document, closing the page.
716 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
717 UnloadPage(page);
718
719 // Reopen the document and make sure it still renders the same. Since the link
720 // does not have a border, it does not affect the rendering.
721 ASSERT_TRUE(OpenSavedDocument());
722 page = LoadSavedPage(0);
723 ASSERT_TRUE(page);
724 VerifySavedRendering(page, 200, 200, pdfium::HelloWorldChecksum());
725 EXPECT_EQ(1, FPDFPage_GetAnnotCount(page));
726
727 {
728 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
729 ASSERT_TRUE(annot);
730 EXPECT_EQ(FPDF_ANNOT_LINK, FPDFAnnot_GetSubtype(annot.get()));
731 VerifyUriActionInLink(document(), FPDFAnnot_GetLink(annot.get()), kUri);
732 VerifyUriActionInLink(document(), FPDFLink_GetLinkAtPoint(page, 40.0, 50.0),
733 kUri);
734 }
735
736 CloseSavedPage(page);
737 CloseSavedDocument();
738 }
739
TEST_F(FPDFAnnotEmbedderTest,AddAndSaveUnderlineAnnotation)740 TEST_F(FPDFAnnotEmbedderTest, AddAndSaveUnderlineAnnotation) {
741 // Open a file with one annotation and load its first page.
742 ASSERT_TRUE(OpenDocument("annotation_highlight_long_content.pdf"));
743 FPDF_PAGE page = LoadPage(0);
744 ASSERT_TRUE(page);
745
746 // Check that there is a total of one annotation on its first page, and verify
747 // its quadpoints.
748 EXPECT_EQ(1, FPDFPage_GetAnnotCount(page));
749 FS_QUADPOINTSF quadpoints;
750 {
751 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
752 ASSERT_TRUE(annot);
753 ASSERT_TRUE(FPDFAnnot_GetAttachmentPoints(annot.get(), 0, &quadpoints));
754 EXPECT_EQ(115.802643f, quadpoints.x1);
755 EXPECT_EQ(718.913940f, quadpoints.y1);
756 EXPECT_EQ(157.211182f, quadpoints.x4);
757 EXPECT_EQ(706.264465f, quadpoints.y4);
758 }
759
760 // Add an underline annotation to the page and set its quadpoints.
761 {
762 ScopedFPDFAnnotation annot(
763 FPDFPage_CreateAnnot(page, FPDF_ANNOT_UNDERLINE));
764 ASSERT_TRUE(annot);
765 quadpoints.x1 = 140.802643f;
766 quadpoints.x3 = 140.802643f;
767 ASSERT_TRUE(FPDFAnnot_AppendAttachmentPoints(annot.get(), &quadpoints));
768 }
769
770 // Save the document and close the page.
771 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
772 UnloadPage(page);
773
774 // Open the saved document.
775 const char* checksum = []() {
776 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
777 #if BUILDFLAG(IS_APPLE)
778 return "24994ad69aa612a66d183eaf9a92aa06";
779 #else
780 return "798fa41303381c9ba6d99092f5cd4d2b";
781 #endif
782 }
783 return "dba153419f67b7c0c0e3d22d3e8910d5";
784 }();
785
786 ASSERT_TRUE(OpenSavedDocument());
787 page = LoadSavedPage(0);
788 ASSERT_TRUE(page);
789 VerifySavedRendering(page, 612, 792, checksum);
790
791 // Check that the saved document has 2 annotations on the first page
792 EXPECT_EQ(2, FPDFPage_GetAnnotCount(page));
793
794 {
795 // Check that the second annotation is an underline annotation and verify
796 // its quadpoints.
797 ScopedFPDFAnnotation new_annot(FPDFPage_GetAnnot(page, 1));
798 ASSERT_TRUE(new_annot);
799 EXPECT_EQ(FPDF_ANNOT_UNDERLINE, FPDFAnnot_GetSubtype(new_annot.get()));
800 FS_QUADPOINTSF new_quadpoints;
801 ASSERT_TRUE(
802 FPDFAnnot_GetAttachmentPoints(new_annot.get(), 0, &new_quadpoints));
803 EXPECT_NEAR(quadpoints.x1, new_quadpoints.x1, 0.001f);
804 EXPECT_NEAR(quadpoints.y1, new_quadpoints.y1, 0.001f);
805 EXPECT_NEAR(quadpoints.x4, new_quadpoints.x4, 0.001f);
806 EXPECT_NEAR(quadpoints.y4, new_quadpoints.y4, 0.001f);
807 }
808
809 CloseSavedPage(page);
810 CloseSavedDocument();
811 }
812
TEST_F(FPDFAnnotEmbedderTest,GetAndSetQuadPoints)813 TEST_F(FPDFAnnotEmbedderTest, GetAndSetQuadPoints) {
814 // Open a file with four annotations and load its first page.
815 ASSERT_TRUE(OpenDocument("annotation_highlight_square_with_ap.pdf"));
816 FPDF_PAGE page = LoadPage(0);
817 ASSERT_TRUE(page);
818 EXPECT_EQ(4, FPDFPage_GetAnnotCount(page));
819
820 // Retrieve the highlight annotation.
821 FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, 0);
822 ASSERT_TRUE(annot);
823 ASSERT_EQ(FPDF_ANNOT_HIGHLIGHT, FPDFAnnot_GetSubtype(annot));
824
825 FS_QUADPOINTSF quadpoints;
826 ASSERT_TRUE(FPDFAnnot_GetAttachmentPoints(annot, 0, &quadpoints));
827
828 {
829 // Verify the current one set of quadpoints.
830 ASSERT_EQ(1u, FPDFAnnot_CountAttachmentPoints(annot));
831
832 EXPECT_NEAR(72.0000f, quadpoints.x1, 0.001f);
833 EXPECT_NEAR(720.792f, quadpoints.y1, 0.001f);
834 EXPECT_NEAR(132.055f, quadpoints.x4, 0.001f);
835 EXPECT_NEAR(704.796f, quadpoints.y4, 0.001f);
836 }
837
838 {
839 // Update the quadpoints.
840 FS_QUADPOINTSF new_quadpoints = quadpoints;
841 new_quadpoints.y1 -= 20.f;
842 new_quadpoints.y2 -= 20.f;
843 new_quadpoints.y3 -= 20.f;
844 new_quadpoints.y4 -= 20.f;
845 ASSERT_TRUE(FPDFAnnot_SetAttachmentPoints(annot, 0, &new_quadpoints));
846
847 // Verify added quadpoint set
848 ASSERT_EQ(1u, FPDFAnnot_CountAttachmentPoints(annot));
849 ASSERT_TRUE(FPDFAnnot_GetAttachmentPoints(annot, 0, &quadpoints));
850 EXPECT_NEAR(new_quadpoints.x1, quadpoints.x1, 0.001f);
851 EXPECT_NEAR(new_quadpoints.y1, quadpoints.y1, 0.001f);
852 EXPECT_NEAR(new_quadpoints.x4, quadpoints.x4, 0.001f);
853 EXPECT_NEAR(new_quadpoints.y4, quadpoints.y4, 0.001f);
854 }
855
856 {
857 // Append a new set of quadpoints.
858 FS_QUADPOINTSF new_quadpoints = quadpoints;
859 new_quadpoints.y1 += 20.f;
860 new_quadpoints.y2 += 20.f;
861 new_quadpoints.y3 += 20.f;
862 new_quadpoints.y4 += 20.f;
863 ASSERT_TRUE(FPDFAnnot_AppendAttachmentPoints(annot, &new_quadpoints));
864
865 // Verify added quadpoint set
866 ASSERT_EQ(2u, FPDFAnnot_CountAttachmentPoints(annot));
867 ASSERT_TRUE(FPDFAnnot_GetAttachmentPoints(annot, 1, &quadpoints));
868 EXPECT_NEAR(new_quadpoints.x1, quadpoints.x1, 0.001f);
869 EXPECT_NEAR(new_quadpoints.y1, quadpoints.y1, 0.001f);
870 EXPECT_NEAR(new_quadpoints.x4, quadpoints.x4, 0.001f);
871 EXPECT_NEAR(new_quadpoints.y4, quadpoints.y4, 0.001f);
872 }
873
874 {
875 // Setting and getting quadpoints at out-of-bound index should fail
876 EXPECT_FALSE(FPDFAnnot_SetAttachmentPoints(annot, 300000, &quadpoints));
877 EXPECT_FALSE(FPDFAnnot_GetAttachmentPoints(annot, 300000, &quadpoints));
878 }
879
880 FPDFPage_CloseAnnot(annot);
881
882 // Retrieve the square annotation
883 FPDF_ANNOTATION squareAnnot = FPDFPage_GetAnnot(page, 2);
884
885 {
886 // Check that attempting to set its quadpoints would fail
887 ASSERT_TRUE(squareAnnot);
888 EXPECT_EQ(FPDF_ANNOT_SQUARE, FPDFAnnot_GetSubtype(squareAnnot));
889 EXPECT_EQ(0u, FPDFAnnot_CountAttachmentPoints(squareAnnot));
890 EXPECT_FALSE(FPDFAnnot_SetAttachmentPoints(squareAnnot, 0, &quadpoints));
891 }
892
893 FPDFPage_CloseAnnot(squareAnnot);
894 UnloadPage(page);
895 }
896
TEST_F(FPDFAnnotEmbedderTest,ModifyRectQuadpointsWithAP)897 TEST_F(FPDFAnnotEmbedderTest, ModifyRectQuadpointsWithAP) {
898 const char* md5_original = []() {
899 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
900 return "2a9d1df839d5ec81a49f982347d9656c";
901 #if BUILDFLAG(IS_APPLE)
902 return "fc59468d154f397fd298c69f47ef565a";
903 #else
904 return "0e27376094f11490f74c65f3dc3a42c5";
905 #endif
906 }();
907 const char* md5_modified_highlight = []() {
908 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
909 return "0fb1653db0e8e8f7ce5d726bb0074bb5";
910 #if BUILDFLAG(IS_APPLE)
911 return "e64bf648f6e9354d1f3eedb47a2c9498";
912 #else
913 return "66f3caef3a7d488a4fa1ad37fc06310e";
914 #endif
915 }();
916 const char* md5_modified_square = []() {
917 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
918 return "879c77a2cb9f79ba65ffe0bbdd720ce3";
919 #if BUILDFLAG(IS_APPLE)
920 return "a66591662c8e7ad3c6059952e234bebf";
921 #else
922 return "a456dad0bc6801ee2d6408a4394af563";
923 #endif
924 }();
925
926 // Open a file with four annotations and load its first page.
927 ASSERT_TRUE(OpenDocument("annotation_highlight_square_with_ap.pdf"));
928 FPDF_PAGE page = LoadPage(0);
929 ASSERT_TRUE(page);
930 EXPECT_EQ(4, FPDFPage_GetAnnotCount(page));
931
932 // Check that the original file renders correctly.
933 {
934 ScopedFPDFBitmap bitmap = RenderLoadedPageWithFlags(page, FPDF_ANNOT);
935 CompareBitmap(bitmap.get(), 612, 792, md5_original);
936 }
937
938 FS_RECTF rect;
939 FS_RECTF new_rect;
940
941 // Retrieve the highlight annotation which has its AP stream already defined.
942 {
943 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
944 ASSERT_TRUE(annot);
945 EXPECT_EQ(FPDF_ANNOT_HIGHLIGHT, FPDFAnnot_GetSubtype(annot.get()));
946
947 // Check that color cannot be set when an AP stream is defined already.
948 EXPECT_FALSE(FPDFAnnot_SetColor(annot.get(), FPDFANNOT_COLORTYPE_Color, 51,
949 102, 153, 204));
950
951 // Verify its attachment points.
952 FS_QUADPOINTSF quadpoints;
953 ASSERT_TRUE(FPDFAnnot_GetAttachmentPoints(annot.get(), 0, &quadpoints));
954 EXPECT_NEAR(72.0000f, quadpoints.x1, 0.001f);
955 EXPECT_NEAR(720.792f, quadpoints.y1, 0.001f);
956 EXPECT_NEAR(132.055f, quadpoints.x4, 0.001f);
957 EXPECT_NEAR(704.796f, quadpoints.y4, 0.001f);
958
959 // Check that updating the attachment points would succeed.
960 quadpoints.x1 -= 50.f;
961 quadpoints.x2 -= 50.f;
962 quadpoints.x3 -= 50.f;
963 quadpoints.x4 -= 50.f;
964 ASSERT_TRUE(FPDFAnnot_SetAttachmentPoints(annot.get(), 0, &quadpoints));
965 FS_QUADPOINTSF new_quadpoints;
966 ASSERT_TRUE(FPDFAnnot_GetAttachmentPoints(annot.get(), 0, &new_quadpoints));
967 EXPECT_EQ(quadpoints.x1, new_quadpoints.x1);
968 EXPECT_EQ(quadpoints.y1, new_quadpoints.y1);
969 EXPECT_EQ(quadpoints.x4, new_quadpoints.x4);
970 EXPECT_EQ(quadpoints.y4, new_quadpoints.y4);
971
972 // Check that updating quadpoints does not change the annotation's position.
973 {
974 ScopedFPDFBitmap bitmap = RenderLoadedPageWithFlags(page, FPDF_ANNOT);
975 CompareBitmap(bitmap.get(), 612, 792, md5_original);
976 }
977
978 // Verify its annotation rectangle.
979 ASSERT_TRUE(FPDFAnnot_GetRect(annot.get(), &rect));
980 EXPECT_NEAR(67.7299f, rect.left, 0.001f);
981 EXPECT_NEAR(704.296f, rect.bottom, 0.001f);
982 EXPECT_NEAR(136.325f, rect.right, 0.001f);
983 EXPECT_NEAR(721.292f, rect.top, 0.001f);
984
985 // Check that updating the rectangle would succeed.
986 rect.left -= 60.f;
987 rect.right -= 60.f;
988 ASSERT_TRUE(FPDFAnnot_SetRect(annot.get(), &rect));
989 ASSERT_TRUE(FPDFAnnot_GetRect(annot.get(), &new_rect));
990 EXPECT_EQ(rect.right, new_rect.right);
991 }
992
993 // Check that updating the rectangle changes the annotation's position.
994 {
995 ScopedFPDFBitmap bitmap = RenderLoadedPageWithFlags(page, FPDF_ANNOT);
996 CompareBitmap(bitmap.get(), 612, 792, md5_modified_highlight);
997 }
998
999 {
1000 // Retrieve the square annotation which has its AP stream already defined.
1001 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 2));
1002 ASSERT_TRUE(annot);
1003 EXPECT_EQ(FPDF_ANNOT_SQUARE, FPDFAnnot_GetSubtype(annot.get()));
1004
1005 // Check that updating the rectangle would succeed.
1006 ASSERT_TRUE(FPDFAnnot_GetRect(annot.get(), &rect));
1007 rect.left += 70.f;
1008 rect.right += 70.f;
1009 ASSERT_TRUE(FPDFAnnot_SetRect(annot.get(), &rect));
1010 ASSERT_TRUE(FPDFAnnot_GetRect(annot.get(), &new_rect));
1011 EXPECT_EQ(rect.right, new_rect.right);
1012
1013 // Check that updating the rectangle changes the square annotation's
1014 // position.
1015 ScopedFPDFBitmap bitmap = RenderLoadedPageWithFlags(page, FPDF_ANNOT);
1016 CompareBitmap(bitmap.get(), 612, 792, md5_modified_square);
1017 }
1018
1019 UnloadPage(page);
1020 }
1021
TEST_F(FPDFAnnotEmbedderTest,CountAttachmentPoints)1022 TEST_F(FPDFAnnotEmbedderTest, CountAttachmentPoints) {
1023 // Open a file with multiline markup annotations.
1024 ASSERT_TRUE(OpenDocument("annotation_markup_multiline_no_ap.pdf"));
1025 FPDF_PAGE page = LoadPage(0);
1026 ASSERT_TRUE(page);
1027 {
1028 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
1029 ASSERT_TRUE(annot);
1030
1031 // This is a three line annotation.
1032 EXPECT_EQ(3u, FPDFAnnot_CountAttachmentPoints(annot.get()));
1033 }
1034 UnloadPage(page);
1035
1036 // null annotation should return 0
1037 EXPECT_EQ(0u, FPDFAnnot_CountAttachmentPoints(nullptr));
1038 }
1039
TEST_F(FPDFAnnotEmbedderTest,RemoveAnnotation)1040 TEST_F(FPDFAnnotEmbedderTest, RemoveAnnotation) {
1041 // Open a file with 3 annotations on its first page.
1042 ASSERT_TRUE(OpenDocument("annotation_ink_multiple.pdf"));
1043 FPDF_PAGE page = LoadPageNoEvents(0);
1044 ASSERT_TRUE(page);
1045 EXPECT_EQ(3, FPDFPage_GetAnnotCount(page));
1046
1047 FS_RECTF rect;
1048
1049 // Check that the annotations have the expected rectangle coordinates.
1050 {
1051 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
1052 ASSERT_TRUE(FPDFAnnot_GetRect(annot.get(), &rect));
1053 EXPECT_NEAR(86.1971f, rect.left, 0.001f);
1054 }
1055
1056 {
1057 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 1));
1058 ASSERT_TRUE(FPDFAnnot_GetRect(annot.get(), &rect));
1059 EXPECT_NEAR(149.8127f, rect.left, 0.001f);
1060 }
1061
1062 {
1063 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 2));
1064 ASSERT_TRUE(FPDFAnnot_GetRect(annot.get(), &rect));
1065 EXPECT_NEAR(351.8204f, rect.left, 0.001f);
1066 }
1067
1068 // Check that nothing happens when attempting to remove an annotation with an
1069 // out-of-bound index.
1070 EXPECT_FALSE(FPDFPage_RemoveAnnot(page, 4));
1071 EXPECT_FALSE(FPDFPage_RemoveAnnot(page, -1));
1072 EXPECT_EQ(3, FPDFPage_GetAnnotCount(page));
1073
1074 // Remove the second annotation.
1075 EXPECT_TRUE(FPDFPage_RemoveAnnot(page, 1));
1076 EXPECT_EQ(2, FPDFPage_GetAnnotCount(page));
1077 EXPECT_FALSE(FPDFPage_GetAnnot(page, 2));
1078
1079 // Save the document and close the page.
1080 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1081 UnloadPageNoEvents(page);
1082
1083 // TODO(npm): VerifySavedRendering changes annot rect dimensions by 1??
1084 // Open the saved document.
1085 std::string new_file = GetString();
1086 FPDF_FILEACCESS file_access;
1087 memset(&file_access, 0, sizeof(file_access));
1088 file_access.m_FileLen = new_file.size();
1089 file_access.m_GetBlock = GetBlockFromString;
1090 file_access.m_Param = &new_file;
1091 FPDF_DOCUMENT new_doc = FPDF_LoadCustomDocument(&file_access, nullptr);
1092 ASSERT_TRUE(new_doc);
1093 FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0);
1094 ASSERT_TRUE(new_page);
1095
1096 // Check that the saved document has 2 annotations on the first page.
1097 EXPECT_EQ(2, FPDFPage_GetAnnotCount(new_page));
1098
1099 // Check that the remaining 2 annotations are the original 1st and 3rd ones
1100 // by verifying their rectangle coordinates.
1101 {
1102 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(new_page, 0));
1103 ASSERT_TRUE(FPDFAnnot_GetRect(annot.get(), &rect));
1104 EXPECT_NEAR(86.1971f, rect.left, 0.001f);
1105 }
1106
1107 {
1108 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(new_page, 1));
1109 ASSERT_TRUE(FPDFAnnot_GetRect(annot.get(), &rect));
1110 EXPECT_NEAR(351.8204f, rect.left, 0.001f);
1111 }
1112 FPDF_ClosePage(new_page);
1113 FPDF_CloseDocument(new_doc);
1114 }
1115
TEST_F(FPDFAnnotEmbedderTest,AddAndModifyPath)1116 TEST_F(FPDFAnnotEmbedderTest, AddAndModifyPath) {
1117 const char* md5_modified_path = []() {
1118 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
1119 return "fb4d5fac05f7eb5d84a4100898c11197";
1120 #if BUILDFLAG(IS_APPLE)
1121 return "34614087e04b729b7b8c37739dcf9af9";
1122 #else
1123 return "31a94d22460171cd83169daf6a6956ee";
1124 #endif
1125 }();
1126 const char* md5_two_paths = []() {
1127 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
1128 return "fcf3e79b2a91d1294b9bbccff727d3c2";
1129 #if BUILDFLAG(IS_APPLE)
1130 return "6cdaf6b3e5145f435d8ccae6db5cf9af";
1131 #else
1132 return "ed49fefef45f14121f8150cde10006c4";
1133 #endif
1134 }();
1135 const char* md5_new_annot = []() {
1136 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
1137 return "7db6321c8ffe502f4e60622aa16d5417";
1138 #if BUILDFLAG(IS_APPLE)
1139 return "55dab4f158fdc284e439b88c4306373c";
1140 #else
1141 return "cc08493b1f079803930388ecc703be9d";
1142 #endif
1143 }();
1144
1145 // Open a file with two annotations and load its first page.
1146 ASSERT_TRUE(OpenDocument("annotation_stamp_with_ap.pdf"));
1147 FPDF_PAGE page = LoadPage(0);
1148 ASSERT_TRUE(page);
1149 EXPECT_EQ(2, FPDFPage_GetAnnotCount(page));
1150
1151 // Check that the page renders correctly.
1152 {
1153 ScopedFPDFBitmap bitmap = RenderLoadedPageWithFlags(page, FPDF_ANNOT);
1154 CompareBitmap(bitmap.get(), 595, 842, AnnotationStampWithApChecksum());
1155 }
1156
1157 {
1158 // Retrieve the stamp annotation which has its AP stream already defined.
1159 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
1160 ASSERT_TRUE(annot);
1161
1162 // Check that this annotation has one path object and retrieve it.
1163 EXPECT_EQ(1, FPDFAnnot_GetObjectCount(annot.get()));
1164 ASSERT_EQ(32, FPDFPage_CountObjects(page));
1165 FPDF_PAGEOBJECT path = FPDFAnnot_GetObject(annot.get(), 1);
1166 EXPECT_FALSE(path);
1167 path = FPDFAnnot_GetObject(annot.get(), 0);
1168 EXPECT_EQ(FPDF_PAGEOBJ_PATH, FPDFPageObj_GetType(path));
1169 EXPECT_TRUE(path);
1170
1171 // Modify the color of the path object.
1172 EXPECT_TRUE(FPDFPageObj_SetStrokeColor(path, 0, 0, 0, 255));
1173 EXPECT_TRUE(FPDFAnnot_UpdateObject(annot.get(), path));
1174
1175 // Check that the page with the modified annotation renders correctly.
1176 {
1177 ScopedFPDFBitmap bitmap = RenderLoadedPageWithFlags(page, FPDF_ANNOT);
1178 CompareBitmap(bitmap.get(), 595, 842, md5_modified_path);
1179 }
1180
1181 // Add a second path object to the same annotation.
1182 FPDF_PAGEOBJECT dot = FPDFPageObj_CreateNewPath(7, 84);
1183 EXPECT_TRUE(FPDFPath_BezierTo(dot, 9, 86, 10, 87, 11, 88));
1184 EXPECT_TRUE(FPDFPageObj_SetStrokeColor(dot, 255, 0, 0, 100));
1185 EXPECT_TRUE(FPDFPageObj_SetStrokeWidth(dot, 14));
1186 EXPECT_TRUE(FPDFPath_SetDrawMode(dot, 0, 1));
1187 EXPECT_TRUE(FPDFAnnot_AppendObject(annot.get(), dot));
1188 EXPECT_EQ(2, FPDFAnnot_GetObjectCount(annot.get()));
1189
1190 // The object is in the annontation, not in the page, so the page object
1191 // array should not change.
1192 ASSERT_EQ(32, FPDFPage_CountObjects(page));
1193
1194 // Check that the page with an annotation with two paths renders correctly.
1195 {
1196 ScopedFPDFBitmap bitmap = RenderLoadedPageWithFlags(page, FPDF_ANNOT);
1197 CompareBitmap(bitmap.get(), 595, 842, md5_two_paths);
1198 }
1199
1200 // Delete the newly added path object.
1201 EXPECT_TRUE(FPDFAnnot_RemoveObject(annot.get(), 1));
1202 EXPECT_EQ(1, FPDFAnnot_GetObjectCount(annot.get()));
1203 ASSERT_EQ(32, FPDFPage_CountObjects(page));
1204 }
1205
1206 // Check that the page renders the same as before.
1207 {
1208 ScopedFPDFBitmap bitmap = RenderLoadedPageWithFlags(page, FPDF_ANNOT);
1209 CompareBitmap(bitmap.get(), 595, 842, md5_modified_path);
1210 }
1211
1212 FS_RECTF rect;
1213
1214 {
1215 // Create another stamp annotation and set its annotation rectangle.
1216 ScopedFPDFAnnotation annot(FPDFPage_CreateAnnot(page, FPDF_ANNOT_STAMP));
1217 ASSERT_TRUE(annot);
1218 rect.left = 200.f;
1219 rect.bottom = 400.f;
1220 rect.right = 500.f;
1221 rect.top = 600.f;
1222 EXPECT_TRUE(FPDFAnnot_SetRect(annot.get(), &rect));
1223
1224 // Add a new path to the annotation.
1225 FPDF_PAGEOBJECT check = FPDFPageObj_CreateNewPath(200, 500);
1226 EXPECT_TRUE(FPDFPath_LineTo(check, 300, 400));
1227 EXPECT_TRUE(FPDFPath_LineTo(check, 500, 600));
1228 EXPECT_TRUE(FPDFPath_MoveTo(check, 350, 550));
1229 EXPECT_TRUE(FPDFPath_LineTo(check, 450, 450));
1230 EXPECT_TRUE(FPDFPageObj_SetStrokeColor(check, 0, 255, 255, 180));
1231 EXPECT_TRUE(FPDFPageObj_SetStrokeWidth(check, 8.35f));
1232 EXPECT_TRUE(FPDFPath_SetDrawMode(check, 0, 1));
1233 EXPECT_TRUE(FPDFAnnot_AppendObject(annot.get(), check));
1234 EXPECT_EQ(1, FPDFAnnot_GetObjectCount(annot.get()));
1235
1236 // Check that the annotation's bounding box came from its rectangle.
1237 FS_RECTF new_rect;
1238 ASSERT_TRUE(FPDFAnnot_GetRect(annot.get(), &new_rect));
1239 EXPECT_EQ(rect.left, new_rect.left);
1240 EXPECT_EQ(rect.bottom, new_rect.bottom);
1241 EXPECT_EQ(rect.right, new_rect.right);
1242 EXPECT_EQ(rect.top, new_rect.top);
1243 }
1244
1245 // Save the document and close the page.
1246 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1247 UnloadPage(page);
1248
1249 // Open the saved document.
1250 ASSERT_TRUE(OpenSavedDocument());
1251 page = LoadSavedPage(0);
1252 ASSERT_TRUE(page);
1253 VerifySavedRendering(page, 595, 842, md5_new_annot);
1254
1255 // Check that the document has a correct count of annotations and objects.
1256 EXPECT_EQ(3, FPDFPage_GetAnnotCount(page));
1257
1258 {
1259 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 2));
1260 ASSERT_TRUE(annot);
1261 EXPECT_EQ(1, FPDFAnnot_GetObjectCount(annot.get()));
1262
1263 // Check that the new annotation's rectangle is as defined.
1264 FS_RECTF new_rect;
1265 ASSERT_TRUE(FPDFAnnot_GetRect(annot.get(), &new_rect));
1266 EXPECT_EQ(rect.left, new_rect.left);
1267 EXPECT_EQ(rect.bottom, new_rect.bottom);
1268 EXPECT_EQ(rect.right, new_rect.right);
1269 EXPECT_EQ(rect.top, new_rect.top);
1270 }
1271
1272 CloseSavedPage(page);
1273 CloseSavedDocument();
1274 }
1275
TEST_F(FPDFAnnotEmbedderTest,ModifyAnnotationFlags)1276 TEST_F(FPDFAnnotEmbedderTest, ModifyAnnotationFlags) {
1277 // Open a file with an annotation and load its first page.
1278 ASSERT_TRUE(OpenDocument("annotation_highlight_rollover_ap.pdf"));
1279 FPDF_PAGE page = LoadPage(0);
1280 ASSERT_TRUE(page);
1281
1282 // Check that the page renders correctly.
1283 {
1284 ScopedFPDFBitmap bitmap = RenderLoadedPageWithFlags(page, FPDF_ANNOT);
1285 CompareBitmap(bitmap.get(), 612, 792, "dc98f06da047bd8aabfa99562d2cbd1e");
1286 }
1287
1288 {
1289 // Retrieve the annotation.
1290 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
1291 ASSERT_TRUE(annot);
1292
1293 // Check that the original flag values are as expected.
1294 int flags = FPDFAnnot_GetFlags(annot.get());
1295 EXPECT_FALSE(flags & FPDF_ANNOT_FLAG_INVISIBLE);
1296 EXPECT_FALSE(flags & FPDF_ANNOT_FLAG_HIDDEN);
1297 EXPECT_TRUE(flags & FPDF_ANNOT_FLAG_PRINT);
1298 EXPECT_FALSE(flags & FPDF_ANNOT_FLAG_NOZOOM);
1299 EXPECT_FALSE(flags & FPDF_ANNOT_FLAG_NOROTATE);
1300 EXPECT_FALSE(flags & FPDF_ANNOT_FLAG_NOVIEW);
1301 EXPECT_FALSE(flags & FPDF_ANNOT_FLAG_READONLY);
1302 EXPECT_FALSE(flags & FPDF_ANNOT_FLAG_LOCKED);
1303 EXPECT_FALSE(flags & FPDF_ANNOT_FLAG_TOGGLENOVIEW);
1304
1305 // Set the HIDDEN flag.
1306 flags |= FPDF_ANNOT_FLAG_HIDDEN;
1307 EXPECT_TRUE(FPDFAnnot_SetFlags(annot.get(), flags));
1308 flags = FPDFAnnot_GetFlags(annot.get());
1309 EXPECT_TRUE(flags & FPDF_ANNOT_FLAG_HIDDEN);
1310 EXPECT_TRUE(flags & FPDF_ANNOT_FLAG_PRINT);
1311
1312 // Check that the page renders correctly without rendering the annotation.
1313 {
1314 ScopedFPDFBitmap bitmap = RenderLoadedPageWithFlags(page, FPDF_ANNOT);
1315 CompareBitmap(bitmap.get(), 612, 792, pdfium::kBlankPage612By792Checksum);
1316 }
1317
1318 // Unset the HIDDEN flag.
1319 EXPECT_TRUE(FPDFAnnot_SetFlags(annot.get(), FPDF_ANNOT_FLAG_NONE));
1320 EXPECT_FALSE(FPDFAnnot_GetFlags(annot.get()));
1321 flags &= ~FPDF_ANNOT_FLAG_HIDDEN;
1322 EXPECT_TRUE(FPDFAnnot_SetFlags(annot.get(), flags));
1323 flags = FPDFAnnot_GetFlags(annot.get());
1324 EXPECT_FALSE(flags & FPDF_ANNOT_FLAG_HIDDEN);
1325 EXPECT_TRUE(flags & FPDF_ANNOT_FLAG_PRINT);
1326
1327 // Check that the page renders correctly as before.
1328 {
1329 ScopedFPDFBitmap bitmap = RenderLoadedPageWithFlags(page, FPDF_ANNOT);
1330 CompareBitmap(bitmap.get(), 612, 792, "dc98f06da047bd8aabfa99562d2cbd1e");
1331 }
1332 }
1333
1334 UnloadPage(page);
1335 }
1336
TEST_F(FPDFAnnotEmbedderTest,AddAndModifyImage)1337 TEST_F(FPDFAnnotEmbedderTest, AddAndModifyImage) {
1338 const char* md5_new_image = []() {
1339 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
1340 return "476596330c0e7daa31f115005c1d36eb";
1341 #if BUILDFLAG(IS_APPLE)
1342 return "17ac49518eabbb6a7632a547269c40a3";
1343 #else
1344 return "e79446398d4508bc2cb47e6cf2a677ed";
1345 #endif
1346 }();
1347 const char* md5_modified_image = []() {
1348 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
1349 return "0047c3e7ea7658e1a963fc339f1c587d";
1350 #if BUILDFLAG(IS_APPLE)
1351 return "ce68959f74242d588af7fb82be5ba0ab";
1352 #else
1353 return "425646a517a23104b9ef22881a19b3e2";
1354 #endif
1355 }();
1356
1357 // Open a file with two annotations and load its first page.
1358 ASSERT_TRUE(OpenDocument("annotation_stamp_with_ap.pdf"));
1359 FPDF_PAGE page = LoadPage(0);
1360 ASSERT_TRUE(page);
1361 EXPECT_EQ(2, FPDFPage_GetAnnotCount(page));
1362
1363 // Check that the page renders correctly.
1364 {
1365 ScopedFPDFBitmap bitmap = RenderLoadedPageWithFlags(page, FPDF_ANNOT);
1366 CompareBitmap(bitmap.get(), 595, 842, AnnotationStampWithApChecksum());
1367 }
1368
1369 constexpr int kBitmapSize = 200;
1370 FPDF_BITMAP image_bitmap;
1371
1372 {
1373 // Create a stamp annotation and set its annotation rectangle.
1374 ScopedFPDFAnnotation annot(FPDFPage_CreateAnnot(page, FPDF_ANNOT_STAMP));
1375 ASSERT_TRUE(annot);
1376 FS_RECTF rect;
1377 rect.left = 200.f;
1378 rect.bottom = 600.f;
1379 rect.right = 400.f;
1380 rect.top = 800.f;
1381 EXPECT_TRUE(FPDFAnnot_SetRect(annot.get(), &rect));
1382
1383 // Add a solid-color translucent image object to the new annotation.
1384 image_bitmap = FPDFBitmap_Create(kBitmapSize, kBitmapSize, 1);
1385 FPDFBitmap_FillRect(image_bitmap, 0, 0, kBitmapSize, kBitmapSize,
1386 0xeeeecccc);
1387 EXPECT_EQ(kBitmapSize, FPDFBitmap_GetWidth(image_bitmap));
1388 EXPECT_EQ(kBitmapSize, FPDFBitmap_GetHeight(image_bitmap));
1389 FPDF_PAGEOBJECT image_object = FPDFPageObj_NewImageObj(document());
1390 ASSERT_TRUE(FPDFImageObj_SetBitmap(&page, 0, image_object, image_bitmap));
1391 static constexpr FS_MATRIX kBitmapScaleMatrix{kBitmapSize, 0, 0,
1392 kBitmapSize, 0, 0};
1393 ASSERT_TRUE(FPDFPageObj_SetMatrix(image_object, &kBitmapScaleMatrix));
1394 FPDFPageObj_Transform(image_object, 1, 0, 0, 1, 200, 600);
1395 EXPECT_TRUE(FPDFAnnot_AppendObject(annot.get(), image_object));
1396 }
1397
1398 // Check that the page renders correctly with the new image object.
1399 {
1400 ScopedFPDFBitmap bitmap = RenderLoadedPageWithFlags(page, FPDF_ANNOT);
1401 CompareBitmap(bitmap.get(), 595, 842, md5_new_image);
1402 }
1403
1404 {
1405 // Retrieve the newly added stamp annotation and its image object.
1406 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 2));
1407 ASSERT_TRUE(annot);
1408 EXPECT_EQ(1, FPDFAnnot_GetObjectCount(annot.get()));
1409 FPDF_PAGEOBJECT image_object = FPDFAnnot_GetObject(annot.get(), 0);
1410 EXPECT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(image_object));
1411
1412 // Modify the image in the new annotation.
1413 FPDFBitmap_FillRect(image_bitmap, 0, 0, kBitmapSize, kBitmapSize,
1414 0xff000000);
1415 ASSERT_TRUE(FPDFImageObj_SetBitmap(&page, 0, image_object, image_bitmap));
1416 EXPECT_TRUE(FPDFAnnot_UpdateObject(annot.get(), image_object));
1417 }
1418
1419 // Save the document and close the page.
1420 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1421 UnloadPage(page);
1422 FPDFBitmap_Destroy(image_bitmap);
1423
1424 // Test that the saved document renders the modified image object correctly.
1425 VerifySavedDocument(595, 842, md5_modified_image);
1426 }
1427
TEST_F(FPDFAnnotEmbedderTest,AddAndModifyText)1428 TEST_F(FPDFAnnotEmbedderTest, AddAndModifyText) {
1429 const char* md5_new_text = []() {
1430 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
1431 return "1e7f98c18775d6e0f4f454747b77cc1a";
1432 }
1433 #if BUILDFLAG(IS_APPLE) && defined(ARCH_CPU_ARM64)
1434 return "0c3448974a4e8da2395da917935e5de1";
1435 #elif BUILDFLAG(IS_APPLE) && !defined(ARCH_CPU_ARM64)
1436 return "5d449d36926c9f212c6cdb6c276d18cc";
1437 #else
1438 return "a9532f555aca2fd099e2107fa40b61e6";
1439 #endif
1440 }();
1441 const char* md5_modified_text = []() {
1442 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
1443 return "37e35705946806f8f98c51e4e25647a2";
1444 }
1445 #if BUILDFLAG(IS_APPLE) && defined(ARCH_CPU_ARM64)
1446 return "9cf1c024a9d2d356bcdd14cb71a32324";
1447 #elif BUILDFLAG(IS_APPLE) && !defined(ARCH_CPU_ARM64)
1448 return "8c992808db99dbe3d74006358a671f05";
1449 #else
1450 return "03cae68322d6a6ba120e738ab325408c";
1451 #endif
1452 }();
1453
1454 // Open a file with two annotations and load its first page.
1455 ASSERT_TRUE(OpenDocument("annotation_stamp_with_ap.pdf"));
1456 FPDF_PAGE page = LoadPage(0);
1457 ASSERT_TRUE(page);
1458 EXPECT_EQ(2, FPDFPage_GetAnnotCount(page));
1459
1460 // Check that the page renders correctly.
1461 {
1462 ScopedFPDFBitmap bitmap = RenderLoadedPageWithFlags(page, FPDF_ANNOT);
1463 CompareBitmap(bitmap.get(), 595, 842, AnnotationStampWithApChecksum());
1464 }
1465
1466 {
1467 // Create a stamp annotation and set its annotation rectangle.
1468 ScopedFPDFAnnotation annot(FPDFPage_CreateAnnot(page, FPDF_ANNOT_STAMP));
1469 ASSERT_TRUE(annot);
1470 FS_RECTF rect;
1471 rect.left = 200.f;
1472 rect.bottom = 550.f;
1473 rect.right = 450.f;
1474 rect.top = 650.f;
1475 EXPECT_TRUE(FPDFAnnot_SetRect(annot.get(), &rect));
1476
1477 // Add a translucent text object to the new annotation.
1478 FPDF_PAGEOBJECT text_object =
1479 FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
1480 EXPECT_TRUE(text_object);
1481 ScopedFPDFWideString text =
1482 GetFPDFWideString(L"I'm a translucent text laying on other text.");
1483 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
1484 EXPECT_TRUE(FPDFPageObj_SetFillColor(text_object, 0, 0, 255, 150));
1485 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 200, 600);
1486 EXPECT_TRUE(FPDFAnnot_AppendObject(annot.get(), text_object));
1487 }
1488
1489 // Check that the page renders correctly with the new text object.
1490 {
1491 ScopedFPDFBitmap bitmap = RenderLoadedPageWithFlags(page, FPDF_ANNOT);
1492 CompareBitmap(bitmap.get(), 595, 842, md5_new_text);
1493 }
1494
1495 {
1496 // Retrieve the newly added stamp annotation and its text object.
1497 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 2));
1498 ASSERT_TRUE(annot);
1499 EXPECT_EQ(1, FPDFAnnot_GetObjectCount(annot.get()));
1500 FPDF_PAGEOBJECT text_object = FPDFAnnot_GetObject(annot.get(), 0);
1501 EXPECT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(text_object));
1502
1503 // Modify the text in the new annotation.
1504 ScopedFPDFWideString new_text = GetFPDFWideString(L"New text!");
1505 EXPECT_TRUE(FPDFText_SetText(text_object, new_text.get()));
1506 EXPECT_TRUE(FPDFAnnot_UpdateObject(annot.get(), text_object));
1507 }
1508
1509 // Check that the page renders correctly with the modified text object.
1510 {
1511 ScopedFPDFBitmap bitmap = RenderLoadedPageWithFlags(page, FPDF_ANNOT);
1512 CompareBitmap(bitmap.get(), 595, 842, md5_modified_text);
1513 }
1514
1515 // Remove the new annotation, and check that the page renders as before.
1516 EXPECT_TRUE(FPDFPage_RemoveAnnot(page, 2));
1517 {
1518 ScopedFPDFBitmap bitmap = RenderLoadedPageWithFlags(page, FPDF_ANNOT);
1519 CompareBitmap(bitmap.get(), 595, 842, AnnotationStampWithApChecksum());
1520 }
1521
1522 UnloadPage(page);
1523 }
1524
TEST_F(FPDFAnnotEmbedderTest,GetSetStringValue)1525 TEST_F(FPDFAnnotEmbedderTest, GetSetStringValue) {
1526 // Open a file with four annotations and load its first page.
1527 ASSERT_TRUE(OpenDocument("annotation_stamp_with_ap.pdf"));
1528 FPDF_PAGE page = LoadPage(0);
1529 ASSERT_TRUE(page);
1530
1531 static const wchar_t kNewDate[] = L"D:201706282359Z00'00'";
1532
1533 {
1534 // Retrieve the first annotation.
1535 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
1536 ASSERT_TRUE(annot);
1537
1538 // Check that a non-existent key does not exist.
1539 EXPECT_FALSE(FPDFAnnot_HasKey(annot.get(), "none"));
1540
1541 // Check that the string value of a non-string dictionary entry is empty.
1542 EXPECT_TRUE(FPDFAnnot_HasKey(annot.get(), pdfium::annotation::kAP));
1543 EXPECT_EQ(FPDF_OBJECT_REFERENCE,
1544 FPDFAnnot_GetValueType(annot.get(), pdfium::annotation::kAP));
1545 EXPECT_EQ(2u, FPDFAnnot_GetStringValue(annot.get(), pdfium::annotation::kAP,
1546 nullptr, 0));
1547
1548 // Check that the string value of the hash is correct.
1549 static const char kHashKey[] = "AAPL:Hash";
1550 EXPECT_EQ(FPDF_OBJECT_NAME, FPDFAnnot_GetValueType(annot.get(), kHashKey));
1551 unsigned long length_bytes =
1552 FPDFAnnot_GetStringValue(annot.get(), kHashKey, nullptr, 0);
1553 ASSERT_EQ(66u, length_bytes);
1554 std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(length_bytes);
1555 EXPECT_EQ(66u, FPDFAnnot_GetStringValue(annot.get(), kHashKey, buf.data(),
1556 length_bytes));
1557 EXPECT_EQ(L"395fbcb98d558681742f30683a62a2ad",
1558 GetPlatformWString(buf.data()));
1559
1560 // Check that the string value of the modified date is correct.
1561 EXPECT_EQ(FPDF_OBJECT_NAME, FPDFAnnot_GetValueType(annot.get(), kHashKey));
1562 length_bytes = FPDFAnnot_GetStringValue(annot.get(), pdfium::annotation::kM,
1563 nullptr, 0);
1564 ASSERT_EQ(44u, length_bytes);
1565 buf = GetFPDFWideStringBuffer(length_bytes);
1566 EXPECT_EQ(44u, FPDFAnnot_GetStringValue(annot.get(), pdfium::annotation::kM,
1567 buf.data(), length_bytes));
1568 EXPECT_EQ(L"D:201706071721Z00'00'", GetPlatformWString(buf.data()));
1569
1570 // Update the date entry for the annotation.
1571 ScopedFPDFWideString text = GetFPDFWideString(kNewDate);
1572 EXPECT_TRUE(FPDFAnnot_SetStringValue(annot.get(), pdfium::annotation::kM,
1573 text.get()));
1574 }
1575
1576 // Save the document and close the page.
1577 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1578 UnloadPage(page);
1579
1580 const char* md5 = []() {
1581 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
1582 return "a95a65d109eda5671c793ff5f7d2a2df";
1583 #if BUILDFLAG(IS_APPLE)
1584 return "52e93c54796f7f7167edf64e81d12bd7";
1585 #else
1586 return "5143f9a98beb7b00ff40b89110a1089f";
1587 #endif
1588 }();
1589
1590 // Open the saved annotation.
1591 ASSERT_TRUE(OpenSavedDocument());
1592 page = LoadSavedPage(0);
1593 ASSERT_TRUE(page);
1594 VerifySavedRendering(page, 595, 842, md5);
1595 {
1596 ScopedFPDFAnnotation new_annot(FPDFPage_GetAnnot(page, 0));
1597
1598 // Check that the string value of the modified date is the newly-set value.
1599 EXPECT_EQ(FPDF_OBJECT_STRING,
1600 FPDFAnnot_GetValueType(new_annot.get(), pdfium::annotation::kM));
1601 unsigned long length_bytes = FPDFAnnot_GetStringValue(
1602 new_annot.get(), pdfium::annotation::kM, nullptr, 0);
1603 ASSERT_EQ(44u, length_bytes);
1604 std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(length_bytes);
1605 EXPECT_EQ(44u,
1606 FPDFAnnot_GetStringValue(new_annot.get(), pdfium::annotation::kM,
1607 buf.data(), length_bytes));
1608 EXPECT_EQ(kNewDate, GetPlatformWString(buf.data()));
1609 }
1610
1611 CloseSavedPage(page);
1612 CloseSavedDocument();
1613 }
1614
TEST_F(FPDFAnnotEmbedderTest,GetNumberValue)1615 TEST_F(FPDFAnnotEmbedderTest, GetNumberValue) {
1616 // Open a file with four text annotations and load its first page.
1617 ASSERT_TRUE(OpenDocument("text_form_multiple.pdf"));
1618 FPDF_PAGE page = LoadPage(0);
1619 ASSERT_TRUE(page);
1620 {
1621 // First two annotations do not have "MaxLen" attribute.
1622 for (int i = 0; i < 2; i++) {
1623 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, i));
1624 ASSERT_TRUE(annot);
1625
1626 // Verify that no "MaxLen" key present.
1627 EXPECT_FALSE(FPDFAnnot_HasKey(annot.get(), "MaxLen"));
1628
1629 float value;
1630 EXPECT_FALSE(FPDFAnnot_GetNumberValue(annot.get(), "MaxLen", &value));
1631 }
1632
1633 // Annotation in index 2 has "MaxLen" of 10.
1634 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 2));
1635 ASSERT_TRUE(annot);
1636
1637 // Verify that "MaxLen" key present.
1638 EXPECT_TRUE(FPDFAnnot_HasKey(annot.get(), "MaxLen"));
1639
1640 float value;
1641 EXPECT_TRUE(FPDFAnnot_GetNumberValue(annot.get(), "MaxLen", &value));
1642 EXPECT_FLOAT_EQ(10.0f, value);
1643
1644 // Check bad inputs.
1645 EXPECT_FALSE(FPDFAnnot_GetNumberValue(nullptr, "MaxLen", &value));
1646 EXPECT_FALSE(FPDFAnnot_GetNumberValue(annot.get(), nullptr, &value));
1647 EXPECT_FALSE(FPDFAnnot_GetNumberValue(annot.get(), "MaxLen", nullptr));
1648 // Ask for key that exists but is not a number.
1649 EXPECT_FALSE(FPDFAnnot_GetNumberValue(annot.get(), "V", &value));
1650 }
1651
1652 UnloadPage(page);
1653 }
1654
TEST_F(FPDFAnnotEmbedderTest,GetSetAP)1655 TEST_F(FPDFAnnotEmbedderTest, GetSetAP) {
1656 // Open a file with four annotations and load its first page.
1657 ASSERT_TRUE(OpenDocument("annotation_stamp_with_ap.pdf"));
1658 FPDF_PAGE page = LoadPage(0);
1659 ASSERT_TRUE(page);
1660
1661 {
1662 static const char kMd5NormalAP[] = "be903df0343fd774fadab9c8900cdf4a";
1663 static constexpr size_t kExpectNormalAPLength = 73970;
1664
1665 // Retrieve the first annotation.
1666 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
1667 ASSERT_TRUE(annot);
1668
1669 // Check that the string value of an AP returns the expected length.
1670 unsigned long normal_length_bytes = FPDFAnnot_GetAP(
1671 annot.get(), FPDF_ANNOT_APPEARANCEMODE_NORMAL, nullptr, 0);
1672 ASSERT_EQ(kExpectNormalAPLength, normal_length_bytes);
1673
1674 // Check that the string value of an AP is not returned if the buffer is too
1675 // small. The result buffer should be overwritten with an empty string.
1676 std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(normal_length_bytes);
1677 // Write in the buffer to verify it's not overwritten.
1678 memcpy(buf.data(), "abcdefgh", 8);
1679 EXPECT_EQ(kExpectNormalAPLength,
1680 FPDFAnnot_GetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_NORMAL,
1681 buf.data(), normal_length_bytes - 1));
1682 EXPECT_EQ(0, memcmp(buf.data(), "abcdefgh", 8));
1683
1684 // Check that the string value of an AP is returned through a buffer that is
1685 // the right size.
1686 EXPECT_EQ(kExpectNormalAPLength,
1687 FPDFAnnot_GetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_NORMAL,
1688 buf.data(), normal_length_bytes));
1689 EXPECT_EQ(kMd5NormalAP,
1690 GenerateMD5Base16({reinterpret_cast<uint8_t*>(buf.data()),
1691 normal_length_bytes}));
1692
1693 // Check that the string value of an AP is returned through a buffer that is
1694 // larger than necessary.
1695 buf = GetFPDFWideStringBuffer(normal_length_bytes + 2);
1696 EXPECT_EQ(kExpectNormalAPLength,
1697 FPDFAnnot_GetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_NORMAL,
1698 buf.data(), normal_length_bytes + 2));
1699 EXPECT_EQ(kMd5NormalAP,
1700 GenerateMD5Base16({reinterpret_cast<uint8_t*>(buf.data()),
1701 normal_length_bytes}));
1702
1703 // Check that getting an AP for a mode that does not have an AP returns an
1704 // empty string.
1705 unsigned long rollover_length_bytes = FPDFAnnot_GetAP(
1706 annot.get(), FPDF_ANNOT_APPEARANCEMODE_ROLLOVER, nullptr, 0);
1707 ASSERT_EQ(2u, rollover_length_bytes);
1708
1709 buf = GetFPDFWideStringBuffer(1000);
1710 EXPECT_EQ(2u,
1711 FPDFAnnot_GetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_ROLLOVER,
1712 buf.data(), 1000));
1713 EXPECT_EQ(L"", GetPlatformWString(buf.data()));
1714
1715 // Check that setting the AP for an invalid appearance mode fails.
1716 ScopedFPDFWideString ap_text = GetFPDFWideString(L"new test ap");
1717 EXPECT_FALSE(FPDFAnnot_SetAP(annot.get(), -1, ap_text.get()));
1718 EXPECT_FALSE(FPDFAnnot_SetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_COUNT,
1719 ap_text.get()));
1720 EXPECT_FALSE(FPDFAnnot_SetAP(
1721 annot.get(), FPDF_ANNOT_APPEARANCEMODE_COUNT + 1, ap_text.get()));
1722
1723 // Set the AP correctly now.
1724 EXPECT_TRUE(FPDFAnnot_SetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_ROLLOVER,
1725 ap_text.get()));
1726
1727 // Check that the new annotation value is equal to the value we just set.
1728 rollover_length_bytes = FPDFAnnot_GetAP(
1729 annot.get(), FPDF_ANNOT_APPEARANCEMODE_ROLLOVER, nullptr, 0);
1730 ASSERT_EQ(24u, rollover_length_bytes);
1731 buf = GetFPDFWideStringBuffer(rollover_length_bytes);
1732 EXPECT_EQ(24u,
1733 FPDFAnnot_GetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_ROLLOVER,
1734 buf.data(), rollover_length_bytes));
1735 EXPECT_EQ(L"new test ap", GetPlatformWString(buf.data()));
1736
1737 // Check that the Normal AP was not touched when the Rollover AP was set.
1738 buf = GetFPDFWideStringBuffer(normal_length_bytes);
1739 EXPECT_EQ(kExpectNormalAPLength,
1740 FPDFAnnot_GetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_NORMAL,
1741 buf.data(), normal_length_bytes));
1742 EXPECT_EQ(kMd5NormalAP,
1743 GenerateMD5Base16({reinterpret_cast<uint8_t*>(buf.data()),
1744 normal_length_bytes}));
1745 }
1746
1747 // Save the modified document, then reopen it.
1748 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1749 UnloadPage(page);
1750
1751 ASSERT_TRUE(OpenSavedDocument());
1752 page = LoadSavedPage(0);
1753 ASSERT_TRUE(page);
1754 {
1755 ScopedFPDFAnnotation new_annot(FPDFPage_GetAnnot(page, 0));
1756
1757 // Check that the new annotation value is equal to the value we set before
1758 // saving.
1759 unsigned long rollover_length_bytes = FPDFAnnot_GetAP(
1760 new_annot.get(), FPDF_ANNOT_APPEARANCEMODE_ROLLOVER, nullptr, 0);
1761 ASSERT_EQ(24u, rollover_length_bytes);
1762 std::vector<FPDF_WCHAR> buf =
1763 GetFPDFWideStringBuffer(rollover_length_bytes);
1764 EXPECT_EQ(24u, FPDFAnnot_GetAP(new_annot.get(),
1765 FPDF_ANNOT_APPEARANCEMODE_ROLLOVER,
1766 buf.data(), rollover_length_bytes));
1767 EXPECT_EQ(L"new test ap", GetPlatformWString(buf.data()));
1768 }
1769
1770 // Close saved document.
1771 CloseSavedPage(page);
1772 CloseSavedDocument();
1773 }
1774
TEST_F(FPDFAnnotEmbedderTest,RemoveOptionalAP)1775 TEST_F(FPDFAnnotEmbedderTest, RemoveOptionalAP) {
1776 // Open a file with four annotations and load its first page.
1777 ASSERT_TRUE(OpenDocument("annotation_stamp_with_ap.pdf"));
1778 FPDF_PAGE page = LoadPage(0);
1779 ASSERT_TRUE(page);
1780
1781 {
1782 // Retrieve the first annotation.
1783 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
1784 ASSERT_TRUE(annot);
1785
1786 // Set Down AP. Normal AP is already set.
1787 ScopedFPDFWideString ap_text = GetFPDFWideString(L"new test ap");
1788 EXPECT_TRUE(FPDFAnnot_SetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_DOWN,
1789 ap_text.get()));
1790 EXPECT_EQ(73970u,
1791 FPDFAnnot_GetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_NORMAL,
1792 nullptr, 0));
1793 EXPECT_EQ(24u, FPDFAnnot_GetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_DOWN,
1794 nullptr, 0));
1795
1796 // Check that setting the Down AP to null removes the Down entry but keeps
1797 // Normal intact.
1798 EXPECT_TRUE(
1799 FPDFAnnot_SetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_DOWN, nullptr));
1800 EXPECT_EQ(73970u,
1801 FPDFAnnot_GetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_NORMAL,
1802 nullptr, 0));
1803 EXPECT_EQ(2u, FPDFAnnot_GetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_DOWN,
1804 nullptr, 0));
1805 }
1806
1807 UnloadPage(page);
1808 }
1809
TEST_F(FPDFAnnotEmbedderTest,RemoveRequiredAP)1810 TEST_F(FPDFAnnotEmbedderTest, RemoveRequiredAP) {
1811 // Open a file with four annotations and load its first page.
1812 ASSERT_TRUE(OpenDocument("annotation_stamp_with_ap.pdf"));
1813 FPDF_PAGE page = LoadPage(0);
1814 ASSERT_TRUE(page);
1815
1816 {
1817 // Retrieve the first annotation.
1818 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
1819 ASSERT_TRUE(annot);
1820
1821 // Set Down AP. Normal AP is already set.
1822 ScopedFPDFWideString ap_text = GetFPDFWideString(L"new test ap");
1823 EXPECT_TRUE(FPDFAnnot_SetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_DOWN,
1824 ap_text.get()));
1825 EXPECT_EQ(73970u,
1826 FPDFAnnot_GetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_NORMAL,
1827 nullptr, 0));
1828 EXPECT_EQ(24u, FPDFAnnot_GetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_DOWN,
1829 nullptr, 0));
1830
1831 // Check that setting the Normal AP to null removes the whole AP dictionary.
1832 EXPECT_TRUE(FPDFAnnot_SetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_NORMAL,
1833 nullptr));
1834 EXPECT_EQ(2u, FPDFAnnot_GetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_NORMAL,
1835 nullptr, 0));
1836 EXPECT_EQ(2u, FPDFAnnot_GetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_DOWN,
1837 nullptr, 0));
1838 }
1839
1840 UnloadPage(page);
1841 }
1842
TEST_F(FPDFAnnotEmbedderTest,ExtractLinkedAnnotations)1843 TEST_F(FPDFAnnotEmbedderTest, ExtractLinkedAnnotations) {
1844 // Open a file with annotations and load its first page.
1845 ASSERT_TRUE(OpenDocument("annotation_highlight_square_with_ap.pdf"));
1846 FPDF_PAGE page = LoadPage(0);
1847 ASSERT_TRUE(page);
1848 EXPECT_EQ(-1, FPDFPage_GetAnnotIndex(page, nullptr));
1849
1850 {
1851 // Retrieve the highlight annotation which has its popup defined.
1852 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
1853 ASSERT_TRUE(annot);
1854 EXPECT_EQ(FPDF_ANNOT_HIGHLIGHT, FPDFAnnot_GetSubtype(annot.get()));
1855 EXPECT_EQ(0, FPDFPage_GetAnnotIndex(page, annot.get()));
1856 static const char kPopupKey[] = "Popup";
1857 ASSERT_TRUE(FPDFAnnot_HasKey(annot.get(), kPopupKey));
1858 ASSERT_EQ(FPDF_OBJECT_REFERENCE,
1859 FPDFAnnot_GetValueType(annot.get(), kPopupKey));
1860
1861 // Retrieve and verify the popup of the highlight annotation.
1862 ScopedFPDFAnnotation popup(
1863 FPDFAnnot_GetLinkedAnnot(annot.get(), kPopupKey));
1864 ASSERT_TRUE(popup);
1865 EXPECT_EQ(FPDF_ANNOT_POPUP, FPDFAnnot_GetSubtype(popup.get()));
1866 EXPECT_EQ(1, FPDFPage_GetAnnotIndex(page, popup.get()));
1867 FS_RECTF rect;
1868 ASSERT_TRUE(FPDFAnnot_GetRect(popup.get(), &rect));
1869 EXPECT_NEAR(612.0f, rect.left, 0.001f);
1870 EXPECT_NEAR(578.792, rect.bottom, 0.001f);
1871
1872 // Attempting to retrieve |annot|'s "IRT"-linked annotation would fail,
1873 // since "IRT" is not a key in |annot|'s dictionary.
1874 static const char kIRTKey[] = "IRT";
1875 ASSERT_FALSE(FPDFAnnot_HasKey(annot.get(), kIRTKey));
1876 EXPECT_FALSE(FPDFAnnot_GetLinkedAnnot(annot.get(), kIRTKey));
1877
1878 // Attempting to retrieve |annot|'s parent dictionary as an annotation
1879 // would fail, since its parent is not an annotation.
1880 ASSERT_TRUE(FPDFAnnot_HasKey(annot.get(), pdfium::annotation::kP));
1881 EXPECT_EQ(FPDF_OBJECT_REFERENCE,
1882 FPDFAnnot_GetValueType(annot.get(), pdfium::annotation::kP));
1883 EXPECT_FALSE(FPDFAnnot_GetLinkedAnnot(annot.get(), pdfium::annotation::kP));
1884 }
1885
1886 UnloadPage(page);
1887 }
1888
TEST_F(FPDFAnnotEmbedderTest,GetFormFieldFlagsTextField)1889 TEST_F(FPDFAnnotEmbedderTest, GetFormFieldFlagsTextField) {
1890 // Open file with form text fields.
1891 ASSERT_TRUE(OpenDocument("text_form_multiple.pdf"));
1892 FPDF_PAGE page = LoadPage(0);
1893 ASSERT_TRUE(page);
1894
1895 {
1896 // Retrieve the first annotation: user-editable text field.
1897 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
1898 ASSERT_TRUE(annot);
1899
1900 // Check that the flag values are as expected.
1901 int flags = FPDFAnnot_GetFormFieldFlags(form_handle(), annot.get());
1902 EXPECT_FALSE(flags & FPDF_FORMFLAG_READONLY);
1903 EXPECT_FALSE(flags & FPDF_FORMFLAG_REQUIRED);
1904 EXPECT_FALSE(flags & FPDF_FORMFLAG_NOEXPORT);
1905 EXPECT_FALSE(flags & FPDF_FORMFLAG_TEXT_MULTILINE);
1906 EXPECT_FALSE(flags & FPDF_FORMFLAG_TEXT_PASSWORD);
1907 }
1908
1909 {
1910 // Retrieve the second annotation: read-only text field.
1911 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 1));
1912 ASSERT_TRUE(annot);
1913
1914 // Check that the flag values are as expected.
1915 int flags = FPDFAnnot_GetFormFieldFlags(form_handle(), annot.get());
1916 EXPECT_TRUE(flags & FPDF_FORMFLAG_READONLY);
1917 EXPECT_FALSE(flags & FPDF_FORMFLAG_REQUIRED);
1918 EXPECT_FALSE(flags & FPDF_FORMFLAG_NOEXPORT);
1919 EXPECT_FALSE(flags & FPDF_FORMFLAG_TEXT_MULTILINE);
1920 EXPECT_FALSE(flags & FPDF_FORMFLAG_TEXT_PASSWORD);
1921 }
1922
1923 {
1924 // Retrieve the fourth annotation: user-editable password text field.
1925 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 3));
1926 ASSERT_TRUE(annot);
1927
1928 // Check that the flag values are as expected.
1929 int flags = FPDFAnnot_GetFormFieldFlags(form_handle(), annot.get());
1930 EXPECT_FALSE(flags & FPDF_FORMFLAG_READONLY);
1931 EXPECT_FALSE(flags & FPDF_FORMFLAG_REQUIRED);
1932 EXPECT_FALSE(flags & FPDF_FORMFLAG_NOEXPORT);
1933 EXPECT_FALSE(flags & FPDF_FORMFLAG_TEXT_MULTILINE);
1934 EXPECT_TRUE(flags & FPDF_FORMFLAG_TEXT_PASSWORD);
1935 }
1936
1937 UnloadPage(page);
1938 }
1939
TEST_F(FPDFAnnotEmbedderTest,GetFormFieldFlagsComboBox)1940 TEST_F(FPDFAnnotEmbedderTest, GetFormFieldFlagsComboBox) {
1941 // Open file with form text fields.
1942 ASSERT_TRUE(OpenDocument("combobox_form.pdf"));
1943 FPDF_PAGE page = LoadPage(0);
1944 ASSERT_TRUE(page);
1945
1946 {
1947 // Retrieve the first annotation: user-editable combobox.
1948 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
1949 ASSERT_TRUE(annot);
1950
1951 // Check that the flag values are as expected.
1952 int flags = FPDFAnnot_GetFormFieldFlags(form_handle(), annot.get());
1953 EXPECT_FALSE(flags & FPDF_FORMFLAG_READONLY);
1954 EXPECT_FALSE(flags & FPDF_FORMFLAG_REQUIRED);
1955 EXPECT_FALSE(flags & FPDF_FORMFLAG_NOEXPORT);
1956 EXPECT_TRUE(flags & FPDF_FORMFLAG_CHOICE_COMBO);
1957 EXPECT_TRUE(flags & FPDF_FORMFLAG_CHOICE_EDIT);
1958 EXPECT_FALSE(flags & FPDF_FORMFLAG_CHOICE_MULTI_SELECT);
1959 }
1960
1961 {
1962 // Retrieve the second annotation: regular combobox.
1963 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 1));
1964 ASSERT_TRUE(annot);
1965
1966 // Check that the flag values are as expected.
1967 int flags = FPDFAnnot_GetFormFieldFlags(form_handle(), annot.get());
1968 EXPECT_FALSE(flags & FPDF_FORMFLAG_READONLY);
1969 EXPECT_FALSE(flags & FPDF_FORMFLAG_REQUIRED);
1970 EXPECT_FALSE(flags & FPDF_FORMFLAG_NOEXPORT);
1971 EXPECT_TRUE(flags & FPDF_FORMFLAG_CHOICE_COMBO);
1972 EXPECT_FALSE(flags & FPDF_FORMFLAG_CHOICE_EDIT);
1973 EXPECT_FALSE(flags & FPDF_FORMFLAG_CHOICE_MULTI_SELECT);
1974 }
1975
1976 {
1977 // Retrieve the third annotation: read-only combobox.
1978 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 2));
1979 ASSERT_TRUE(annot);
1980
1981 // Check that the flag values are as expected.
1982 int flags = FPDFAnnot_GetFormFieldFlags(form_handle(), annot.get());
1983 EXPECT_TRUE(flags & FPDF_FORMFLAG_READONLY);
1984 EXPECT_FALSE(flags & FPDF_FORMFLAG_REQUIRED);
1985 EXPECT_FALSE(flags & FPDF_FORMFLAG_NOEXPORT);
1986 EXPECT_TRUE(flags & FPDF_FORMFLAG_CHOICE_COMBO);
1987 EXPECT_FALSE(flags & FPDF_FORMFLAG_CHOICE_EDIT);
1988 EXPECT_FALSE(flags & FPDF_FORMFLAG_CHOICE_MULTI_SELECT);
1989 }
1990
1991 UnloadPage(page);
1992 }
1993
TEST_F(FPDFAnnotEmbedderTest,GetFormAnnotNull)1994 TEST_F(FPDFAnnotEmbedderTest, GetFormAnnotNull) {
1995 // Open file with form text fields.
1996 ASSERT_TRUE(OpenDocument("text_form.pdf"));
1997 FPDF_PAGE page = LoadPage(0);
1998 ASSERT_TRUE(page);
1999
2000 // Attempt to get an annotation where no annotation exists on page.
2001 static const FS_POINTF kOriginPoint = {0.0f, 0.0f};
2002 EXPECT_FALSE(
2003 FPDFAnnot_GetFormFieldAtPoint(form_handle(), page, &kOriginPoint));
2004
2005 static const FS_POINTF kValidPoint = {120.0f, 120.0f};
2006 {
2007 // Verify there is an annotation.
2008 ScopedFPDFAnnotation annot(
2009 FPDFAnnot_GetFormFieldAtPoint(form_handle(), page, &kValidPoint));
2010 EXPECT_TRUE(annot);
2011 }
2012
2013 // Try other bad inputs at a valid location.
2014 EXPECT_FALSE(FPDFAnnot_GetFormFieldAtPoint(nullptr, nullptr, &kValidPoint));
2015 EXPECT_FALSE(FPDFAnnot_GetFormFieldAtPoint(nullptr, page, &kValidPoint));
2016 EXPECT_FALSE(
2017 FPDFAnnot_GetFormFieldAtPoint(form_handle(), nullptr, &kValidPoint));
2018
2019 UnloadPage(page);
2020 }
2021
TEST_F(FPDFAnnotEmbedderTest,GetFormAnnotAndCheckFlagsTextField)2022 TEST_F(FPDFAnnotEmbedderTest, GetFormAnnotAndCheckFlagsTextField) {
2023 // Open file with form text fields.
2024 ASSERT_TRUE(OpenDocument("text_form_multiple.pdf"));
2025 FPDF_PAGE page = LoadPage(0);
2026 ASSERT_TRUE(page);
2027
2028 {
2029 // Retrieve user-editable text field annotation.
2030 static const FS_POINTF kPoint = {105.0f, 118.0f};
2031 ScopedFPDFAnnotation annot(
2032 FPDFAnnot_GetFormFieldAtPoint(form_handle(), page, &kPoint));
2033 ASSERT_TRUE(annot);
2034
2035 // Check that interactive form annotation flag values are as expected.
2036 int flags = FPDFAnnot_GetFormFieldFlags(form_handle(), annot.get());
2037 EXPECT_FALSE(flags & FPDF_FORMFLAG_REQUIRED);
2038 EXPECT_FALSE(flags & FPDF_FORMFLAG_NOEXPORT);
2039 EXPECT_FALSE(flags & FPDF_FORMFLAG_READONLY);
2040 }
2041
2042 {
2043 // Retrieve read-only text field annotation.
2044 static const FS_POINTF kPoint = {105.0f, 202.0f};
2045 ScopedFPDFAnnotation annot(
2046 FPDFAnnot_GetFormFieldAtPoint(form_handle(), page, &kPoint));
2047 ASSERT_TRUE(annot);
2048
2049 // Check that interactive form annotation flag values are as expected.
2050 int flags = FPDFAnnot_GetFormFieldFlags(form_handle(), annot.get());
2051 EXPECT_TRUE(flags & FPDF_FORMFLAG_READONLY);
2052 EXPECT_FALSE(flags & FPDF_FORMFLAG_REQUIRED);
2053 EXPECT_FALSE(flags & FPDF_FORMFLAG_NOEXPORT);
2054 }
2055
2056 UnloadPage(page);
2057 }
2058
TEST_F(FPDFAnnotEmbedderTest,GetFormAnnotAndCheckFlagsComboBox)2059 TEST_F(FPDFAnnotEmbedderTest, GetFormAnnotAndCheckFlagsComboBox) {
2060 // Open file with form comboboxes.
2061 ASSERT_TRUE(OpenDocument("combobox_form.pdf"));
2062 FPDF_PAGE page = LoadPage(0);
2063 ASSERT_TRUE(page);
2064
2065 {
2066 // Retrieve user-editable combobox annotation.
2067 static const FS_POINTF kPoint = {102.0f, 363.0f};
2068 ScopedFPDFAnnotation annot(
2069 FPDFAnnot_GetFormFieldAtPoint(form_handle(), page, &kPoint));
2070 ASSERT_TRUE(annot);
2071
2072 // Check that interactive form annotation flag values are as expected.
2073 int flags = FPDFAnnot_GetFormFieldFlags(form_handle(), annot.get());
2074 EXPECT_FALSE(flags & FPDF_FORMFLAG_READONLY);
2075 EXPECT_FALSE(flags & FPDF_FORMFLAG_REQUIRED);
2076 EXPECT_FALSE(flags & FPDF_FORMFLAG_NOEXPORT);
2077 EXPECT_TRUE(flags & FPDF_FORMFLAG_CHOICE_COMBO);
2078 EXPECT_TRUE(flags & FPDF_FORMFLAG_CHOICE_EDIT);
2079 EXPECT_FALSE(flags & FPDF_FORMFLAG_CHOICE_MULTI_SELECT);
2080 }
2081
2082 {
2083 // Retrieve regular combobox annotation.
2084 static const FS_POINTF kPoint = {102.0f, 413.0f};
2085 ScopedFPDFAnnotation annot(
2086 FPDFAnnot_GetFormFieldAtPoint(form_handle(), page, &kPoint));
2087 ASSERT_TRUE(annot);
2088
2089 // Check that interactive form annotation flag values are as expected.
2090 int flags = FPDFAnnot_GetFormFieldFlags(form_handle(), annot.get());
2091 EXPECT_FALSE(flags & FPDF_FORMFLAG_READONLY);
2092 EXPECT_FALSE(flags & FPDF_FORMFLAG_REQUIRED);
2093 EXPECT_FALSE(flags & FPDF_FORMFLAG_NOEXPORT);
2094 EXPECT_TRUE(flags & FPDF_FORMFLAG_CHOICE_COMBO);
2095 EXPECT_FALSE(flags & FPDF_FORMFLAG_CHOICE_EDIT);
2096 EXPECT_FALSE(flags & FPDF_FORMFLAG_CHOICE_MULTI_SELECT);
2097 }
2098
2099 {
2100 // Retrieve read-only combobox annotation.
2101 static const FS_POINTF kPoint = {102.0f, 513.0f};
2102 ScopedFPDFAnnotation annot(
2103 FPDFAnnot_GetFormFieldAtPoint(form_handle(), page, &kPoint));
2104 ASSERT_TRUE(annot);
2105
2106 // Check that interactive form annotation flag values are as expected.
2107 int flags = FPDFAnnot_GetFormFieldFlags(form_handle(), annot.get());
2108 EXPECT_TRUE(flags & FPDF_FORMFLAG_READONLY);
2109 EXPECT_FALSE(flags & FPDF_FORMFLAG_REQUIRED);
2110 EXPECT_FALSE(flags & FPDF_FORMFLAG_NOEXPORT);
2111 EXPECT_TRUE(flags & FPDF_FORMFLAG_CHOICE_COMBO);
2112 EXPECT_FALSE(flags & FPDF_FORMFLAG_CHOICE_EDIT);
2113 EXPECT_FALSE(flags & FPDF_FORMFLAG_CHOICE_MULTI_SELECT);
2114 }
2115
2116 UnloadPage(page);
2117 }
2118
TEST_F(FPDFAnnotEmbedderTest,BUG_1206)2119 TEST_F(FPDFAnnotEmbedderTest, BUG_1206) {
2120 const char* expected_bitmap = []() {
2121 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
2122 return "a1ea1ceebb26922fae576cb79ce63af0";
2123 return "0d9fc05c6762fd788bd23fd87a4967bc";
2124 }();
2125 static constexpr size_t kExpectedSize = 1590;
2126
2127 ASSERT_TRUE(OpenDocument("bug_1206.pdf"));
2128
2129 FPDF_PAGE page = LoadPage(0);
2130 ASSERT_TRUE(page);
2131
2132 ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2133 EXPECT_EQ(kExpectedSize, GetString().size());
2134 ClearString();
2135
2136 for (size_t i = 0; i < 10; ++i) {
2137 ScopedFPDFBitmap bitmap = RenderLoadedPageWithFlags(page, FPDF_ANNOT);
2138 CompareBitmap(bitmap.get(), 612, 792, expected_bitmap);
2139
2140 ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2141 // TODO(https://crbug.com/pdfium/1206): This is wrong. The size should be
2142 // equal, not bigger.
2143 EXPECT_LT(kExpectedSize, GetString().size());
2144 ClearString();
2145 }
2146
2147 UnloadPage(page);
2148 }
2149
TEST_F(FPDFAnnotEmbedderTest,BUG_1212)2150 TEST_F(FPDFAnnotEmbedderTest, BUG_1212) {
2151 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
2152 FPDF_PAGE page = LoadPage(0);
2153 ASSERT_TRUE(page);
2154 EXPECT_EQ(0, FPDFPage_GetAnnotCount(page));
2155
2156 static const char kTestKey[] = "test";
2157 static const wchar_t kData[] = L"\xf6\xe4";
2158 static const size_t kBufSize = 12;
2159 std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(kBufSize);
2160
2161 {
2162 // Add a text annotation to the page.
2163 ScopedFPDFAnnotation annot(FPDFPage_CreateAnnot(page, FPDF_ANNOT_TEXT));
2164 ASSERT_TRUE(annot);
2165 EXPECT_EQ(1, FPDFPage_GetAnnotCount(page));
2166 EXPECT_EQ(FPDF_ANNOT_TEXT, FPDFAnnot_GetSubtype(annot.get()));
2167
2168 // Make sure there is no test key, add set a value there, and read it back.
2169 std::fill(buf.begin(), buf.end(), 'x');
2170 ASSERT_EQ(2u, FPDFAnnot_GetStringValue(annot.get(), kTestKey, buf.data(),
2171 kBufSize));
2172 EXPECT_EQ(L"", GetPlatformWString(buf.data()));
2173
2174 ScopedFPDFWideString text = GetFPDFWideString(kData);
2175 EXPECT_TRUE(FPDFAnnot_SetStringValue(annot.get(), kTestKey, text.get()));
2176
2177 std::fill(buf.begin(), buf.end(), 'x');
2178 ASSERT_EQ(6u, FPDFAnnot_GetStringValue(annot.get(), kTestKey, buf.data(),
2179 kBufSize));
2180 EXPECT_EQ(kData, GetPlatformWString(buf.data()));
2181 }
2182
2183 {
2184 ScopedFPDFAnnotation annot(FPDFPage_CreateAnnot(page, FPDF_ANNOT_STAMP));
2185 ASSERT_TRUE(annot);
2186 const FS_RECTF bounding_rect{206.0f, 753.0f, 339.0f, 709.0f};
2187 EXPECT_TRUE(FPDFAnnot_SetRect(annot.get(), &bounding_rect));
2188 EXPECT_EQ(2, FPDFPage_GetAnnotCount(page));
2189 EXPECT_EQ(FPDF_ANNOT_STAMP, FPDFAnnot_GetSubtype(annot.get()));
2190 // Also do the same test for its appearance string.
2191 std::fill(buf.begin(), buf.end(), 'x');
2192 ASSERT_EQ(2u,
2193 FPDFAnnot_GetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_ROLLOVER,
2194 buf.data(), kBufSize));
2195 EXPECT_EQ(L"", GetPlatformWString(buf.data()));
2196
2197 ScopedFPDFWideString text = GetFPDFWideString(kData);
2198 EXPECT_TRUE(FPDFAnnot_SetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_ROLLOVER,
2199 text.get()));
2200
2201 std::fill(buf.begin(), buf.end(), 'x');
2202 ASSERT_EQ(6u,
2203 FPDFAnnot_GetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_ROLLOVER,
2204 buf.data(), kBufSize));
2205 EXPECT_EQ(kData, GetPlatformWString(buf.data()));
2206 }
2207
2208 UnloadPage(page);
2209
2210 {
2211 // Save a copy, open the copy, and check the annotation again.
2212 // Note that it renders the rotation.
2213 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2214 ASSERT_TRUE(OpenSavedDocument());
2215 FPDF_PAGE saved_page = LoadSavedPage(0);
2216 ASSERT_TRUE(saved_page);
2217
2218 EXPECT_EQ(2, FPDFPage_GetAnnotCount(saved_page));
2219 {
2220 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(saved_page, 0));
2221 ASSERT_TRUE(annot);
2222 EXPECT_EQ(FPDF_ANNOT_TEXT, FPDFAnnot_GetSubtype(annot.get()));
2223
2224 std::fill(buf.begin(), buf.end(), 'x');
2225 ASSERT_EQ(6u, FPDFAnnot_GetStringValue(annot.get(), kTestKey, buf.data(),
2226 kBufSize));
2227 EXPECT_EQ(kData, GetPlatformWString(buf.data()));
2228 }
2229
2230 {
2231 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(saved_page, 0));
2232 ASSERT_TRUE(annot);
2233 // TODO(thestig): This return FPDF_ANNOT_UNKNOWN for some reason.
2234 // EXPECT_EQ(FPDF_ANNOT_TEXT, FPDFAnnot_GetSubtype(annot.get()));
2235
2236 std::fill(buf.begin(), buf.end(), 'x');
2237 ASSERT_EQ(6u, FPDFAnnot_GetStringValue(annot.get(), kTestKey, buf.data(),
2238 kBufSize));
2239 EXPECT_EQ(kData, GetPlatformWString(buf.data()));
2240 }
2241
2242 CloseSavedPage(saved_page);
2243 CloseSavedDocument();
2244 }
2245 }
2246
TEST_F(FPDFAnnotEmbedderTest,GetOptionCountCombobox)2247 TEST_F(FPDFAnnotEmbedderTest, GetOptionCountCombobox) {
2248 // Open a file with combobox widget annotations and load its first page.
2249 ASSERT_TRUE(OpenDocument("combobox_form.pdf"));
2250 FPDF_PAGE page = LoadPage(0);
2251 ASSERT_TRUE(page);
2252
2253 {
2254 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
2255 ASSERT_TRUE(annot);
2256
2257 EXPECT_EQ(3, FPDFAnnot_GetOptionCount(form_handle(), annot.get()));
2258
2259 annot.reset(FPDFPage_GetAnnot(page, 1));
2260 ASSERT_TRUE(annot);
2261
2262 EXPECT_EQ(26, FPDFAnnot_GetOptionCount(form_handle(), annot.get()));
2263
2264 // Check bad form handle / annot.
2265 EXPECT_EQ(-1, FPDFAnnot_GetOptionCount(nullptr, nullptr));
2266 EXPECT_EQ(-1, FPDFAnnot_GetOptionCount(form_handle(), nullptr));
2267 EXPECT_EQ(-1, FPDFAnnot_GetOptionCount(nullptr, annot.get()));
2268 }
2269
2270 UnloadPage(page);
2271 }
2272
TEST_F(FPDFAnnotEmbedderTest,GetOptionCountListbox)2273 TEST_F(FPDFAnnotEmbedderTest, GetOptionCountListbox) {
2274 // Open a file with listbox widget annotations and load its first page.
2275 ASSERT_TRUE(OpenDocument("listbox_form.pdf"));
2276 FPDF_PAGE page = LoadPage(0);
2277 ASSERT_TRUE(page);
2278
2279 {
2280 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
2281 ASSERT_TRUE(annot);
2282
2283 EXPECT_EQ(3, FPDFAnnot_GetOptionCount(form_handle(), annot.get()));
2284
2285 annot.reset(FPDFPage_GetAnnot(page, 1));
2286 ASSERT_TRUE(annot);
2287
2288 EXPECT_EQ(26, FPDFAnnot_GetOptionCount(form_handle(), annot.get()));
2289 }
2290
2291 UnloadPage(page);
2292 }
2293
TEST_F(FPDFAnnotEmbedderTest,GetOptionCountInvalidAnnotations)2294 TEST_F(FPDFAnnotEmbedderTest, GetOptionCountInvalidAnnotations) {
2295 // Open a file with ink annotations and load its first page.
2296 ASSERT_TRUE(OpenDocument("annotation_ink_multiple.pdf"));
2297 FPDF_PAGE page = LoadPage(0);
2298 ASSERT_TRUE(page);
2299
2300 {
2301 // annotations do not have "Opt" array and will return -1
2302 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
2303 ASSERT_TRUE(annot);
2304
2305 EXPECT_EQ(-1, FPDFAnnot_GetOptionCount(form_handle(), annot.get()));
2306
2307 annot.reset(FPDFPage_GetAnnot(page, 1));
2308 ASSERT_TRUE(annot);
2309
2310 EXPECT_EQ(-1, FPDFAnnot_GetOptionCount(form_handle(), annot.get()));
2311 }
2312
2313 UnloadPage(page);
2314 }
2315
TEST_F(FPDFAnnotEmbedderTest,GetOptionLabelCombobox)2316 TEST_F(FPDFAnnotEmbedderTest, GetOptionLabelCombobox) {
2317 // Open a file with combobox widget annotations and load its first page.
2318 ASSERT_TRUE(OpenDocument("combobox_form.pdf"));
2319 FPDF_PAGE page = LoadPage(0);
2320 ASSERT_TRUE(page);
2321
2322 {
2323 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
2324 ASSERT_TRUE(annot);
2325
2326 int index = 0;
2327 unsigned long length_bytes =
2328 FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), index, nullptr, 0);
2329 ASSERT_EQ(8u, length_bytes);
2330 std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(length_bytes);
2331 EXPECT_EQ(8u, FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), index,
2332 buf.data(), length_bytes));
2333 EXPECT_EQ(L"Foo", GetPlatformWString(buf.data()));
2334
2335 annot.reset(FPDFPage_GetAnnot(page, 1));
2336 ASSERT_TRUE(annot);
2337
2338 index = 0;
2339 length_bytes =
2340 FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), index, nullptr, 0);
2341 ASSERT_EQ(12u, length_bytes);
2342 buf = GetFPDFWideStringBuffer(length_bytes);
2343 EXPECT_EQ(12u, FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), index,
2344 buf.data(), length_bytes));
2345 EXPECT_EQ(L"Apple", GetPlatformWString(buf.data()));
2346
2347 index = 25;
2348 length_bytes =
2349 FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), index, nullptr, 0);
2350 buf = GetFPDFWideStringBuffer(length_bytes);
2351 EXPECT_EQ(18u, FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), index,
2352 buf.data(), length_bytes));
2353 EXPECT_EQ(L"Zucchini", GetPlatformWString(buf.data()));
2354
2355 // Indices out of range
2356 EXPECT_EQ(0u, FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), -1,
2357 nullptr, 0));
2358 EXPECT_EQ(0u, FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), 26,
2359 nullptr, 0));
2360
2361 // Check bad form handle / annot.
2362 EXPECT_EQ(0u, FPDFAnnot_GetOptionLabel(nullptr, nullptr, 0, nullptr, 0));
2363 EXPECT_EQ(0u,
2364 FPDFAnnot_GetOptionLabel(nullptr, annot.get(), 0, nullptr, 0));
2365 EXPECT_EQ(0u,
2366 FPDFAnnot_GetOptionLabel(form_handle(), nullptr, 0, nullptr, 0));
2367 }
2368
2369 UnloadPage(page);
2370 }
2371
TEST_F(FPDFAnnotEmbedderTest,GetOptionLabelListbox)2372 TEST_F(FPDFAnnotEmbedderTest, GetOptionLabelListbox) {
2373 // Open a file with listbox widget annotations and load its first page.
2374 ASSERT_TRUE(OpenDocument("listbox_form.pdf"));
2375 FPDF_PAGE page = LoadPage(0);
2376 ASSERT_TRUE(page);
2377
2378 {
2379 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
2380 ASSERT_TRUE(annot);
2381
2382 int index = 0;
2383 unsigned long length_bytes =
2384 FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), index, nullptr, 0);
2385 ASSERT_EQ(8u, length_bytes);
2386 std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(length_bytes);
2387 EXPECT_EQ(8u, FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), index,
2388 buf.data(), length_bytes));
2389 EXPECT_EQ(L"Foo", GetPlatformWString(buf.data()));
2390
2391 annot.reset(FPDFPage_GetAnnot(page, 1));
2392 ASSERT_TRUE(annot);
2393
2394 index = 0;
2395 length_bytes =
2396 FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), index, nullptr, 0);
2397 ASSERT_EQ(12u, length_bytes);
2398 buf = GetFPDFWideStringBuffer(length_bytes);
2399 EXPECT_EQ(12u, FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), index,
2400 buf.data(), length_bytes));
2401 EXPECT_EQ(L"Apple", GetPlatformWString(buf.data()));
2402
2403 index = 25;
2404 length_bytes =
2405 FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), index, nullptr, 0);
2406 ASSERT_EQ(18u, length_bytes);
2407 buf = GetFPDFWideStringBuffer(length_bytes);
2408 EXPECT_EQ(18u, FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), index,
2409 buf.data(), length_bytes));
2410 EXPECT_EQ(L"Zucchini", GetPlatformWString(buf.data()));
2411
2412 // indices out of range
2413 EXPECT_EQ(0u, FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), -1,
2414 nullptr, 0));
2415 EXPECT_EQ(0u, FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), 26,
2416 nullptr, 0));
2417 }
2418
2419 UnloadPage(page);
2420 }
2421
TEST_F(FPDFAnnotEmbedderTest,GetOptionLabelInvalidAnnotations)2422 TEST_F(FPDFAnnotEmbedderTest, GetOptionLabelInvalidAnnotations) {
2423 // Open a file with ink annotations and load its first page.
2424 ASSERT_TRUE(OpenDocument("annotation_ink_multiple.pdf"));
2425 FPDF_PAGE page = LoadPage(0);
2426 ASSERT_TRUE(page);
2427
2428 {
2429 // annotations do not have "Opt" array and will return 0
2430 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
2431 ASSERT_TRUE(annot);
2432
2433 EXPECT_EQ(0u, FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), 0,
2434 nullptr, 0));
2435
2436 annot.reset(FPDFPage_GetAnnot(page, 1));
2437 ASSERT_TRUE(annot);
2438
2439 EXPECT_EQ(0u, FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), 0,
2440 nullptr, 0));
2441 }
2442
2443 UnloadPage(page);
2444 }
2445
TEST_F(FPDFAnnotEmbedderTest,IsOptionSelectedCombobox)2446 TEST_F(FPDFAnnotEmbedderTest, IsOptionSelectedCombobox) {
2447 // Open a file with combobox widget annotations and load its first page.
2448 ASSERT_TRUE(OpenDocument("combobox_form.pdf"));
2449 FPDF_PAGE page = LoadPage(0);
2450 ASSERT_TRUE(page);
2451
2452 {
2453 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
2454 ASSERT_TRUE(annot);
2455
2456 // Checks for Combobox with no Values (/V) or Selected Indices (/I) objects.
2457 int count = FPDFAnnot_GetOptionCount(form_handle(), annot.get());
2458 ASSERT_EQ(3, count);
2459 for (int i = 0; i < count; i++) {
2460 EXPECT_FALSE(FPDFAnnot_IsOptionSelected(form_handle(), annot.get(), i));
2461 }
2462
2463 annot.reset(FPDFPage_GetAnnot(page, 1));
2464 ASSERT_TRUE(annot);
2465
2466 // Checks for Combobox with Values (/V) object which is just a string.
2467 count = FPDFAnnot_GetOptionCount(form_handle(), annot.get());
2468 ASSERT_EQ(26, count);
2469 for (int i = 0; i < count; i++) {
2470 EXPECT_EQ(i == 1,
2471 FPDFAnnot_IsOptionSelected(form_handle(), annot.get(), i));
2472 }
2473
2474 // Checks for index outside bound i.e. (index >= CountOption()).
2475 EXPECT_FALSE(FPDFAnnot_IsOptionSelected(form_handle(), annot.get(),
2476 /*index=*/26));
2477 // Checks for negetive index.
2478 EXPECT_FALSE(FPDFAnnot_IsOptionSelected(form_handle(), annot.get(),
2479 /*index=*/-1));
2480
2481 // Checks for bad form handle/annot.
2482 EXPECT_FALSE(FPDFAnnot_IsOptionSelected(nullptr, nullptr, /*index=*/0));
2483 EXPECT_FALSE(
2484 FPDFAnnot_IsOptionSelected(form_handle(), nullptr, /*index=*/0));
2485 EXPECT_FALSE(FPDFAnnot_IsOptionSelected(nullptr, annot.get(), /*index=*/0));
2486 }
2487
2488 UnloadPage(page);
2489 }
2490
TEST_F(FPDFAnnotEmbedderTest,IsOptionSelectedListbox)2491 TEST_F(FPDFAnnotEmbedderTest, IsOptionSelectedListbox) {
2492 // Open a file with listbox widget annotations and load its first page.
2493 ASSERT_TRUE(OpenDocument("listbox_form.pdf"));
2494 FPDF_PAGE page = LoadPage(0);
2495 ASSERT_TRUE(page);
2496
2497 {
2498 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
2499 ASSERT_TRUE(annot);
2500
2501 // Checks for Listbox with no Values (/V) or Selected Indices (/I) objects.
2502 int count = FPDFAnnot_GetOptionCount(form_handle(), annot.get());
2503 ASSERT_EQ(3, count);
2504 for (int i = 0; i < count; i++) {
2505 EXPECT_FALSE(FPDFAnnot_IsOptionSelected(form_handle(), annot.get(), i));
2506 }
2507
2508 annot.reset(FPDFPage_GetAnnot(page, 1));
2509 ASSERT_TRUE(annot);
2510
2511 // Checks for Listbox with Values (/V) object which is just a string.
2512 count = FPDFAnnot_GetOptionCount(form_handle(), annot.get());
2513 ASSERT_EQ(26, count);
2514 for (int i = 0; i < count; i++) {
2515 EXPECT_EQ(i == 1,
2516 FPDFAnnot_IsOptionSelected(form_handle(), annot.get(), i));
2517 }
2518
2519 annot.reset(FPDFPage_GetAnnot(page, 3));
2520 ASSERT_TRUE(annot);
2521
2522 // Checks for Listbox with only Selected indices (/I) object which is an
2523 // array with multiple objects.
2524 count = FPDFAnnot_GetOptionCount(form_handle(), annot.get());
2525 ASSERT_EQ(5, count);
2526 for (int i = 0; i < count; i++) {
2527 bool expected = (i == 1 || i == 3);
2528 EXPECT_EQ(expected,
2529 FPDFAnnot_IsOptionSelected(form_handle(), annot.get(), i));
2530 }
2531
2532 annot.reset(FPDFPage_GetAnnot(page, 4));
2533 ASSERT_TRUE(annot);
2534
2535 // Checks for Listbox with Values (/V) object which is an array with
2536 // multiple objects.
2537 count = FPDFAnnot_GetOptionCount(form_handle(), annot.get());
2538 ASSERT_EQ(5, count);
2539 for (int i = 0; i < count; i++) {
2540 bool expected = (i == 2 || i == 4);
2541 EXPECT_EQ(expected,
2542 FPDFAnnot_IsOptionSelected(form_handle(), annot.get(), i));
2543 }
2544
2545 annot.reset(FPDFPage_GetAnnot(page, 5));
2546 ASSERT_TRUE(annot);
2547
2548 // Checks for Listbox with both Values (/V) and Selected Indices (/I)
2549 // objects conflict with different lengths.
2550 count = FPDFAnnot_GetOptionCount(form_handle(), annot.get());
2551 ASSERT_EQ(5, count);
2552 for (int i = 0; i < count; i++) {
2553 bool expected = (i == 0 || i == 2);
2554 EXPECT_EQ(expected,
2555 FPDFAnnot_IsOptionSelected(form_handle(), annot.get(), i));
2556 }
2557 }
2558
2559 UnloadPage(page);
2560 }
2561
TEST_F(FPDFAnnotEmbedderTest,IsOptionSelectedInvalidAnnotations)2562 TEST_F(FPDFAnnotEmbedderTest, IsOptionSelectedInvalidAnnotations) {
2563 // Open a file with multiple form field annotations and load its first page.
2564 ASSERT_TRUE(OpenDocument("multiple_form_types.pdf"));
2565 FPDF_PAGE page = LoadPage(0);
2566 ASSERT_TRUE(page);
2567
2568 {
2569 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
2570 ASSERT_TRUE(annot);
2571
2572 // Checks for link annotation.
2573 EXPECT_FALSE(FPDFAnnot_IsOptionSelected(form_handle(), annot.get(),
2574 /*index=*/0));
2575
2576 annot.reset(FPDFPage_GetAnnot(page, 3));
2577 ASSERT_TRUE(annot);
2578
2579 // Checks for text field annotation.
2580 EXPECT_FALSE(FPDFAnnot_IsOptionSelected(form_handle(), annot.get(),
2581 /*index=*/0));
2582 }
2583
2584 UnloadPage(page);
2585 }
2586
TEST_F(FPDFAnnotEmbedderTest,GetFontSizeCombobox)2587 TEST_F(FPDFAnnotEmbedderTest, GetFontSizeCombobox) {
2588 // Open a file with combobox annotations and load its first page.
2589 ASSERT_TRUE(OpenDocument("combobox_form.pdf"));
2590 FPDF_PAGE page = LoadPage(0);
2591 ASSERT_TRUE(page);
2592
2593 {
2594 // All 3 widgets have Tf font size 12.
2595 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
2596 ASSERT_TRUE(annot);
2597
2598 float value;
2599 ASSERT_TRUE(FPDFAnnot_GetFontSize(form_handle(), annot.get(), &value));
2600 EXPECT_EQ(12.0, value);
2601
2602 annot.reset(FPDFPage_GetAnnot(page, 1));
2603 ASSERT_TRUE(annot);
2604
2605 float value_two;
2606 ASSERT_TRUE(FPDFAnnot_GetFontSize(form_handle(), annot.get(), &value_two));
2607 EXPECT_EQ(12.0, value_two);
2608
2609 annot.reset(FPDFPage_GetAnnot(page, 2));
2610 ASSERT_TRUE(annot);
2611
2612 float value_three;
2613 ASSERT_TRUE(
2614 FPDFAnnot_GetFontSize(form_handle(), annot.get(), &value_three));
2615 EXPECT_EQ(12.0, value_three);
2616 }
2617
2618 UnloadPage(page);
2619 }
2620
TEST_F(FPDFAnnotEmbedderTest,GetFontSizeTextField)2621 TEST_F(FPDFAnnotEmbedderTest, GetFontSizeTextField) {
2622 // Open a file with textfield annotations and load its first page.
2623 ASSERT_TRUE(OpenDocument("text_form_multiple.pdf"));
2624 FPDF_PAGE page = LoadPage(0);
2625 ASSERT_TRUE(page);
2626
2627 {
2628 // All 4 widgets have Tf font size 12.
2629 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
2630 ASSERT_TRUE(annot);
2631
2632 float value;
2633 ASSERT_TRUE(FPDFAnnot_GetFontSize(form_handle(), annot.get(), &value));
2634 EXPECT_EQ(12.0, value);
2635
2636 annot.reset(FPDFPage_GetAnnot(page, 1));
2637 ASSERT_TRUE(annot);
2638
2639 float value_two;
2640 ASSERT_TRUE(FPDFAnnot_GetFontSize(form_handle(), annot.get(), &value_two));
2641 EXPECT_EQ(12.0, value_two);
2642
2643 annot.reset(FPDFPage_GetAnnot(page, 2));
2644 ASSERT_TRUE(annot);
2645
2646 float value_three;
2647 ASSERT_TRUE(
2648 FPDFAnnot_GetFontSize(form_handle(), annot.get(), &value_three));
2649 EXPECT_EQ(12.0, value_three);
2650
2651 float value_four;
2652 ASSERT_TRUE(FPDFAnnot_GetFontSize(form_handle(), annot.get(), &value_four));
2653 EXPECT_EQ(12.0, value_four);
2654 }
2655
2656 UnloadPage(page);
2657 }
2658
TEST_F(FPDFAnnotEmbedderTest,GetFontSizeInvalidAnnotationTypes)2659 TEST_F(FPDFAnnotEmbedderTest, GetFontSizeInvalidAnnotationTypes) {
2660 // Open a file with ink annotations and load its first page.
2661 ASSERT_TRUE(OpenDocument("annotation_ink_multiple.pdf"));
2662 FPDF_PAGE page = LoadPage(0);
2663 ASSERT_TRUE(page);
2664
2665 {
2666 // Annotations that do not have variable text and will return -1.
2667 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
2668 ASSERT_TRUE(annot);
2669
2670 float value;
2671 ASSERT_FALSE(FPDFAnnot_GetFontSize(form_handle(), annot.get(), &value));
2672
2673 annot.reset(FPDFPage_GetAnnot(page, 1));
2674 ASSERT_TRUE(annot);
2675
2676 ASSERT_FALSE(FPDFAnnot_GetFontSize(form_handle(), annot.get(), &value));
2677 }
2678
2679 UnloadPage(page);
2680 }
2681
TEST_F(FPDFAnnotEmbedderTest,GetFontSizeInvalidArguments)2682 TEST_F(FPDFAnnotEmbedderTest, GetFontSizeInvalidArguments) {
2683 // Open a file with combobox annotations and load its first page.
2684 ASSERT_TRUE(OpenDocument("combobox_form.pdf"));
2685 FPDF_PAGE page = LoadPage(0);
2686 ASSERT_TRUE(page);
2687
2688 {
2689 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
2690 ASSERT_TRUE(annot);
2691
2692 // Check bad form handle / annot.
2693 float value;
2694 ASSERT_FALSE(FPDFAnnot_GetFontSize(nullptr, annot.get(), &value));
2695 ASSERT_FALSE(FPDFAnnot_GetFontSize(form_handle(), nullptr, &value));
2696 ASSERT_FALSE(FPDFAnnot_GetFontSize(nullptr, nullptr, &value));
2697 }
2698
2699 UnloadPage(page);
2700 }
2701
TEST_F(FPDFAnnotEmbedderTest,GetFontSizeNegative)2702 TEST_F(FPDFAnnotEmbedderTest, GetFontSizeNegative) {
2703 // Open a file with textfield annotations and load its first page.
2704 ASSERT_TRUE(OpenDocument("text_form_negative_fontsize.pdf"));
2705 FPDF_PAGE page = LoadPage(0);
2706 ASSERT_TRUE(page);
2707
2708 {
2709 // Obtain the first annotation, a text field with negative font size, -12.
2710 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
2711 ASSERT_TRUE(annot);
2712
2713 float value;
2714 ASSERT_TRUE(FPDFAnnot_GetFontSize(form_handle(), annot.get(), &value));
2715 EXPECT_EQ(-12.0, value);
2716 }
2717
2718 UnloadPage(page);
2719 }
2720
TEST_F(FPDFAnnotEmbedderTest,IsCheckedCheckbox)2721 TEST_F(FPDFAnnotEmbedderTest, IsCheckedCheckbox) {
2722 // Open a file with checkbox and radiobuttons widget annotations and load its
2723 // first page.
2724 ASSERT_TRUE(OpenDocument("click_form.pdf"));
2725 FPDF_PAGE page = LoadPage(0);
2726 ASSERT_TRUE(page);
2727
2728 {
2729 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 1));
2730 ASSERT_TRUE(annot);
2731 ASSERT_FALSE(FPDFAnnot_IsChecked(form_handle(), annot.get()));
2732 }
2733
2734 UnloadPage(page);
2735 }
2736
TEST_F(FPDFAnnotEmbedderTest,IsCheckedCheckboxReadOnly)2737 TEST_F(FPDFAnnotEmbedderTest, IsCheckedCheckboxReadOnly) {
2738 // Open a file with checkbox and radiobutton widget annotations and load its
2739 // first page.
2740 ASSERT_TRUE(OpenDocument("click_form.pdf"));
2741 FPDF_PAGE page = LoadPage(0);
2742 ASSERT_TRUE(page);
2743
2744 {
2745 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
2746 ASSERT_TRUE(annot);
2747 ASSERT_TRUE(FPDFAnnot_IsChecked(form_handle(), annot.get()));
2748 }
2749
2750 UnloadPage(page);
2751 }
2752
TEST_F(FPDFAnnotEmbedderTest,IsCheckedRadioButton)2753 TEST_F(FPDFAnnotEmbedderTest, IsCheckedRadioButton) {
2754 // Open a file with checkbox and radiobutton widget annotations and load its
2755 // first page.
2756 ASSERT_TRUE(OpenDocument("click_form.pdf"));
2757 FPDF_PAGE page = LoadPage(0);
2758 ASSERT_TRUE(page);
2759
2760 {
2761 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 5));
2762 ASSERT_TRUE(annot);
2763 ASSERT_FALSE(FPDFAnnot_IsChecked(form_handle(), annot.get()));
2764
2765 annot.reset(FPDFPage_GetAnnot(page, 6));
2766 ASSERT_FALSE(FPDFAnnot_IsChecked(form_handle(), annot.get()));
2767
2768 annot.reset(FPDFPage_GetAnnot(page, 7));
2769 ASSERT_TRUE(FPDFAnnot_IsChecked(form_handle(), annot.get()));
2770 }
2771
2772 UnloadPage(page);
2773 }
2774
TEST_F(FPDFAnnotEmbedderTest,IsCheckedRadioButtonReadOnly)2775 TEST_F(FPDFAnnotEmbedderTest, IsCheckedRadioButtonReadOnly) {
2776 // Open a file with checkbox and radiobutton widget annotations and load its
2777 // first page.
2778 ASSERT_TRUE(OpenDocument("click_form.pdf"));
2779 FPDF_PAGE page = LoadPage(0);
2780 ASSERT_TRUE(page);
2781
2782 {
2783 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 2));
2784 ASSERT_TRUE(annot);
2785 ASSERT_FALSE(FPDFAnnot_IsChecked(form_handle(), annot.get()));
2786
2787 annot.reset(FPDFPage_GetAnnot(page, 3));
2788 ASSERT_FALSE(FPDFAnnot_IsChecked(form_handle(), annot.get()));
2789
2790 annot.reset(FPDFPage_GetAnnot(page, 4));
2791 ASSERT_TRUE(FPDFAnnot_IsChecked(form_handle(), annot.get()));
2792 }
2793
2794 UnloadPage(page);
2795 }
2796
TEST_F(FPDFAnnotEmbedderTest,IsCheckedInvalidArguments)2797 TEST_F(FPDFAnnotEmbedderTest, IsCheckedInvalidArguments) {
2798 // Open a file with checkbox and radiobuttons widget annotations and load its
2799 // first page.
2800 ASSERT_TRUE(OpenDocument("click_form.pdf"));
2801 FPDF_PAGE page = LoadPage(0);
2802 ASSERT_TRUE(page);
2803
2804 {
2805 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
2806 ASSERT_TRUE(annot);
2807 ASSERT_FALSE(FPDFAnnot_IsChecked(nullptr, annot.get()));
2808 ASSERT_FALSE(FPDFAnnot_IsChecked(form_handle(), nullptr));
2809 ASSERT_FALSE(FPDFAnnot_IsChecked(nullptr, nullptr));
2810 }
2811
2812 UnloadPage(page);
2813 }
2814
TEST_F(FPDFAnnotEmbedderTest,IsCheckedInvalidWidgetType)2815 TEST_F(FPDFAnnotEmbedderTest, IsCheckedInvalidWidgetType) {
2816 // Open a file with text widget annotations and load its first page.
2817 ASSERT_TRUE(OpenDocument("text_form.pdf"));
2818 FPDF_PAGE page = LoadPage(0);
2819 ASSERT_TRUE(page);
2820
2821 {
2822 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
2823 ASSERT_TRUE(annot);
2824 ASSERT_FALSE(FPDFAnnot_IsChecked(form_handle(), annot.get()));
2825 }
2826
2827 UnloadPage(page);
2828 }
2829
TEST_F(FPDFAnnotEmbedderTest,GetFormFieldType)2830 TEST_F(FPDFAnnotEmbedderTest, GetFormFieldType) {
2831 ASSERT_TRUE(OpenDocument("multiple_form_types.pdf"));
2832 FPDF_PAGE page = LoadPage(0);
2833 ASSERT_TRUE(page);
2834
2835 EXPECT_EQ(-1, FPDFAnnot_GetFormFieldType(form_handle(), nullptr));
2836
2837 {
2838 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 1));
2839 ASSERT_TRUE(annot);
2840 EXPECT_EQ(-1, FPDFAnnot_GetFormFieldType(nullptr, annot.get()));
2841 }
2842
2843 constexpr int kExpectedAnnotTypes[] = {-1,
2844 FPDF_FORMFIELD_COMBOBOX,
2845 FPDF_FORMFIELD_LISTBOX,
2846 FPDF_FORMFIELD_TEXTFIELD,
2847 FPDF_FORMFIELD_CHECKBOX,
2848 FPDF_FORMFIELD_RADIOBUTTON};
2849
2850 for (size_t i = 0; i < std::size(kExpectedAnnotTypes); ++i) {
2851 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, i));
2852 ASSERT_TRUE(annot);
2853 EXPECT_EQ(kExpectedAnnotTypes[i],
2854 FPDFAnnot_GetFormFieldType(form_handle(), annot.get()));
2855 }
2856 UnloadPage(page);
2857 }
2858
TEST_F(FPDFAnnotEmbedderTest,GetFormFieldValueTextField)2859 TEST_F(FPDFAnnotEmbedderTest, GetFormFieldValueTextField) {
2860 ASSERT_TRUE(OpenDocument("text_form_multiple.pdf"));
2861 FPDF_PAGE page = LoadPage(0);
2862 ASSERT_TRUE(page);
2863
2864 {
2865 EXPECT_EQ(0u,
2866 FPDFAnnot_GetFormFieldValue(form_handle(), nullptr, nullptr, 0));
2867
2868 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
2869 ASSERT_TRUE(annot);
2870
2871 EXPECT_EQ(0u,
2872 FPDFAnnot_GetFormFieldValue(nullptr, annot.get(), nullptr, 0));
2873
2874 unsigned long length_bytes =
2875 FPDFAnnot_GetFormFieldValue(form_handle(), annot.get(), nullptr, 0);
2876 ASSERT_EQ(2u, length_bytes);
2877 std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(length_bytes);
2878 EXPECT_EQ(2u, FPDFAnnot_GetFormFieldValue(form_handle(), annot.get(),
2879 buf.data(), length_bytes));
2880 EXPECT_EQ(L"", GetPlatformWString(buf.data()));
2881 }
2882 {
2883 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 2));
2884 ASSERT_TRUE(annot);
2885
2886 unsigned long length_bytes =
2887 FPDFAnnot_GetFormFieldValue(form_handle(), annot.get(), nullptr, 0);
2888 ASSERT_EQ(18u, length_bytes);
2889 std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(length_bytes);
2890 EXPECT_EQ(18u, FPDFAnnot_GetFormFieldValue(form_handle(), annot.get(),
2891 buf.data(), length_bytes));
2892 EXPECT_EQ(L"Elephant", GetPlatformWString(buf.data()));
2893 }
2894 UnloadPage(page);
2895 }
2896
TEST_F(FPDFAnnotEmbedderTest,GetFormFieldValueComboBox)2897 TEST_F(FPDFAnnotEmbedderTest, GetFormFieldValueComboBox) {
2898 ASSERT_TRUE(OpenDocument("combobox_form.pdf"));
2899 FPDF_PAGE page = LoadPage(0);
2900 ASSERT_TRUE(page);
2901
2902 {
2903 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
2904 ASSERT_TRUE(annot);
2905
2906 unsigned long length_bytes =
2907 FPDFAnnot_GetFormFieldValue(form_handle(), annot.get(), nullptr, 0);
2908 ASSERT_EQ(2u, length_bytes);
2909 std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(length_bytes);
2910 EXPECT_EQ(2u, FPDFAnnot_GetFormFieldValue(form_handle(), annot.get(),
2911 buf.data(), length_bytes));
2912 EXPECT_EQ(L"", GetPlatformWString(buf.data()));
2913 }
2914 {
2915 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 1));
2916 ASSERT_TRUE(annot);
2917
2918 unsigned long length_bytes =
2919 FPDFAnnot_GetFormFieldValue(form_handle(), annot.get(), nullptr, 0);
2920 ASSERT_EQ(14u, length_bytes);
2921 std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(length_bytes);
2922 EXPECT_EQ(14u, FPDFAnnot_GetFormFieldValue(form_handle(), annot.get(),
2923 buf.data(), length_bytes));
2924 EXPECT_EQ(L"Banana", GetPlatformWString(buf.data()));
2925 }
2926 UnloadPage(page);
2927 }
2928
TEST_F(FPDFAnnotEmbedderTest,GetFormFieldNameTextField)2929 TEST_F(FPDFAnnotEmbedderTest, GetFormFieldNameTextField) {
2930 ASSERT_TRUE(OpenDocument("text_form.pdf"));
2931 FPDF_PAGE page = LoadPage(0);
2932 ASSERT_TRUE(page);
2933
2934 {
2935 EXPECT_EQ(0u,
2936 FPDFAnnot_GetFormFieldName(form_handle(), nullptr, nullptr, 0));
2937
2938 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
2939 ASSERT_TRUE(annot);
2940
2941 EXPECT_EQ(0u, FPDFAnnot_GetFormFieldName(nullptr, annot.get(), nullptr, 0));
2942
2943 unsigned long length_bytes =
2944 FPDFAnnot_GetFormFieldName(form_handle(), annot.get(), nullptr, 0);
2945 ASSERT_EQ(18u, length_bytes);
2946 std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(length_bytes);
2947 EXPECT_EQ(18u, FPDFAnnot_GetFormFieldName(form_handle(), annot.get(),
2948 buf.data(), length_bytes));
2949 EXPECT_EQ(L"Text Box", GetPlatformWString(buf.data()));
2950 }
2951 UnloadPage(page);
2952 }
2953
TEST_F(FPDFAnnotEmbedderTest,GetFormFieldNameComboBox)2954 TEST_F(FPDFAnnotEmbedderTest, GetFormFieldNameComboBox) {
2955 ASSERT_TRUE(OpenDocument("combobox_form.pdf"));
2956 FPDF_PAGE page = LoadPage(0);
2957 ASSERT_TRUE(page);
2958
2959 {
2960 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
2961 ASSERT_TRUE(annot);
2962
2963 unsigned long length_bytes =
2964 FPDFAnnot_GetFormFieldName(form_handle(), annot.get(), nullptr, 0);
2965 ASSERT_EQ(30u, length_bytes);
2966 std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(length_bytes);
2967 EXPECT_EQ(30u, FPDFAnnot_GetFormFieldName(form_handle(), annot.get(),
2968 buf.data(), length_bytes));
2969 EXPECT_EQ(L"Combo_Editable", GetPlatformWString(buf.data()));
2970 }
2971 UnloadPage(page);
2972 }
2973
TEST_F(FPDFAnnotEmbedderTest,FocusableAnnotSubtypes)2974 TEST_F(FPDFAnnotEmbedderTest, FocusableAnnotSubtypes) {
2975 ASSERT_TRUE(OpenDocument("annots.pdf"));
2976 FPDF_PAGE page = LoadPage(0);
2977 ASSERT_TRUE(page);
2978
2979 // Verify widgets are by default focusable.
2980 const FPDF_ANNOTATION_SUBTYPE kDefaultSubtypes[] = {FPDF_ANNOT_WIDGET};
2981 VerifyFocusableAnnotSubtypes(form_handle(), kDefaultSubtypes);
2982
2983 // Expected annot subtypes for page 0 of annots.pdf.
2984 const FPDF_ANNOTATION_SUBTYPE kExpectedAnnotSubtypes[] = {
2985 FPDF_ANNOT_LINK, FPDF_ANNOT_LINK, FPDF_ANNOT_LINK,
2986 FPDF_ANNOT_LINK, FPDF_ANNOT_HIGHLIGHT, FPDF_ANNOT_HIGHLIGHT,
2987 FPDF_ANNOT_POPUP, FPDF_ANNOT_HIGHLIGHT, FPDF_ANNOT_WIDGET,
2988 };
2989
2990 const FPDF_ANNOTATION_SUBTYPE kExpectedDefaultFocusableSubtypes[] = {
2991 FPDF_ANNOT_WIDGET};
2992 VerifyAnnotationSubtypesAndFocusability(form_handle(), page,
2993 kExpectedAnnotSubtypes,
2994 kExpectedDefaultFocusableSubtypes);
2995
2996 // Make no annotation type focusable using the preferred method.
2997 ASSERT_TRUE(FPDFAnnot_SetFocusableSubtypes(form_handle(), nullptr, 0));
2998 ASSERT_EQ(0, FPDFAnnot_GetFocusableSubtypesCount(form_handle()));
2999
3000 // Restore the focusable type count back to 1, then set it back to 0 using a
3001 // different method.
3002 SetAndVerifyFocusableAnnotSubtypes(form_handle(), kDefaultSubtypes);
3003 ASSERT_TRUE(
3004 FPDFAnnot_SetFocusableSubtypes(form_handle(), kDefaultSubtypes, 0));
3005 ASSERT_EQ(0, FPDFAnnot_GetFocusableSubtypesCount(form_handle()));
3006
3007 VerifyAnnotationSubtypesAndFocusability(form_handle(), page,
3008 kExpectedAnnotSubtypes, {});
3009
3010 // Now make links focusable.
3011 const FPDF_ANNOTATION_SUBTYPE kLinkSubtypes[] = {FPDF_ANNOT_LINK};
3012 SetAndVerifyFocusableAnnotSubtypes(form_handle(), kLinkSubtypes);
3013
3014 const FPDF_ANNOTATION_SUBTYPE kExpectedLinkocusableSubtypes[] = {
3015 FPDF_ANNOT_LINK};
3016 VerifyAnnotationSubtypesAndFocusability(form_handle(), page,
3017 kExpectedAnnotSubtypes,
3018 kExpectedLinkocusableSubtypes);
3019
3020 // Test invalid parameters.
3021 EXPECT_FALSE(FPDFAnnot_SetFocusableSubtypes(nullptr, kDefaultSubtypes,
3022 std::size(kDefaultSubtypes)));
3023 EXPECT_FALSE(FPDFAnnot_SetFocusableSubtypes(form_handle(), nullptr,
3024 std::size(kDefaultSubtypes)));
3025 EXPECT_EQ(-1, FPDFAnnot_GetFocusableSubtypesCount(nullptr));
3026
3027 std::vector<FPDF_ANNOTATION_SUBTYPE> subtypes(1);
3028 EXPECT_FALSE(FPDFAnnot_GetFocusableSubtypes(nullptr, subtypes.data(),
3029 subtypes.size()));
3030 EXPECT_FALSE(
3031 FPDFAnnot_GetFocusableSubtypes(form_handle(), nullptr, subtypes.size()));
3032 EXPECT_FALSE(
3033 FPDFAnnot_GetFocusableSubtypes(form_handle(), subtypes.data(), 0));
3034
3035 UnloadPage(page);
3036 }
3037
TEST_F(FPDFAnnotEmbedderTest,FocusableAnnotRendering)3038 TEST_F(FPDFAnnotEmbedderTest, FocusableAnnotRendering) {
3039 ASSERT_TRUE(OpenDocument("annots.pdf"));
3040 FPDF_PAGE page = LoadPage(0);
3041 ASSERT_TRUE(page);
3042
3043 {
3044 const char* md5_sum = []() {
3045 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
3046 return "c09b129c071ec1569deb003676b617b0";
3047 #if BUILDFLAG(IS_APPLE)
3048 return "108a46c517c4eaace9982ee83e8e3296";
3049 #else
3050 return "5550d8dcb4d1af1f50e8b4bcaef2ee60";
3051 #endif
3052 }();
3053 // Check the initial rendering.
3054 ScopedFPDFBitmap bitmap = RenderLoadedPageWithFlags(page, FPDF_ANNOT);
3055 CompareBitmap(bitmap.get(), 612, 792, md5_sum);
3056 }
3057
3058 // Make links and highlights focusable.
3059 static constexpr FPDF_ANNOTATION_SUBTYPE kSubTypes[] = {FPDF_ANNOT_LINK,
3060 FPDF_ANNOT_HIGHLIGHT};
3061 constexpr int kSubTypesCount = std::size(kSubTypes);
3062 ASSERT_TRUE(
3063 FPDFAnnot_SetFocusableSubtypes(form_handle(), kSubTypes, kSubTypesCount));
3064 ASSERT_EQ(kSubTypesCount, FPDFAnnot_GetFocusableSubtypesCount(form_handle()));
3065 std::vector<FPDF_ANNOTATION_SUBTYPE> subtypes(kSubTypesCount);
3066 ASSERT_TRUE(FPDFAnnot_GetFocusableSubtypes(form_handle(), subtypes.data(),
3067 subtypes.size()));
3068 ASSERT_EQ(FPDF_ANNOT_LINK, subtypes[0]);
3069 ASSERT_EQ(FPDF_ANNOT_HIGHLIGHT, subtypes[1]);
3070
3071 {
3072 const char* md5_sum = []() {
3073 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
3074 return "277f1b9e70031539d034d22bc6064838";
3075 #if BUILDFLAG(IS_APPLE)
3076 return "eb3869335e7a219e1b5f25c1c6037b97";
3077 #else
3078 return "805fe7bb751ac4ed2b82bb66efe6db40";
3079 #endif
3080 }();
3081 // Focus the first link and check the rendering.
3082 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
3083 ASSERT_TRUE(annot);
3084 EXPECT_EQ(FPDF_ANNOT_LINK, FPDFAnnot_GetSubtype(annot.get()));
3085 EXPECT_TRUE(FORM_SetFocusedAnnot(form_handle(), annot.get()));
3086 ScopedFPDFBitmap bitmap = RenderLoadedPageWithFlags(page, FPDF_ANNOT);
3087 CompareBitmap(bitmap.get(), 612, 792, md5_sum);
3088 }
3089
3090 {
3091 const char* md5_sum = []() {
3092 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
3093 return "d980005939cd4ae0a199d8600a0abdf3";
3094 #if BUILDFLAG(IS_APPLE)
3095 return "d20b1978da2362d3942ea0fc6d230997";
3096 #else
3097 return "c5c5dcb462af3ef5f43b298ec048feef";
3098 #endif
3099 }();
3100 // Focus the first highlight and check the rendering.
3101 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 4));
3102 ASSERT_TRUE(annot);
3103 EXPECT_EQ(FPDF_ANNOT_HIGHLIGHT, FPDFAnnot_GetSubtype(annot.get()));
3104 EXPECT_TRUE(FORM_SetFocusedAnnot(form_handle(), annot.get()));
3105 ScopedFPDFBitmap bitmap = RenderLoadedPageWithFlags(page, FPDF_ANNOT);
3106 CompareBitmap(bitmap.get(), 612, 792, md5_sum);
3107 }
3108
3109 UnloadPage(page);
3110 }
3111
TEST_F(FPDFAnnotEmbedderTest,GetLinkFromAnnotation)3112 TEST_F(FPDFAnnotEmbedderTest, GetLinkFromAnnotation) {
3113 ASSERT_TRUE(OpenDocument("annots.pdf"));
3114 FPDF_PAGE page = LoadPage(0);
3115 ASSERT_TRUE(page);
3116 {
3117 constexpr char kExpectedResult[] =
3118 "https://cs.chromium.org/chromium/src/third_party/pdfium/public/"
3119 "fpdf_text.h";
3120
3121 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 3));
3122 ASSERT_TRUE(annot);
3123 EXPECT_EQ(FPDF_ANNOT_LINK, FPDFAnnot_GetSubtype(annot.get()));
3124 VerifyUriActionInLink(document(), FPDFAnnot_GetLink(annot.get()),
3125 kExpectedResult);
3126 }
3127
3128 {
3129 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 4));
3130 ASSERT_TRUE(annot);
3131 EXPECT_EQ(FPDF_ANNOT_HIGHLIGHT, FPDFAnnot_GetSubtype(annot.get()));
3132 EXPECT_FALSE(FPDFAnnot_GetLink(annot.get()));
3133 }
3134
3135 EXPECT_FALSE(FPDFAnnot_GetLink(nullptr));
3136
3137 UnloadPage(page);
3138 }
3139
TEST_F(FPDFAnnotEmbedderTest,GetFormControlCountRadioButton)3140 TEST_F(FPDFAnnotEmbedderTest, GetFormControlCountRadioButton) {
3141 // Open a file with radio button widget annotations and load its first page.
3142 ASSERT_TRUE(OpenDocument("click_form.pdf"));
3143 FPDF_PAGE page = LoadPage(0);
3144 ASSERT_TRUE(page);
3145
3146 {
3147 // Checks for bad annot.
3148 EXPECT_EQ(-1,
3149 FPDFAnnot_GetFormControlCount(form_handle(), /*annot=*/nullptr));
3150
3151 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 3));
3152 ASSERT_TRUE(annot);
3153
3154 // Checks for bad form handle.
3155 EXPECT_EQ(-1,
3156 FPDFAnnot_GetFormControlCount(/*hHandle=*/nullptr, annot.get()));
3157
3158 EXPECT_EQ(3, FPDFAnnot_GetFormControlCount(form_handle(), annot.get()));
3159 }
3160
3161 UnloadPage(page);
3162 }
3163
TEST_F(FPDFAnnotEmbedderTest,GetFormControlCountCheckBox)3164 TEST_F(FPDFAnnotEmbedderTest, GetFormControlCountCheckBox) {
3165 // Open a file with checkbox widget annotations and load its first page.
3166 ASSERT_TRUE(OpenDocument("click_form.pdf"));
3167 FPDF_PAGE page = LoadPage(0);
3168 ASSERT_TRUE(page);
3169
3170 {
3171 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
3172 ASSERT_TRUE(annot);
3173 EXPECT_EQ(1, FPDFAnnot_GetFormControlCount(form_handle(), annot.get()));
3174 }
3175
3176 UnloadPage(page);
3177 }
3178
TEST_F(FPDFAnnotEmbedderTest,GetFormControlCountInvalidAnnotation)3179 TEST_F(FPDFAnnotEmbedderTest, GetFormControlCountInvalidAnnotation) {
3180 // Open a file with ink annotations and load its first page.
3181 ASSERT_TRUE(OpenDocument("annotation_ink_multiple.pdf"));
3182 FPDF_PAGE page = LoadPage(0);
3183 ASSERT_TRUE(page);
3184
3185 {
3186 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
3187 ASSERT_TRUE(annot);
3188 EXPECT_EQ(-1, FPDFAnnot_GetFormControlCount(form_handle(), annot.get()));
3189 }
3190
3191 UnloadPage(page);
3192 }
3193
TEST_F(FPDFAnnotEmbedderTest,GetFormControlIndexRadioButton)3194 TEST_F(FPDFAnnotEmbedderTest, GetFormControlIndexRadioButton) {
3195 // Open a file with radio button widget annotations and load its first page.
3196 ASSERT_TRUE(OpenDocument("click_form.pdf"));
3197 FPDF_PAGE page = LoadPage(0);
3198 ASSERT_TRUE(page);
3199
3200 {
3201 // Checks for bad annot.
3202 EXPECT_EQ(-1,
3203 FPDFAnnot_GetFormControlIndex(form_handle(), /*annot=*/nullptr));
3204
3205 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 3));
3206 ASSERT_TRUE(annot);
3207
3208 // Checks for bad form handle.
3209 EXPECT_EQ(-1,
3210 FPDFAnnot_GetFormControlIndex(/*hHandle=*/nullptr, annot.get()));
3211
3212 EXPECT_EQ(1, FPDFAnnot_GetFormControlIndex(form_handle(), annot.get()));
3213 }
3214
3215 UnloadPage(page);
3216 }
3217
TEST_F(FPDFAnnotEmbedderTest,GetFormControlIndexCheckBox)3218 TEST_F(FPDFAnnotEmbedderTest, GetFormControlIndexCheckBox) {
3219 // Open a file with checkbox widget annotations and load its first page.
3220 ASSERT_TRUE(OpenDocument("click_form.pdf"));
3221 FPDF_PAGE page = LoadPage(0);
3222 ASSERT_TRUE(page);
3223
3224 {
3225 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
3226 ASSERT_TRUE(annot);
3227 EXPECT_EQ(0, FPDFAnnot_GetFormControlIndex(form_handle(), annot.get()));
3228 }
3229
3230 UnloadPage(page);
3231 }
3232
TEST_F(FPDFAnnotEmbedderTest,GetFormControlIndexInvalidAnnotation)3233 TEST_F(FPDFAnnotEmbedderTest, GetFormControlIndexInvalidAnnotation) {
3234 // Open a file with ink annotations and load its first page.
3235 ASSERT_TRUE(OpenDocument("annotation_ink_multiple.pdf"));
3236 FPDF_PAGE page = LoadPage(0);
3237 ASSERT_TRUE(page);
3238
3239 {
3240 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
3241 ASSERT_TRUE(annot);
3242 EXPECT_EQ(-1, FPDFAnnot_GetFormControlIndex(form_handle(), annot.get()));
3243 }
3244
3245 UnloadPage(page);
3246 }
3247
TEST_F(FPDFAnnotEmbedderTest,GetFormFieldExportValueRadioButton)3248 TEST_F(FPDFAnnotEmbedderTest, GetFormFieldExportValueRadioButton) {
3249 // Open a file with radio button widget annotations and load its first page.
3250 ASSERT_TRUE(OpenDocument("click_form.pdf"));
3251 FPDF_PAGE page = LoadPage(0);
3252 ASSERT_TRUE(page);
3253
3254 {
3255 // Checks for bad annot.
3256 EXPECT_EQ(0u, FPDFAnnot_GetFormFieldExportValue(
3257 form_handle(), /*annot=*/nullptr,
3258 /*buffer=*/nullptr, /*buflen=*/0));
3259
3260 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 6));
3261 ASSERT_TRUE(annot);
3262
3263 // Checks for bad form handle.
3264 EXPECT_EQ(0u, FPDFAnnot_GetFormFieldExportValue(
3265 /*hHandle=*/nullptr, annot.get(),
3266 /*buffer=*/nullptr, /*buflen=*/0));
3267
3268 unsigned long length_bytes =
3269 FPDFAnnot_GetFormFieldExportValue(form_handle(), annot.get(),
3270 /*buffer=*/nullptr, /*buflen=*/0);
3271 ASSERT_EQ(14u, length_bytes);
3272 std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(length_bytes);
3273 EXPECT_EQ(14u, FPDFAnnot_GetFormFieldExportValue(form_handle(), annot.get(),
3274 buf.data(), length_bytes));
3275 EXPECT_EQ(L"value2", GetPlatformWString(buf.data()));
3276 }
3277
3278 UnloadPage(page);
3279 }
3280
TEST_F(FPDFAnnotEmbedderTest,GetFormFieldExportValueCheckBox)3281 TEST_F(FPDFAnnotEmbedderTest, GetFormFieldExportValueCheckBox) {
3282 // Open a file with checkbox widget annotations and load its first page.
3283 ASSERT_TRUE(OpenDocument("click_form.pdf"));
3284 FPDF_PAGE page = LoadPage(0);
3285 ASSERT_TRUE(page);
3286
3287 {
3288 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
3289 ASSERT_TRUE(annot);
3290
3291 unsigned long length_bytes =
3292 FPDFAnnot_GetFormFieldExportValue(form_handle(), annot.get(),
3293 /*buffer=*/nullptr, /*buflen=*/0);
3294 ASSERT_EQ(8u, length_bytes);
3295 std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(length_bytes);
3296 EXPECT_EQ(8u, FPDFAnnot_GetFormFieldExportValue(form_handle(), annot.get(),
3297 buf.data(), length_bytes));
3298 EXPECT_EQ(L"Yes", GetPlatformWString(buf.data()));
3299 }
3300
3301 UnloadPage(page);
3302 }
3303
TEST_F(FPDFAnnotEmbedderTest,GetFormFieldExportValueInvalidAnnotation)3304 TEST_F(FPDFAnnotEmbedderTest, GetFormFieldExportValueInvalidAnnotation) {
3305 // Open a file with ink annotations and load its first page.
3306 ASSERT_TRUE(OpenDocument("annotation_ink_multiple.pdf"));
3307 FPDF_PAGE page = LoadPage(0);
3308 ASSERT_TRUE(page);
3309
3310 {
3311 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
3312 ASSERT_TRUE(annot);
3313 EXPECT_EQ(0u, FPDFAnnot_GetFormFieldExportValue(form_handle(), annot.get(),
3314 /*buffer=*/nullptr,
3315 /*buflen=*/0));
3316 }
3317
3318 UnloadPage(page);
3319 }
3320
TEST_F(FPDFAnnotEmbedderTest,Redactannotation)3321 TEST_F(FPDFAnnotEmbedderTest, Redactannotation) {
3322 ASSERT_TRUE(OpenDocument("redact_annot.pdf"));
3323 FPDF_PAGE page = LoadPage(0);
3324 ASSERT_TRUE(page);
3325 EXPECT_EQ(1, FPDFPage_GetAnnotCount(page));
3326
3327 {
3328 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
3329 ASSERT_TRUE(annot);
3330 EXPECT_EQ(FPDF_ANNOT_REDACT, FPDFAnnot_GetSubtype(annot.get()));
3331 }
3332
3333 UnloadPage(page);
3334 }
3335
TEST_F(FPDFAnnotEmbedderTest,PolygonAnnotation)3336 TEST_F(FPDFAnnotEmbedderTest, PolygonAnnotation) {
3337 ASSERT_TRUE(OpenDocument("polygon_annot.pdf"));
3338 FPDF_PAGE page = LoadPage(0);
3339 ASSERT_TRUE(page);
3340 EXPECT_EQ(2, FPDFPage_GetAnnotCount(page));
3341
3342 {
3343 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
3344 ASSERT_TRUE(annot);
3345
3346 // FPDFAnnot_GetVertices() positive testing.
3347 unsigned long size = FPDFAnnot_GetVertices(annot.get(), nullptr, 0);
3348 const size_t kExpectedSize = 3;
3349 ASSERT_EQ(kExpectedSize, size);
3350 std::vector<FS_POINTF> vertices_buffer(size);
3351 EXPECT_EQ(size,
3352 FPDFAnnot_GetVertices(annot.get(), vertices_buffer.data(), size));
3353 EXPECT_FLOAT_EQ(159.0f, vertices_buffer[0].x);
3354 EXPECT_FLOAT_EQ(296.0f, vertices_buffer[0].y);
3355 EXPECT_FLOAT_EQ(350.0f, vertices_buffer[1].x);
3356 EXPECT_FLOAT_EQ(411.0f, vertices_buffer[1].y);
3357 EXPECT_FLOAT_EQ(472.0f, vertices_buffer[2].x);
3358 EXPECT_FLOAT_EQ(243.42f, vertices_buffer[2].y);
3359
3360 // FPDFAnnot_GetVertices() negative testing.
3361 EXPECT_EQ(0U, FPDFAnnot_GetVertices(nullptr, nullptr, 0));
3362
3363 // vertices_buffer is not overwritten if it is too small.
3364 vertices_buffer.resize(1);
3365 vertices_buffer[0].x = 42;
3366 vertices_buffer[0].y = 43;
3367 size = FPDFAnnot_GetVertices(annot.get(), vertices_buffer.data(),
3368 vertices_buffer.size());
3369 EXPECT_EQ(kExpectedSize, size);
3370 EXPECT_FLOAT_EQ(42, vertices_buffer[0].x);
3371 EXPECT_FLOAT_EQ(43, vertices_buffer[0].y);
3372 }
3373
3374 {
3375 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 1));
3376 ASSERT_TRUE(annot);
3377
3378 // This has an odd number of elements in the vertices array, ignore the last
3379 // element.
3380 unsigned long size = FPDFAnnot_GetVertices(annot.get(), nullptr, 0);
3381 const size_t kExpectedSize = 3;
3382 ASSERT_EQ(kExpectedSize, size);
3383 std::vector<FS_POINTF> vertices_buffer(size);
3384 EXPECT_EQ(size,
3385 FPDFAnnot_GetVertices(annot.get(), vertices_buffer.data(), size));
3386 EXPECT_FLOAT_EQ(259.0f, vertices_buffer[0].x);
3387 EXPECT_FLOAT_EQ(396.0f, vertices_buffer[0].y);
3388 EXPECT_FLOAT_EQ(450.0f, vertices_buffer[1].x);
3389 EXPECT_FLOAT_EQ(511.0f, vertices_buffer[1].y);
3390 EXPECT_FLOAT_EQ(572.0f, vertices_buffer[2].x);
3391 EXPECT_FLOAT_EQ(343.0f, vertices_buffer[2].y);
3392 }
3393
3394 {
3395 // Wrong annotation type.
3396 ScopedFPDFAnnotation ink_annot(FPDFPage_CreateAnnot(page, FPDF_ANNOT_INK));
3397 EXPECT_EQ(0U, FPDFAnnot_GetVertices(ink_annot.get(), nullptr, 0));
3398 }
3399
3400 UnloadPage(page);
3401 }
3402
TEST_F(FPDFAnnotEmbedderTest,InkAnnotation)3403 TEST_F(FPDFAnnotEmbedderTest, InkAnnotation) {
3404 ASSERT_TRUE(OpenDocument("ink_annot.pdf"));
3405 FPDF_PAGE page = LoadPage(0);
3406 ASSERT_TRUE(page);
3407 EXPECT_EQ(2, FPDFPage_GetAnnotCount(page));
3408
3409 {
3410 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
3411 ASSERT_TRUE(annot);
3412
3413 // FPDFAnnot_GetInkListCount() and FPDFAnnot_GetInkListPath() positive
3414 // testing.
3415 unsigned long size = FPDFAnnot_GetInkListCount(annot.get());
3416 const size_t kExpectedSize = 1;
3417 ASSERT_EQ(kExpectedSize, size);
3418 const unsigned long kPathIndex = 0;
3419 unsigned long path_size =
3420 FPDFAnnot_GetInkListPath(annot.get(), kPathIndex, nullptr, 0);
3421 const size_t kExpectedPathSize = 3;
3422 ASSERT_EQ(kExpectedPathSize, path_size);
3423 std::vector<FS_POINTF> path_buffer(path_size);
3424 EXPECT_EQ(path_size,
3425 FPDFAnnot_GetInkListPath(annot.get(), kPathIndex,
3426 path_buffer.data(), path_size));
3427 EXPECT_FLOAT_EQ(159.0f, path_buffer[0].x);
3428 EXPECT_FLOAT_EQ(296.0f, path_buffer[0].y);
3429 EXPECT_FLOAT_EQ(350.0f, path_buffer[1].x);
3430 EXPECT_FLOAT_EQ(411.0f, path_buffer[1].y);
3431 EXPECT_FLOAT_EQ(472.0f, path_buffer[2].x);
3432 EXPECT_FLOAT_EQ(243.42f, path_buffer[2].y);
3433
3434 // FPDFAnnot_GetInkListCount() and FPDFAnnot_GetInkListPath() negative
3435 // testing.
3436 EXPECT_EQ(0U, FPDFAnnot_GetInkListCount(nullptr));
3437 EXPECT_EQ(0U, FPDFAnnot_GetInkListPath(nullptr, 0, nullptr, 0));
3438
3439 // out of bounds path_index.
3440 EXPECT_EQ(0U, FPDFAnnot_GetInkListPath(nullptr, 42, nullptr, 0));
3441
3442 // path_buffer is not overwritten if it is too small.
3443 path_buffer.resize(1);
3444 path_buffer[0].x = 42;
3445 path_buffer[0].y = 43;
3446 path_size = FPDFAnnot_GetInkListPath(
3447 annot.get(), kPathIndex, path_buffer.data(), path_buffer.size());
3448 EXPECT_EQ(kExpectedPathSize, path_size);
3449 EXPECT_FLOAT_EQ(42, path_buffer[0].x);
3450 EXPECT_FLOAT_EQ(43, path_buffer[0].y);
3451 }
3452
3453 {
3454 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 1));
3455 ASSERT_TRUE(annot);
3456
3457 // This has an odd number of elements in the path array, ignore the last
3458 // element.
3459 unsigned long size = FPDFAnnot_GetInkListCount(annot.get());
3460 const size_t kExpectedSize = 1;
3461 ASSERT_EQ(kExpectedSize, size);
3462 const unsigned long kPathIndex = 0;
3463 unsigned long path_size =
3464 FPDFAnnot_GetInkListPath(annot.get(), kPathIndex, nullptr, 0);
3465 const size_t kExpectedPathSize = 3;
3466 ASSERT_EQ(kExpectedPathSize, path_size);
3467 std::vector<FS_POINTF> path_buffer(path_size);
3468 EXPECT_EQ(path_size,
3469 FPDFAnnot_GetInkListPath(annot.get(), kPathIndex,
3470 path_buffer.data(), path_size));
3471 EXPECT_FLOAT_EQ(259.0f, path_buffer[0].x);
3472 EXPECT_FLOAT_EQ(396.0f, path_buffer[0].y);
3473 EXPECT_FLOAT_EQ(450.0f, path_buffer[1].x);
3474 EXPECT_FLOAT_EQ(511.0f, path_buffer[1].y);
3475 EXPECT_FLOAT_EQ(572.0f, path_buffer[2].x);
3476 EXPECT_FLOAT_EQ(343.0f, path_buffer[2].y);
3477 }
3478
3479 {
3480 // Wrong annotation type.
3481 ScopedFPDFAnnotation polygon_annot(
3482 FPDFPage_CreateAnnot(page, FPDF_ANNOT_POLYGON));
3483 EXPECT_EQ(0U, FPDFAnnot_GetInkListCount(polygon_annot.get()));
3484 const unsigned long kPathIndex = 0;
3485 EXPECT_EQ(0U, FPDFAnnot_GetInkListPath(polygon_annot.get(), kPathIndex,
3486 nullptr, 0));
3487 }
3488
3489 UnloadPage(page);
3490 }
3491
TEST_F(FPDFAnnotEmbedderTest,LineAnnotation)3492 TEST_F(FPDFAnnotEmbedderTest, LineAnnotation) {
3493 ASSERT_TRUE(OpenDocument("line_annot.pdf"));
3494 FPDF_PAGE page = LoadPage(0);
3495 ASSERT_TRUE(page);
3496 EXPECT_EQ(2, FPDFPage_GetAnnotCount(page));
3497
3498 {
3499 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
3500 ASSERT_TRUE(annot);
3501
3502 // FPDFAnnot_GetVertices() positive testing.
3503 FS_POINTF start;
3504 FS_POINTF end;
3505 ASSERT_TRUE(FPDFAnnot_GetLine(annot.get(), &start, &end));
3506 EXPECT_FLOAT_EQ(159.0f, start.x);
3507 EXPECT_FLOAT_EQ(296.0f, start.y);
3508 EXPECT_FLOAT_EQ(472.0f, end.x);
3509 EXPECT_FLOAT_EQ(243.42f, end.y);
3510
3511 // FPDFAnnot_GetVertices() negative testing.
3512 EXPECT_FALSE(FPDFAnnot_GetLine(nullptr, nullptr, nullptr));
3513 EXPECT_FALSE(FPDFAnnot_GetLine(annot.get(), nullptr, nullptr));
3514 }
3515
3516 {
3517 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 1));
3518 ASSERT_TRUE(annot);
3519
3520 // Too few elements in the line array.
3521 FS_POINTF start;
3522 FS_POINTF end;
3523 EXPECT_FALSE(FPDFAnnot_GetLine(annot.get(), &start, &end));
3524 }
3525
3526 {
3527 // Wrong annotation type.
3528 ScopedFPDFAnnotation ink_annot(FPDFPage_CreateAnnot(page, FPDF_ANNOT_INK));
3529 FS_POINTF start;
3530 FS_POINTF end;
3531 EXPECT_FALSE(FPDFAnnot_GetLine(ink_annot.get(), &start, &end));
3532 }
3533
3534 UnloadPage(page);
3535 }
3536
TEST_F(FPDFAnnotEmbedderTest,AnnotationBorder)3537 TEST_F(FPDFAnnotEmbedderTest, AnnotationBorder) {
3538 ASSERT_TRUE(OpenDocument("line_annot.pdf"));
3539 FPDF_PAGE page = LoadPage(0);
3540 ASSERT_TRUE(page);
3541 EXPECT_EQ(2, FPDFPage_GetAnnotCount(page));
3542
3543 {
3544 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
3545 ASSERT_TRUE(annot);
3546
3547 // FPDFAnnot_GetBorder() positive testing.
3548 float horizontal_radius;
3549 float vertical_radius;
3550 float border_width;
3551 ASSERT_TRUE(FPDFAnnot_GetBorder(annot.get(), &horizontal_radius,
3552 &vertical_radius, &border_width));
3553 EXPECT_FLOAT_EQ(0.25f, horizontal_radius);
3554 EXPECT_FLOAT_EQ(0.5f, vertical_radius);
3555 EXPECT_FLOAT_EQ(2.0f, border_width);
3556
3557 // FPDFAnnot_GetBorder() negative testing.
3558 EXPECT_FALSE(FPDFAnnot_GetBorder(nullptr, nullptr, nullptr, nullptr));
3559 EXPECT_FALSE(FPDFAnnot_GetBorder(annot.get(), nullptr, nullptr, nullptr));
3560 }
3561
3562 {
3563 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 1));
3564 ASSERT_TRUE(annot);
3565
3566 // Too few elements in the border array.
3567 float horizontal_radius;
3568 float vertical_radius;
3569 float border_width;
3570 EXPECT_FALSE(FPDFAnnot_GetBorder(annot.get(), &horizontal_radius,
3571 &vertical_radius, &border_width));
3572
3573 // FPDFAnnot_SetBorder() positive testing.
3574 EXPECT_TRUE(FPDFAnnot_SetBorder(annot.get(), /*horizontal_radius=*/2.0f,
3575 /*vertical_radius=*/3.5f,
3576 /*border_width=*/4.0f));
3577
3578 EXPECT_TRUE(FPDFAnnot_GetBorder(annot.get(), &horizontal_radius,
3579 &vertical_radius, &border_width));
3580 EXPECT_FLOAT_EQ(2.0f, horizontal_radius);
3581 EXPECT_FLOAT_EQ(3.5f, vertical_radius);
3582 EXPECT_FLOAT_EQ(4.0f, border_width);
3583
3584 // FPDFAnnot_SetBorder() negative testing.
3585 EXPECT_FALSE(FPDFAnnot_SetBorder(nullptr, /*horizontal_radius=*/1.0f,
3586 /*vertical_radius=*/2.5f,
3587 /*border_width=*/3.0f));
3588 }
3589
3590 UnloadPage(page);
3591 }
3592
TEST_F(FPDFAnnotEmbedderTest,AnnotationJavaScript)3593 TEST_F(FPDFAnnotEmbedderTest, AnnotationJavaScript) {
3594 ASSERT_TRUE(OpenDocument("annot_javascript.pdf"));
3595 FPDF_PAGE page = LoadPage(0);
3596 ASSERT_TRUE(page);
3597 EXPECT_EQ(1, FPDFPage_GetAnnotCount(page));
3598
3599 {
3600 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
3601 ASSERT_TRUE(annot);
3602
3603 // FPDFAnnot_GetFormAdditionalActionJavaScript() positive testing.
3604 unsigned long length_bytes = FPDFAnnot_GetFormAdditionalActionJavaScript(
3605 form_handle(), annot.get(), FPDF_ANNOT_AACTION_FORMAT, nullptr, 0);
3606 ASSERT_EQ(62u, length_bytes);
3607 std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(length_bytes);
3608 EXPECT_EQ(62u, FPDFAnnot_GetFormAdditionalActionJavaScript(
3609 form_handle(), annot.get(), FPDF_ANNOT_AACTION_FORMAT,
3610 buf.data(), length_bytes));
3611 EXPECT_EQ(L"AFDate_FormatEx(\"yyyy-mm-dd\");",
3612 GetPlatformWString(buf.data()));
3613
3614 // FPDFAnnot_GetFormAdditionalActionJavaScript() negative testing.
3615 EXPECT_EQ(0u, FPDFAnnot_GetFormAdditionalActionJavaScript(
3616 form_handle(), nullptr, 0, nullptr, 0));
3617 EXPECT_EQ(0u, FPDFAnnot_GetFormAdditionalActionJavaScript(
3618 nullptr, annot.get(), 0, nullptr, 0));
3619 EXPECT_EQ(0u, FPDFAnnot_GetFormAdditionalActionJavaScript(
3620 form_handle(), annot.get(), 0, nullptr, 0));
3621 EXPECT_EQ(2u, FPDFAnnot_GetFormAdditionalActionJavaScript(
3622 form_handle(), annot.get(), FPDF_ANNOT_AACTION_KEY_STROKE,
3623 nullptr, 0));
3624 }
3625
3626 UnloadPage(page);
3627 }
3628
TEST_F(FPDFAnnotEmbedderTest,FormFieldAlternateName)3629 TEST_F(FPDFAnnotEmbedderTest, FormFieldAlternateName) {
3630 ASSERT_TRUE(OpenDocument("click_form.pdf"));
3631 FPDF_PAGE page = LoadPage(0);
3632 ASSERT_TRUE(page);
3633 EXPECT_EQ(8, FPDFPage_GetAnnotCount(page));
3634
3635 {
3636 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
3637 ASSERT_TRUE(annot);
3638
3639 // FPDFAnnot_GetFormFieldAlternateName() positive testing.
3640 unsigned long length_bytes = FPDFAnnot_GetFormFieldAlternateName(
3641 form_handle(), annot.get(), nullptr, 0);
3642 ASSERT_EQ(34u, length_bytes);
3643 std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(length_bytes);
3644 EXPECT_EQ(34u, FPDFAnnot_GetFormFieldAlternateName(
3645 form_handle(), annot.get(), buf.data(), length_bytes));
3646 EXPECT_EQ(L"readOnlyCheckbox", GetPlatformWString(buf.data()));
3647
3648 // FPDFAnnot_GetFormFieldAlternateName() negative testing.
3649 EXPECT_EQ(0u, FPDFAnnot_GetFormFieldAlternateName(form_handle(), nullptr,
3650 nullptr, 0));
3651 EXPECT_EQ(0u, FPDFAnnot_GetFormFieldAlternateName(nullptr, annot.get(),
3652 nullptr, 0));
3653 }
3654
3655 UnloadPage(page);
3656 }
3657
3658 // Due to https://crbug.com/pdfium/570, the AnnotationBorder test above cannot
3659 // actually render the line annotations inside line_annot.pdf. For now, use a
3660 // square annotation in annots.pdf for testing.
TEST_F(FPDFAnnotEmbedderTest,AnnotationBorderRendering)3661 TEST_F(FPDFAnnotEmbedderTest, AnnotationBorderRendering) {
3662 ASSERT_TRUE(OpenDocument("annots.pdf"));
3663 FPDF_PAGE page = LoadPage(1);
3664 ASSERT_TRUE(page);
3665 EXPECT_EQ(3, FPDFPage_GetAnnotCount(page));
3666
3667 const char* original_checksum = []() {
3668 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
3669 return "238dccc7df0ac61ac580c28e1109da3c";
3670 }
3671 #if BUILDFLAG(IS_APPLE)
3672 return "522a4a6b6c7eab5bf95ded1f21ea372e";
3673 #else
3674 return "12127303aecd80c6288460f7c0d79f3f";
3675 #endif
3676 }();
3677 const char* modified_checksum = []() {
3678 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
3679 return "0f326acb3eb583125ca584d703ccb13b";
3680 }
3681 #if BUILDFLAG(IS_APPLE)
3682 return "6844019e07b83cc01723415f58218d06";
3683 #else
3684 return "73d06ff4c665fe85029acef30240dcca";
3685 #endif
3686 }();
3687
3688 {
3689 ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 2));
3690 ASSERT_TRUE(annot);
3691 EXPECT_EQ(FPDF_ANNOT_SQUARE, FPDFAnnot_GetSubtype(annot.get()));
3692
3693 {
3694 ScopedFPDFBitmap bitmap = RenderLoadedPageWithFlags(page, FPDF_ANNOT);
3695 CompareBitmap(bitmap.get(), 612, 792, original_checksum);
3696 }
3697
3698 EXPECT_TRUE(FPDFAnnot_SetBorder(annot.get(), /*horizontal_radius=*/2.0f,
3699 /*vertical_radius=*/3.5f,
3700 /*border_width=*/4.0f));
3701
3702 {
3703 ScopedFPDFBitmap bitmap = RenderLoadedPageWithFlags(page, FPDF_ANNOT);
3704 CompareBitmap(bitmap.get(), 612, 792, modified_checksum);
3705 }
3706 }
3707
3708 // Save the document and close the page.
3709 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3710 UnloadPage(page);
3711
3712 ASSERT_TRUE(OpenSavedDocument());
3713 page = LoadSavedPage(1);
3714 ASSERT_TRUE(page);
3715 VerifySavedRendering(page, 612, 792, modified_checksum);
3716
3717 CloseSavedPage(page);
3718 CloseSavedDocument();
3719 }
3720