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