blob: fcbed5c2ce00b772fe06fd1b46ae6e967f5bb679 [file] [log] [blame]
Jane Liu4fd9a472017-06-01 18:56:09 -04001// 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
Jane Liu4fd9a472017-06-01 18:56:09 -04005#include "public/fpdf_annot.h"
6
Jane Liud60e9ad2017-06-26 11:28:36 -04007#include <memory>
Jane Liu20eafda2017-06-07 10:33:24 -04008#include <utility>
9
Jane Liubaa7ff42017-06-29 19:18:23 -040010#include "core/fpdfapi/edit/cpdf_pagecontentgenerator.h"
Jane Liue10509a2017-06-20 16:47:41 -040011#include "core/fpdfapi/page/cpdf_form.h"
Jane Liu4fd9a472017-06-01 18:56:09 -040012#include "core/fpdfapi/page/cpdf_page.h"
Jane Liubaa7ff42017-06-29 19:18:23 -040013#include "core/fpdfapi/page/cpdf_pageobject.h"
Jane Liu4fd9a472017-06-01 18:56:09 -040014#include "core/fpdfapi/parser/cpdf_array.h"
15#include "core/fpdfapi/parser/cpdf_dictionary.h"
Jane Liu20eafda2017-06-07 10:33:24 -040016#include "core/fpdfapi/parser/cpdf_document.h"
17#include "core/fpdfapi/parser/cpdf_name.h"
18#include "core/fpdfapi/parser/cpdf_number.h"
19#include "core/fpdfapi/parser/cpdf_string.h"
Jane Liu4fd9a472017-06-01 18:56:09 -040020#include "core/fpdfdoc/cpdf_annot.h"
Diana Gage7e0c05d2017-07-19 17:33:33 -070021#include "core/fpdfdoc/cpdf_formfield.h"
22#include "core/fpdfdoc/cpdf_interform.h"
Jane Liu4fd9a472017-06-01 18:56:09 -040023#include "core/fpdfdoc/cpvt_color.h"
24#include "core/fpdfdoc/cpvt_generateap.h"
25#include "fpdfsdk/fsdk_define.h"
26
Jane Liue10509a2017-06-20 16:47:41 -040027namespace {
28
Jane Liu4fd9a472017-06-01 18:56:09 -040029// These checks ensure the consistency of annotation subtype values across core/
30// and public.
31static_assert(static_cast<int>(CPDF_Annot::Subtype::UNKNOWN) ==
32 FPDF_ANNOT_UNKNOWN,
33 "CPDF_Annot::UNKNOWN value mismatch");
34static_assert(static_cast<int>(CPDF_Annot::Subtype::TEXT) == FPDF_ANNOT_TEXT,
35 "CPDF_Annot::TEXT value mismatch");
36static_assert(static_cast<int>(CPDF_Annot::Subtype::LINK) == FPDF_ANNOT_LINK,
37 "CPDF_Annot::LINK value mismatch");
38static_assert(static_cast<int>(CPDF_Annot::Subtype::FREETEXT) ==
39 FPDF_ANNOT_FREETEXT,
40 "CPDF_Annot::FREETEXT value mismatch");
41static_assert(static_cast<int>(CPDF_Annot::Subtype::LINE) == FPDF_ANNOT_LINE,
42 "CPDF_Annot::LINE value mismatch");
43static_assert(static_cast<int>(CPDF_Annot::Subtype::SQUARE) ==
44 FPDF_ANNOT_SQUARE,
45 "CPDF_Annot::SQUARE value mismatch");
46static_assert(static_cast<int>(CPDF_Annot::Subtype::CIRCLE) ==
47 FPDF_ANNOT_CIRCLE,
48 "CPDF_Annot::CIRCLE value mismatch");
49static_assert(static_cast<int>(CPDF_Annot::Subtype::POLYGON) ==
50 FPDF_ANNOT_POLYGON,
51 "CPDF_Annot::POLYGON value mismatch");
52static_assert(static_cast<int>(CPDF_Annot::Subtype::POLYLINE) ==
53 FPDF_ANNOT_POLYLINE,
54 "CPDF_Annot::POLYLINE value mismatch");
55static_assert(static_cast<int>(CPDF_Annot::Subtype::HIGHLIGHT) ==
56 FPDF_ANNOT_HIGHLIGHT,
57 "CPDF_Annot::HIGHLIGHT value mismatch");
58static_assert(static_cast<int>(CPDF_Annot::Subtype::UNDERLINE) ==
59 FPDF_ANNOT_UNDERLINE,
60 "CPDF_Annot::UNDERLINE value mismatch");
61static_assert(static_cast<int>(CPDF_Annot::Subtype::SQUIGGLY) ==
62 FPDF_ANNOT_SQUIGGLY,
63 "CPDF_Annot::SQUIGGLY value mismatch");
64static_assert(static_cast<int>(CPDF_Annot::Subtype::STRIKEOUT) ==
65 FPDF_ANNOT_STRIKEOUT,
66 "CPDF_Annot::STRIKEOUT value mismatch");
67static_assert(static_cast<int>(CPDF_Annot::Subtype::STAMP) == FPDF_ANNOT_STAMP,
68 "CPDF_Annot::STAMP value mismatch");
69static_assert(static_cast<int>(CPDF_Annot::Subtype::CARET) == FPDF_ANNOT_CARET,
70 "CPDF_Annot::CARET value mismatch");
71static_assert(static_cast<int>(CPDF_Annot::Subtype::INK) == FPDF_ANNOT_INK,
72 "CPDF_Annot::INK value mismatch");
73static_assert(static_cast<int>(CPDF_Annot::Subtype::POPUP) == FPDF_ANNOT_POPUP,
74 "CPDF_Annot::POPUP value mismatch");
75static_assert(static_cast<int>(CPDF_Annot::Subtype::FILEATTACHMENT) ==
76 FPDF_ANNOT_FILEATTACHMENT,
77 "CPDF_Annot::FILEATTACHMENT value mismatch");
78static_assert(static_cast<int>(CPDF_Annot::Subtype::SOUND) == FPDF_ANNOT_SOUND,
79 "CPDF_Annot::SOUND value mismatch");
80static_assert(static_cast<int>(CPDF_Annot::Subtype::MOVIE) == FPDF_ANNOT_MOVIE,
81 "CPDF_Annot::MOVIE value mismatch");
82static_assert(static_cast<int>(CPDF_Annot::Subtype::WIDGET) ==
83 FPDF_ANNOT_WIDGET,
84 "CPDF_Annot::WIDGET value mismatch");
85static_assert(static_cast<int>(CPDF_Annot::Subtype::SCREEN) ==
86 FPDF_ANNOT_SCREEN,
87 "CPDF_Annot::SCREEN value mismatch");
88static_assert(static_cast<int>(CPDF_Annot::Subtype::PRINTERMARK) ==
89 FPDF_ANNOT_PRINTERMARK,
90 "CPDF_Annot::PRINTERMARK value mismatch");
91static_assert(static_cast<int>(CPDF_Annot::Subtype::TRAPNET) ==
92 FPDF_ANNOT_TRAPNET,
93 "CPDF_Annot::TRAPNET value mismatch");
94static_assert(static_cast<int>(CPDF_Annot::Subtype::WATERMARK) ==
95 FPDF_ANNOT_WATERMARK,
96 "CPDF_Annot::WATERMARK value mismatch");
97static_assert(static_cast<int>(CPDF_Annot::Subtype::THREED) ==
98 FPDF_ANNOT_THREED,
99 "CPDF_Annot::THREED value mismatch");
100static_assert(static_cast<int>(CPDF_Annot::Subtype::RICHMEDIA) ==
101 FPDF_ANNOT_RICHMEDIA,
102 "CPDF_Annot::RICHMEDIA value mismatch");
103static_assert(static_cast<int>(CPDF_Annot::Subtype::XFAWIDGET) ==
104 FPDF_ANNOT_XFAWIDGET,
105 "CPDF_Annot::XFAWIDGET value mismatch");
106
Jane Liu2e1a32b2017-07-06 12:01:25 -0400107// These checks ensure the consistency of dictionary value types across core/
108// and public/.
109static_assert(static_cast<int>(CPDF_Object::Type::BOOLEAN) ==
110 FPDF_OBJECT_BOOLEAN,
111 "CPDF_Object::BOOLEAN value mismatch");
112static_assert(static_cast<int>(CPDF_Object::Type::NUMBER) == FPDF_OBJECT_NUMBER,
113 "CPDF_Object::NUMBER value mismatch");
114static_assert(static_cast<int>(CPDF_Object::Type::STRING) == FPDF_OBJECT_STRING,
115 "CPDF_Object::STRING value mismatch");
116static_assert(static_cast<int>(CPDF_Object::Type::NAME) == FPDF_OBJECT_NAME,
117 "CPDF_Object::NAME value mismatch");
118static_assert(static_cast<int>(CPDF_Object::Type::ARRAY) == FPDF_OBJECT_ARRAY,
119 "CPDF_Object::ARRAY value mismatch");
120static_assert(static_cast<int>(CPDF_Object::Type::DICTIONARY) ==
121 FPDF_OBJECT_DICTIONARY,
122 "CPDF_Object::DICTIONARY value mismatch");
123static_assert(static_cast<int>(CPDF_Object::Type::STREAM) == FPDF_OBJECT_STREAM,
124 "CPDF_Object::STREAM value mismatch");
125static_assert(static_cast<int>(CPDF_Object::Type::NULLOBJ) ==
126 FPDF_OBJECT_NULLOBJ,
127 "CPDF_Object::NULLOBJ value mismatch");
128static_assert(static_cast<int>(CPDF_Object::Type::REFERENCE) ==
129 FPDF_OBJECT_REFERENCE,
130 "CPDF_Object::REFERENCE value mismatch");
131
Jane Liue10509a2017-06-20 16:47:41 -0400132class CPDF_AnnotContext {
133 public:
134 CPDF_AnnotContext(CPDF_Dictionary* pAnnotDict,
135 CPDF_Page* pPage,
136 CPDF_Stream* pStream)
137 : m_pAnnotDict(pAnnotDict), m_pPage(pPage) {
138 SetForm(pStream);
139 }
140 ~CPDF_AnnotContext() {}
141
142 bool HasForm() const { return !!m_pAnnotForm; }
143
144 void SetForm(CPDF_Stream* pStream) {
145 if (!pStream)
146 return;
147
Jane Liubaa7ff42017-06-29 19:18:23 -0400148 // Reset the annotation matrix to be the identity matrix, since the
149 // appearance stream already takes matrix into account.
150 pStream->GetDict()->SetMatrixFor("Matrix", CFX_Matrix());
151
Jane Liue10509a2017-06-20 16:47:41 -0400152 m_pAnnotForm = pdfium::MakeUnique<CPDF_Form>(
153 m_pPage->m_pDocument.Get(), m_pPage->m_pResources.Get(), pStream);
154 m_pAnnotForm->ParseContent(nullptr, nullptr, nullptr);
155 }
156
157 CPDF_Form* GetForm() const { return m_pAnnotForm.get(); }
158 CPDF_Dictionary* GetAnnotDict() const { return m_pAnnotDict.Get(); }
Jane Liubaa7ff42017-06-29 19:18:23 -0400159 CPDF_Page* GetPage() const { return m_pPage.Get(); }
Jane Liue10509a2017-06-20 16:47:41 -0400160
161 private:
162 std::unique_ptr<CPDF_Form> m_pAnnotForm;
163 CFX_UnownedPtr<CPDF_Dictionary> m_pAnnotDict;
164 CFX_UnownedPtr<CPDF_Page> m_pPage;
165};
166
Jane Liue10509a2017-06-20 16:47:41 -0400167CPDF_AnnotContext* CPDFAnnotContextFromFPDFAnnotation(FPDF_ANNOTATION annot) {
168 return static_cast<CPDF_AnnotContext*>(annot);
169}
170
Jane Liu06462752017-06-27 16:41:14 -0400171bool HasAPStream(const CPDF_Dictionary* pAnnotDict) {
172 return !!FPDFDOC_GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal);
173}
174
Jane Liu7a9a38b2017-07-11 13:47:37 -0400175void UpdateContentStream(CPDF_Form* pForm, CPDF_Stream* pStream) {
176 ASSERT(pForm);
177 ASSERT(pStream);
178
179 CPDF_PageContentGenerator generator(pForm);
180 std::ostringstream buf;
181 generator.ProcessPageObjects(&buf);
182 pStream->SetData(&buf);
183}
Jane Liu2e1a32b2017-07-06 12:01:25 -0400184
Jane Liue10509a2017-06-20 16:47:41 -0400185} // namespace
186
Jane Liu20eafda2017-06-07 10:33:24 -0400187DLLEXPORT FPDF_BOOL STDCALL
188FPDFAnnot_IsSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype) {
Jane Liubaa7ff42017-06-29 19:18:23 -0400189 // The supported subtypes must also be communicated in the user doc.
Jane Liu20eafda2017-06-07 10:33:24 -0400190 return subtype == FPDF_ANNOT_CIRCLE || subtype == FPDF_ANNOT_HIGHLIGHT ||
191 subtype == FPDF_ANNOT_INK || subtype == FPDF_ANNOT_POPUP ||
192 subtype == FPDF_ANNOT_SQUARE || subtype == FPDF_ANNOT_SQUIGGLY ||
Jane Liubaa7ff42017-06-29 19:18:23 -0400193 subtype == FPDF_ANNOT_STAMP || subtype == FPDF_ANNOT_STRIKEOUT ||
194 subtype == FPDF_ANNOT_TEXT || subtype == FPDF_ANNOT_UNDERLINE;
Jane Liu20eafda2017-06-07 10:33:24 -0400195}
196
Jane Liud60e9ad2017-06-26 11:28:36 -0400197DLLEXPORT FPDF_ANNOTATION STDCALL
198FPDFPage_CreateAnnot(FPDF_PAGE page, FPDF_ANNOTATION_SUBTYPE subtype) {
Jane Liu20eafda2017-06-07 10:33:24 -0400199 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
200 if (!pPage || !FPDFAnnot_IsSupportedSubtype(subtype))
Jane Liud60e9ad2017-06-26 11:28:36 -0400201 return nullptr;
Jane Liu20eafda2017-06-07 10:33:24 -0400202
203 auto pDict = pdfium::MakeUnique<CPDF_Dictionary>(
204 pPage->m_pDocument->GetByteStringPool());
205 pDict->SetNewFor<CPDF_Name>("Type", "Annot");
206 pDict->SetNewFor<CPDF_Name>("Subtype",
207 CPDF_Annot::AnnotSubtypeToString(
208 static_cast<CPDF_Annot::Subtype>(subtype)));
Jane Liud60e9ad2017-06-26 11:28:36 -0400209 auto pNewAnnot =
210 pdfium::MakeUnique<CPDF_AnnotContext>(pDict.get(), pPage, nullptr);
Jane Liu20eafda2017-06-07 10:33:24 -0400211
212 CPDF_Array* pAnnotList = pPage->m_pFormDict->GetArrayFor("Annots");
213 if (!pAnnotList)
214 pAnnotList = pPage->m_pFormDict->SetNewFor<CPDF_Array>("Annots");
215
216 pAnnotList->Add(std::move(pDict));
Jane Liud60e9ad2017-06-26 11:28:36 -0400217 return pNewAnnot.release();
Jane Liu20eafda2017-06-07 10:33:24 -0400218}
219
Jane Liu4fd9a472017-06-01 18:56:09 -0400220DLLEXPORT int STDCALL FPDFPage_GetAnnotCount(FPDF_PAGE page) {
221 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
222 if (!pPage || !pPage->m_pFormDict)
223 return 0;
Jane Liu20eafda2017-06-07 10:33:24 -0400224
Jane Liu4fd9a472017-06-01 18:56:09 -0400225 CPDF_Array* pAnnots = pPage->m_pFormDict->GetArrayFor("Annots");
226 return pAnnots ? pAnnots->GetCount() : 0;
227}
228
Jane Liud60e9ad2017-06-26 11:28:36 -0400229DLLEXPORT FPDF_ANNOTATION STDCALL FPDFPage_GetAnnot(FPDF_PAGE page, int index) {
Jane Liu4fd9a472017-06-01 18:56:09 -0400230 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
Jane Liud60e9ad2017-06-26 11:28:36 -0400231 if (!pPage || !pPage->m_pFormDict || index < 0)
232 return nullptr;
Jane Liu20eafda2017-06-07 10:33:24 -0400233
Jane Liu4fd9a472017-06-01 18:56:09 -0400234 CPDF_Array* pAnnots = pPage->m_pFormDict->GetArrayFor("Annots");
235 if (!pAnnots || static_cast<size_t>(index) >= pAnnots->GetCount())
Jane Liud60e9ad2017-06-26 11:28:36 -0400236 return nullptr;
Jane Liu4fd9a472017-06-01 18:56:09 -0400237
238 CPDF_Dictionary* pDict = ToDictionary(pAnnots->GetDirectObjectAt(index));
Jane Liue10509a2017-06-20 16:47:41 -0400239 auto pNewAnnot = pdfium::MakeUnique<CPDF_AnnotContext>(pDict, pPage, nullptr);
Jane Liud60e9ad2017-06-26 11:28:36 -0400240 return pNewAnnot.release();
Jane Liue10509a2017-06-20 16:47:41 -0400241}
242
243DLLEXPORT void STDCALL FPDFPage_CloseAnnot(FPDF_ANNOTATION annot) {
244 delete CPDFAnnotContextFromFPDFAnnotation(annot);
Jane Liu4fd9a472017-06-01 18:56:09 -0400245}
246
Jane Liu8ce58f52017-06-29 13:40:22 -0400247DLLEXPORT FPDF_BOOL STDCALL FPDFPage_RemoveAnnot(FPDF_PAGE page, int index) {
248 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
249 if (!pPage || !pPage->m_pFormDict || index < 0)
250 return false;
251
252 CPDF_Array* pAnnots = pPage->m_pFormDict->GetArrayFor("Annots");
253 if (!pAnnots || static_cast<size_t>(index) >= pAnnots->GetCount())
254 return false;
255
256 pAnnots->RemoveAt(index);
257 return true;
258}
259
Jane Liu4fd9a472017-06-01 18:56:09 -0400260DLLEXPORT FPDF_ANNOTATION_SUBTYPE STDCALL
261FPDFAnnot_GetSubtype(FPDF_ANNOTATION annot) {
Jane Liud60e9ad2017-06-26 11:28:36 -0400262 if (!annot)
263 return FPDF_ANNOT_UNKNOWN;
264
Jane Liue10509a2017-06-20 16:47:41 -0400265 CPDF_Dictionary* pAnnotDict =
266 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liu4fd9a472017-06-01 18:56:09 -0400267 if (!pAnnotDict)
268 return FPDF_ANNOT_UNKNOWN;
Jane Liu20eafda2017-06-07 10:33:24 -0400269
Jane Liu4fd9a472017-06-01 18:56:09 -0400270 return static_cast<FPDF_ANNOTATION_SUBTYPE>(
271 CPDF_Annot::StringToAnnotSubtype(pAnnotDict->GetStringFor("Subtype")));
272}
273
Jane Liu7a9a38b2017-07-11 13:47:37 -0400274DLLEXPORT FPDF_BOOL STDCALL
275FPDFAnnot_IsObjectSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype) {
276 // The supported subtypes must also be communicated in the user doc.
277 return subtype == FPDF_ANNOT_INK || subtype == FPDF_ANNOT_STAMP;
278}
279
Jane Liu36567742017-07-06 11:13:35 -0400280DLLEXPORT FPDF_BOOL STDCALL FPDFAnnot_UpdateObject(FPDF_ANNOTATION annot,
281 FPDF_PAGEOBJECT obj) {
Jane Liubaa7ff42017-06-29 19:18:23 -0400282 CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
Jane Liu36567742017-07-06 11:13:35 -0400283 CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(obj);
284 if (!pAnnot || !pAnnot->GetAnnotDict() || !pAnnot->HasForm() || !pObj)
Jane Liubaa7ff42017-06-29 19:18:23 -0400285 return false;
286
287 // Check that the annotation type is supported by this method.
Jane Liu7a9a38b2017-07-11 13:47:37 -0400288 if (!FPDFAnnot_IsObjectSupportedSubtype(FPDFAnnot_GetSubtype(annot)))
Jane Liubaa7ff42017-06-29 19:18:23 -0400289 return false;
290
291 // Check that the annotation already has an appearance stream, since an
Jane Liu36567742017-07-06 11:13:35 -0400292 // existing object is to be updated.
Jane Liubaa7ff42017-06-29 19:18:23 -0400293 CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(pAnnot->GetAnnotDict(),
294 CPDF_Annot::AppearanceMode::Normal);
295 if (!pStream)
296 return false;
297
Jane Liu36567742017-07-06 11:13:35 -0400298 // Check that the object is already in this annotation's object list.
Jane Liu7a9a38b2017-07-11 13:47:37 -0400299 CPDF_Form* pForm = pAnnot->GetForm();
300 CPDF_PageObjectList* pObjList = pForm->GetPageObjectList();
Jane Liu36567742017-07-06 11:13:35 -0400301 auto it =
302 std::find_if(pObjList->begin(), pObjList->end(),
303 [pObj](const std::unique_ptr<CPDF_PageObject>& candidate) {
304 return candidate.get() == pObj;
305 });
Jane Liubaa7ff42017-06-29 19:18:23 -0400306 if (it == pObjList->end())
307 return false;
308
309 // Update the content stream data in the annotation's AP stream.
Jane Liu7a9a38b2017-07-11 13:47:37 -0400310 UpdateContentStream(pForm, pStream);
Jane Liubaa7ff42017-06-29 19:18:23 -0400311 return true;
312}
313
Jane Liu36567742017-07-06 11:13:35 -0400314DLLEXPORT FPDF_BOOL STDCALL FPDFAnnot_AppendObject(FPDF_ANNOTATION annot,
315 FPDF_PAGEOBJECT obj) {
Jane Liubaa7ff42017-06-29 19:18:23 -0400316 CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
Jane Liu36567742017-07-06 11:13:35 -0400317 CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(obj);
318 if (!pAnnot || !pObj)
Jane Liubaa7ff42017-06-29 19:18:23 -0400319 return false;
320
321 CPDF_Dictionary* pAnnotDict = pAnnot->GetAnnotDict();
322 CPDF_Page* pPage = pAnnot->GetPage();
323 if (!pAnnotDict || !pPage)
324 return false;
325
326 // Check that the annotation type is supported by this method.
Jane Liu7a9a38b2017-07-11 13:47:37 -0400327 if (!FPDFAnnot_IsObjectSupportedSubtype(FPDFAnnot_GetSubtype(annot)))
Jane Liubaa7ff42017-06-29 19:18:23 -0400328 return false;
329
330 // If the annotation does not have an AP stream yet, generate and set it.
331 CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(pAnnot->GetAnnotDict(),
332 CPDF_Annot::AppearanceMode::Normal);
333 if (!pStream) {
334 auto pExtGStateDict =
335 CPVT_GenerateAP::GenerateExtGStateDict(*pAnnotDict, "GS", "Normal");
336 auto pResourceDict = CPVT_GenerateAP::GenerateResourceDict(
337 pPage->m_pDocument.Get(), std::move(pExtGStateDict), nullptr);
338 std::ostringstream sStream;
339 CPVT_GenerateAP::GenerateAndSetAPDict(pPage->m_pDocument.Get(), pAnnotDict,
340 &sStream, std::move(pResourceDict),
341 false);
342 pStream =
343 FPDFDOC_GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal);
344 if (!pStream)
345 return false;
346 }
347
348 // Get the annotation's corresponding form object for parsing its AP stream.
349 if (!pAnnot->HasForm())
350 pAnnot->SetForm(pStream);
351
Jane Liu36567742017-07-06 11:13:35 -0400352 // Check that the object did not come from the same annotation. If this check
353 // succeeds, then it is assumed that the object came from
354 // FPDFPageObj_CreateNew{Path|Rect}() or FPDFPageObj_New{Text|Image}Obj().
355 // Note that an object that came from a different annotation must not be
356 // passed here, since an object cannot belong to more than one annotation.
Jane Liu7a9a38b2017-07-11 13:47:37 -0400357 CPDF_Form* pForm = pAnnot->GetForm();
Jane Liubaa7ff42017-06-29 19:18:23 -0400358 CPDF_PageObjectList* pObjList = pForm->GetPageObjectList();
Jane Liu36567742017-07-06 11:13:35 -0400359 auto it =
360 std::find_if(pObjList->begin(), pObjList->end(),
361 [pObj](const std::unique_ptr<CPDF_PageObject>& candidate) {
362 return candidate.get() == pObj;
363 });
Jane Liubaa7ff42017-06-29 19:18:23 -0400364 if (it != pObjList->end())
365 return false;
366
Jane Liu36567742017-07-06 11:13:35 -0400367 // Append the object to the object list.
368 std::unique_ptr<CPDF_PageObject> pPageObjHolder(pObj);
Jane Liubaa7ff42017-06-29 19:18:23 -0400369 pObjList->push_back(std::move(pPageObjHolder));
370
371 // Set the content stream data in the annotation's AP stream.
Jane Liu7a9a38b2017-07-11 13:47:37 -0400372 UpdateContentStream(pForm, pStream);
Jane Liubaa7ff42017-06-29 19:18:23 -0400373 return true;
374}
375
Jane Liu36567742017-07-06 11:13:35 -0400376DLLEXPORT int STDCALL FPDFAnnot_GetObjectCount(FPDF_ANNOTATION annot) {
Jane Liubaa7ff42017-06-29 19:18:23 -0400377 CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
Jane Liu36567742017-07-06 11:13:35 -0400378 if (!pAnnot || !pAnnot->GetAnnotDict())
Jane Liubaa7ff42017-06-29 19:18:23 -0400379 return 0;
380
381 if (!pAnnot->HasForm()) {
382 CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(
383 pAnnot->GetAnnotDict(), CPDF_Annot::AppearanceMode::Normal);
384 if (!pStream)
385 return 0;
386
387 pAnnot->SetForm(pStream);
388 }
Jane Liu57f228d2017-07-13 18:10:30 -0400389 return pdfium::CollectionSize<int>(*pAnnot->GetForm()->GetPageObjectList());
Jane Liubaa7ff42017-06-29 19:18:23 -0400390}
391
Jane Liu36567742017-07-06 11:13:35 -0400392DLLEXPORT FPDF_PAGEOBJECT STDCALL FPDFAnnot_GetObject(FPDF_ANNOTATION annot,
393 int index) {
Jane Liubaa7ff42017-06-29 19:18:23 -0400394 CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
Jane Liu36567742017-07-06 11:13:35 -0400395 if (!pAnnot || !pAnnot->GetAnnotDict() || index < 0)
Jane Liubaa7ff42017-06-29 19:18:23 -0400396 return nullptr;
397
398 if (!pAnnot->HasForm()) {
399 CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(
400 pAnnot->GetAnnotDict(), CPDF_Annot::AppearanceMode::Normal);
401 if (!pStream)
402 return nullptr;
403
404 pAnnot->SetForm(pStream);
405 }
406
Jane Liu36567742017-07-06 11:13:35 -0400407 return pAnnot->GetForm()->GetPageObjectList()->GetPageObjectByIndex(index);
Jane Liubaa7ff42017-06-29 19:18:23 -0400408}
409
Jane Liu7a9a38b2017-07-11 13:47:37 -0400410DLLEXPORT FPDF_BOOL STDCALL FPDFAnnot_RemoveObject(FPDF_ANNOTATION annot,
411 int index) {
412 CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
413 if (!pAnnot || !pAnnot->GetAnnotDict() || !pAnnot->HasForm() || index < 0)
414 return false;
415
416 // Check that the annotation type is supported by this method.
417 if (!FPDFAnnot_IsObjectSupportedSubtype(FPDFAnnot_GetSubtype(annot)))
418 return false;
419
420 // Check that the annotation already has an appearance stream, since an
421 // existing object is to be deleted.
422 CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(pAnnot->GetAnnotDict(),
423 CPDF_Annot::AppearanceMode::Normal);
424 if (!pStream)
425 return false;
426
427 CPDF_PageObjectList* pObjList = pAnnot->GetForm()->GetPageObjectList();
428 if (static_cast<size_t>(index) >= pObjList->size())
429 return false;
430
431 pObjList->erase(pObjList->begin() + index);
432 UpdateContentStream(pAnnot->GetForm(), pStream);
433 return true;
434}
435
Jane Liu20eafda2017-06-07 10:33:24 -0400436DLLEXPORT FPDF_BOOL STDCALL FPDFAnnot_SetColor(FPDF_ANNOTATION annot,
437 FPDFANNOT_COLORTYPE type,
438 unsigned int R,
439 unsigned int G,
440 unsigned int B,
441 unsigned int A) {
Jane Liud60e9ad2017-06-26 11:28:36 -0400442 if (!annot || R > 255 || G > 255 || B > 255 || A > 255)
443 return false;
444
Jane Liue10509a2017-06-20 16:47:41 -0400445 CPDF_Dictionary* pAnnotDict =
446 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liud60e9ad2017-06-26 11:28:36 -0400447 if (!pAnnotDict)
Jane Liu20eafda2017-06-07 10:33:24 -0400448 return false;
449
Jane Liu06462752017-06-27 16:41:14 -0400450 // For annotations with their appearance streams already defined, the path
451 // stream's own color definitions take priority over the annotation color
452 // definitions set by this method, hence this method will simply fail.
453 if (HasAPStream(pAnnotDict))
454 return false;
455
Jane Liu20eafda2017-06-07 10:33:24 -0400456 // Set the opacity of the annotation.
457 pAnnotDict->SetNewFor<CPDF_Number>("CA", A / 255.f);
458
459 // Set the color of the annotation.
460 CFX_ByteString key = type == FPDFANNOT_COLORTYPE_InteriorColor ? "IC" : "C";
461 CPDF_Array* pColor = pAnnotDict->GetArrayFor(key);
462 if (pColor)
Lei Zhang59c1ac02017-06-09 11:04:41 -0700463 pColor->Clear();
Jane Liu20eafda2017-06-07 10:33:24 -0400464 else
465 pColor = pAnnotDict->SetNewFor<CPDF_Array>(key);
466
467 pColor->AddNew<CPDF_Number>(R / 255.f);
468 pColor->AddNew<CPDF_Number>(G / 255.f);
469 pColor->AddNew<CPDF_Number>(B / 255.f);
470
471 return true;
472}
473
Jane Liu4fd9a472017-06-01 18:56:09 -0400474DLLEXPORT FPDF_BOOL STDCALL FPDFAnnot_GetColor(FPDF_ANNOTATION annot,
475 FPDFANNOT_COLORTYPE type,
476 unsigned int* R,
477 unsigned int* G,
478 unsigned int* B,
479 unsigned int* A) {
Jane Liud60e9ad2017-06-26 11:28:36 -0400480 if (!annot || !R || !G || !B || !A)
481 return false;
482
Jane Liue10509a2017-06-20 16:47:41 -0400483 CPDF_Dictionary* pAnnotDict =
484 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liud60e9ad2017-06-26 11:28:36 -0400485 if (!pAnnotDict)
Jane Liu4fd9a472017-06-01 18:56:09 -0400486 return false;
487
Jane Liu06462752017-06-27 16:41:14 -0400488 // For annotations with their appearance streams already defined, the path
489 // stream's own color definitions take priority over the annotation color
490 // definitions retrieved by this method, hence this method will simply fail.
491 if (HasAPStream(pAnnotDict))
492 return false;
493
Jane Liu4fd9a472017-06-01 18:56:09 -0400494 CPDF_Array* pColor = pAnnotDict->GetArrayFor(
495 type == FPDFANNOT_COLORTYPE_InteriorColor ? "IC" : "C");
496 *A =
497 (pAnnotDict->KeyExist("CA") ? pAnnotDict->GetNumberFor("CA") : 1) * 255.f;
498 if (!pColor) {
499 // Use default color. The default colors must be consistent with the ones
500 // used to generate AP. See calls to GetColorStringWithDefault() in
501 // CPVT_GenerateAP::Generate*AP().
502 if (pAnnotDict->GetStringFor("Subtype") == "Highlight") {
503 *R = 255;
504 *G = 255;
505 *B = 0;
506 } else {
507 *R = 0;
508 *G = 0;
509 *B = 0;
510 }
511 return true;
512 }
513 CPVT_Color color = CPVT_Color::ParseColor(*pColor);
514 switch (color.nColorType) {
515 case CPVT_Color::kRGB:
516 *R = color.fColor1 * 255.f;
517 *G = color.fColor2 * 255.f;
518 *B = color.fColor3 * 255.f;
519 break;
520 case CPVT_Color::kGray:
521 *R = 255.f * color.fColor1;
522 *G = 255.f * color.fColor1;
523 *B = 255.f * color.fColor1;
524 break;
525 case CPVT_Color::kCMYK:
526 *R = 255.f * (1 - color.fColor1) * (1 - color.fColor4);
527 *G = 255.f * (1 - color.fColor2) * (1 - color.fColor4);
528 *B = 255.f * (1 - color.fColor3) * (1 - color.fColor4);
529 break;
530 case CPVT_Color::kTransparent:
531 *R = 0;
532 *G = 0;
533 *B = 0;
534 break;
535 }
536 return true;
537}
538
539DLLEXPORT FPDF_BOOL STDCALL
540FPDFAnnot_HasAttachmentPoints(FPDF_ANNOTATION annot) {
541 if (!annot)
542 return false;
Jane Liu20eafda2017-06-07 10:33:24 -0400543
Jane Liu4fd9a472017-06-01 18:56:09 -0400544 FPDF_ANNOTATION_SUBTYPE subtype = FPDFAnnot_GetSubtype(annot);
545 return subtype == FPDF_ANNOT_LINK || subtype == FPDF_ANNOT_HIGHLIGHT ||
546 subtype == FPDF_ANNOT_UNDERLINE || subtype == FPDF_ANNOT_SQUIGGLY ||
547 subtype == FPDF_ANNOT_STRIKEOUT;
548}
549
550DLLEXPORT FPDF_BOOL STDCALL
Jane Liu20eafda2017-06-07 10:33:24 -0400551FPDFAnnot_SetAttachmentPoints(FPDF_ANNOTATION annot,
Jane Liu06462752017-06-27 16:41:14 -0400552 const FS_QUADPOINTSF* quadPoints) {
553 if (!annot || !quadPoints || !FPDFAnnot_HasAttachmentPoints(annot))
Jane Liu20eafda2017-06-07 10:33:24 -0400554 return false;
555
Jane Liue10509a2017-06-20 16:47:41 -0400556 CPDF_Dictionary* pAnnotDict =
557 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liud60e9ad2017-06-26 11:28:36 -0400558 if (!pAnnotDict)
559 return false;
560
Jane Liu06462752017-06-27 16:41:14 -0400561 // Update the "QuadPoints" entry in the annotation dictionary.
Jane Liu20eafda2017-06-07 10:33:24 -0400562 CPDF_Array* pQuadPoints = pAnnotDict->GetArrayFor("QuadPoints");
563 if (pQuadPoints)
Lei Zhang59c1ac02017-06-09 11:04:41 -0700564 pQuadPoints->Clear();
Jane Liu20eafda2017-06-07 10:33:24 -0400565 else
566 pQuadPoints = pAnnotDict->SetNewFor<CPDF_Array>("QuadPoints");
567
Jane Liu06462752017-06-27 16:41:14 -0400568 pQuadPoints->AddNew<CPDF_Number>(quadPoints->x1);
569 pQuadPoints->AddNew<CPDF_Number>(quadPoints->y1);
570 pQuadPoints->AddNew<CPDF_Number>(quadPoints->x2);
571 pQuadPoints->AddNew<CPDF_Number>(quadPoints->y2);
572 pQuadPoints->AddNew<CPDF_Number>(quadPoints->x3);
573 pQuadPoints->AddNew<CPDF_Number>(quadPoints->y3);
574 pQuadPoints->AddNew<CPDF_Number>(quadPoints->x4);
575 pQuadPoints->AddNew<CPDF_Number>(quadPoints->y4);
576
577 // If the annotation's appearance stream is defined, and the new quadpoints
578 // defines a bigger bounding box than the appearance stream currently
579 // specifies, then update the "BBox" entry in the AP dictionary too, since it
580 // comes from annotation dictionary's "QuadPoints" entry.
581 CPDF_Stream* pStream =
582 FPDFDOC_GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal);
583 if (pStream) {
584 CFX_FloatRect newRect = CPDF_Annot::RectFromQuadPoints(pAnnotDict);
585 if (newRect.Contains(pStream->GetDict()->GetRectFor("BBox")))
586 pStream->GetDict()->SetRectFor("BBox", newRect);
587 }
Jane Liu20eafda2017-06-07 10:33:24 -0400588 return true;
589}
590
Jane Liud60e9ad2017-06-26 11:28:36 -0400591DLLEXPORT FS_QUADPOINTSF STDCALL
592FPDFAnnot_GetAttachmentPoints(FPDF_ANNOTATION annot) {
593 if (!annot || !FPDFAnnot_HasAttachmentPoints(annot))
594 return FS_QUADPOINTSF();
Jane Liu20eafda2017-06-07 10:33:24 -0400595
Jane Liud60e9ad2017-06-26 11:28:36 -0400596 CPDF_Dictionary* pAnnotDict =
597 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
598 if (!pAnnotDict)
599 return FS_QUADPOINTSF();
600
Jane Liu06462752017-06-27 16:41:14 -0400601 // If the annotation's appearance stream is defined, then retrieve the
602 // quadpoints defined by the "BBox" entry in the AP dictionary, since its
603 // "BBox" entry comes from annotation dictionary's "QuadPoints" entry, but
604 // takes priority over "QuadPoints" when rendering. Otherwise, retrieve
605 // the "Quadpoints" entry from the annotation dictionary.
606 CPDF_Array* pArray;
Jane Liud60e9ad2017-06-26 11:28:36 -0400607 FS_QUADPOINTSF quadPoints;
Jane Liu06462752017-06-27 16:41:14 -0400608 CPDF_Stream* pStream =
609 FPDFDOC_GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal);
610 if (pStream) {
611 pArray = pStream->GetDict()->GetArrayFor("BBox");
612 if (!pArray)
613 return FS_QUADPOINTSF();
614
615 // Convert the BBox array into quadpoint coordinates. BBox array follows the
616 // order of a rectangle array: (left, bottom, right, up); and quadpoints
617 // follows the following order: (top-left vertex, top-right vertex, bottom-
618 // left vertex, bottom-right vertex).
619 quadPoints.x1 = pArray->GetNumberAt(0);
620 quadPoints.y1 = pArray->GetNumberAt(3);
621 quadPoints.x2 = pArray->GetNumberAt(2);
622 quadPoints.y2 = pArray->GetNumberAt(3);
623 quadPoints.x3 = pArray->GetNumberAt(0);
624 quadPoints.y3 = pArray->GetNumberAt(1);
625 quadPoints.x4 = pArray->GetNumberAt(2);
626 quadPoints.y4 = pArray->GetNumberAt(1);
627 } else {
628 pArray = pAnnotDict->GetArrayFor("QuadPoints");
629 if (!pArray)
630 return FS_QUADPOINTSF();
631
632 quadPoints.x1 = pArray->GetNumberAt(0);
633 quadPoints.y1 = pArray->GetNumberAt(1);
634 quadPoints.x2 = pArray->GetNumberAt(2);
635 quadPoints.y2 = pArray->GetNumberAt(3);
636 quadPoints.x3 = pArray->GetNumberAt(4);
637 quadPoints.y3 = pArray->GetNumberAt(5);
638 quadPoints.x4 = pArray->GetNumberAt(6);
639 quadPoints.y4 = pArray->GetNumberAt(7);
640 }
Jane Liud60e9ad2017-06-26 11:28:36 -0400641 return quadPoints;
Jane Liu4fd9a472017-06-01 18:56:09 -0400642}
643
Jane Liu20eafda2017-06-07 10:33:24 -0400644DLLEXPORT FPDF_BOOL STDCALL FPDFAnnot_SetRect(FPDF_ANNOTATION annot,
Jane Liu06462752017-06-27 16:41:14 -0400645 const FS_RECTF* rect) {
646 if (!annot || !rect)
Jane Liud60e9ad2017-06-26 11:28:36 -0400647 return false;
648
Jane Liue10509a2017-06-20 16:47:41 -0400649 CPDF_Dictionary* pAnnotDict =
650 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liu20eafda2017-06-07 10:33:24 -0400651 if (!pAnnotDict)
652 return false;
653
Jane Liu06462752017-06-27 16:41:14 -0400654 CFX_FloatRect newRect(rect->left, rect->bottom, rect->right, rect->top);
Jane Liu20eafda2017-06-07 10:33:24 -0400655
Jane Liu06462752017-06-27 16:41:14 -0400656 // Update the "Rect" entry in the annotation dictionary.
657 pAnnotDict->SetRectFor("Rect", newRect);
658
659 // If the annotation's appearance stream is defined, the annotation is of a
660 // type that does not have quadpoints, and the new rectangle is bigger than
661 // the current bounding box, then update the "BBox" entry in the AP
662 // dictionary too, since its "BBox" entry comes from annotation dictionary's
663 // "Rect" entry.
664 if (FPDFAnnot_HasAttachmentPoints(annot))
665 return true;
666
667 CPDF_Stream* pStream =
668 FPDFDOC_GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal);
669 if (pStream && newRect.Contains(pStream->GetDict()->GetRectFor("BBox")))
670 pStream->GetDict()->SetRectFor("BBox", newRect);
Jane Liu20eafda2017-06-07 10:33:24 -0400671 return true;
672}
673
Jane Liud60e9ad2017-06-26 11:28:36 -0400674DLLEXPORT FS_RECTF STDCALL FPDFAnnot_GetRect(FPDF_ANNOTATION annot) {
675 if (!annot)
676 return FS_RECTF();
677
Jane Liue10509a2017-06-20 16:47:41 -0400678 CPDF_Dictionary* pAnnotDict =
679 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liud60e9ad2017-06-26 11:28:36 -0400680 if (!pAnnotDict)
681 return FS_RECTF();
Jane Liu20eafda2017-06-07 10:33:24 -0400682
Jane Liu06462752017-06-27 16:41:14 -0400683 // If the annotation's appearance stream is defined and the annotation is of
684 // a type that does not have quadpoints, then retrieve the rectangle defined
685 // by the "BBox" entry in the AP dictionary, since its "BBox" entry comes
686 // from annotation dictionary's "Rect" entry, but takes priority over "Rect"
687 // when rendering. Otherwise, retrieve the "Rect" entry from the annotation
688 // dictionary.
689 CFX_FloatRect rt;
690 CPDF_Stream* pStream =
691 FPDFDOC_GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal);
692 if (!pStream || FPDFAnnot_HasAttachmentPoints(annot))
693 rt = pAnnotDict->GetRectFor("Rect");
694 else
695 rt = pStream->GetDict()->GetRectFor("BBox");
Jane Liu20eafda2017-06-07 10:33:24 -0400696
Jane Liud60e9ad2017-06-26 11:28:36 -0400697 FS_RECTF rect;
698 rect.left = rt.left;
699 rect.bottom = rt.bottom;
700 rect.right = rt.right;
701 rect.top = rt.top;
702 return rect;
Jane Liu4fd9a472017-06-01 18:56:09 -0400703}
704
Jane Liu2e1a32b2017-07-06 12:01:25 -0400705DLLEXPORT FPDF_BOOL STDCALL FPDFAnnot_HasKey(FPDF_ANNOTATION annot,
706 FPDF_WIDESTRING key) {
Jane Liud60e9ad2017-06-26 11:28:36 -0400707 if (!annot)
708 return false;
709
Jane Liue10509a2017-06-20 16:47:41 -0400710 CPDF_Dictionary* pAnnotDict =
711 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liu20eafda2017-06-07 10:33:24 -0400712 if (!pAnnotDict)
713 return false;
714
Jane Liu2e1a32b2017-07-06 12:01:25 -0400715 return pAnnotDict->KeyExist(CFXByteStringFromFPDFWideString(key));
716}
717
718DLLEXPORT FPDF_OBJECT_TYPE STDCALL FPDFAnnot_GetValueType(FPDF_ANNOTATION annot,
719 FPDF_WIDESTRING key) {
720 if (!FPDFAnnot_HasKey(annot, key))
721 return FPDF_OBJECT_UNKNOWN;
722
723 CPDF_Object* pObj =
724 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict()->GetObjectFor(
725 CFXByteStringFromFPDFWideString(key));
726 if (!pObj)
727 return FPDF_OBJECT_UNKNOWN;
728
729 return pObj->GetType();
730}
731
732DLLEXPORT FPDF_BOOL STDCALL FPDFAnnot_SetStringValue(FPDF_ANNOTATION annot,
733 FPDF_WIDESTRING key,
734 FPDF_WIDESTRING value) {
735 if (!annot)
736 return false;
737
738 CPDF_Dictionary* pAnnotDict =
739 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
740 if (!pAnnotDict)
741 return false;
742
743 pAnnotDict->SetNewFor<CPDF_String>(CFXByteStringFromFPDFWideString(key),
744 CFXByteStringFromFPDFWideString(value),
745 false);
Jane Liu20eafda2017-06-07 10:33:24 -0400746 return true;
747}
748
Jane Liu2e1a32b2017-07-06 12:01:25 -0400749DLLEXPORT unsigned long STDCALL FPDFAnnot_GetStringValue(FPDF_ANNOTATION annot,
750 FPDF_WIDESTRING key,
751 void* buffer,
752 unsigned long buflen) {
Jane Liud60e9ad2017-06-26 11:28:36 -0400753 if (!annot)
754 return 0;
755
Jane Liue10509a2017-06-20 16:47:41 -0400756 CPDF_Dictionary* pAnnotDict =
757 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liu4fd9a472017-06-01 18:56:09 -0400758 if (!pAnnotDict)
759 return 0;
Jane Liu20eafda2017-06-07 10:33:24 -0400760
Jane Liu18ae06d2017-07-18 10:15:16 -0400761 return Utf16EncodeMaybeCopyAndReturnLength(
762 pAnnotDict->GetUnicodeTextFor(CFXByteStringFromFPDFWideString(key)),
763 buffer, buflen);
Jane Liu4fd9a472017-06-01 18:56:09 -0400764}
Jane Liub137e752017-07-05 15:04:33 -0400765
766DLLEXPORT int STDCALL FPDFAnnot_GetFlags(FPDF_ANNOTATION annot) {
767 if (!annot)
768 return FPDF_ANNOT_FLAG_NONE;
769
770 CPDF_Dictionary* pAnnotDict =
771 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
772 if (!pAnnotDict)
773 return FPDF_ANNOT_FLAG_NONE;
774
775 return pAnnotDict->GetIntegerFor("F");
776}
777
778DLLEXPORT FPDF_BOOL STDCALL FPDFAnnot_SetFlags(FPDF_ANNOTATION annot,
779 int flags) {
780 if (!annot)
781 return false;
782
783 CPDF_Dictionary* pAnnotDict =
784 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
785 if (!pAnnotDict)
786 return false;
787
788 pAnnotDict->SetNewFor<CPDF_Number>("F", flags);
789 return true;
790}
Diana Gage7e0c05d2017-07-19 17:33:33 -0700791
792DLLEXPORT int STDCALL FPDFAnnot_GetFormFieldFlags(FPDF_PAGE page,
793 FPDF_ANNOTATION annot) {
794 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
795 if (!pPage || !annot)
796 return FPDF_FORMFLAG_NONE;
797
798 CPDF_Dictionary* pAnnotDict =
799 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
800 if (!pAnnotDict)
801 return FPDF_FORMFLAG_NONE;
802
803 CPDF_InterForm interform(pPage->m_pDocument.Get());
804 CPDF_FormField* pFormField = interform.GetFieldByDict(pAnnotDict);
805 return pFormField ? pFormField->GetFieldFlags() : FPDF_FORMFLAG_NONE;
806}
Diana Gage40870db2017-07-19 18:16:03 -0700807
808DLLEXPORT FPDF_ANNOTATION STDCALL
809FPDFAnnot_GetFormFieldAtPoint(FPDF_FORMHANDLE hHandle,
810 FPDF_PAGE page,
811 double page_x,
812 double page_y) {
813 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
814 if (!hHandle || !pPage)
815 return nullptr;
816
817 CPDF_InterForm interform(pPage->m_pDocument.Get());
818 int annot_index = -1;
819 CPDF_FormControl* pFormCtrl = interform.GetControlAtPoint(
820 pPage, CFX_PointF(static_cast<float>(page_x), static_cast<float>(page_y)),
821 &annot_index);
822 if (!pFormCtrl || annot_index == -1)
823 return nullptr;
824 return FPDFPage_GetAnnot(page, annot_index);
825}