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