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