blob: c4623bb726824304056664b8e298b370409c035d [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"
Lei Zhangc3450652018-10-11 16:54:42 +000022#include "core/fpdfdoc/cpdf_interactiveform.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"
Tom Sepez525147a2018-05-03 17:19:53 +000025#include "fpdfsdk/cpdf_annotcontext.h"
Dan Sinclair00d47a62018-03-28 18:39:04 +000026#include "fpdfsdk/cpdfsdk_helpers.h"
Lei Zhang99f5bbb2018-10-09 21:31:28 +000027#include "third_party/base/ptr_util.h"
Jane Liu4fd9a472017-06-01 18:56:09 -040028
Jane Liue10509a2017-06-20 16:47:41 -040029namespace {
30
Jane Liu4fd9a472017-06-01 18:56:09 -040031// These checks ensure the consistency of annotation subtype values across core/
32// and public.
33static_assert(static_cast<int>(CPDF_Annot::Subtype::UNKNOWN) ==
34 FPDF_ANNOT_UNKNOWN,
35 "CPDF_Annot::UNKNOWN value mismatch");
36static_assert(static_cast<int>(CPDF_Annot::Subtype::TEXT) == FPDF_ANNOT_TEXT,
37 "CPDF_Annot::TEXT value mismatch");
38static_assert(static_cast<int>(CPDF_Annot::Subtype::LINK) == FPDF_ANNOT_LINK,
39 "CPDF_Annot::LINK value mismatch");
40static_assert(static_cast<int>(CPDF_Annot::Subtype::FREETEXT) ==
41 FPDF_ANNOT_FREETEXT,
42 "CPDF_Annot::FREETEXT value mismatch");
43static_assert(static_cast<int>(CPDF_Annot::Subtype::LINE) == FPDF_ANNOT_LINE,
44 "CPDF_Annot::LINE value mismatch");
45static_assert(static_cast<int>(CPDF_Annot::Subtype::SQUARE) ==
46 FPDF_ANNOT_SQUARE,
47 "CPDF_Annot::SQUARE value mismatch");
48static_assert(static_cast<int>(CPDF_Annot::Subtype::CIRCLE) ==
49 FPDF_ANNOT_CIRCLE,
50 "CPDF_Annot::CIRCLE value mismatch");
51static_assert(static_cast<int>(CPDF_Annot::Subtype::POLYGON) ==
52 FPDF_ANNOT_POLYGON,
53 "CPDF_Annot::POLYGON value mismatch");
54static_assert(static_cast<int>(CPDF_Annot::Subtype::POLYLINE) ==
55 FPDF_ANNOT_POLYLINE,
56 "CPDF_Annot::POLYLINE value mismatch");
57static_assert(static_cast<int>(CPDF_Annot::Subtype::HIGHLIGHT) ==
58 FPDF_ANNOT_HIGHLIGHT,
59 "CPDF_Annot::HIGHLIGHT value mismatch");
60static_assert(static_cast<int>(CPDF_Annot::Subtype::UNDERLINE) ==
61 FPDF_ANNOT_UNDERLINE,
62 "CPDF_Annot::UNDERLINE value mismatch");
63static_assert(static_cast<int>(CPDF_Annot::Subtype::SQUIGGLY) ==
64 FPDF_ANNOT_SQUIGGLY,
65 "CPDF_Annot::SQUIGGLY value mismatch");
66static_assert(static_cast<int>(CPDF_Annot::Subtype::STRIKEOUT) ==
67 FPDF_ANNOT_STRIKEOUT,
68 "CPDF_Annot::STRIKEOUT value mismatch");
69static_assert(static_cast<int>(CPDF_Annot::Subtype::STAMP) == FPDF_ANNOT_STAMP,
70 "CPDF_Annot::STAMP value mismatch");
71static_assert(static_cast<int>(CPDF_Annot::Subtype::CARET) == FPDF_ANNOT_CARET,
72 "CPDF_Annot::CARET value mismatch");
73static_assert(static_cast<int>(CPDF_Annot::Subtype::INK) == FPDF_ANNOT_INK,
74 "CPDF_Annot::INK value mismatch");
75static_assert(static_cast<int>(CPDF_Annot::Subtype::POPUP) == FPDF_ANNOT_POPUP,
76 "CPDF_Annot::POPUP value mismatch");
77static_assert(static_cast<int>(CPDF_Annot::Subtype::FILEATTACHMENT) ==
78 FPDF_ANNOT_FILEATTACHMENT,
79 "CPDF_Annot::FILEATTACHMENT value mismatch");
80static_assert(static_cast<int>(CPDF_Annot::Subtype::SOUND) == FPDF_ANNOT_SOUND,
81 "CPDF_Annot::SOUND value mismatch");
82static_assert(static_cast<int>(CPDF_Annot::Subtype::MOVIE) == FPDF_ANNOT_MOVIE,
83 "CPDF_Annot::MOVIE value mismatch");
84static_assert(static_cast<int>(CPDF_Annot::Subtype::WIDGET) ==
85 FPDF_ANNOT_WIDGET,
86 "CPDF_Annot::WIDGET value mismatch");
87static_assert(static_cast<int>(CPDF_Annot::Subtype::SCREEN) ==
88 FPDF_ANNOT_SCREEN,
89 "CPDF_Annot::SCREEN value mismatch");
90static_assert(static_cast<int>(CPDF_Annot::Subtype::PRINTERMARK) ==
91 FPDF_ANNOT_PRINTERMARK,
92 "CPDF_Annot::PRINTERMARK value mismatch");
93static_assert(static_cast<int>(CPDF_Annot::Subtype::TRAPNET) ==
94 FPDF_ANNOT_TRAPNET,
95 "CPDF_Annot::TRAPNET value mismatch");
96static_assert(static_cast<int>(CPDF_Annot::Subtype::WATERMARK) ==
97 FPDF_ANNOT_WATERMARK,
98 "CPDF_Annot::WATERMARK value mismatch");
99static_assert(static_cast<int>(CPDF_Annot::Subtype::THREED) ==
100 FPDF_ANNOT_THREED,
101 "CPDF_Annot::THREED value mismatch");
102static_assert(static_cast<int>(CPDF_Annot::Subtype::RICHMEDIA) ==
103 FPDF_ANNOT_RICHMEDIA,
104 "CPDF_Annot::RICHMEDIA value mismatch");
105static_assert(static_cast<int>(CPDF_Annot::Subtype::XFAWIDGET) ==
106 FPDF_ANNOT_XFAWIDGET,
107 "CPDF_Annot::XFAWIDGET value mismatch");
108
Henrique Nakashimaa74e75d2018-01-10 18:06:55 +0000109// These checks ensure the consistency of annotation appearance mode values
110// across core/ and public.
111static_assert(static_cast<int>(CPDF_Annot::AppearanceMode::Normal) ==
112 FPDF_ANNOT_APPEARANCEMODE_NORMAL,
113 "CPDF_Annot::AppearanceMode::Normal value mismatch");
114static_assert(static_cast<int>(CPDF_Annot::AppearanceMode::Rollover) ==
115 FPDF_ANNOT_APPEARANCEMODE_ROLLOVER,
116 "CPDF_Annot::AppearanceMode::Rollover value mismatch");
117static_assert(static_cast<int>(CPDF_Annot::AppearanceMode::Down) ==
118 FPDF_ANNOT_APPEARANCEMODE_DOWN,
119 "CPDF_Annot::AppearanceMode::Down value mismatch");
120
Jane Liu2e1a32b2017-07-06 12:01:25 -0400121// These checks ensure the consistency of dictionary value types across core/
122// and public/.
123static_assert(static_cast<int>(CPDF_Object::Type::BOOLEAN) ==
124 FPDF_OBJECT_BOOLEAN,
125 "CPDF_Object::BOOLEAN value mismatch");
126static_assert(static_cast<int>(CPDF_Object::Type::NUMBER) == FPDF_OBJECT_NUMBER,
127 "CPDF_Object::NUMBER value mismatch");
128static_assert(static_cast<int>(CPDF_Object::Type::STRING) == FPDF_OBJECT_STRING,
129 "CPDF_Object::STRING value mismatch");
130static_assert(static_cast<int>(CPDF_Object::Type::NAME) == FPDF_OBJECT_NAME,
131 "CPDF_Object::NAME value mismatch");
132static_assert(static_cast<int>(CPDF_Object::Type::ARRAY) == FPDF_OBJECT_ARRAY,
133 "CPDF_Object::ARRAY value mismatch");
134static_assert(static_cast<int>(CPDF_Object::Type::DICTIONARY) ==
135 FPDF_OBJECT_DICTIONARY,
136 "CPDF_Object::DICTIONARY value mismatch");
137static_assert(static_cast<int>(CPDF_Object::Type::STREAM) == FPDF_OBJECT_STREAM,
138 "CPDF_Object::STREAM value mismatch");
139static_assert(static_cast<int>(CPDF_Object::Type::NULLOBJ) ==
140 FPDF_OBJECT_NULLOBJ,
141 "CPDF_Object::NULLOBJ value mismatch");
142static_assert(static_cast<int>(CPDF_Object::Type::REFERENCE) ==
143 FPDF_OBJECT_REFERENCE,
144 "CPDF_Object::REFERENCE value mismatch");
145
Lei Zhangfffdeeb2018-05-28 17:51:28 +0000146bool HasAPStream(CPDF_Dictionary* pAnnotDict) {
Tom Sepez456e9702018-08-29 19:35:37 +0000147 return !!GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal);
Jane Liu06462752017-06-27 16:41:14 -0400148}
149
Jane Liu7a9a38b2017-07-11 13:47:37 -0400150void UpdateContentStream(CPDF_Form* pForm, CPDF_Stream* pStream) {
151 ASSERT(pForm);
152 ASSERT(pStream);
153
154 CPDF_PageContentGenerator generator(pForm);
155 std::ostringstream buf;
156 generator.ProcessPageObjects(&buf);
Tom Sepez367ed462018-08-23 23:52:53 +0000157 pStream->SetDataFromStringstreamAndRemoveFilter(&buf);
Jane Liu7a9a38b2017-07-11 13:47:37 -0400158}
Jane Liu2e1a32b2017-07-06 12:01:25 -0400159
Ralf Sippl16381792018-04-12 21:20:26 +0000160void SetQuadPointsAtIndex(CPDF_Array* array,
161 size_t quad_index,
162 const FS_QUADPOINTSF* quad_points) {
163 ASSERT(array);
164 ASSERT(quad_points);
165 ASSERT(IsValidQuadPointsIndex(array, quad_index));
166
167 size_t nIndex = quad_index * 8;
168 array->SetNewAt<CPDF_Number>(nIndex, quad_points->x1);
169 array->SetNewAt<CPDF_Number>(++nIndex, quad_points->y1);
170 array->SetNewAt<CPDF_Number>(++nIndex, quad_points->x2);
171 array->SetNewAt<CPDF_Number>(++nIndex, quad_points->y2);
172 array->SetNewAt<CPDF_Number>(++nIndex, quad_points->x3);
173 array->SetNewAt<CPDF_Number>(++nIndex, quad_points->y3);
174 array->SetNewAt<CPDF_Number>(++nIndex, quad_points->x4);
175 array->SetNewAt<CPDF_Number>(++nIndex, quad_points->y4);
176}
177
178void AppendQuadPoints(CPDF_Array* array, const FS_QUADPOINTSF* quad_points) {
179 ASSERT(quad_points);
180 ASSERT(array);
181
182 array->AddNew<CPDF_Number>(quad_points->x1);
183 array->AddNew<CPDF_Number>(quad_points->y1);
184 array->AddNew<CPDF_Number>(quad_points->x2);
185 array->AddNew<CPDF_Number>(quad_points->y2);
186 array->AddNew<CPDF_Number>(quad_points->x3);
187 array->AddNew<CPDF_Number>(quad_points->y3);
188 array->AddNew<CPDF_Number>(quad_points->x4);
189 array->AddNew<CPDF_Number>(quad_points->y4);
190}
191
Lei Zhangfffdeeb2018-05-28 17:51:28 +0000192void UpdateBBox(CPDF_Dictionary* annot_dict) {
Ralf Sippl16381792018-04-12 21:20:26 +0000193 // Update BBox entry in appearance stream based on the bounding rectangle
194 // of the annotation's quadpoints.
195 CPDF_Stream* pStream =
Tom Sepez456e9702018-08-29 19:35:37 +0000196 GetAnnotAP(annot_dict, CPDF_Annot::AppearanceMode::Normal);
Ralf Sippl16381792018-04-12 21:20:26 +0000197 if (pStream) {
198 CFX_FloatRect boundingRect =
199 CPDF_Annot::BoundingRectFromQuadPoints(annot_dict);
200 if (boundingRect.Contains(pStream->GetDict()->GetRectFor("BBox")))
201 pStream->GetDict()->SetRectFor("BBox", boundingRect);
202 }
203}
204
Jane Liue10509a2017-06-20 16:47:41 -0400205} // namespace
206
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400207FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
Jane Liu20eafda2017-06-07 10:33:24 -0400208FPDFAnnot_IsSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype) {
Jane Liubaa7ff42017-06-29 19:18:23 -0400209 // The supported subtypes must also be communicated in the user doc.
Henrique Nakashimaae0853d2018-02-12 18:29:57 +0000210 return subtype == FPDF_ANNOT_CIRCLE || subtype == FPDF_ANNOT_FREETEXT ||
211 subtype == FPDF_ANNOT_HIGHLIGHT || subtype == FPDF_ANNOT_INK ||
212 subtype == FPDF_ANNOT_POPUP || subtype == FPDF_ANNOT_SQUARE ||
213 subtype == FPDF_ANNOT_SQUIGGLY || subtype == FPDF_ANNOT_STAMP ||
214 subtype == FPDF_ANNOT_STRIKEOUT || subtype == FPDF_ANNOT_TEXT ||
215 subtype == FPDF_ANNOT_UNDERLINE;
Jane Liu20eafda2017-06-07 10:33:24 -0400216}
217
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400218FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV
Jane Liud60e9ad2017-06-26 11:28:36 -0400219FPDFPage_CreateAnnot(FPDF_PAGE page, FPDF_ANNOTATION_SUBTYPE subtype) {
Jane Liu20eafda2017-06-07 10:33:24 -0400220 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
221 if (!pPage || !FPDFAnnot_IsSupportedSubtype(subtype))
Jane Liud60e9ad2017-06-26 11:28:36 -0400222 return nullptr;
Jane Liu20eafda2017-06-07 10:33:24 -0400223
224 auto pDict = pdfium::MakeUnique<CPDF_Dictionary>(
Lei Zhang8f637632018-05-07 23:36:26 +0000225 pPage->GetDocument()->GetByteStringPool());
Jane Liu20eafda2017-06-07 10:33:24 -0400226 pDict->SetNewFor<CPDF_Name>("Type", "Annot");
227 pDict->SetNewFor<CPDF_Name>("Subtype",
228 CPDF_Annot::AnnotSubtypeToString(
229 static_cast<CPDF_Annot::Subtype>(subtype)));
Jane Liud60e9ad2017-06-26 11:28:36 -0400230 auto pNewAnnot =
231 pdfium::MakeUnique<CPDF_AnnotContext>(pDict.get(), pPage, nullptr);
Jane Liu20eafda2017-06-07 10:33:24 -0400232
Henrique Nakashima888af472018-06-07 19:43:42 +0000233 CPDF_Array* pAnnotList = pPage->GetDict()->GetArrayFor("Annots");
Jane Liu20eafda2017-06-07 10:33:24 -0400234 if (!pAnnotList)
Henrique Nakashima888af472018-06-07 19:43:42 +0000235 pAnnotList = pPage->GetDict()->SetNewFor<CPDF_Array>("Annots");
Jane Liu20eafda2017-06-07 10:33:24 -0400236 pAnnotList->Add(std::move(pDict));
Tom Sepez525147a2018-05-03 17:19:53 +0000237
238 // Caller takes ownership.
239 return FPDFAnnotationFromCPDFAnnotContext(pNewAnnot.release());
Jane Liu20eafda2017-06-07 10:33:24 -0400240}
241
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400242FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetAnnotCount(FPDF_PAGE page) {
Jane Liu4fd9a472017-06-01 18:56:09 -0400243 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
Henrique Nakashima888af472018-06-07 19:43:42 +0000244 if (!pPage || !pPage->GetDict())
Jane Liu4fd9a472017-06-01 18:56:09 -0400245 return 0;
Jane Liu20eafda2017-06-07 10:33:24 -0400246
Henrique Nakashima888af472018-06-07 19:43:42 +0000247 CPDF_Array* pAnnots = pPage->GetDict()->GetArrayFor("Annots");
Lei Zhangf40380f2018-10-12 18:31:51 +0000248 return pAnnots ? pAnnots->size() : 0;
Jane Liu4fd9a472017-06-01 18:56:09 -0400249}
250
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400251FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFPage_GetAnnot(FPDF_PAGE page,
252 int index) {
Jane Liu4fd9a472017-06-01 18:56:09 -0400253 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
Henrique Nakashima888af472018-06-07 19:43:42 +0000254 if (!pPage || !pPage->GetDict() || index < 0)
Jane Liud60e9ad2017-06-26 11:28:36 -0400255 return nullptr;
Jane Liu20eafda2017-06-07 10:33:24 -0400256
Henrique Nakashima888af472018-06-07 19:43:42 +0000257 CPDF_Array* pAnnots = pPage->GetDict()->GetArrayFor("Annots");
Lei Zhangf40380f2018-10-12 18:31:51 +0000258 if (!pAnnots || static_cast<size_t>(index) >= pAnnots->size())
Jane Liud60e9ad2017-06-26 11:28:36 -0400259 return nullptr;
Jane Liu4fd9a472017-06-01 18:56:09 -0400260
261 CPDF_Dictionary* pDict = ToDictionary(pAnnots->GetDirectObjectAt(index));
Jane Liue10509a2017-06-20 16:47:41 -0400262 auto pNewAnnot = pdfium::MakeUnique<CPDF_AnnotContext>(pDict, pPage, nullptr);
Tom Sepez525147a2018-05-03 17:19:53 +0000263
264 // Caller takes ownership.
265 return FPDFAnnotationFromCPDFAnnotContext(pNewAnnot.release());
Jane Liue10509a2017-06-20 16:47:41 -0400266}
267
Jane Liud1ed1ce2017-08-24 12:31:10 -0400268FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetAnnotIndex(FPDF_PAGE page,
269 FPDF_ANNOTATION annot) {
270 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
271 CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
Henrique Nakashima888af472018-06-07 19:43:42 +0000272 if (!pPage || !pPage->GetDict() || !pAnnot || !pAnnot->GetAnnotDict())
Jane Liud1ed1ce2017-08-24 12:31:10 -0400273 return -1;
274
Henrique Nakashima888af472018-06-07 19:43:42 +0000275 CPDF_Array* pAnnots = pPage->GetDict()->GetArrayFor("Annots");
Jane Liud1ed1ce2017-08-24 12:31:10 -0400276 if (!pAnnots)
277 return -1;
278
279 CPDF_Dictionary* pDict = pAnnot->GetAnnotDict();
280 auto it =
281 std::find_if(pAnnots->begin(), pAnnots->end(),
282 [pDict](const std::unique_ptr<CPDF_Object>& candidate) {
283 return candidate->GetDirect() == pDict;
284 });
285
286 if (it == pAnnots->end())
287 return -1;
288
289 return it - pAnnots->begin();
290}
291
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400292FPDF_EXPORT void FPDF_CALLCONV FPDFPage_CloseAnnot(FPDF_ANNOTATION annot) {
Jane Liue10509a2017-06-20 16:47:41 -0400293 delete CPDFAnnotContextFromFPDFAnnotation(annot);
Jane Liu4fd9a472017-06-01 18:56:09 -0400294}
295
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400296FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_RemoveAnnot(FPDF_PAGE page,
297 int index) {
Jane Liu8ce58f52017-06-29 13:40:22 -0400298 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
Henrique Nakashima888af472018-06-07 19:43:42 +0000299 if (!pPage || !pPage->GetDict() || index < 0)
Jane Liu8ce58f52017-06-29 13:40:22 -0400300 return false;
301
Henrique Nakashima888af472018-06-07 19:43:42 +0000302 CPDF_Array* pAnnots = pPage->GetDict()->GetArrayFor("Annots");
Lei Zhangf40380f2018-10-12 18:31:51 +0000303 if (!pAnnots || static_cast<size_t>(index) >= pAnnots->size())
Jane Liu8ce58f52017-06-29 13:40:22 -0400304 return false;
305
306 pAnnots->RemoveAt(index);
307 return true;
308}
309
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400310FPDF_EXPORT FPDF_ANNOTATION_SUBTYPE FPDF_CALLCONV
Jane Liu4fd9a472017-06-01 18:56:09 -0400311FPDFAnnot_GetSubtype(FPDF_ANNOTATION annot) {
Jane Liud60e9ad2017-06-26 11:28:36 -0400312 if (!annot)
313 return FPDF_ANNOT_UNKNOWN;
314
Jane Liue10509a2017-06-20 16:47:41 -0400315 CPDF_Dictionary* pAnnotDict =
316 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liu4fd9a472017-06-01 18:56:09 -0400317 if (!pAnnotDict)
318 return FPDF_ANNOT_UNKNOWN;
Jane Liu20eafda2017-06-07 10:33:24 -0400319
Jane Liu4fd9a472017-06-01 18:56:09 -0400320 return static_cast<FPDF_ANNOTATION_SUBTYPE>(
321 CPDF_Annot::StringToAnnotSubtype(pAnnotDict->GetStringFor("Subtype")));
322}
323
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400324FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
Jane Liu7a9a38b2017-07-11 13:47:37 -0400325FPDFAnnot_IsObjectSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype) {
326 // The supported subtypes must also be communicated in the user doc.
327 return subtype == FPDF_ANNOT_INK || subtype == FPDF_ANNOT_STAMP;
328}
329
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400330FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
331FPDFAnnot_UpdateObject(FPDF_ANNOTATION annot, FPDF_PAGEOBJECT obj) {
Jane Liubaa7ff42017-06-29 19:18:23 -0400332 CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
Jane Liu36567742017-07-06 11:13:35 -0400333 CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(obj);
334 if (!pAnnot || !pAnnot->GetAnnotDict() || !pAnnot->HasForm() || !pObj)
Jane Liubaa7ff42017-06-29 19:18:23 -0400335 return false;
336
337 // Check that the annotation type is supported by this method.
Jane Liu7a9a38b2017-07-11 13:47:37 -0400338 if (!FPDFAnnot_IsObjectSupportedSubtype(FPDFAnnot_GetSubtype(annot)))
Jane Liubaa7ff42017-06-29 19:18:23 -0400339 return false;
340
341 // Check that the annotation already has an appearance stream, since an
Jane Liu36567742017-07-06 11:13:35 -0400342 // existing object is to be updated.
Tom Sepez456e9702018-08-29 19:35:37 +0000343 CPDF_Stream* pStream =
344 GetAnnotAP(pAnnot->GetAnnotDict(), CPDF_Annot::AppearanceMode::Normal);
Jane Liubaa7ff42017-06-29 19:18:23 -0400345 if (!pStream)
346 return false;
347
Jane Liu36567742017-07-06 11:13:35 -0400348 // Check that the object is already in this annotation's object list.
Jane Liu7a9a38b2017-07-11 13:47:37 -0400349 CPDF_Form* pForm = pAnnot->GetForm();
Henrique Nakashima6b26e1a2018-04-16 21:48:37 +0000350 const CPDF_PageObjectList* pObjList = pForm->GetPageObjectList();
Jane Liu36567742017-07-06 11:13:35 -0400351 auto it =
352 std::find_if(pObjList->begin(), pObjList->end(),
353 [pObj](const std::unique_ptr<CPDF_PageObject>& candidate) {
354 return candidate.get() == pObj;
355 });
Jane Liubaa7ff42017-06-29 19:18:23 -0400356 if (it == pObjList->end())
357 return false;
358
359 // Update the content stream data in the annotation's AP stream.
Jane Liu7a9a38b2017-07-11 13:47:37 -0400360 UpdateContentStream(pForm, pStream);
Jane Liubaa7ff42017-06-29 19:18:23 -0400361 return true;
362}
363
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400364FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
365FPDFAnnot_AppendObject(FPDF_ANNOTATION annot, FPDF_PAGEOBJECT obj) {
Jane Liubaa7ff42017-06-29 19:18:23 -0400366 CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
Jane Liu36567742017-07-06 11:13:35 -0400367 CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(obj);
368 if (!pAnnot || !pObj)
Jane Liubaa7ff42017-06-29 19:18:23 -0400369 return false;
370
371 CPDF_Dictionary* pAnnotDict = pAnnot->GetAnnotDict();
372 CPDF_Page* pPage = pAnnot->GetPage();
373 if (!pAnnotDict || !pPage)
374 return false;
375
376 // Check that the annotation type is supported by this method.
Jane Liu7a9a38b2017-07-11 13:47:37 -0400377 if (!FPDFAnnot_IsObjectSupportedSubtype(FPDFAnnot_GetSubtype(annot)))
Jane Liubaa7ff42017-06-29 19:18:23 -0400378 return false;
379
380 // If the annotation does not have an AP stream yet, generate and set it.
Tom Sepez456e9702018-08-29 19:35:37 +0000381 CPDF_Stream* pStream =
382 GetAnnotAP(pAnnot->GetAnnotDict(), CPDF_Annot::AppearanceMode::Normal);
Jane Liubaa7ff42017-06-29 19:18:23 -0400383 if (!pStream) {
Lei Zhang8f637632018-05-07 23:36:26 +0000384 CPVT_GenerateAP::GenerateEmptyAP(pPage->GetDocument(), pAnnotDict);
Tom Sepez456e9702018-08-29 19:35:37 +0000385 pStream = GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal);
Jane Liubaa7ff42017-06-29 19:18:23 -0400386 if (!pStream)
387 return false;
388 }
389
390 // Get the annotation's corresponding form object for parsing its AP stream.
391 if (!pAnnot->HasForm())
392 pAnnot->SetForm(pStream);
393
Jane Liu36567742017-07-06 11:13:35 -0400394 // Check that the object did not come from the same annotation. If this check
395 // succeeds, then it is assumed that the object came from
396 // FPDFPageObj_CreateNew{Path|Rect}() or FPDFPageObj_New{Text|Image}Obj().
397 // Note that an object that came from a different annotation must not be
398 // passed here, since an object cannot belong to more than one annotation.
Jane Liu7a9a38b2017-07-11 13:47:37 -0400399 CPDF_Form* pForm = pAnnot->GetForm();
Henrique Nakashima6b26e1a2018-04-16 21:48:37 +0000400 const CPDF_PageObjectList* pObjList = pForm->GetPageObjectList();
Jane Liu36567742017-07-06 11:13:35 -0400401 auto it =
402 std::find_if(pObjList->begin(), pObjList->end(),
403 [pObj](const std::unique_ptr<CPDF_PageObject>& candidate) {
404 return candidate.get() == pObj;
405 });
Jane Liubaa7ff42017-06-29 19:18:23 -0400406 if (it != pObjList->end())
407 return false;
408
Jane Liu36567742017-07-06 11:13:35 -0400409 // Append the object to the object list.
Henrique Nakashima6b26e1a2018-04-16 21:48:37 +0000410 pForm->AppendPageObject(pdfium::WrapUnique(pObj));
Jane Liubaa7ff42017-06-29 19:18:23 -0400411
412 // Set the content stream data in the annotation's AP stream.
Jane Liu7a9a38b2017-07-11 13:47:37 -0400413 UpdateContentStream(pForm, pStream);
Jane Liubaa7ff42017-06-29 19:18:23 -0400414 return true;
415}
416
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400417FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetObjectCount(FPDF_ANNOTATION annot) {
Jane Liubaa7ff42017-06-29 19:18:23 -0400418 CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
Jane Liu36567742017-07-06 11:13:35 -0400419 if (!pAnnot || !pAnnot->GetAnnotDict())
Jane Liubaa7ff42017-06-29 19:18:23 -0400420 return 0;
421
422 if (!pAnnot->HasForm()) {
Tom Sepez456e9702018-08-29 19:35:37 +0000423 CPDF_Stream* pStream =
424 GetAnnotAP(pAnnot->GetAnnotDict(), CPDF_Annot::AppearanceMode::Normal);
Jane Liubaa7ff42017-06-29 19:18:23 -0400425 if (!pStream)
426 return 0;
427
428 pAnnot->SetForm(pStream);
429 }
Jane Liu57f228d2017-07-13 18:10:30 -0400430 return pdfium::CollectionSize<int>(*pAnnot->GetForm()->GetPageObjectList());
Jane Liubaa7ff42017-06-29 19:18:23 -0400431}
432
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400433FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV
434FPDFAnnot_GetObject(FPDF_ANNOTATION annot, int index) {
Jane Liubaa7ff42017-06-29 19:18:23 -0400435 CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
Jane Liu36567742017-07-06 11:13:35 -0400436 if (!pAnnot || !pAnnot->GetAnnotDict() || index < 0)
Jane Liubaa7ff42017-06-29 19:18:23 -0400437 return nullptr;
438
439 if (!pAnnot->HasForm()) {
Tom Sepez456e9702018-08-29 19:35:37 +0000440 CPDF_Stream* pStream =
441 GetAnnotAP(pAnnot->GetAnnotDict(), CPDF_Annot::AppearanceMode::Normal);
Jane Liubaa7ff42017-06-29 19:18:23 -0400442 if (!pStream)
443 return nullptr;
444
445 pAnnot->SetForm(pStream);
446 }
447
Tom Sepez525147a2018-05-03 17:19:53 +0000448 return FPDFPageObjectFromCPDFPageObject(
449 pAnnot->GetForm()->GetPageObjectByIndex(index));
Jane Liubaa7ff42017-06-29 19:18:23 -0400450}
451
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400452FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
453FPDFAnnot_RemoveObject(FPDF_ANNOTATION annot, int index) {
Jane Liu7a9a38b2017-07-11 13:47:37 -0400454 CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
455 if (!pAnnot || !pAnnot->GetAnnotDict() || !pAnnot->HasForm() || index < 0)
456 return false;
457
458 // Check that the annotation type is supported by this method.
459 if (!FPDFAnnot_IsObjectSupportedSubtype(FPDFAnnot_GetSubtype(annot)))
460 return false;
461
462 // Check that the annotation already has an appearance stream, since an
463 // existing object is to be deleted.
Tom Sepez456e9702018-08-29 19:35:37 +0000464 CPDF_Stream* pStream =
465 GetAnnotAP(pAnnot->GetAnnotDict(), CPDF_Annot::AppearanceMode::Normal);
Jane Liu7a9a38b2017-07-11 13:47:37 -0400466 if (!pStream)
467 return false;
468
Henrique Nakashima6b26e1a2018-04-16 21:48:37 +0000469 if (!pAnnot->GetForm()->ErasePageObjectAtIndex(index))
Jane Liu7a9a38b2017-07-11 13:47:37 -0400470 return false;
471
Jane Liu7a9a38b2017-07-11 13:47:37 -0400472 UpdateContentStream(pAnnot->GetForm(), pStream);
473 return true;
474}
475
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400476FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetColor(FPDF_ANNOTATION annot,
477 FPDFANNOT_COLORTYPE type,
478 unsigned int R,
479 unsigned int G,
480 unsigned int B,
481 unsigned int A) {
Jane Liud60e9ad2017-06-26 11:28:36 -0400482 if (!annot || R > 255 || G > 255 || B > 255 || A > 255)
483 return false;
484
Jane Liue10509a2017-06-20 16:47:41 -0400485 CPDF_Dictionary* pAnnotDict =
486 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liud60e9ad2017-06-26 11:28:36 -0400487 if (!pAnnotDict)
Jane Liu20eafda2017-06-07 10:33:24 -0400488 return false;
489
Jane Liu06462752017-06-27 16:41:14 -0400490 // For annotations with their appearance streams already defined, the path
491 // stream's own color definitions take priority over the annotation color
492 // definitions set by this method, hence this method will simply fail.
493 if (HasAPStream(pAnnotDict))
494 return false;
495
Jane Liu20eafda2017-06-07 10:33:24 -0400496 // Set the opacity of the annotation.
497 pAnnotDict->SetNewFor<CPDF_Number>("CA", A / 255.f);
498
499 // Set the color of the annotation.
Ryan Harrison275e2602017-09-18 14:23:18 -0400500 ByteString key = type == FPDFANNOT_COLORTYPE_InteriorColor ? "IC" : "C";
Jane Liu20eafda2017-06-07 10:33:24 -0400501 CPDF_Array* pColor = pAnnotDict->GetArrayFor(key);
502 if (pColor)
Lei Zhang59c1ac02017-06-09 11:04:41 -0700503 pColor->Clear();
Jane Liu20eafda2017-06-07 10:33:24 -0400504 else
505 pColor = pAnnotDict->SetNewFor<CPDF_Array>(key);
506
507 pColor->AddNew<CPDF_Number>(R / 255.f);
508 pColor->AddNew<CPDF_Number>(G / 255.f);
509 pColor->AddNew<CPDF_Number>(B / 255.f);
510
511 return true;
512}
513
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400514FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetColor(FPDF_ANNOTATION annot,
515 FPDFANNOT_COLORTYPE type,
516 unsigned int* R,
517 unsigned int* G,
518 unsigned int* B,
519 unsigned int* A) {
Jane Liud60e9ad2017-06-26 11:28:36 -0400520 if (!annot || !R || !G || !B || !A)
521 return false;
522
Jane Liue10509a2017-06-20 16:47:41 -0400523 CPDF_Dictionary* pAnnotDict =
524 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liud60e9ad2017-06-26 11:28:36 -0400525 if (!pAnnotDict)
Jane Liu4fd9a472017-06-01 18:56:09 -0400526 return false;
527
Jane Liu06462752017-06-27 16:41:14 -0400528 // For annotations with their appearance streams already defined, the path
529 // stream's own color definitions take priority over the annotation color
530 // definitions retrieved by this method, hence this method will simply fail.
531 if (HasAPStream(pAnnotDict))
532 return false;
533
Jane Liu4fd9a472017-06-01 18:56:09 -0400534 CPDF_Array* pColor = pAnnotDict->GetArrayFor(
535 type == FPDFANNOT_COLORTYPE_InteriorColor ? "IC" : "C");
536 *A =
537 (pAnnotDict->KeyExist("CA") ? pAnnotDict->GetNumberFor("CA") : 1) * 255.f;
538 if (!pColor) {
539 // Use default color. The default colors must be consistent with the ones
540 // used to generate AP. See calls to GetColorStringWithDefault() in
541 // CPVT_GenerateAP::Generate*AP().
542 if (pAnnotDict->GetStringFor("Subtype") == "Highlight") {
543 *R = 255;
544 *G = 255;
545 *B = 0;
546 } else {
547 *R = 0;
548 *G = 0;
549 *B = 0;
550 }
551 return true;
552 }
Dan Sinclair8e7f9322017-10-16 11:35:42 -0400553
554 CFX_Color color = CFX_Color::ParseColor(*pColor);
Jane Liu4fd9a472017-06-01 18:56:09 -0400555 switch (color.nColorType) {
Dan Sinclair8e7f9322017-10-16 11:35:42 -0400556 case CFX_Color::kRGB:
Jane Liu4fd9a472017-06-01 18:56:09 -0400557 *R = color.fColor1 * 255.f;
558 *G = color.fColor2 * 255.f;
559 *B = color.fColor3 * 255.f;
560 break;
Dan Sinclair8e7f9322017-10-16 11:35:42 -0400561 case CFX_Color::kGray:
Jane Liu4fd9a472017-06-01 18:56:09 -0400562 *R = 255.f * color.fColor1;
563 *G = 255.f * color.fColor1;
564 *B = 255.f * color.fColor1;
565 break;
Dan Sinclair8e7f9322017-10-16 11:35:42 -0400566 case CFX_Color::kCMYK:
Jane Liu4fd9a472017-06-01 18:56:09 -0400567 *R = 255.f * (1 - color.fColor1) * (1 - color.fColor4);
568 *G = 255.f * (1 - color.fColor2) * (1 - color.fColor4);
569 *B = 255.f * (1 - color.fColor3) * (1 - color.fColor4);
570 break;
Dan Sinclair8e7f9322017-10-16 11:35:42 -0400571 case CFX_Color::kTransparent:
Jane Liu4fd9a472017-06-01 18:56:09 -0400572 *R = 0;
573 *G = 0;
574 *B = 0;
575 break;
576 }
577 return true;
578}
579
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400580FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
Jane Liu4fd9a472017-06-01 18:56:09 -0400581FPDFAnnot_HasAttachmentPoints(FPDF_ANNOTATION annot) {
582 if (!annot)
583 return false;
Jane Liu20eafda2017-06-07 10:33:24 -0400584
Jane Liu4fd9a472017-06-01 18:56:09 -0400585 FPDF_ANNOTATION_SUBTYPE subtype = FPDFAnnot_GetSubtype(annot);
586 return subtype == FPDF_ANNOT_LINK || subtype == FPDF_ANNOT_HIGHLIGHT ||
587 subtype == FPDF_ANNOT_UNDERLINE || subtype == FPDF_ANNOT_SQUIGGLY ||
588 subtype == FPDF_ANNOT_STRIKEOUT;
589}
590
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400591FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
Jane Liu20eafda2017-06-07 10:33:24 -0400592FPDFAnnot_SetAttachmentPoints(FPDF_ANNOTATION annot,
Ralf Sippl16381792018-04-12 21:20:26 +0000593 size_t quad_index,
Lei Zhangc3cffbe2018-03-21 13:37:46 +0000594 const FS_QUADPOINTSF* quad_points) {
Henrique Nakashima5098b252018-03-26 21:46:00 +0000595 if (!FPDFAnnot_HasAttachmentPoints(annot) || !quad_points)
Jane Liu20eafda2017-06-07 10:33:24 -0400596 return false;
597
Jane Liue10509a2017-06-20 16:47:41 -0400598 CPDF_Dictionary* pAnnotDict =
599 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Ralf Sippl16381792018-04-12 21:20:26 +0000600 CPDF_Array* pQuadPointsArray = GetQuadPointsArrayFromDictionary(pAnnotDict);
601 if (!IsValidQuadPointsIndex(pQuadPointsArray, quad_index))
Jane Liud60e9ad2017-06-26 11:28:36 -0400602 return false;
603
Ralf Sippl16381792018-04-12 21:20:26 +0000604 SetQuadPointsAtIndex(pQuadPointsArray, quad_index, quad_points);
605 UpdateBBox(pAnnotDict);
606 return true;
607}
Jane Liu20eafda2017-06-07 10:33:24 -0400608
Ralf Sippl16381792018-04-12 21:20:26 +0000609FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
610FPDFAnnot_AppendAttachmentPoints(FPDF_ANNOTATION annot,
611 const FS_QUADPOINTSF* quad_points) {
612 if (!FPDFAnnot_HasAttachmentPoints(annot) || !quad_points)
613 return false;
Jane Liu06462752017-06-27 16:41:14 -0400614
Ralf Sippl16381792018-04-12 21:20:26 +0000615 CPDF_Dictionary* pAnnotDict =
616 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
617 CPDF_Array* pQuadPointsArray = GetQuadPointsArrayFromDictionary(pAnnotDict);
618 if (!pQuadPointsArray)
619 pQuadPointsArray = AddQuadPointsArrayToDictionary(pAnnotDict);
620 AppendQuadPoints(pQuadPointsArray, quad_points);
621 UpdateBBox(pAnnotDict);
Jane Liu20eafda2017-06-07 10:33:24 -0400622 return true;
623}
624
Henrique Nakashima5098b252018-03-26 21:46:00 +0000625FPDF_EXPORT size_t FPDF_CALLCONV
626FPDFAnnot_CountAttachmentPoints(FPDF_ANNOTATION annot) {
627 if (!FPDFAnnot_HasAttachmentPoints(annot))
628 return 0;
629
630 CPDF_Dictionary* pAnnotDict =
631 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
632 const CPDF_Array* pArray = GetQuadPointsArrayFromDictionary(pAnnotDict);
Lei Zhangf40380f2018-10-12 18:31:51 +0000633 return pArray ? pArray->size() / 8 : 0;
Henrique Nakashima5098b252018-03-26 21:46:00 +0000634}
635
Jane Liu0c6b07d2017-08-15 10:50:22 -0400636FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
637FPDFAnnot_GetAttachmentPoints(FPDF_ANNOTATION annot,
Ralf Sippl16381792018-04-12 21:20:26 +0000638 size_t quad_index,
Lei Zhangc3cffbe2018-03-21 13:37:46 +0000639 FS_QUADPOINTSF* quad_points) {
Henrique Nakashima5098b252018-03-26 21:46:00 +0000640 if (!FPDFAnnot_HasAttachmentPoints(annot) || !quad_points)
Jane Liu0c6b07d2017-08-15 10:50:22 -0400641 return false;
Jane Liu20eafda2017-06-07 10:33:24 -0400642
Ralf Sippl16381792018-04-12 21:20:26 +0000643 CPDF_Dictionary* pAnnotDict =
644 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
645 if (!pAnnotDict)
646 return false;
647
648 const CPDF_Array* pArray = GetQuadPointsArrayFromDictionary(pAnnotDict);
649 if (!pArray)
650 return false;
651
652 return GetQuadPointsAtIndex(pArray, quad_index, quad_points);
Jane Liu4fd9a472017-06-01 18:56:09 -0400653}
654
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400655FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetRect(FPDF_ANNOTATION annot,
656 const FS_RECTF* rect) {
Jane Liu06462752017-06-27 16:41:14 -0400657 if (!annot || !rect)
Jane Liud60e9ad2017-06-26 11:28:36 -0400658 return false;
659
Jane Liue10509a2017-06-20 16:47:41 -0400660 CPDF_Dictionary* pAnnotDict =
661 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liu20eafda2017-06-07 10:33:24 -0400662 if (!pAnnotDict)
663 return false;
664
Lei Zhang367e7de2017-10-31 13:32:17 +0000665 CFX_FloatRect newRect = CFXFloatRectFromFSRECTF(*rect);
Jane Liu20eafda2017-06-07 10:33:24 -0400666
Jane Liu06462752017-06-27 16:41:14 -0400667 // Update the "Rect" entry in the annotation dictionary.
668 pAnnotDict->SetRectFor("Rect", newRect);
669
670 // If the annotation's appearance stream is defined, the annotation is of a
671 // type that does not have quadpoints, and the new rectangle is bigger than
672 // the current bounding box, then update the "BBox" entry in the AP
673 // dictionary too, since its "BBox" entry comes from annotation dictionary's
674 // "Rect" entry.
675 if (FPDFAnnot_HasAttachmentPoints(annot))
676 return true;
677
678 CPDF_Stream* pStream =
Tom Sepez456e9702018-08-29 19:35:37 +0000679 GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal);
Jane Liu06462752017-06-27 16:41:14 -0400680 if (pStream && newRect.Contains(pStream->GetDict()->GetRectFor("BBox")))
681 pStream->GetDict()->SetRectFor("BBox", newRect);
Jane Liu20eafda2017-06-07 10:33:24 -0400682 return true;
683}
684
Jane Liu0c6b07d2017-08-15 10:50:22 -0400685FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetRect(FPDF_ANNOTATION annot,
686 FS_RECTF* rect) {
687 if (!annot || !rect)
688 return false;
Jane Liud60e9ad2017-06-26 11:28:36 -0400689
Jane Liue10509a2017-06-20 16:47:41 -0400690 CPDF_Dictionary* pAnnotDict =
691 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liud60e9ad2017-06-26 11:28:36 -0400692 if (!pAnnotDict)
Jane Liu0c6b07d2017-08-15 10:50:22 -0400693 return false;
Jane Liu20eafda2017-06-07 10:33:24 -0400694
Lei Zhang367e7de2017-10-31 13:32:17 +0000695 FSRECTFFromCFXFloatRect(pAnnotDict->GetRectFor("Rect"), rect);
Jane Liu0c6b07d2017-08-15 10:50:22 -0400696 return true;
Jane Liu4fd9a472017-06-01 18:56:09 -0400697}
698
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400699FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_HasKey(FPDF_ANNOTATION annot,
Lei Zhangdf064df2017-08-31 02:33:27 -0700700 FPDF_BYTESTRING key) {
Jane Liud60e9ad2017-06-26 11:28:36 -0400701 if (!annot)
702 return false;
703
Jane Liue10509a2017-06-20 16:47:41 -0400704 CPDF_Dictionary* pAnnotDict =
705 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liu20eafda2017-06-07 10:33:24 -0400706 if (!pAnnotDict)
707 return false;
708
Lei Zhangdf064df2017-08-31 02:33:27 -0700709 return pAnnotDict->KeyExist(key);
Jane Liu2e1a32b2017-07-06 12:01:25 -0400710}
711
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400712FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV
Lei Zhangdf064df2017-08-31 02:33:27 -0700713FPDFAnnot_GetValueType(FPDF_ANNOTATION annot, FPDF_BYTESTRING key) {
Jane Liu2e1a32b2017-07-06 12:01:25 -0400714 if (!FPDFAnnot_HasKey(annot, key))
715 return FPDF_OBJECT_UNKNOWN;
716
Lei Zhangdf064df2017-08-31 02:33:27 -0700717 auto* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
718 CPDF_Object* pObj = pAnnot->GetAnnotDict()->GetObjectFor(key);
719 return pObj ? pObj->GetType() : FPDF_OBJECT_UNKNOWN;
Jane Liu2e1a32b2017-07-06 12:01:25 -0400720}
721
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400722FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
723FPDFAnnot_SetStringValue(FPDF_ANNOTATION annot,
Lei Zhangdf064df2017-08-31 02:33:27 -0700724 FPDF_BYTESTRING key,
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400725 FPDF_WIDESTRING value) {
Jane Liu2e1a32b2017-07-06 12:01:25 -0400726 if (!annot)
727 return false;
728
729 CPDF_Dictionary* pAnnotDict =
730 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
731 if (!pAnnotDict)
732 return false;
733
Lei Zhangdf064df2017-08-31 02:33:27 -0700734 pAnnotDict->SetNewFor<CPDF_String>(
735 key, CFXByteStringFromFPDFWideString(value), false);
Jane Liu20eafda2017-06-07 10:33:24 -0400736 return true;
737}
738
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400739FPDF_EXPORT unsigned long FPDF_CALLCONV
740FPDFAnnot_GetStringValue(FPDF_ANNOTATION annot,
Lei Zhangdf064df2017-08-31 02:33:27 -0700741 FPDF_BYTESTRING key,
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400742 void* buffer,
743 unsigned long buflen) {
Jane Liud60e9ad2017-06-26 11:28:36 -0400744 if (!annot)
745 return 0;
746
Jane Liue10509a2017-06-20 16:47:41 -0400747 CPDF_Dictionary* pAnnotDict =
748 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liu4fd9a472017-06-01 18:56:09 -0400749 if (!pAnnotDict)
750 return 0;
Jane Liu20eafda2017-06-07 10:33:24 -0400751
Lei Zhangdf064df2017-08-31 02:33:27 -0700752 return Utf16EncodeMaybeCopyAndReturnLength(pAnnotDict->GetUnicodeTextFor(key),
753 buffer, buflen);
Jane Liu4fd9a472017-06-01 18:56:09 -0400754}
Jane Liub137e752017-07-05 15:04:33 -0400755
Henrique Nakashima5970a472018-01-11 22:40:59 +0000756FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
757FPDFAnnot_SetAP(FPDF_ANNOTATION annot,
758 FPDF_ANNOT_APPEARANCEMODE appearanceMode,
759 FPDF_WIDESTRING value) {
760 if (appearanceMode < 0 || appearanceMode >= FPDF_ANNOT_APPEARANCEMODE_COUNT)
761 return false;
762
763 if (!annot)
764 return false;
765
766 CPDF_Dictionary* pAnnotDict =
767 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
768 if (!pAnnotDict)
769 return false;
770
771 constexpr const char* modeKeyForMode[] = {"N", "R", "D"};
772 static_assert(FX_ArraySize(modeKeyForMode) == FPDF_ANNOT_APPEARANCEMODE_COUNT,
773 "length of modeKeyForMode should be equal to "
774 "FPDF_ANNOT_APPEARANCEMODE_COUNT");
775 const char* modeKey = modeKeyForMode[appearanceMode];
776
777 CPDF_Dictionary* pApDict = pAnnotDict->GetDictFor("AP");
778
779 // If value is null, we're in remove mode. Otherwise, we're in add/update
780 // mode.
781 if (value) {
782 if (!pApDict)
783 pApDict = pAnnotDict->SetNewFor<CPDF_Dictionary>("AP");
784
785 ByteString newValue = CFXByteStringFromFPDFWideString(value);
786 auto pNewApStream = pdfium::MakeUnique<CPDF_Stream>();
Tom Sepez367ed462018-08-23 23:52:53 +0000787 pNewApStream->SetData(newValue.AsRawSpan());
Henrique Nakashima5970a472018-01-11 22:40:59 +0000788 pApDict->SetFor(modeKey, std::move(pNewApStream));
789 } else {
790 if (pApDict) {
791 if (appearanceMode == FPDF_ANNOT_APPEARANCEMODE_NORMAL)
792 pAnnotDict->RemoveFor("AP");
793 else
794 pApDict->RemoveFor(modeKey);
795 }
796 }
797
798 return true;
799}
800
Henrique Nakashimaa74e75d2018-01-10 18:06:55 +0000801FPDF_EXPORT unsigned long FPDF_CALLCONV
802FPDFAnnot_GetAP(FPDF_ANNOTATION annot,
803 FPDF_ANNOT_APPEARANCEMODE appearanceMode,
804 void* buffer,
805 unsigned long buflen) {
806 if (appearanceMode < 0 || appearanceMode >= FPDF_ANNOT_APPEARANCEMODE_COUNT)
807 return 0;
808
809 if (!annot)
810 return 0;
811
812 CPDF_Dictionary* pAnnotDict =
813 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
814 if (!pAnnotDict)
815 return 0;
816
817 CPDF_Annot::AppearanceMode mode =
818 static_cast<CPDF_Annot::AppearanceMode>(appearanceMode);
819
Tom Sepez456e9702018-08-29 19:35:37 +0000820 CPDF_Stream* pStream = GetAnnotAPNoFallback(pAnnotDict, mode);
Lei Zhang4afee172018-01-10 20:57:15 +0000821 return Utf16EncodeMaybeCopyAndReturnLength(
822 pStream ? pStream->GetUnicodeText() : L"", buffer, buflen);
Henrique Nakashimaa74e75d2018-01-10 18:06:55 +0000823}
824
Jane Liu300bb272017-08-21 14:37:53 -0400825FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV
Lei Zhangdf064df2017-08-31 02:33:27 -0700826FPDFAnnot_GetLinkedAnnot(FPDF_ANNOTATION annot, FPDF_BYTESTRING key) {
Jane Liu300bb272017-08-21 14:37:53 -0400827 CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot);
828 if (!pAnnot || !pAnnot->GetAnnotDict())
829 return nullptr;
830
Lei Zhangdf064df2017-08-31 02:33:27 -0700831 CPDF_Dictionary* pLinkedDict = pAnnot->GetAnnotDict()->GetDictFor(key);
Jane Liu300bb272017-08-21 14:37:53 -0400832 if (!pLinkedDict || pLinkedDict->GetStringFor("Type") != "Annot")
833 return nullptr;
834
835 auto pLinkedAnnot = pdfium::MakeUnique<CPDF_AnnotContext>(
836 pLinkedDict, pAnnot->GetPage(), nullptr);
Tom Sepez525147a2018-05-03 17:19:53 +0000837
838 // Caller takes ownership.
839 return FPDFAnnotationFromCPDFAnnotContext(pLinkedAnnot.release());
Jane Liu300bb272017-08-21 14:37:53 -0400840}
841
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400842FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFlags(FPDF_ANNOTATION annot) {
Jane Liub137e752017-07-05 15:04:33 -0400843 if (!annot)
844 return FPDF_ANNOT_FLAG_NONE;
845
846 CPDF_Dictionary* pAnnotDict =
847 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Lei Zhangdf064df2017-08-31 02:33:27 -0700848 return pAnnotDict ? pAnnotDict->GetIntegerFor("F") : FPDF_ANNOT_FLAG_NONE;
Jane Liub137e752017-07-05 15:04:33 -0400849}
850
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400851FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetFlags(FPDF_ANNOTATION annot,
852 int flags) {
Jane Liub137e752017-07-05 15:04:33 -0400853 if (!annot)
854 return false;
855
856 CPDF_Dictionary* pAnnotDict =
857 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
858 if (!pAnnotDict)
859 return false;
860
861 pAnnotDict->SetNewFor<CPDF_Number>("F", flags);
862 return true;
863}
Diana Gage7e0c05d2017-07-19 17:33:33 -0700864
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400865FPDF_EXPORT int FPDF_CALLCONV
866FPDFAnnot_GetFormFieldFlags(FPDF_PAGE page, FPDF_ANNOTATION annot) {
Diana Gage7e0c05d2017-07-19 17:33:33 -0700867 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
868 if (!pPage || !annot)
869 return FPDF_FORMFLAG_NONE;
870
871 CPDF_Dictionary* pAnnotDict =
872 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
873 if (!pAnnotDict)
874 return FPDF_FORMFLAG_NONE;
875
Lei Zhang073ecf42018-10-11 16:56:00 +0000876 CPDF_InteractiveForm interactive_form(pPage->GetDocument());
877 CPDF_FormField* pFormField = interactive_form.GetFieldByDict(pAnnotDict);
Diana Gage7e0c05d2017-07-19 17:33:33 -0700878 return pFormField ? pFormField->GetFieldFlags() : FPDF_FORMFLAG_NONE;
879}
Diana Gage40870db2017-07-19 18:16:03 -0700880
Dan Sinclair00d2ad12017-08-10 14:13:02 -0400881FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV
Diana Gage40870db2017-07-19 18:16:03 -0700882FPDFAnnot_GetFormFieldAtPoint(FPDF_FORMHANDLE hHandle,
883 FPDF_PAGE page,
884 double page_x,
885 double page_y) {
886 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
887 if (!hHandle || !pPage)
888 return nullptr;
889
Lei Zhang073ecf42018-10-11 16:56:00 +0000890 CPDF_InteractiveForm interactive_form(pPage->GetDocument());
Diana Gage40870db2017-07-19 18:16:03 -0700891 int annot_index = -1;
Lei Zhang073ecf42018-10-11 16:56:00 +0000892 CPDF_FormControl* pFormCtrl = interactive_form.GetControlAtPoint(
Diana Gage40870db2017-07-19 18:16:03 -0700893 pPage, CFX_PointF(static_cast<float>(page_x), static_cast<float>(page_y)),
894 &annot_index);
895 if (!pFormCtrl || annot_index == -1)
896 return nullptr;
897 return FPDFPage_GetAnnot(page, annot_index);
898}