blob: 09bf42af92d4e4bfe167b150dfb5b0af9dabcab6 [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_generateap.h"
Dan Sinclair8e7f9322017-10-16 11:35:42 -040024#include "core/fxge/cfx_color.h"
Jane Liu4fd9a472017-06-01 18:56:09 -040025#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);
Lei Zhangaf59cf12017-08-28 18:09:38 -0700154 m_pAnnotForm->ParseContent();
Jane Liue10509a2017-06-20 16:47:41 -0400155 }
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;
Dan Sinclairaee0db02017-09-21 16:53:58 -0400163 UnownedPtr<CPDF_Dictionary> m_pAnnotDict;
164 UnownedPtr<CPDF_Page> m_pPage;
Jane Liue10509a2017-06-20 16:47:41 -0400165};
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);
Artem Strygin90555e02017-07-28 19:41:59 +0300182 pStream->SetDataAndRemoveFilter(&buf);
Jane Liu7a9a38b2017-07-11 13:47:37 -0400183}
Jane Liu2e1a32b2017-07-06 12:01:25 -0400184
Jane Liue10509a2017-06-20 16:47:41 -0400185} // namespace
186
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400187FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
Jane Liu20eafda2017-06-07 10:33:24 -0400188FPDFAnnot_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
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400197FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV
Jane Liud60e9ad2017-06-26 11:28:36 -0400198FPDFPage_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
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400220FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetAnnotCount(FPDF_PAGE page) {
Jane Liu4fd9a472017-06-01 18:56:09 -0400221 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
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400229FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFPage_GetAnnot(FPDF_PAGE page,
230 int index) {
Jane Liu4fd9a472017-06-01 18:56:09 -0400231 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
Jane Liud60e9ad2017-06-26 11:28:36 -0400232 if (!pPage || !pPage->m_pFormDict || index < 0)
233 return nullptr;
Jane Liu20eafda2017-06-07 10:33:24 -0400234
Jane Liu4fd9a472017-06-01 18:56:09 -0400235 CPDF_Array* pAnnots = pPage->m_pFormDict->GetArrayFor("Annots");
236 if (!pAnnots || static_cast<size_t>(index) >= pAnnots->GetCount())
Jane Liud60e9ad2017-06-26 11:28:36 -0400237 return nullptr;
Jane Liu4fd9a472017-06-01 18:56:09 -0400238
239 CPDF_Dictionary* pDict = ToDictionary(pAnnots->GetDirectObjectAt(index));
Jane Liue10509a2017-06-20 16:47:41 -0400240 auto pNewAnnot = pdfium::MakeUnique<CPDF_AnnotContext>(pDict, pPage, nullptr);
Jane Liud60e9ad2017-06-26 11:28:36 -0400241 return pNewAnnot.release();
Jane Liue10509a2017-06-20 16:47:41 -0400242}
243
Jane Liud1ed1ce2017-08-24 12:31:10 -0400244FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetAnnotIndex(FPDF_PAGE page,
245 FPDF_ANNOTATION annot) {
246 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
247 CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
248 if (!pPage || !pPage->m_pFormDict || !pAnnot || !pAnnot->GetAnnotDict())
249 return -1;
250
251 CPDF_Array* pAnnots = pPage->m_pFormDict->GetArrayFor("Annots");
252 if (!pAnnots)
253 return -1;
254
255 CPDF_Dictionary* pDict = pAnnot->GetAnnotDict();
256 auto it =
257 std::find_if(pAnnots->begin(), pAnnots->end(),
258 [pDict](const std::unique_ptr<CPDF_Object>& candidate) {
259 return candidate->GetDirect() == pDict;
260 });
261
262 if (it == pAnnots->end())
263 return -1;
264
265 return it - pAnnots->begin();
266}
267
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400268FPDF_EXPORT void FPDF_CALLCONV FPDFPage_CloseAnnot(FPDF_ANNOTATION annot) {
Jane Liue10509a2017-06-20 16:47:41 -0400269 delete CPDFAnnotContextFromFPDFAnnotation(annot);
Jane Liu4fd9a472017-06-01 18:56:09 -0400270}
271
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400272FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_RemoveAnnot(FPDF_PAGE page,
273 int index) {
Jane Liu8ce58f52017-06-29 13:40:22 -0400274 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
275 if (!pPage || !pPage->m_pFormDict || index < 0)
276 return false;
277
278 CPDF_Array* pAnnots = pPage->m_pFormDict->GetArrayFor("Annots");
279 if (!pAnnots || static_cast<size_t>(index) >= pAnnots->GetCount())
280 return false;
281
282 pAnnots->RemoveAt(index);
283 return true;
284}
285
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400286FPDF_EXPORT FPDF_ANNOTATION_SUBTYPE FPDF_CALLCONV
Jane Liu4fd9a472017-06-01 18:56:09 -0400287FPDFAnnot_GetSubtype(FPDF_ANNOTATION annot) {
Jane Liud60e9ad2017-06-26 11:28:36 -0400288 if (!annot)
289 return FPDF_ANNOT_UNKNOWN;
290
Jane Liue10509a2017-06-20 16:47:41 -0400291 CPDF_Dictionary* pAnnotDict =
292 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liu4fd9a472017-06-01 18:56:09 -0400293 if (!pAnnotDict)
294 return FPDF_ANNOT_UNKNOWN;
Jane Liu20eafda2017-06-07 10:33:24 -0400295
Jane Liu4fd9a472017-06-01 18:56:09 -0400296 return static_cast<FPDF_ANNOTATION_SUBTYPE>(
297 CPDF_Annot::StringToAnnotSubtype(pAnnotDict->GetStringFor("Subtype")));
298}
299
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400300FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
Jane Liu7a9a38b2017-07-11 13:47:37 -0400301FPDFAnnot_IsObjectSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype) {
302 // The supported subtypes must also be communicated in the user doc.
303 return subtype == FPDF_ANNOT_INK || subtype == FPDF_ANNOT_STAMP;
304}
305
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400306FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
307FPDFAnnot_UpdateObject(FPDF_ANNOTATION annot, FPDF_PAGEOBJECT obj) {
Jane Liubaa7ff42017-06-29 19:18:23 -0400308 CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
Jane Liu36567742017-07-06 11:13:35 -0400309 CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(obj);
310 if (!pAnnot || !pAnnot->GetAnnotDict() || !pAnnot->HasForm() || !pObj)
Jane Liubaa7ff42017-06-29 19:18:23 -0400311 return false;
312
313 // Check that the annotation type is supported by this method.
Jane Liu7a9a38b2017-07-11 13:47:37 -0400314 if (!FPDFAnnot_IsObjectSupportedSubtype(FPDFAnnot_GetSubtype(annot)))
Jane Liubaa7ff42017-06-29 19:18:23 -0400315 return false;
316
317 // Check that the annotation already has an appearance stream, since an
Jane Liu36567742017-07-06 11:13:35 -0400318 // existing object is to be updated.
Jane Liubaa7ff42017-06-29 19:18:23 -0400319 CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(pAnnot->GetAnnotDict(),
320 CPDF_Annot::AppearanceMode::Normal);
321 if (!pStream)
322 return false;
323
Jane Liu36567742017-07-06 11:13:35 -0400324 // Check that the object is already in this annotation's object list.
Jane Liu7a9a38b2017-07-11 13:47:37 -0400325 CPDF_Form* pForm = pAnnot->GetForm();
326 CPDF_PageObjectList* pObjList = pForm->GetPageObjectList();
Jane Liu36567742017-07-06 11:13:35 -0400327 auto it =
328 std::find_if(pObjList->begin(), pObjList->end(),
329 [pObj](const std::unique_ptr<CPDF_PageObject>& candidate) {
330 return candidate.get() == pObj;
331 });
Jane Liubaa7ff42017-06-29 19:18:23 -0400332 if (it == pObjList->end())
333 return false;
334
335 // Update the content stream data in the annotation's AP stream.
Jane Liu7a9a38b2017-07-11 13:47:37 -0400336 UpdateContentStream(pForm, pStream);
Jane Liubaa7ff42017-06-29 19:18:23 -0400337 return true;
338}
339
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400340FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
341FPDFAnnot_AppendObject(FPDF_ANNOTATION annot, FPDF_PAGEOBJECT obj) {
Jane Liubaa7ff42017-06-29 19:18:23 -0400342 CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
Jane Liu36567742017-07-06 11:13:35 -0400343 CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(obj);
344 if (!pAnnot || !pObj)
Jane Liubaa7ff42017-06-29 19:18:23 -0400345 return false;
346
347 CPDF_Dictionary* pAnnotDict = pAnnot->GetAnnotDict();
348 CPDF_Page* pPage = pAnnot->GetPage();
349 if (!pAnnotDict || !pPage)
350 return false;
351
352 // Check that the annotation type is supported by this method.
Jane Liu7a9a38b2017-07-11 13:47:37 -0400353 if (!FPDFAnnot_IsObjectSupportedSubtype(FPDFAnnot_GetSubtype(annot)))
Jane Liubaa7ff42017-06-29 19:18:23 -0400354 return false;
355
356 // If the annotation does not have an AP stream yet, generate and set it.
357 CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(pAnnot->GetAnnotDict(),
358 CPDF_Annot::AppearanceMode::Normal);
359 if (!pStream) {
Dan Sinclair90fffb32017-10-16 15:34:05 -0400360 CPVT_GenerateAP::GenerateEmptyAP(pPage->m_pDocument.Get(), pAnnotDict);
Jane Liubaa7ff42017-06-29 19:18:23 -0400361 pStream =
362 FPDFDOC_GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal);
363 if (!pStream)
364 return false;
365 }
366
367 // Get the annotation's corresponding form object for parsing its AP stream.
368 if (!pAnnot->HasForm())
369 pAnnot->SetForm(pStream);
370
Jane Liu36567742017-07-06 11:13:35 -0400371 // Check that the object did not come from the same annotation. If this check
372 // succeeds, then it is assumed that the object came from
373 // FPDFPageObj_CreateNew{Path|Rect}() or FPDFPageObj_New{Text|Image}Obj().
374 // Note that an object that came from a different annotation must not be
375 // passed here, since an object cannot belong to more than one annotation.
Jane Liu7a9a38b2017-07-11 13:47:37 -0400376 CPDF_Form* pForm = pAnnot->GetForm();
Jane Liubaa7ff42017-06-29 19:18:23 -0400377 CPDF_PageObjectList* pObjList = pForm->GetPageObjectList();
Jane Liu36567742017-07-06 11:13:35 -0400378 auto it =
379 std::find_if(pObjList->begin(), pObjList->end(),
380 [pObj](const std::unique_ptr<CPDF_PageObject>& candidate) {
381 return candidate.get() == pObj;
382 });
Jane Liubaa7ff42017-06-29 19:18:23 -0400383 if (it != pObjList->end())
384 return false;
385
Jane Liu36567742017-07-06 11:13:35 -0400386 // Append the object to the object list.
387 std::unique_ptr<CPDF_PageObject> pPageObjHolder(pObj);
Jane Liubaa7ff42017-06-29 19:18:23 -0400388 pObjList->push_back(std::move(pPageObjHolder));
389
390 // Set the content stream data in the annotation's AP stream.
Jane Liu7a9a38b2017-07-11 13:47:37 -0400391 UpdateContentStream(pForm, pStream);
Jane Liubaa7ff42017-06-29 19:18:23 -0400392 return true;
393}
394
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400395FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetObjectCount(FPDF_ANNOTATION annot) {
Jane Liubaa7ff42017-06-29 19:18:23 -0400396 CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
Jane Liu36567742017-07-06 11:13:35 -0400397 if (!pAnnot || !pAnnot->GetAnnotDict())
Jane Liubaa7ff42017-06-29 19:18:23 -0400398 return 0;
399
400 if (!pAnnot->HasForm()) {
401 CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(
402 pAnnot->GetAnnotDict(), CPDF_Annot::AppearanceMode::Normal);
403 if (!pStream)
404 return 0;
405
406 pAnnot->SetForm(pStream);
407 }
Jane Liu57f228d2017-07-13 18:10:30 -0400408 return pdfium::CollectionSize<int>(*pAnnot->GetForm()->GetPageObjectList());
Jane Liubaa7ff42017-06-29 19:18:23 -0400409}
410
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400411FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV
412FPDFAnnot_GetObject(FPDF_ANNOTATION annot, int index) {
Jane Liubaa7ff42017-06-29 19:18:23 -0400413 CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
Jane Liu36567742017-07-06 11:13:35 -0400414 if (!pAnnot || !pAnnot->GetAnnotDict() || index < 0)
Jane Liubaa7ff42017-06-29 19:18:23 -0400415 return nullptr;
416
417 if (!pAnnot->HasForm()) {
418 CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(
419 pAnnot->GetAnnotDict(), CPDF_Annot::AppearanceMode::Normal);
420 if (!pStream)
421 return nullptr;
422
423 pAnnot->SetForm(pStream);
424 }
425
Jane Liu36567742017-07-06 11:13:35 -0400426 return pAnnot->GetForm()->GetPageObjectList()->GetPageObjectByIndex(index);
Jane Liubaa7ff42017-06-29 19:18:23 -0400427}
428
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400429FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
430FPDFAnnot_RemoveObject(FPDF_ANNOTATION annot, int index) {
Jane Liu7a9a38b2017-07-11 13:47:37 -0400431 CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
432 if (!pAnnot || !pAnnot->GetAnnotDict() || !pAnnot->HasForm() || index < 0)
433 return false;
434
435 // Check that the annotation type is supported by this method.
436 if (!FPDFAnnot_IsObjectSupportedSubtype(FPDFAnnot_GetSubtype(annot)))
437 return false;
438
439 // Check that the annotation already has an appearance stream, since an
440 // existing object is to be deleted.
441 CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(pAnnot->GetAnnotDict(),
442 CPDF_Annot::AppearanceMode::Normal);
443 if (!pStream)
444 return false;
445
446 CPDF_PageObjectList* pObjList = pAnnot->GetForm()->GetPageObjectList();
447 if (static_cast<size_t>(index) >= pObjList->size())
448 return false;
449
450 pObjList->erase(pObjList->begin() + index);
451 UpdateContentStream(pAnnot->GetForm(), pStream);
452 return true;
453}
454
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400455FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetColor(FPDF_ANNOTATION annot,
456 FPDFANNOT_COLORTYPE type,
457 unsigned int R,
458 unsigned int G,
459 unsigned int B,
460 unsigned int A) {
Jane Liud60e9ad2017-06-26 11:28:36 -0400461 if (!annot || R > 255 || G > 255 || B > 255 || A > 255)
462 return false;
463
Jane Liue10509a2017-06-20 16:47:41 -0400464 CPDF_Dictionary* pAnnotDict =
465 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liud60e9ad2017-06-26 11:28:36 -0400466 if (!pAnnotDict)
Jane Liu20eafda2017-06-07 10:33:24 -0400467 return false;
468
Jane Liu06462752017-06-27 16:41:14 -0400469 // For annotations with their appearance streams already defined, the path
470 // stream's own color definitions take priority over the annotation color
471 // definitions set by this method, hence this method will simply fail.
472 if (HasAPStream(pAnnotDict))
473 return false;
474
Jane Liu20eafda2017-06-07 10:33:24 -0400475 // Set the opacity of the annotation.
476 pAnnotDict->SetNewFor<CPDF_Number>("CA", A / 255.f);
477
478 // Set the color of the annotation.
Ryan Harrison275e2602017-09-18 14:23:18 -0400479 ByteString key = type == FPDFANNOT_COLORTYPE_InteriorColor ? "IC" : "C";
Jane Liu20eafda2017-06-07 10:33:24 -0400480 CPDF_Array* pColor = pAnnotDict->GetArrayFor(key);
481 if (pColor)
Lei Zhang59c1ac02017-06-09 11:04:41 -0700482 pColor->Clear();
Jane Liu20eafda2017-06-07 10:33:24 -0400483 else
484 pColor = pAnnotDict->SetNewFor<CPDF_Array>(key);
485
486 pColor->AddNew<CPDF_Number>(R / 255.f);
487 pColor->AddNew<CPDF_Number>(G / 255.f);
488 pColor->AddNew<CPDF_Number>(B / 255.f);
489
490 return true;
491}
492
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400493FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetColor(FPDF_ANNOTATION annot,
494 FPDFANNOT_COLORTYPE type,
495 unsigned int* R,
496 unsigned int* G,
497 unsigned int* B,
498 unsigned int* A) {
Jane Liud60e9ad2017-06-26 11:28:36 -0400499 if (!annot || !R || !G || !B || !A)
500 return false;
501
Jane Liue10509a2017-06-20 16:47:41 -0400502 CPDF_Dictionary* pAnnotDict =
503 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liud60e9ad2017-06-26 11:28:36 -0400504 if (!pAnnotDict)
Jane Liu4fd9a472017-06-01 18:56:09 -0400505 return false;
506
Jane Liu06462752017-06-27 16:41:14 -0400507 // For annotations with their appearance streams already defined, the path
508 // stream's own color definitions take priority over the annotation color
509 // definitions retrieved by this method, hence this method will simply fail.
510 if (HasAPStream(pAnnotDict))
511 return false;
512
Jane Liu4fd9a472017-06-01 18:56:09 -0400513 CPDF_Array* pColor = pAnnotDict->GetArrayFor(
514 type == FPDFANNOT_COLORTYPE_InteriorColor ? "IC" : "C");
515 *A =
516 (pAnnotDict->KeyExist("CA") ? pAnnotDict->GetNumberFor("CA") : 1) * 255.f;
517 if (!pColor) {
518 // Use default color. The default colors must be consistent with the ones
519 // used to generate AP. See calls to GetColorStringWithDefault() in
520 // CPVT_GenerateAP::Generate*AP().
521 if (pAnnotDict->GetStringFor("Subtype") == "Highlight") {
522 *R = 255;
523 *G = 255;
524 *B = 0;
525 } else {
526 *R = 0;
527 *G = 0;
528 *B = 0;
529 }
530 return true;
531 }
Dan Sinclair8e7f9322017-10-16 11:35:42 -0400532
533 CFX_Color color = CFX_Color::ParseColor(*pColor);
Jane Liu4fd9a472017-06-01 18:56:09 -0400534 switch (color.nColorType) {
Dan Sinclair8e7f9322017-10-16 11:35:42 -0400535 case CFX_Color::kRGB:
Jane Liu4fd9a472017-06-01 18:56:09 -0400536 *R = color.fColor1 * 255.f;
537 *G = color.fColor2 * 255.f;
538 *B = color.fColor3 * 255.f;
539 break;
Dan Sinclair8e7f9322017-10-16 11:35:42 -0400540 case CFX_Color::kGray:
Jane Liu4fd9a472017-06-01 18:56:09 -0400541 *R = 255.f * color.fColor1;
542 *G = 255.f * color.fColor1;
543 *B = 255.f * color.fColor1;
544 break;
Dan Sinclair8e7f9322017-10-16 11:35:42 -0400545 case CFX_Color::kCMYK:
Jane Liu4fd9a472017-06-01 18:56:09 -0400546 *R = 255.f * (1 - color.fColor1) * (1 - color.fColor4);
547 *G = 255.f * (1 - color.fColor2) * (1 - color.fColor4);
548 *B = 255.f * (1 - color.fColor3) * (1 - color.fColor4);
549 break;
Dan Sinclair8e7f9322017-10-16 11:35:42 -0400550 case CFX_Color::kTransparent:
Jane Liu4fd9a472017-06-01 18:56:09 -0400551 *R = 0;
552 *G = 0;
553 *B = 0;
554 break;
555 }
556 return true;
557}
558
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400559FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
Jane Liu4fd9a472017-06-01 18:56:09 -0400560FPDFAnnot_HasAttachmentPoints(FPDF_ANNOTATION annot) {
561 if (!annot)
562 return false;
Jane Liu20eafda2017-06-07 10:33:24 -0400563
Jane Liu4fd9a472017-06-01 18:56:09 -0400564 FPDF_ANNOTATION_SUBTYPE subtype = FPDFAnnot_GetSubtype(annot);
565 return subtype == FPDF_ANNOT_LINK || subtype == FPDF_ANNOT_HIGHLIGHT ||
566 subtype == FPDF_ANNOT_UNDERLINE || subtype == FPDF_ANNOT_SQUIGGLY ||
567 subtype == FPDF_ANNOT_STRIKEOUT;
568}
569
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400570FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
Jane Liu20eafda2017-06-07 10:33:24 -0400571FPDFAnnot_SetAttachmentPoints(FPDF_ANNOTATION annot,
Jane Liu06462752017-06-27 16:41:14 -0400572 const FS_QUADPOINTSF* quadPoints) {
573 if (!annot || !quadPoints || !FPDFAnnot_HasAttachmentPoints(annot))
Jane Liu20eafda2017-06-07 10:33:24 -0400574 return false;
575
Jane Liue10509a2017-06-20 16:47:41 -0400576 CPDF_Dictionary* pAnnotDict =
577 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liud60e9ad2017-06-26 11:28:36 -0400578 if (!pAnnotDict)
579 return false;
580
Jane Liu06462752017-06-27 16:41:14 -0400581 // Update the "QuadPoints" entry in the annotation dictionary.
Jane Liu20eafda2017-06-07 10:33:24 -0400582 CPDF_Array* pQuadPoints = pAnnotDict->GetArrayFor("QuadPoints");
583 if (pQuadPoints)
Lei Zhang59c1ac02017-06-09 11:04:41 -0700584 pQuadPoints->Clear();
Jane Liu20eafda2017-06-07 10:33:24 -0400585 else
586 pQuadPoints = pAnnotDict->SetNewFor<CPDF_Array>("QuadPoints");
587
Jane Liu06462752017-06-27 16:41:14 -0400588 pQuadPoints->AddNew<CPDF_Number>(quadPoints->x1);
589 pQuadPoints->AddNew<CPDF_Number>(quadPoints->y1);
590 pQuadPoints->AddNew<CPDF_Number>(quadPoints->x2);
591 pQuadPoints->AddNew<CPDF_Number>(quadPoints->y2);
592 pQuadPoints->AddNew<CPDF_Number>(quadPoints->x3);
593 pQuadPoints->AddNew<CPDF_Number>(quadPoints->y3);
594 pQuadPoints->AddNew<CPDF_Number>(quadPoints->x4);
595 pQuadPoints->AddNew<CPDF_Number>(quadPoints->y4);
596
597 // If the annotation's appearance stream is defined, and the new quadpoints
598 // defines a bigger bounding box than the appearance stream currently
599 // specifies, then update the "BBox" entry in the AP dictionary too, since it
600 // comes from annotation dictionary's "QuadPoints" entry.
601 CPDF_Stream* pStream =
602 FPDFDOC_GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal);
603 if (pStream) {
604 CFX_FloatRect newRect = CPDF_Annot::RectFromQuadPoints(pAnnotDict);
605 if (newRect.Contains(pStream->GetDict()->GetRectFor("BBox")))
606 pStream->GetDict()->SetRectFor("BBox", newRect);
607 }
Jane Liu20eafda2017-06-07 10:33:24 -0400608 return true;
609}
610
Jane Liu0c6b07d2017-08-15 10:50:22 -0400611FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
612FPDFAnnot_GetAttachmentPoints(FPDF_ANNOTATION annot,
613 FS_QUADPOINTSF* quadPoints) {
614 if (!annot || !FPDFAnnot_HasAttachmentPoints(annot) || !quadPoints)
615 return false;
Jane Liu20eafda2017-06-07 10:33:24 -0400616
Jane Liud60e9ad2017-06-26 11:28:36 -0400617 CPDF_Dictionary* pAnnotDict =
618 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
619 if (!pAnnotDict)
Jane Liu0c6b07d2017-08-15 10:50:22 -0400620 return false;
Jane Liud60e9ad2017-06-26 11:28:36 -0400621
Jane Liub370e5a2017-08-16 13:24:58 -0400622 CPDF_Array* pArray = pAnnotDict->GetArrayFor("QuadPoints");
623 if (!pArray)
624 return false;
Jane Liu06462752017-06-27 16:41:14 -0400625
Jane Liub370e5a2017-08-16 13:24:58 -0400626 quadPoints->x1 = pArray->GetNumberAt(0);
627 quadPoints->y1 = pArray->GetNumberAt(1);
628 quadPoints->x2 = pArray->GetNumberAt(2);
629 quadPoints->y2 = pArray->GetNumberAt(3);
630 quadPoints->x3 = pArray->GetNumberAt(4);
631 quadPoints->y3 = pArray->GetNumberAt(5);
632 quadPoints->x4 = pArray->GetNumberAt(6);
633 quadPoints->y4 = pArray->GetNumberAt(7);
Jane Liu0c6b07d2017-08-15 10:50:22 -0400634 return true;
Jane Liu4fd9a472017-06-01 18:56:09 -0400635}
636
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400637FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetRect(FPDF_ANNOTATION annot,
638 const FS_RECTF* rect) {
Jane Liu06462752017-06-27 16:41:14 -0400639 if (!annot || !rect)
Jane Liud60e9ad2017-06-26 11:28:36 -0400640 return false;
641
Jane Liue10509a2017-06-20 16:47:41 -0400642 CPDF_Dictionary* pAnnotDict =
643 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liu20eafda2017-06-07 10:33:24 -0400644 if (!pAnnotDict)
645 return false;
646
Jane Liu06462752017-06-27 16:41:14 -0400647 CFX_FloatRect newRect(rect->left, rect->bottom, rect->right, rect->top);
Jane Liu20eafda2017-06-07 10:33:24 -0400648
Jane Liu06462752017-06-27 16:41:14 -0400649 // Update the "Rect" entry in the annotation dictionary.
650 pAnnotDict->SetRectFor("Rect", newRect);
651
652 // If the annotation's appearance stream is defined, the annotation is of a
653 // type that does not have quadpoints, and the new rectangle is bigger than
654 // the current bounding box, then update the "BBox" entry in the AP
655 // dictionary too, since its "BBox" entry comes from annotation dictionary's
656 // "Rect" entry.
657 if (FPDFAnnot_HasAttachmentPoints(annot))
658 return true;
659
660 CPDF_Stream* pStream =
661 FPDFDOC_GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal);
662 if (pStream && newRect.Contains(pStream->GetDict()->GetRectFor("BBox")))
663 pStream->GetDict()->SetRectFor("BBox", newRect);
Jane Liu20eafda2017-06-07 10:33:24 -0400664 return true;
665}
666
Jane Liu0c6b07d2017-08-15 10:50:22 -0400667FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetRect(FPDF_ANNOTATION annot,
668 FS_RECTF* rect) {
669 if (!annot || !rect)
670 return false;
Jane Liud60e9ad2017-06-26 11:28:36 -0400671
Jane Liue10509a2017-06-20 16:47:41 -0400672 CPDF_Dictionary* pAnnotDict =
673 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liud60e9ad2017-06-26 11:28:36 -0400674 if (!pAnnotDict)
Jane Liu0c6b07d2017-08-15 10:50:22 -0400675 return false;
Jane Liu20eafda2017-06-07 10:33:24 -0400676
Jane Liub370e5a2017-08-16 13:24:58 -0400677 CFX_FloatRect rt = pAnnotDict->GetRectFor("Rect");
Jane Liu0c6b07d2017-08-15 10:50:22 -0400678 rect->left = rt.left;
679 rect->bottom = rt.bottom;
680 rect->right = rt.right;
681 rect->top = rt.top;
682 return true;
Jane Liu4fd9a472017-06-01 18:56:09 -0400683}
684
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400685FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_HasKey(FPDF_ANNOTATION annot,
Lei Zhangdf064df2017-08-31 02:33:27 -0700686 FPDF_BYTESTRING key) {
Jane Liud60e9ad2017-06-26 11:28:36 -0400687 if (!annot)
688 return false;
689
Jane Liue10509a2017-06-20 16:47:41 -0400690 CPDF_Dictionary* pAnnotDict =
691 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liu20eafda2017-06-07 10:33:24 -0400692 if (!pAnnotDict)
693 return false;
694
Lei Zhangdf064df2017-08-31 02:33:27 -0700695 return pAnnotDict->KeyExist(key);
Jane Liu2e1a32b2017-07-06 12:01:25 -0400696}
697
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400698FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV
Lei Zhangdf064df2017-08-31 02:33:27 -0700699FPDFAnnot_GetValueType(FPDF_ANNOTATION annot, FPDF_BYTESTRING key) {
Jane Liu2e1a32b2017-07-06 12:01:25 -0400700 if (!FPDFAnnot_HasKey(annot, key))
701 return FPDF_OBJECT_UNKNOWN;
702
Lei Zhangdf064df2017-08-31 02:33:27 -0700703 auto* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
704 CPDF_Object* pObj = pAnnot->GetAnnotDict()->GetObjectFor(key);
705 return pObj ? pObj->GetType() : FPDF_OBJECT_UNKNOWN;
Jane Liu2e1a32b2017-07-06 12:01:25 -0400706}
707
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400708FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
709FPDFAnnot_SetStringValue(FPDF_ANNOTATION annot,
Lei Zhangdf064df2017-08-31 02:33:27 -0700710 FPDF_BYTESTRING key,
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400711 FPDF_WIDESTRING value) {
Jane Liu2e1a32b2017-07-06 12:01:25 -0400712 if (!annot)
713 return false;
714
715 CPDF_Dictionary* pAnnotDict =
716 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
717 if (!pAnnotDict)
718 return false;
719
Lei Zhangdf064df2017-08-31 02:33:27 -0700720 pAnnotDict->SetNewFor<CPDF_String>(
721 key, CFXByteStringFromFPDFWideString(value), false);
Jane Liu20eafda2017-06-07 10:33:24 -0400722 return true;
723}
724
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400725FPDF_EXPORT unsigned long FPDF_CALLCONV
726FPDFAnnot_GetStringValue(FPDF_ANNOTATION annot,
Lei Zhangdf064df2017-08-31 02:33:27 -0700727 FPDF_BYTESTRING key,
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400728 void* buffer,
729 unsigned long buflen) {
Jane Liud60e9ad2017-06-26 11:28:36 -0400730 if (!annot)
731 return 0;
732
Jane Liue10509a2017-06-20 16:47:41 -0400733 CPDF_Dictionary* pAnnotDict =
734 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liu4fd9a472017-06-01 18:56:09 -0400735 if (!pAnnotDict)
736 return 0;
Jane Liu20eafda2017-06-07 10:33:24 -0400737
Lei Zhangdf064df2017-08-31 02:33:27 -0700738 return Utf16EncodeMaybeCopyAndReturnLength(pAnnotDict->GetUnicodeTextFor(key),
739 buffer, buflen);
Jane Liu4fd9a472017-06-01 18:56:09 -0400740}
Jane Liub137e752017-07-05 15:04:33 -0400741
Jane Liu300bb272017-08-21 14:37:53 -0400742FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV
Lei Zhangdf064df2017-08-31 02:33:27 -0700743FPDFAnnot_GetLinkedAnnot(FPDF_ANNOTATION annot, FPDF_BYTESTRING key) {
Jane Liu300bb272017-08-21 14:37:53 -0400744 CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
745 if (!pAnnot || !pAnnot->GetAnnotDict())
746 return nullptr;
747
Lei Zhangdf064df2017-08-31 02:33:27 -0700748 CPDF_Dictionary* pLinkedDict = pAnnot->GetAnnotDict()->GetDictFor(key);
Jane Liu300bb272017-08-21 14:37:53 -0400749 if (!pLinkedDict || pLinkedDict->GetStringFor("Type") != "Annot")
750 return nullptr;
751
752 auto pLinkedAnnot = pdfium::MakeUnique<CPDF_AnnotContext>(
753 pLinkedDict, pAnnot->GetPage(), nullptr);
754 return pLinkedAnnot.release();
755}
756
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400757FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFlags(FPDF_ANNOTATION annot) {
Jane Liub137e752017-07-05 15:04:33 -0400758 if (!annot)
759 return FPDF_ANNOT_FLAG_NONE;
760
761 CPDF_Dictionary* pAnnotDict =
762 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Lei Zhangdf064df2017-08-31 02:33:27 -0700763 return pAnnotDict ? pAnnotDict->GetIntegerFor("F") : FPDF_ANNOT_FLAG_NONE;
Jane Liub137e752017-07-05 15:04:33 -0400764}
765
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400766FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetFlags(FPDF_ANNOTATION annot,
767 int flags) {
Jane Liub137e752017-07-05 15:04:33 -0400768 if (!annot)
769 return false;
770
771 CPDF_Dictionary* pAnnotDict =
772 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
773 if (!pAnnotDict)
774 return false;
775
776 pAnnotDict->SetNewFor<CPDF_Number>("F", flags);
777 return true;
778}
Diana Gage7e0c05d2017-07-19 17:33:33 -0700779
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400780FPDF_EXPORT int FPDF_CALLCONV
781FPDFAnnot_GetFormFieldFlags(FPDF_PAGE page, FPDF_ANNOTATION annot) {
Diana Gage7e0c05d2017-07-19 17:33:33 -0700782 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
783 if (!pPage || !annot)
784 return FPDF_FORMFLAG_NONE;
785
786 CPDF_Dictionary* pAnnotDict =
787 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
788 if (!pAnnotDict)
789 return FPDF_FORMFLAG_NONE;
790
791 CPDF_InterForm interform(pPage->m_pDocument.Get());
792 CPDF_FormField* pFormField = interform.GetFieldByDict(pAnnotDict);
793 return pFormField ? pFormField->GetFieldFlags() : FPDF_FORMFLAG_NONE;
794}
Diana Gage40870db2017-07-19 18:16:03 -0700795
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400796FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV
Diana Gage40870db2017-07-19 18:16:03 -0700797FPDFAnnot_GetFormFieldAtPoint(FPDF_FORMHANDLE hHandle,
798 FPDF_PAGE page,
799 double page_x,
800 double page_y) {
801 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
802 if (!hHandle || !pPage)
803 return nullptr;
804
805 CPDF_InterForm interform(pPage->m_pDocument.Get());
806 int annot_index = -1;
807 CPDF_FormControl* pFormCtrl = interform.GetControlAtPoint(
808 pPage, CFX_PointF(static_cast<float>(page_x), static_cast<float>(page_y)),
809 &annot_index);
810 if (!pFormCtrl || annot_index == -1)
811 return nullptr;
812 return FPDFPage_GetAnnot(page, annot_index);
813}