• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "public/fpdf_annot.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "constants/annotation_common.h"
11 #include "core/fpdfapi/edit/cpdf_pagecontentgenerator.h"
12 #include "core/fpdfapi/page/cpdf_annotcontext.h"
13 #include "core/fpdfapi/page/cpdf_form.h"
14 #include "core/fpdfapi/page/cpdf_page.h"
15 #include "core/fpdfapi/page/cpdf_pageobject.h"
16 #include "core/fpdfapi/parser/cpdf_array.h"
17 #include "core/fpdfapi/parser/cpdf_boolean.h"
18 #include "core/fpdfapi/parser/cpdf_dictionary.h"
19 #include "core/fpdfapi/parser/cpdf_document.h"
20 #include "core/fpdfapi/parser/cpdf_name.h"
21 #include "core/fpdfapi/parser/cpdf_number.h"
22 #include "core/fpdfapi/parser/cpdf_reference.h"
23 #include "core/fpdfapi/parser/cpdf_stream.h"
24 #include "core/fpdfapi/parser/cpdf_string.h"
25 #include "core/fpdfdoc/cpdf_annot.h"
26 #include "core/fpdfdoc/cpdf_color_utils.h"
27 #include "core/fpdfdoc/cpdf_formfield.h"
28 #include "core/fpdfdoc/cpdf_interactiveform.h"
29 #include "core/fpdfdoc/cpvt_generateap.h"
30 #include "core/fxge/cfx_color.h"
31 #include "fpdfsdk/cpdfsdk_helpers.h"
32 #include "fpdfsdk/cpdfsdk_interactiveform.h"
33 #include "third_party/base/ptr_util.h"
34 #include "third_party/base/stl_util.h"
35 
36 namespace {
37 
38 // These checks ensure the consistency of annotation subtype values across core/
39 // and public.
40 static_assert(static_cast<int>(CPDF_Annot::Subtype::UNKNOWN) ==
41                   FPDF_ANNOT_UNKNOWN,
42               "CPDF_Annot::UNKNOWN value mismatch");
43 static_assert(static_cast<int>(CPDF_Annot::Subtype::TEXT) == FPDF_ANNOT_TEXT,
44               "CPDF_Annot::TEXT value mismatch");
45 static_assert(static_cast<int>(CPDF_Annot::Subtype::LINK) == FPDF_ANNOT_LINK,
46               "CPDF_Annot::LINK value mismatch");
47 static_assert(static_cast<int>(CPDF_Annot::Subtype::FREETEXT) ==
48                   FPDF_ANNOT_FREETEXT,
49               "CPDF_Annot::FREETEXT value mismatch");
50 static_assert(static_cast<int>(CPDF_Annot::Subtype::LINE) == FPDF_ANNOT_LINE,
51               "CPDF_Annot::LINE value mismatch");
52 static_assert(static_cast<int>(CPDF_Annot::Subtype::SQUARE) ==
53                   FPDF_ANNOT_SQUARE,
54               "CPDF_Annot::SQUARE value mismatch");
55 static_assert(static_cast<int>(CPDF_Annot::Subtype::CIRCLE) ==
56                   FPDF_ANNOT_CIRCLE,
57               "CPDF_Annot::CIRCLE value mismatch");
58 static_assert(static_cast<int>(CPDF_Annot::Subtype::POLYGON) ==
59                   FPDF_ANNOT_POLYGON,
60               "CPDF_Annot::POLYGON value mismatch");
61 static_assert(static_cast<int>(CPDF_Annot::Subtype::POLYLINE) ==
62                   FPDF_ANNOT_POLYLINE,
63               "CPDF_Annot::POLYLINE value mismatch");
64 static_assert(static_cast<int>(CPDF_Annot::Subtype::HIGHLIGHT) ==
65                   FPDF_ANNOT_HIGHLIGHT,
66               "CPDF_Annot::HIGHLIGHT value mismatch");
67 static_assert(static_cast<int>(CPDF_Annot::Subtype::UNDERLINE) ==
68                   FPDF_ANNOT_UNDERLINE,
69               "CPDF_Annot::UNDERLINE value mismatch");
70 static_assert(static_cast<int>(CPDF_Annot::Subtype::SQUIGGLY) ==
71                   FPDF_ANNOT_SQUIGGLY,
72               "CPDF_Annot::SQUIGGLY value mismatch");
73 static_assert(static_cast<int>(CPDF_Annot::Subtype::STRIKEOUT) ==
74                   FPDF_ANNOT_STRIKEOUT,
75               "CPDF_Annot::STRIKEOUT value mismatch");
76 static_assert(static_cast<int>(CPDF_Annot::Subtype::STAMP) == FPDF_ANNOT_STAMP,
77               "CPDF_Annot::STAMP value mismatch");
78 static_assert(static_cast<int>(CPDF_Annot::Subtype::CARET) == FPDF_ANNOT_CARET,
79               "CPDF_Annot::CARET value mismatch");
80 static_assert(static_cast<int>(CPDF_Annot::Subtype::INK) == FPDF_ANNOT_INK,
81               "CPDF_Annot::INK value mismatch");
82 static_assert(static_cast<int>(CPDF_Annot::Subtype::POPUP) == FPDF_ANNOT_POPUP,
83               "CPDF_Annot::POPUP value mismatch");
84 static_assert(static_cast<int>(CPDF_Annot::Subtype::FILEATTACHMENT) ==
85                   FPDF_ANNOT_FILEATTACHMENT,
86               "CPDF_Annot::FILEATTACHMENT value mismatch");
87 static_assert(static_cast<int>(CPDF_Annot::Subtype::SOUND) == FPDF_ANNOT_SOUND,
88               "CPDF_Annot::SOUND value mismatch");
89 static_assert(static_cast<int>(CPDF_Annot::Subtype::MOVIE) == FPDF_ANNOT_MOVIE,
90               "CPDF_Annot::MOVIE value mismatch");
91 static_assert(static_cast<int>(CPDF_Annot::Subtype::WIDGET) ==
92                   FPDF_ANNOT_WIDGET,
93               "CPDF_Annot::WIDGET value mismatch");
94 static_assert(static_cast<int>(CPDF_Annot::Subtype::SCREEN) ==
95                   FPDF_ANNOT_SCREEN,
96               "CPDF_Annot::SCREEN value mismatch");
97 static_assert(static_cast<int>(CPDF_Annot::Subtype::PRINTERMARK) ==
98                   FPDF_ANNOT_PRINTERMARK,
99               "CPDF_Annot::PRINTERMARK value mismatch");
100 static_assert(static_cast<int>(CPDF_Annot::Subtype::TRAPNET) ==
101                   FPDF_ANNOT_TRAPNET,
102               "CPDF_Annot::TRAPNET value mismatch");
103 static_assert(static_cast<int>(CPDF_Annot::Subtype::WATERMARK) ==
104                   FPDF_ANNOT_WATERMARK,
105               "CPDF_Annot::WATERMARK value mismatch");
106 static_assert(static_cast<int>(CPDF_Annot::Subtype::THREED) ==
107                   FPDF_ANNOT_THREED,
108               "CPDF_Annot::THREED value mismatch");
109 static_assert(static_cast<int>(CPDF_Annot::Subtype::RICHMEDIA) ==
110                   FPDF_ANNOT_RICHMEDIA,
111               "CPDF_Annot::RICHMEDIA value mismatch");
112 static_assert(static_cast<int>(CPDF_Annot::Subtype::XFAWIDGET) ==
113                   FPDF_ANNOT_XFAWIDGET,
114               "CPDF_Annot::XFAWIDGET value mismatch");
115 
116 // These checks ensure the consistency of annotation appearance mode values
117 // across core/ and public.
118 static_assert(static_cast<int>(CPDF_Annot::AppearanceMode::Normal) ==
119                   FPDF_ANNOT_APPEARANCEMODE_NORMAL,
120               "CPDF_Annot::AppearanceMode::Normal value mismatch");
121 static_assert(static_cast<int>(CPDF_Annot::AppearanceMode::Rollover) ==
122                   FPDF_ANNOT_APPEARANCEMODE_ROLLOVER,
123               "CPDF_Annot::AppearanceMode::Rollover value mismatch");
124 static_assert(static_cast<int>(CPDF_Annot::AppearanceMode::Down) ==
125                   FPDF_ANNOT_APPEARANCEMODE_DOWN,
126               "CPDF_Annot::AppearanceMode::Down value mismatch");
127 
128 // These checks ensure the consistency of dictionary value types across core/
129 // and public/.
130 static_assert(static_cast<int>(CPDF_Object::Type::kBoolean) ==
131                   FPDF_OBJECT_BOOLEAN,
132               "CPDF_Object::kBoolean value mismatch");
133 static_assert(static_cast<int>(CPDF_Object::Type::kNumber) ==
134                   FPDF_OBJECT_NUMBER,
135               "CPDF_Object::kNumber value mismatch");
136 static_assert(static_cast<int>(CPDF_Object::Type::kString) ==
137                   FPDF_OBJECT_STRING,
138               "CPDF_Object::kString value mismatch");
139 static_assert(static_cast<int>(CPDF_Object::Type::kName) == FPDF_OBJECT_NAME,
140               "CPDF_Object::kName value mismatch");
141 static_assert(static_cast<int>(CPDF_Object::Type::kArray) == FPDF_OBJECT_ARRAY,
142               "CPDF_Object::kArray value mismatch");
143 static_assert(static_cast<int>(CPDF_Object::Type::kDictionary) ==
144                   FPDF_OBJECT_DICTIONARY,
145               "CPDF_Object::kDictionary value mismatch");
146 static_assert(static_cast<int>(CPDF_Object::Type::kStream) ==
147                   FPDF_OBJECT_STREAM,
148               "CPDF_Object::kStream value mismatch");
149 static_assert(static_cast<int>(CPDF_Object::Type::kNullobj) ==
150                   FPDF_OBJECT_NULLOBJ,
151               "CPDF_Object::kNullobj value mismatch");
152 static_assert(static_cast<int>(CPDF_Object::Type::kReference) ==
153                   FPDF_OBJECT_REFERENCE,
154               "CPDF_Object::kReference value mismatch");
155 
HasAPStream(CPDF_Dictionary * pAnnotDict)156 bool HasAPStream(CPDF_Dictionary* pAnnotDict) {
157   return !!GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal);
158 }
159 
UpdateContentStream(CPDF_Form * pForm,CPDF_Stream * pStream)160 void UpdateContentStream(CPDF_Form* pForm, CPDF_Stream* pStream) {
161   ASSERT(pForm);
162   ASSERT(pStream);
163 
164   CPDF_PageContentGenerator generator(pForm);
165   std::ostringstream buf;
166   generator.ProcessPageObjects(&buf);
167   pStream->SetDataFromStringstreamAndRemoveFilter(&buf);
168 }
169 
SetQuadPointsAtIndex(CPDF_Array * array,size_t quad_index,const FS_QUADPOINTSF * quad_points)170 void SetQuadPointsAtIndex(CPDF_Array* array,
171                           size_t quad_index,
172                           const FS_QUADPOINTSF* quad_points) {
173   ASSERT(array);
174   ASSERT(quad_points);
175   ASSERT(IsValidQuadPointsIndex(array, quad_index));
176 
177   size_t nIndex = quad_index * 8;
178   array->SetNewAt<CPDF_Number>(nIndex, quad_points->x1);
179   array->SetNewAt<CPDF_Number>(++nIndex, quad_points->y1);
180   array->SetNewAt<CPDF_Number>(++nIndex, quad_points->x2);
181   array->SetNewAt<CPDF_Number>(++nIndex, quad_points->y2);
182   array->SetNewAt<CPDF_Number>(++nIndex, quad_points->x3);
183   array->SetNewAt<CPDF_Number>(++nIndex, quad_points->y3);
184   array->SetNewAt<CPDF_Number>(++nIndex, quad_points->x4);
185   array->SetNewAt<CPDF_Number>(++nIndex, quad_points->y4);
186 }
187 
AppendQuadPoints(CPDF_Array * array,const FS_QUADPOINTSF * quad_points)188 void AppendQuadPoints(CPDF_Array* array, const FS_QUADPOINTSF* quad_points) {
189   ASSERT(quad_points);
190   ASSERT(array);
191 
192   array->AddNew<CPDF_Number>(quad_points->x1);
193   array->AddNew<CPDF_Number>(quad_points->y1);
194   array->AddNew<CPDF_Number>(quad_points->x2);
195   array->AddNew<CPDF_Number>(quad_points->y2);
196   array->AddNew<CPDF_Number>(quad_points->x3);
197   array->AddNew<CPDF_Number>(quad_points->y3);
198   array->AddNew<CPDF_Number>(quad_points->x4);
199   array->AddNew<CPDF_Number>(quad_points->y4);
200 }
201 
UpdateBBox(CPDF_Dictionary * annot_dict)202 void UpdateBBox(CPDF_Dictionary* annot_dict) {
203   ASSERT(annot_dict);
204   // Update BBox entry in appearance stream based on the bounding rectangle
205   // of the annotation's quadpoints.
206   CPDF_Stream* pStream =
207       GetAnnotAP(annot_dict, CPDF_Annot::AppearanceMode::Normal);
208   if (pStream) {
209     CFX_FloatRect boundingRect =
210         CPDF_Annot::BoundingRectFromQuadPoints(annot_dict);
211     if (boundingRect.Contains(pStream->GetDict()->GetRectFor("BBox")))
212       pStream->GetDict()->SetRectFor("BBox", boundingRect);
213   }
214 }
215 
GetAnnotDictFromFPDFAnnotation(FPDF_ANNOTATION annot)216 CPDF_Dictionary* GetAnnotDictFromFPDFAnnotation(FPDF_ANNOTATION annot) {
217   CPDF_AnnotContext* context = CPDFAnnotContextFromFPDFAnnotation(annot);
218   return context ? context->GetAnnotDict() : nullptr;
219 }
220 
SetExtGStateInResourceDict(CPDF_Document * pDoc,const CPDF_Dictionary * pAnnotDict,const ByteString & sBlendMode)221 RetainPtr<CPDF_Dictionary> SetExtGStateInResourceDict(
222     CPDF_Document* pDoc,
223     const CPDF_Dictionary* pAnnotDict,
224     const ByteString& sBlendMode) {
225   auto pGSDict =
226       pdfium::MakeRetain<CPDF_Dictionary>(pAnnotDict->GetByteStringPool());
227 
228   // ExtGState represents a graphics state parameter dictionary.
229   pGSDict->SetNewFor<CPDF_Name>("Type", "ExtGState");
230 
231   // CA respresents current stroking alpha specifying constant opacity
232   // value that should be used in transparent imaging model.
233   float fOpacity = pAnnotDict->GetNumberFor("CA");
234 
235   pGSDict->SetNewFor<CPDF_Number>("CA", fOpacity);
236 
237   // ca represents fill color alpha specifying constant opacity
238   // value that should be used in transparent imaging model.
239   pGSDict->SetNewFor<CPDF_Number>("ca", fOpacity);
240 
241   // AIS represents alpha source flag specifying whether current alpha
242   // constant shall be interpreted as shape value (true) or opacity value
243   // (false).
244   pGSDict->SetNewFor<CPDF_Boolean>("AIS", false);
245 
246   // BM represents Blend Mode
247   pGSDict->SetNewFor<CPDF_Name>("BM", sBlendMode);
248 
249   auto pExtGStateDict =
250       pdfium::MakeRetain<CPDF_Dictionary>(pAnnotDict->GetByteStringPool());
251 
252   pExtGStateDict->SetFor("GS", pGSDict);
253 
254   auto pResourceDict = pDoc->New<CPDF_Dictionary>();
255   pResourceDict->SetFor("ExtGState", pExtGStateDict);
256   return pResourceDict;
257 }
258 
GetFormField(FPDF_FORMHANDLE hHandle,FPDF_ANNOTATION annot)259 CPDF_FormField* GetFormField(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot) {
260   CPDF_Dictionary* pAnnotDict = GetAnnotDictFromFPDFAnnotation(annot);
261   if (!pAnnotDict)
262     return nullptr;
263 
264   CPDFSDK_InteractiveForm* pForm = FormHandleToInteractiveForm(hHandle);
265   if (!pForm)
266     return nullptr;
267 
268   CPDF_InteractiveForm* pPDFForm = pForm->GetInteractiveForm();
269   return pPDFForm->GetFieldByDict(pAnnotDict);
270 }
271 
272 }  // namespace
273 
274 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFAnnot_IsSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype)275 FPDFAnnot_IsSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype) {
276   // The supported subtypes must also be communicated in the user doc.
277   return subtype == FPDF_ANNOT_CIRCLE || subtype == FPDF_ANNOT_FREETEXT ||
278          subtype == FPDF_ANNOT_HIGHLIGHT || subtype == FPDF_ANNOT_INK ||
279          subtype == FPDF_ANNOT_POPUP || subtype == FPDF_ANNOT_SQUARE ||
280          subtype == FPDF_ANNOT_SQUIGGLY || subtype == FPDF_ANNOT_STAMP ||
281          subtype == FPDF_ANNOT_STRIKEOUT || subtype == FPDF_ANNOT_TEXT ||
282          subtype == FPDF_ANNOT_UNDERLINE;
283 }
284 
285 FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV
FPDFPage_CreateAnnot(FPDF_PAGE page,FPDF_ANNOTATION_SUBTYPE subtype)286 FPDFPage_CreateAnnot(FPDF_PAGE page, FPDF_ANNOTATION_SUBTYPE subtype) {
287   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
288   if (!pPage || !FPDFAnnot_IsSupportedSubtype(subtype))
289     return nullptr;
290 
291   auto pDict = pPage->GetDocument()->New<CPDF_Dictionary>();
292   pDict->SetNewFor<CPDF_Name>(pdfium::annotation::kType, "Annot");
293   pDict->SetNewFor<CPDF_Name>(pdfium::annotation::kSubtype,
294                               CPDF_Annot::AnnotSubtypeToString(
295                                   static_cast<CPDF_Annot::Subtype>(subtype)));
296   auto pNewAnnot = pdfium::MakeUnique<CPDF_AnnotContext>(pDict.Get(), pPage);
297 
298   CPDF_Array* pAnnotList = pPage->GetDict()->GetArrayFor("Annots");
299   if (!pAnnotList)
300     pAnnotList = pPage->GetDict()->SetNewFor<CPDF_Array>("Annots");
301   pAnnotList->Add(pDict);
302 
303   // Caller takes ownership.
304   return FPDFAnnotationFromCPDFAnnotContext(pNewAnnot.release());
305 }
306 
FPDFPage_GetAnnotCount(FPDF_PAGE page)307 FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetAnnotCount(FPDF_PAGE page) {
308   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
309   if (!pPage)
310     return 0;
311 
312   CPDF_Array* pAnnots = pPage->GetDict()->GetArrayFor("Annots");
313   return pAnnots ? pAnnots->size() : 0;
314 }
315 
FPDFPage_GetAnnot(FPDF_PAGE page,int index)316 FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFPage_GetAnnot(FPDF_PAGE page,
317                                                             int index) {
318   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
319   if (!pPage || index < 0)
320     return nullptr;
321 
322   CPDF_Array* pAnnots = pPage->GetDict()->GetArrayFor("Annots");
323   if (!pAnnots || static_cast<size_t>(index) >= pAnnots->size())
324     return nullptr;
325 
326   CPDF_Dictionary* pDict = ToDictionary(pAnnots->GetDirectObjectAt(index));
327   if (!pDict)
328     return nullptr;
329 
330   auto pNewAnnot = pdfium::MakeUnique<CPDF_AnnotContext>(pDict, pPage);
331 
332   // Caller takes ownership.
333   return FPDFAnnotationFromCPDFAnnotContext(pNewAnnot.release());
334 }
335 
FPDFPage_GetAnnotIndex(FPDF_PAGE page,FPDF_ANNOTATION annot)336 FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetAnnotIndex(FPDF_PAGE page,
337                                                      FPDF_ANNOTATION annot) {
338   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
339   if (!pPage)
340     return -1;
341 
342   CPDF_Dictionary* pAnnotDict = GetAnnotDictFromFPDFAnnotation(annot);
343   if (!pAnnotDict)
344     return -1;
345 
346   CPDF_Array* pAnnots = pPage->GetDict()->GetArrayFor("Annots");
347   if (!pAnnots)
348     return -1;
349 
350   CPDF_ArrayLocker locker(pAnnots);
351   auto it = std::find_if(locker.begin(), locker.end(),
352                          [pAnnotDict](const RetainPtr<CPDF_Object>& candidate) {
353                            return candidate->GetDirect() == pAnnotDict;
354                          });
355 
356   if (it == locker.end())
357     return -1;
358 
359   return it - locker.begin();
360 }
361 
FPDFPage_CloseAnnot(FPDF_ANNOTATION annot)362 FPDF_EXPORT void FPDF_CALLCONV FPDFPage_CloseAnnot(FPDF_ANNOTATION annot) {
363   delete CPDFAnnotContextFromFPDFAnnotation(annot);
364 }
365 
FPDFPage_RemoveAnnot(FPDF_PAGE page,int index)366 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_RemoveAnnot(FPDF_PAGE page,
367                                                          int index) {
368   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
369   if (!pPage || index < 0)
370     return false;
371 
372   CPDF_Array* pAnnots = pPage->GetDict()->GetArrayFor("Annots");
373   if (!pAnnots || static_cast<size_t>(index) >= pAnnots->size())
374     return false;
375 
376   pAnnots->RemoveAt(index);
377   return true;
378 }
379 
380 FPDF_EXPORT FPDF_ANNOTATION_SUBTYPE FPDF_CALLCONV
FPDFAnnot_GetSubtype(FPDF_ANNOTATION annot)381 FPDFAnnot_GetSubtype(FPDF_ANNOTATION annot) {
382   CPDF_Dictionary* pAnnotDict = GetAnnotDictFromFPDFAnnotation(annot);
383   if (!pAnnotDict)
384     return FPDF_ANNOT_UNKNOWN;
385 
386   return static_cast<FPDF_ANNOTATION_SUBTYPE>(CPDF_Annot::StringToAnnotSubtype(
387       pAnnotDict->GetStringFor(pdfium::annotation::kSubtype)));
388 }
389 
390 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFAnnot_IsObjectSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype)391 FPDFAnnot_IsObjectSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype) {
392   // The supported subtypes must also be communicated in the user doc.
393   return subtype == FPDF_ANNOT_INK || subtype == FPDF_ANNOT_STAMP;
394 }
395 
396 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFAnnot_UpdateObject(FPDF_ANNOTATION annot,FPDF_PAGEOBJECT obj)397 FPDFAnnot_UpdateObject(FPDF_ANNOTATION annot, FPDF_PAGEOBJECT obj) {
398   CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
399   CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(obj);
400   if (!pAnnot || !pAnnot->HasForm() || !pObj)
401     return false;
402 
403   // Check that the annotation type is supported by this method.
404   if (!FPDFAnnot_IsObjectSupportedSubtype(FPDFAnnot_GetSubtype(annot)))
405     return false;
406 
407   // Check that the annotation already has an appearance stream, since an
408   // existing object is to be updated.
409   CPDF_Stream* pStream =
410       GetAnnotAP(pAnnot->GetAnnotDict(), CPDF_Annot::AppearanceMode::Normal);
411   if (!pStream)
412     return false;
413 
414   // Check that the object is already in this annotation's object list.
415   CPDF_Form* pForm = pAnnot->GetForm();
416   auto it =
417       std::find_if(pForm->begin(), pForm->end(),
418                    [pObj](const std::unique_ptr<CPDF_PageObject>& candidate) {
419                      return candidate.get() == pObj;
420                    });
421   if (it == pForm->end())
422     return false;
423 
424   // Update the content stream data in the annotation's AP stream.
425   UpdateContentStream(pForm, pStream);
426   return true;
427 }
428 
429 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFAnnot_AppendObject(FPDF_ANNOTATION annot,FPDF_PAGEOBJECT obj)430 FPDFAnnot_AppendObject(FPDF_ANNOTATION annot, FPDF_PAGEOBJECT obj) {
431   CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
432   CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(obj);
433   if (!pAnnot || !pObj)
434     return false;
435 
436   // Check that the annotation type is supported by this method.
437   if (!FPDFAnnot_IsObjectSupportedSubtype(FPDFAnnot_GetSubtype(annot)))
438     return false;
439 
440   // If the annotation does not have an AP stream yet, generate and set it.
441   CPDF_Dictionary* pAnnotDict = pAnnot->GetAnnotDict();
442   CPDF_Stream* pStream =
443       GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal);
444   if (!pStream) {
445     CPVT_GenerateAP::GenerateEmptyAP(pAnnot->GetPage()->GetDocument(),
446                                      pAnnotDict);
447     pStream = GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal);
448     if (!pStream)
449       return false;
450   }
451 
452   // Get the annotation's corresponding form object for parsing its AP stream.
453   if (!pAnnot->HasForm())
454     pAnnot->SetForm(pStream);
455 
456   // Check that the object did not come from the same annotation. If this check
457   // succeeds, then it is assumed that the object came from
458   // FPDFPageObj_CreateNew{Path|Rect}() or FPDFPageObj_New{Text|Image}Obj().
459   // Note that an object that came from a different annotation must not be
460   // passed here, since an object cannot belong to more than one annotation.
461   CPDF_Form* pForm = pAnnot->GetForm();
462   auto it =
463       std::find_if(pForm->begin(), pForm->end(),
464                    [pObj](const std::unique_ptr<CPDF_PageObject>& candidate) {
465                      return candidate.get() == pObj;
466                    });
467   if (it != pForm->end())
468     return false;
469 
470   // Append the object to the object list.
471   pForm->AppendPageObject(pdfium::WrapUnique(pObj));
472 
473   // Set the content stream data in the annotation's AP stream.
474   UpdateContentStream(pForm, pStream);
475   return true;
476 }
477 
FPDFAnnot_GetObjectCount(FPDF_ANNOTATION annot)478 FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetObjectCount(FPDF_ANNOTATION annot) {
479   CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
480   if (!pAnnot)
481     return 0;
482 
483   if (!pAnnot->HasForm()) {
484     CPDF_Stream* pStream =
485         GetAnnotAP(pAnnot->GetAnnotDict(), CPDF_Annot::AppearanceMode::Normal);
486     if (!pStream)
487       return 0;
488 
489     pAnnot->SetForm(pStream);
490   }
491   return pAnnot->GetForm()->GetPageObjectCount();
492 }
493 
494 FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV
FPDFAnnot_GetObject(FPDF_ANNOTATION annot,int index)495 FPDFAnnot_GetObject(FPDF_ANNOTATION annot, int index) {
496   CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
497   if (!pAnnot || index < 0)
498     return nullptr;
499 
500   if (!pAnnot->HasForm()) {
501     CPDF_Stream* pStream =
502         GetAnnotAP(pAnnot->GetAnnotDict(), CPDF_Annot::AppearanceMode::Normal);
503     if (!pStream)
504       return nullptr;
505 
506     pAnnot->SetForm(pStream);
507   }
508 
509   return FPDFPageObjectFromCPDFPageObject(
510       pAnnot->GetForm()->GetPageObjectByIndex(index));
511 }
512 
513 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFAnnot_RemoveObject(FPDF_ANNOTATION annot,int index)514 FPDFAnnot_RemoveObject(FPDF_ANNOTATION annot, int index) {
515   CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
516   if (!pAnnot || !pAnnot->HasForm() || index < 0)
517     return false;
518 
519   // Check that the annotation type is supported by this method.
520   if (!FPDFAnnot_IsObjectSupportedSubtype(FPDFAnnot_GetSubtype(annot)))
521     return false;
522 
523   // Check that the annotation already has an appearance stream, since an
524   // existing object is to be deleted.
525   CPDF_Stream* pStream =
526       GetAnnotAP(pAnnot->GetAnnotDict(), CPDF_Annot::AppearanceMode::Normal);
527   if (!pStream)
528     return false;
529 
530   if (!pAnnot->GetForm()->ErasePageObjectAtIndex(index))
531     return false;
532 
533   UpdateContentStream(pAnnot->GetForm(), pStream);
534   return true;
535 }
536 
FPDFAnnot_SetColor(FPDF_ANNOTATION annot,FPDFANNOT_COLORTYPE type,unsigned int R,unsigned int G,unsigned int B,unsigned int A)537 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetColor(FPDF_ANNOTATION annot,
538                                                        FPDFANNOT_COLORTYPE type,
539                                                        unsigned int R,
540                                                        unsigned int G,
541                                                        unsigned int B,
542                                                        unsigned int A) {
543   CPDF_Dictionary* pAnnotDict = GetAnnotDictFromFPDFAnnotation(annot);
544   if (!pAnnotDict || R > 255 || G > 255 || B > 255 || A > 255)
545     return false;
546 
547   // For annotations with their appearance streams already defined, the path
548   // stream's own color definitions take priority over the annotation color
549   // definitions set by this method, hence this method will simply fail.
550   if (HasAPStream(pAnnotDict))
551     return false;
552 
553   // Set the opacity of the annotation.
554   pAnnotDict->SetNewFor<CPDF_Number>("CA", A / 255.f);
555 
556   // Set the color of the annotation.
557   ByteString key = type == FPDFANNOT_COLORTYPE_InteriorColor ? "IC" : "C";
558   CPDF_Array* pColor = pAnnotDict->GetArrayFor(key);
559   if (pColor)
560     pColor->Clear();
561   else
562     pColor = pAnnotDict->SetNewFor<CPDF_Array>(key);
563 
564   pColor->AddNew<CPDF_Number>(R / 255.f);
565   pColor->AddNew<CPDF_Number>(G / 255.f);
566   pColor->AddNew<CPDF_Number>(B / 255.f);
567 
568   return true;
569 }
570 
FPDFAnnot_GetColor(FPDF_ANNOTATION annot,FPDFANNOT_COLORTYPE type,unsigned int * R,unsigned int * G,unsigned int * B,unsigned int * A)571 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetColor(FPDF_ANNOTATION annot,
572                                                        FPDFANNOT_COLORTYPE type,
573                                                        unsigned int* R,
574                                                        unsigned int* G,
575                                                        unsigned int* B,
576                                                        unsigned int* A) {
577   CPDF_Dictionary* pAnnotDict = GetAnnotDictFromFPDFAnnotation(annot);
578   if (!pAnnotDict || !R || !G || !B || !A)
579     return false;
580 
581   // For annotations with their appearance streams already defined, the path
582   // stream's own color definitions take priority over the annotation color
583   // definitions retrieved by this method, hence this method will simply fail.
584   if (HasAPStream(pAnnotDict))
585     return false;
586 
587   CPDF_Array* pColor = pAnnotDict->GetArrayFor(
588       type == FPDFANNOT_COLORTYPE_InteriorColor ? "IC" : "C");
589   *A =
590       (pAnnotDict->KeyExist("CA") ? pAnnotDict->GetNumberFor("CA") : 1) * 255.f;
591   if (!pColor) {
592     // Use default color. The default colors must be consistent with the ones
593     // used to generate AP. See calls to GetColorStringWithDefault() in
594     // CPVT_GenerateAP::Generate*AP().
595     if (pAnnotDict->GetStringFor(pdfium::annotation::kSubtype) == "Highlight") {
596       *R = 255;
597       *G = 255;
598       *B = 0;
599     } else {
600       *R = 0;
601       *G = 0;
602       *B = 0;
603     }
604     return true;
605   }
606 
607   CFX_Color color = fpdfdoc::CFXColorFromArray(*pColor);
608   switch (color.nColorType) {
609     case CFX_Color::kRGB:
610       *R = color.fColor1 * 255.f;
611       *G = color.fColor2 * 255.f;
612       *B = color.fColor3 * 255.f;
613       break;
614     case CFX_Color::kGray:
615       *R = 255.f * color.fColor1;
616       *G = 255.f * color.fColor1;
617       *B = 255.f * color.fColor1;
618       break;
619     case CFX_Color::kCMYK:
620       *R = 255.f * (1 - color.fColor1) * (1 - color.fColor4);
621       *G = 255.f * (1 - color.fColor2) * (1 - color.fColor4);
622       *B = 255.f * (1 - color.fColor3) * (1 - color.fColor4);
623       break;
624     case CFX_Color::kTransparent:
625       *R = 0;
626       *G = 0;
627       *B = 0;
628       break;
629   }
630   return true;
631 }
632 
633 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFAnnot_HasAttachmentPoints(FPDF_ANNOTATION annot)634 FPDFAnnot_HasAttachmentPoints(FPDF_ANNOTATION annot) {
635   if (!annot)
636     return false;
637 
638   FPDF_ANNOTATION_SUBTYPE subtype = FPDFAnnot_GetSubtype(annot);
639   return subtype == FPDF_ANNOT_LINK || subtype == FPDF_ANNOT_HIGHLIGHT ||
640          subtype == FPDF_ANNOT_UNDERLINE || subtype == FPDF_ANNOT_SQUIGGLY ||
641          subtype == FPDF_ANNOT_STRIKEOUT;
642 }
643 
644 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFAnnot_SetAttachmentPoints(FPDF_ANNOTATION annot,size_t quad_index,const FS_QUADPOINTSF * quad_points)645 FPDFAnnot_SetAttachmentPoints(FPDF_ANNOTATION annot,
646                               size_t quad_index,
647                               const FS_QUADPOINTSF* quad_points) {
648   if (!FPDFAnnot_HasAttachmentPoints(annot) || !quad_points)
649     return false;
650 
651   CPDF_Dictionary* pAnnotDict =
652       CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
653   CPDF_Array* pQuadPointsArray = GetQuadPointsArrayFromDictionary(pAnnotDict);
654   if (!IsValidQuadPointsIndex(pQuadPointsArray, quad_index))
655     return false;
656 
657   SetQuadPointsAtIndex(pQuadPointsArray, quad_index, quad_points);
658   UpdateBBox(pAnnotDict);
659   return true;
660 }
661 
662 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFAnnot_AppendAttachmentPoints(FPDF_ANNOTATION annot,const FS_QUADPOINTSF * quad_points)663 FPDFAnnot_AppendAttachmentPoints(FPDF_ANNOTATION annot,
664                                  const FS_QUADPOINTSF* quad_points) {
665   if (!FPDFAnnot_HasAttachmentPoints(annot) || !quad_points)
666     return false;
667 
668   CPDF_Dictionary* pAnnotDict =
669       CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
670   CPDF_Array* pQuadPointsArray = GetQuadPointsArrayFromDictionary(pAnnotDict);
671   if (!pQuadPointsArray)
672     pQuadPointsArray = AddQuadPointsArrayToDictionary(pAnnotDict);
673   AppendQuadPoints(pQuadPointsArray, quad_points);
674   UpdateBBox(pAnnotDict);
675   return true;
676 }
677 
678 FPDF_EXPORT size_t FPDF_CALLCONV
FPDFAnnot_CountAttachmentPoints(FPDF_ANNOTATION annot)679 FPDFAnnot_CountAttachmentPoints(FPDF_ANNOTATION annot) {
680   if (!FPDFAnnot_HasAttachmentPoints(annot))
681     return 0;
682 
683   const CPDF_Dictionary* pAnnotDict =
684       CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
685   const CPDF_Array* pArray = GetQuadPointsArrayFromDictionary(pAnnotDict);
686   return pArray ? pArray->size() / 8 : 0;
687 }
688 
689 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFAnnot_GetAttachmentPoints(FPDF_ANNOTATION annot,size_t quad_index,FS_QUADPOINTSF * quad_points)690 FPDFAnnot_GetAttachmentPoints(FPDF_ANNOTATION annot,
691                               size_t quad_index,
692                               FS_QUADPOINTSF* quad_points) {
693   if (!FPDFAnnot_HasAttachmentPoints(annot) || !quad_points)
694     return false;
695 
696   const CPDF_Dictionary* pAnnotDict =
697       CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
698   const CPDF_Array* pArray = GetQuadPointsArrayFromDictionary(pAnnotDict);
699   if (!pArray)
700     return false;
701 
702   return GetQuadPointsAtIndex(pArray, quad_index, quad_points);
703 }
704 
FPDFAnnot_SetRect(FPDF_ANNOTATION annot,const FS_RECTF * rect)705 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetRect(FPDF_ANNOTATION annot,
706                                                       const FS_RECTF* rect) {
707   CPDF_Dictionary* pAnnotDict = GetAnnotDictFromFPDFAnnotation(annot);
708   if (!pAnnotDict || !rect)
709     return false;
710 
711   CFX_FloatRect newRect = CFXFloatRectFromFSRectF(*rect);
712 
713   // Update the "Rect" entry in the annotation dictionary.
714   pAnnotDict->SetRectFor(pdfium::annotation::kRect, newRect);
715 
716   // If the annotation's appearance stream is defined, the annotation is of a
717   // type that does not have quadpoints, and the new rectangle is bigger than
718   // the current bounding box, then update the "BBox" entry in the AP
719   // dictionary too, since its "BBox" entry comes from annotation dictionary's
720   // "Rect" entry.
721   if (FPDFAnnot_HasAttachmentPoints(annot))
722     return true;
723 
724   CPDF_Stream* pStream =
725       GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal);
726   if (pStream && newRect.Contains(pStream->GetDict()->GetRectFor("BBox")))
727     pStream->GetDict()->SetRectFor("BBox", newRect);
728   return true;
729 }
730 
FPDFAnnot_GetRect(FPDF_ANNOTATION annot,FS_RECTF * rect)731 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetRect(FPDF_ANNOTATION annot,
732                                                       FS_RECTF* rect) {
733   CPDF_Dictionary* pAnnotDict = GetAnnotDictFromFPDFAnnotation(annot);
734   if (!pAnnotDict || !rect)
735     return false;
736 
737   *rect = FSRectFFromCFXFloatRect(
738       pAnnotDict->GetRectFor(pdfium::annotation::kRect));
739   return true;
740 }
741 
FPDFAnnot_HasKey(FPDF_ANNOTATION annot,FPDF_BYTESTRING key)742 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_HasKey(FPDF_ANNOTATION annot,
743                                                      FPDF_BYTESTRING key) {
744   CPDF_Dictionary* pAnnotDict = GetAnnotDictFromFPDFAnnotation(annot);
745   return pAnnotDict && pAnnotDict->KeyExist(key);
746 }
747 
748 FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV
FPDFAnnot_GetValueType(FPDF_ANNOTATION annot,FPDF_BYTESTRING key)749 FPDFAnnot_GetValueType(FPDF_ANNOTATION annot, FPDF_BYTESTRING key) {
750   if (!FPDFAnnot_HasKey(annot, key))
751     return FPDF_OBJECT_UNKNOWN;
752 
753   auto* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
754   CPDF_Object* pObj = pAnnot->GetAnnotDict()->GetObjectFor(key);
755   return pObj ? pObj->GetType() : FPDF_OBJECT_UNKNOWN;
756 }
757 
758 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFAnnot_SetStringValue(FPDF_ANNOTATION annot,FPDF_BYTESTRING key,FPDF_WIDESTRING value)759 FPDFAnnot_SetStringValue(FPDF_ANNOTATION annot,
760                          FPDF_BYTESTRING key,
761                          FPDF_WIDESTRING value) {
762   CPDF_Dictionary* pAnnotDict = GetAnnotDictFromFPDFAnnotation(annot);
763   if (!pAnnotDict)
764     return false;
765 
766   pAnnotDict->SetNewFor<CPDF_String>(key, WideStringFromFPDFWideString(value));
767   return true;
768 }
769 
770 FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDFAnnot_GetStringValue(FPDF_ANNOTATION annot,FPDF_BYTESTRING key,FPDF_WCHAR * buffer,unsigned long buflen)771 FPDFAnnot_GetStringValue(FPDF_ANNOTATION annot,
772                          FPDF_BYTESTRING key,
773                          FPDF_WCHAR* buffer,
774                          unsigned long buflen) {
775   CPDF_Dictionary* pAnnotDict = GetAnnotDictFromFPDFAnnotation(annot);
776   if (!pAnnotDict)
777     return 0;
778 
779   return Utf16EncodeMaybeCopyAndReturnLength(pAnnotDict->GetUnicodeTextFor(key),
780                                              buffer, buflen);
781 }
782 
783 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFAnnot_GetNumberValue(FPDF_ANNOTATION annot,FPDF_BYTESTRING key,float * value)784 FPDFAnnot_GetNumberValue(FPDF_ANNOTATION annot,
785                          FPDF_BYTESTRING key,
786                          float* value) {
787   if (!value)
788     return false;
789 
790   CPDF_Dictionary* pAnnotDict = GetAnnotDictFromFPDFAnnotation(annot);
791   if (!pAnnotDict)
792     return false;
793 
794   const CPDF_Object* p = pAnnotDict->GetObjectFor(key);
795   if (!p || p->GetType() != FPDF_OBJECT_NUMBER)
796     return false;
797 
798   *value = p->GetNumber();
799   return true;
800 }
801 
802 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFAnnot_SetAP(FPDF_ANNOTATION annot,FPDF_ANNOT_APPEARANCEMODE appearanceMode,FPDF_WIDESTRING value)803 FPDFAnnot_SetAP(FPDF_ANNOTATION annot,
804                 FPDF_ANNOT_APPEARANCEMODE appearanceMode,
805                 FPDF_WIDESTRING value) {
806   CPDF_Dictionary* pAnnotDict = GetAnnotDictFromFPDFAnnotation(annot);
807   if (!pAnnotDict)
808     return false;
809 
810   if (appearanceMode < 0 || appearanceMode >= FPDF_ANNOT_APPEARANCEMODE_COUNT)
811     return false;
812 
813   static constexpr const char* kModeKeyForMode[] = {"N", "R", "D"};
814   static_assert(
815       FX_ArraySize(kModeKeyForMode) == FPDF_ANNOT_APPEARANCEMODE_COUNT,
816       "length of kModeKeyForMode should be equal to "
817       "FPDF_ANNOT_APPEARANCEMODE_COUNT");
818   const char* modeKey = kModeKeyForMode[appearanceMode];
819 
820   CPDF_Dictionary* pApDict = pAnnotDict->GetDictFor(pdfium::annotation::kAP);
821 
822   // If value is null, we're in remove mode. Otherwise, we're in add/update
823   // mode.
824   if (value) {
825     // Annotation object's non-empty bounding rect will be used as the /BBox
826     // for the associated /XObject object
827     CFX_FloatRect rect = pAnnotDict->GetRectFor(pdfium::annotation::kRect);
828     constexpr float kMinSize = 0.000001f;
829     if (rect.Width() < kMinSize || rect.Height() < kMinSize)
830       return false;
831 
832     CPDF_AnnotContext* pAnnotContext =
833         CPDFAnnotContextFromFPDFAnnotation(annot);
834 
835     CPDF_Document* pDoc = pAnnotContext->GetPage()->GetDocument();
836     if (!pDoc)
837       return false;
838 
839     CPDF_Stream* pNewIndirectStream = pDoc->NewIndirect<CPDF_Stream>();
840 
841     ByteString newAPStream =
842         PDF_EncodeText(WideStringFromFPDFWideString(value));
843     pNewIndirectStream->SetData(newAPStream.raw_span());
844 
845     CPDF_Dictionary* pStreamDict = pNewIndirectStream->GetDict();
846     pStreamDict->SetNewFor<CPDF_Name>(pdfium::annotation::kType, "XObject");
847     pStreamDict->SetNewFor<CPDF_Name>(pdfium::annotation::kSubtype, "Form");
848     pStreamDict->SetRectFor("BBox", rect);
849     // Transparency values are specified in range [0.0f, 1.0f]. We are strictly
850     // checking for value < 1 and not <= 1 so that the output PDF size does not
851     // unnecessarily bloat up by creating a new dictionary in case of solid
852     // color.
853     if (pAnnotDict->KeyExist("CA") && pAnnotDict->GetNumberFor("CA") < 1.0f) {
854       RetainPtr<CPDF_Dictionary> pResourceDict =
855           SetExtGStateInResourceDict(pDoc, pAnnotDict, "Normal");
856       pStreamDict->SetFor("Resources", pResourceDict);
857     }
858 
859     // Storing reference to indirect object in annotation's AP
860     if (!pApDict)
861       pApDict = pAnnotDict->SetNewFor<CPDF_Dictionary>(pdfium::annotation::kAP);
862 
863     pApDict->SetNewFor<CPDF_Reference>(modeKey, pDoc,
864                                        pNewIndirectStream->GetObjNum());
865   } else {
866     if (pApDict) {
867       if (appearanceMode == FPDF_ANNOT_APPEARANCEMODE_NORMAL)
868         pAnnotDict->RemoveFor(pdfium::annotation::kAP);
869       else
870         pApDict->RemoveFor(modeKey);
871     }
872   }
873 
874   return true;
875 }
876 
877 FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDFAnnot_GetAP(FPDF_ANNOTATION annot,FPDF_ANNOT_APPEARANCEMODE appearanceMode,FPDF_WCHAR * buffer,unsigned long buflen)878 FPDFAnnot_GetAP(FPDF_ANNOTATION annot,
879                 FPDF_ANNOT_APPEARANCEMODE appearanceMode,
880                 FPDF_WCHAR* buffer,
881                 unsigned long buflen) {
882   CPDF_Dictionary* pAnnotDict = GetAnnotDictFromFPDFAnnotation(annot);
883   if (!pAnnotDict)
884     return 0;
885 
886   if (appearanceMode < 0 || appearanceMode >= FPDF_ANNOT_APPEARANCEMODE_COUNT)
887     return 0;
888 
889   CPDF_Annot::AppearanceMode mode =
890       static_cast<CPDF_Annot::AppearanceMode>(appearanceMode);
891 
892   CPDF_Stream* pStream = GetAnnotAPNoFallback(pAnnotDict, mode);
893   return Utf16EncodeMaybeCopyAndReturnLength(
894       pStream ? pStream->GetUnicodeText() : WideString(), buffer, buflen);
895 }
896 
897 FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV
FPDFAnnot_GetLinkedAnnot(FPDF_ANNOTATION annot,FPDF_BYTESTRING key)898 FPDFAnnot_GetLinkedAnnot(FPDF_ANNOTATION annot, FPDF_BYTESTRING key) {
899   CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
900   if (!pAnnot)
901     return nullptr;
902 
903   CPDF_Dictionary* pLinkedDict = pAnnot->GetAnnotDict()->GetDictFor(key);
904   if (!pLinkedDict || pLinkedDict->GetStringFor("Type") != "Annot")
905     return nullptr;
906 
907   auto pLinkedAnnot =
908       pdfium::MakeUnique<CPDF_AnnotContext>(pLinkedDict, pAnnot->GetPage());
909 
910   // Caller takes ownership.
911   return FPDFAnnotationFromCPDFAnnotContext(pLinkedAnnot.release());
912 }
913 
FPDFAnnot_GetFlags(FPDF_ANNOTATION annot)914 FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFlags(FPDF_ANNOTATION annot) {
915   CPDF_Dictionary* pAnnotDict = GetAnnotDictFromFPDFAnnotation(annot);
916   return pAnnotDict ? pAnnotDict->GetIntegerFor(pdfium::annotation::kF)
917                     : FPDF_ANNOT_FLAG_NONE;
918 }
919 
FPDFAnnot_SetFlags(FPDF_ANNOTATION annot,int flags)920 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetFlags(FPDF_ANNOTATION annot,
921                                                        int flags) {
922   CPDF_Dictionary* pAnnotDict = GetAnnotDictFromFPDFAnnotation(annot);
923   if (!pAnnotDict)
924     return false;
925 
926   pAnnotDict->SetNewFor<CPDF_Number>(pdfium::annotation::kF, flags);
927   return true;
928 }
929 
930 FPDF_EXPORT int FPDF_CALLCONV
FPDFAnnot_GetFormFieldFlags(FPDF_FORMHANDLE hHandle,FPDF_ANNOTATION annot)931 FPDFAnnot_GetFormFieldFlags(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot) {
932   CPDF_FormField* pFormField = GetFormField(hHandle, annot);
933   return pFormField ? pFormField->GetFieldFlags() : FPDF_FORMFLAG_NONE;
934 }
935 
936 FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV
FPDFAnnot_GetFormFieldAtPoint(FPDF_FORMHANDLE hHandle,FPDF_PAGE page,const FS_POINTF * point)937 FPDFAnnot_GetFormFieldAtPoint(FPDF_FORMHANDLE hHandle,
938                               FPDF_PAGE page,
939                               const FS_POINTF* point) {
940   if (!point)
941     return nullptr;
942 
943   CPDFSDK_InteractiveForm* pForm = FormHandleToInteractiveForm(hHandle);
944   if (!pForm)
945     return nullptr;
946 
947   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
948   if (!pPage)
949     return nullptr;
950 
951   CPDF_InteractiveForm* pPDFForm = pForm->GetInteractiveForm();
952   int annot_index = -1;
953   CPDF_FormControl* pFormCtrl = pPDFForm->GetControlAtPoint(
954       pPage, CFXPointFFromFSPointF(*point), &annot_index);
955   if (!pFormCtrl || annot_index == -1)
956     return nullptr;
957   return FPDFPage_GetAnnot(page, annot_index);
958 }
959 
960 FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDFAnnot_GetFormFieldName(FPDF_FORMHANDLE hHandle,FPDF_ANNOTATION annot,FPDF_WCHAR * buffer,unsigned long buflen)961 FPDFAnnot_GetFormFieldName(FPDF_FORMHANDLE hHandle,
962                            FPDF_ANNOTATION annot,
963                            FPDF_WCHAR* buffer,
964                            unsigned long buflen) {
965   CPDF_FormField* pFormField = GetFormField(hHandle, annot);
966   if (!pFormField)
967     return 0;
968   return Utf16EncodeMaybeCopyAndReturnLength(pFormField->GetFullName(), buffer,
969                                              buflen);
970 }
971 
972 FPDF_EXPORT int FPDF_CALLCONV
FPDFAnnot_GetFormFieldType(FPDF_FORMHANDLE hHandle,FPDF_ANNOTATION annot)973 FPDFAnnot_GetFormFieldType(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot) {
974   CPDF_FormField* pFormField = GetFormField(hHandle, annot);
975   return pFormField ? static_cast<int>(pFormField->GetFieldType()) : -1;
976 }
977 
978 FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDFAnnot_GetFormFieldValue(FPDF_FORMHANDLE hHandle,FPDF_ANNOTATION annot,FPDF_WCHAR * buffer,unsigned long buflen)979 FPDFAnnot_GetFormFieldValue(FPDF_FORMHANDLE hHandle,
980                             FPDF_ANNOTATION annot,
981                             FPDF_WCHAR* buffer,
982                             unsigned long buflen) {
983   CPDF_FormField* pFormField = GetFormField(hHandle, annot);
984   if (!pFormField)
985     return 0;
986   return Utf16EncodeMaybeCopyAndReturnLength(pFormField->GetValue(), buffer,
987                                              buflen);
988 }
989 
FPDFAnnot_GetOptionCount(FPDF_FORMHANDLE hHandle,FPDF_ANNOTATION annot)990 FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetOptionCount(FPDF_FORMHANDLE hHandle,
991                                                        FPDF_ANNOTATION annot) {
992   CPDF_FormField* pFormField = GetFormField(hHandle, annot);
993   return pFormField ? pFormField->CountOptions() : -1;
994 }
995 
996 FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDFAnnot_GetOptionLabel(FPDF_FORMHANDLE hHandle,FPDF_ANNOTATION annot,int index,FPDF_WCHAR * buffer,unsigned long buflen)997 FPDFAnnot_GetOptionLabel(FPDF_FORMHANDLE hHandle,
998                          FPDF_ANNOTATION annot,
999                          int index,
1000                          FPDF_WCHAR* buffer,
1001                          unsigned long buflen) {
1002   if (index < 0)
1003     return 0;
1004 
1005   CPDF_FormField* pFormField = GetFormField(hHandle, annot);
1006   if (!pFormField || index >= pFormField->CountOptions())
1007     return 0;
1008 
1009   WideString ws = pFormField->GetOptionLabel(index);
1010   return Utf16EncodeMaybeCopyAndReturnLength(ws, buffer, buflen);
1011 }
1012 
1013 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFAnnot_GetFontSize(FPDF_FORMHANDLE hHandle,FPDF_ANNOTATION annot,float * value)1014 FPDFAnnot_GetFontSize(FPDF_FORMHANDLE hHandle,
1015                       FPDF_ANNOTATION annot,
1016                       float* value) {
1017   if (!value)
1018     return false;
1019 
1020   CPDFSDK_InteractiveForm* pForm = FormHandleToInteractiveForm(hHandle);
1021   if (!pForm)
1022     return false;
1023 
1024   CPDF_Dictionary* pAnnotDict = GetAnnotDictFromFPDFAnnotation(annot);
1025   if (!pAnnotDict)
1026     return false;
1027 
1028   CPDF_InteractiveForm* pPDFForm = pForm->GetInteractiveForm();
1029   CPDF_FormControl* pFormControl = pPDFForm->GetControlByDict(pAnnotDict);
1030   if (!pFormControl)
1031     return false;
1032 
1033   CPDFSDK_Widget* pWidget = pForm->GetWidget(pFormControl);
1034   if (!pWidget)
1035     return false;
1036 
1037   *value = pWidget->GetFontSize();
1038   return true;
1039 }
1040 
FPDFAnnot_IsChecked(FPDF_FORMHANDLE hHandle,FPDF_ANNOTATION annot)1041 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_IsChecked(FPDF_FORMHANDLE hHandle,
1042                                                         FPDF_ANNOTATION annot) {
1043   CPDFSDK_InteractiveForm* pForm = FormHandleToInteractiveForm(hHandle);
1044   if (!pForm)
1045     return false;
1046 
1047   CPDF_Dictionary* pAnnotDict = GetAnnotDictFromFPDFAnnotation(annot);
1048   if (!pAnnotDict)
1049     return false;
1050 
1051   CPDF_InteractiveForm* pPDFForm = pForm->GetInteractiveForm();
1052   CPDF_FormField* pFormField = pPDFForm->GetFieldByDict(pAnnotDict);
1053   if (!pFormField)
1054     return false;
1055 
1056   if (pFormField->GetType() != CPDF_FormField::kCheckBox &&
1057       pFormField->GetType() != CPDF_FormField::kRadioButton) {
1058     return false;
1059   }
1060 
1061   CPDF_FormControl* pFormControl = pPDFForm->GetControlByDict(pAnnotDict);
1062   if (!pFormControl)
1063     return false;
1064 
1065   CPDFSDK_Widget* pWidget = pForm->GetWidget(pFormControl);
1066   return pWidget && pWidget->IsChecked();
1067 }
1068