blob: 4a288b7df7367be9a1c490d894ce1dbcc1579365 [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
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "public/fpdf_annot.h"
8
Jane Liud60e9ad2017-06-26 11:28:36 -04009#include <memory>
Jane Liu20eafda2017-06-07 10:33:24 -040010#include <utility>
11
Jane Liue10509a2017-06-20 16:47:41 -040012#include "core/fpdfapi/page/cpdf_form.h"
Jane Liu4fd9a472017-06-01 18:56:09 -040013#include "core/fpdfapi/page/cpdf_page.h"
14#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"
21#include "core/fpdfdoc/cpvt_color.h"
22#include "core/fpdfdoc/cpvt_generateap.h"
23#include "fpdfsdk/fsdk_define.h"
24
Jane Liue10509a2017-06-20 16:47:41 -040025namespace {
26
Jane Liu4fd9a472017-06-01 18:56:09 -040027// These checks ensure the consistency of annotation subtype values across core/
28// and public.
29static_assert(static_cast<int>(CPDF_Annot::Subtype::UNKNOWN) ==
30 FPDF_ANNOT_UNKNOWN,
31 "CPDF_Annot::UNKNOWN value mismatch");
32static_assert(static_cast<int>(CPDF_Annot::Subtype::TEXT) == FPDF_ANNOT_TEXT,
33 "CPDF_Annot::TEXT value mismatch");
34static_assert(static_cast<int>(CPDF_Annot::Subtype::LINK) == FPDF_ANNOT_LINK,
35 "CPDF_Annot::LINK value mismatch");
36static_assert(static_cast<int>(CPDF_Annot::Subtype::FREETEXT) ==
37 FPDF_ANNOT_FREETEXT,
38 "CPDF_Annot::FREETEXT value mismatch");
39static_assert(static_cast<int>(CPDF_Annot::Subtype::LINE) == FPDF_ANNOT_LINE,
40 "CPDF_Annot::LINE value mismatch");
41static_assert(static_cast<int>(CPDF_Annot::Subtype::SQUARE) ==
42 FPDF_ANNOT_SQUARE,
43 "CPDF_Annot::SQUARE value mismatch");
44static_assert(static_cast<int>(CPDF_Annot::Subtype::CIRCLE) ==
45 FPDF_ANNOT_CIRCLE,
46 "CPDF_Annot::CIRCLE value mismatch");
47static_assert(static_cast<int>(CPDF_Annot::Subtype::POLYGON) ==
48 FPDF_ANNOT_POLYGON,
49 "CPDF_Annot::POLYGON value mismatch");
50static_assert(static_cast<int>(CPDF_Annot::Subtype::POLYLINE) ==
51 FPDF_ANNOT_POLYLINE,
52 "CPDF_Annot::POLYLINE value mismatch");
53static_assert(static_cast<int>(CPDF_Annot::Subtype::HIGHLIGHT) ==
54 FPDF_ANNOT_HIGHLIGHT,
55 "CPDF_Annot::HIGHLIGHT value mismatch");
56static_assert(static_cast<int>(CPDF_Annot::Subtype::UNDERLINE) ==
57 FPDF_ANNOT_UNDERLINE,
58 "CPDF_Annot::UNDERLINE value mismatch");
59static_assert(static_cast<int>(CPDF_Annot::Subtype::SQUIGGLY) ==
60 FPDF_ANNOT_SQUIGGLY,
61 "CPDF_Annot::SQUIGGLY value mismatch");
62static_assert(static_cast<int>(CPDF_Annot::Subtype::STRIKEOUT) ==
63 FPDF_ANNOT_STRIKEOUT,
64 "CPDF_Annot::STRIKEOUT value mismatch");
65static_assert(static_cast<int>(CPDF_Annot::Subtype::STAMP) == FPDF_ANNOT_STAMP,
66 "CPDF_Annot::STAMP value mismatch");
67static_assert(static_cast<int>(CPDF_Annot::Subtype::CARET) == FPDF_ANNOT_CARET,
68 "CPDF_Annot::CARET value mismatch");
69static_assert(static_cast<int>(CPDF_Annot::Subtype::INK) == FPDF_ANNOT_INK,
70 "CPDF_Annot::INK value mismatch");
71static_assert(static_cast<int>(CPDF_Annot::Subtype::POPUP) == FPDF_ANNOT_POPUP,
72 "CPDF_Annot::POPUP value mismatch");
73static_assert(static_cast<int>(CPDF_Annot::Subtype::FILEATTACHMENT) ==
74 FPDF_ANNOT_FILEATTACHMENT,
75 "CPDF_Annot::FILEATTACHMENT value mismatch");
76static_assert(static_cast<int>(CPDF_Annot::Subtype::SOUND) == FPDF_ANNOT_SOUND,
77 "CPDF_Annot::SOUND value mismatch");
78static_assert(static_cast<int>(CPDF_Annot::Subtype::MOVIE) == FPDF_ANNOT_MOVIE,
79 "CPDF_Annot::MOVIE value mismatch");
80static_assert(static_cast<int>(CPDF_Annot::Subtype::WIDGET) ==
81 FPDF_ANNOT_WIDGET,
82 "CPDF_Annot::WIDGET value mismatch");
83static_assert(static_cast<int>(CPDF_Annot::Subtype::SCREEN) ==
84 FPDF_ANNOT_SCREEN,
85 "CPDF_Annot::SCREEN value mismatch");
86static_assert(static_cast<int>(CPDF_Annot::Subtype::PRINTERMARK) ==
87 FPDF_ANNOT_PRINTERMARK,
88 "CPDF_Annot::PRINTERMARK value mismatch");
89static_assert(static_cast<int>(CPDF_Annot::Subtype::TRAPNET) ==
90 FPDF_ANNOT_TRAPNET,
91 "CPDF_Annot::TRAPNET value mismatch");
92static_assert(static_cast<int>(CPDF_Annot::Subtype::WATERMARK) ==
93 FPDF_ANNOT_WATERMARK,
94 "CPDF_Annot::WATERMARK value mismatch");
95static_assert(static_cast<int>(CPDF_Annot::Subtype::THREED) ==
96 FPDF_ANNOT_THREED,
97 "CPDF_Annot::THREED value mismatch");
98static_assert(static_cast<int>(CPDF_Annot::Subtype::RICHMEDIA) ==
99 FPDF_ANNOT_RICHMEDIA,
100 "CPDF_Annot::RICHMEDIA value mismatch");
101static_assert(static_cast<int>(CPDF_Annot::Subtype::XFAWIDGET) ==
102 FPDF_ANNOT_XFAWIDGET,
103 "CPDF_Annot::XFAWIDGET value mismatch");
104
Jane Liue10509a2017-06-20 16:47:41 -0400105class CPDF_AnnotContext {
106 public:
107 CPDF_AnnotContext(CPDF_Dictionary* pAnnotDict,
108 CPDF_Page* pPage,
109 CPDF_Stream* pStream)
110 : m_pAnnotDict(pAnnotDict), m_pPage(pPage) {
111 SetForm(pStream);
112 }
113 ~CPDF_AnnotContext() {}
114
115 bool HasForm() const { return !!m_pAnnotForm; }
116
117 void SetForm(CPDF_Stream* pStream) {
118 if (!pStream)
119 return;
120
121 m_pAnnotForm = pdfium::MakeUnique<CPDF_Form>(
122 m_pPage->m_pDocument.Get(), m_pPage->m_pResources.Get(), pStream);
123 m_pAnnotForm->ParseContent(nullptr, nullptr, nullptr);
124 }
125
126 CPDF_Form* GetForm() const { return m_pAnnotForm.get(); }
127 CPDF_Dictionary* GetAnnotDict() const { return m_pAnnotDict.Get(); }
128
129 private:
130 std::unique_ptr<CPDF_Form> m_pAnnotForm;
131 CFX_UnownedPtr<CPDF_Dictionary> m_pAnnotDict;
132 CFX_UnownedPtr<CPDF_Page> m_pPage;
133};
134
Jane Liue10509a2017-06-20 16:47:41 -0400135CPDF_AnnotContext* CPDFAnnotContextFromFPDFAnnotation(FPDF_ANNOTATION annot) {
136 return static_cast<CPDF_AnnotContext*>(annot);
137}
138
Jane Liu06462752017-06-27 16:41:14 -0400139bool HasAPStream(const CPDF_Dictionary* pAnnotDict) {
140 return !!FPDFDOC_GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal);
141}
142
Jane Liue10509a2017-06-20 16:47:41 -0400143} // namespace
144
Jane Liu20eafda2017-06-07 10:33:24 -0400145DLLEXPORT FPDF_BOOL STDCALL
146FPDFAnnot_IsSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype) {
147 return subtype == FPDF_ANNOT_CIRCLE || subtype == FPDF_ANNOT_HIGHLIGHT ||
148 subtype == FPDF_ANNOT_INK || subtype == FPDF_ANNOT_POPUP ||
149 subtype == FPDF_ANNOT_SQUARE || subtype == FPDF_ANNOT_SQUIGGLY ||
150 subtype == FPDF_ANNOT_STRIKEOUT || subtype == FPDF_ANNOT_TEXT ||
151 subtype == FPDF_ANNOT_UNDERLINE;
152}
153
Jane Liud60e9ad2017-06-26 11:28:36 -0400154DLLEXPORT FPDF_ANNOTATION STDCALL
155FPDFPage_CreateAnnot(FPDF_PAGE page, FPDF_ANNOTATION_SUBTYPE subtype) {
Jane Liu20eafda2017-06-07 10:33:24 -0400156 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
157 if (!pPage || !FPDFAnnot_IsSupportedSubtype(subtype))
Jane Liud60e9ad2017-06-26 11:28:36 -0400158 return nullptr;
Jane Liu20eafda2017-06-07 10:33:24 -0400159
160 auto pDict = pdfium::MakeUnique<CPDF_Dictionary>(
161 pPage->m_pDocument->GetByteStringPool());
162 pDict->SetNewFor<CPDF_Name>("Type", "Annot");
163 pDict->SetNewFor<CPDF_Name>("Subtype",
164 CPDF_Annot::AnnotSubtypeToString(
165 static_cast<CPDF_Annot::Subtype>(subtype)));
Jane Liud60e9ad2017-06-26 11:28:36 -0400166 auto pNewAnnot =
167 pdfium::MakeUnique<CPDF_AnnotContext>(pDict.get(), pPage, nullptr);
Jane Liu20eafda2017-06-07 10:33:24 -0400168
169 CPDF_Array* pAnnotList = pPage->m_pFormDict->GetArrayFor("Annots");
170 if (!pAnnotList)
171 pAnnotList = pPage->m_pFormDict->SetNewFor<CPDF_Array>("Annots");
172
173 pAnnotList->Add(std::move(pDict));
Jane Liud60e9ad2017-06-26 11:28:36 -0400174 return pNewAnnot.release();
Jane Liu20eafda2017-06-07 10:33:24 -0400175}
176
Jane Liu4fd9a472017-06-01 18:56:09 -0400177DLLEXPORT int STDCALL FPDFPage_GetAnnotCount(FPDF_PAGE page) {
178 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
179 if (!pPage || !pPage->m_pFormDict)
180 return 0;
Jane Liu20eafda2017-06-07 10:33:24 -0400181
Jane Liu4fd9a472017-06-01 18:56:09 -0400182 CPDF_Array* pAnnots = pPage->m_pFormDict->GetArrayFor("Annots");
183 return pAnnots ? pAnnots->GetCount() : 0;
184}
185
Jane Liud60e9ad2017-06-26 11:28:36 -0400186DLLEXPORT FPDF_ANNOTATION STDCALL FPDFPage_GetAnnot(FPDF_PAGE page, int index) {
Jane Liu4fd9a472017-06-01 18:56:09 -0400187 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
Jane Liud60e9ad2017-06-26 11:28:36 -0400188 if (!pPage || !pPage->m_pFormDict || index < 0)
189 return nullptr;
Jane Liu20eafda2017-06-07 10:33:24 -0400190
Jane Liu4fd9a472017-06-01 18:56:09 -0400191 CPDF_Array* pAnnots = pPage->m_pFormDict->GetArrayFor("Annots");
192 if (!pAnnots || static_cast<size_t>(index) >= pAnnots->GetCount())
Jane Liud60e9ad2017-06-26 11:28:36 -0400193 return nullptr;
Jane Liu4fd9a472017-06-01 18:56:09 -0400194
195 CPDF_Dictionary* pDict = ToDictionary(pAnnots->GetDirectObjectAt(index));
Jane Liue10509a2017-06-20 16:47:41 -0400196 auto pNewAnnot = pdfium::MakeUnique<CPDF_AnnotContext>(pDict, pPage, nullptr);
Jane Liud60e9ad2017-06-26 11:28:36 -0400197 return pNewAnnot.release();
Jane Liue10509a2017-06-20 16:47:41 -0400198}
199
200DLLEXPORT void STDCALL FPDFPage_CloseAnnot(FPDF_ANNOTATION annot) {
201 delete CPDFAnnotContextFromFPDFAnnotation(annot);
Jane Liu4fd9a472017-06-01 18:56:09 -0400202}
203
204DLLEXPORT FPDF_ANNOTATION_SUBTYPE STDCALL
205FPDFAnnot_GetSubtype(FPDF_ANNOTATION annot) {
Jane Liud60e9ad2017-06-26 11:28:36 -0400206 if (!annot)
207 return FPDF_ANNOT_UNKNOWN;
208
Jane Liue10509a2017-06-20 16:47:41 -0400209 CPDF_Dictionary* pAnnotDict =
210 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liu4fd9a472017-06-01 18:56:09 -0400211 if (!pAnnotDict)
212 return FPDF_ANNOT_UNKNOWN;
Jane Liu20eafda2017-06-07 10:33:24 -0400213
Jane Liu4fd9a472017-06-01 18:56:09 -0400214 return static_cast<FPDF_ANNOTATION_SUBTYPE>(
215 CPDF_Annot::StringToAnnotSubtype(pAnnotDict->GetStringFor("Subtype")));
216}
217
Jane Liu20eafda2017-06-07 10:33:24 -0400218DLLEXPORT FPDF_BOOL STDCALL FPDFAnnot_SetColor(FPDF_ANNOTATION annot,
219 FPDFANNOT_COLORTYPE type,
220 unsigned int R,
221 unsigned int G,
222 unsigned int B,
223 unsigned int A) {
Jane Liud60e9ad2017-06-26 11:28:36 -0400224 if (!annot || R > 255 || G > 255 || B > 255 || A > 255)
225 return false;
226
Jane Liue10509a2017-06-20 16:47:41 -0400227 CPDF_Dictionary* pAnnotDict =
228 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liud60e9ad2017-06-26 11:28:36 -0400229 if (!pAnnotDict)
Jane Liu20eafda2017-06-07 10:33:24 -0400230 return false;
231
Jane Liu06462752017-06-27 16:41:14 -0400232 // For annotations with their appearance streams already defined, the path
233 // stream's own color definitions take priority over the annotation color
234 // definitions set by this method, hence this method will simply fail.
235 if (HasAPStream(pAnnotDict))
236 return false;
237
Jane Liu20eafda2017-06-07 10:33:24 -0400238 // Set the opacity of the annotation.
239 pAnnotDict->SetNewFor<CPDF_Number>("CA", A / 255.f);
240
241 // Set the color of the annotation.
242 CFX_ByteString key = type == FPDFANNOT_COLORTYPE_InteriorColor ? "IC" : "C";
243 CPDF_Array* pColor = pAnnotDict->GetArrayFor(key);
244 if (pColor)
Lei Zhang59c1ac02017-06-09 11:04:41 -0700245 pColor->Clear();
Jane Liu20eafda2017-06-07 10:33:24 -0400246 else
247 pColor = pAnnotDict->SetNewFor<CPDF_Array>(key);
248
249 pColor->AddNew<CPDF_Number>(R / 255.f);
250 pColor->AddNew<CPDF_Number>(G / 255.f);
251 pColor->AddNew<CPDF_Number>(B / 255.f);
252
253 return true;
254}
255
Jane Liu4fd9a472017-06-01 18:56:09 -0400256DLLEXPORT FPDF_BOOL STDCALL FPDFAnnot_GetColor(FPDF_ANNOTATION annot,
257 FPDFANNOT_COLORTYPE type,
258 unsigned int* R,
259 unsigned int* G,
260 unsigned int* B,
261 unsigned int* A) {
Jane Liud60e9ad2017-06-26 11:28:36 -0400262 if (!annot || !R || !G || !B || !A)
263 return false;
264
Jane Liue10509a2017-06-20 16:47:41 -0400265 CPDF_Dictionary* pAnnotDict =
266 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liud60e9ad2017-06-26 11:28:36 -0400267 if (!pAnnotDict)
Jane Liu4fd9a472017-06-01 18:56:09 -0400268 return false;
269
Jane Liu06462752017-06-27 16:41:14 -0400270 // For annotations with their appearance streams already defined, the path
271 // stream's own color definitions take priority over the annotation color
272 // definitions retrieved by this method, hence this method will simply fail.
273 if (HasAPStream(pAnnotDict))
274 return false;
275
Jane Liu4fd9a472017-06-01 18:56:09 -0400276 CPDF_Array* pColor = pAnnotDict->GetArrayFor(
277 type == FPDFANNOT_COLORTYPE_InteriorColor ? "IC" : "C");
278 *A =
279 (pAnnotDict->KeyExist("CA") ? pAnnotDict->GetNumberFor("CA") : 1) * 255.f;
280 if (!pColor) {
281 // Use default color. The default colors must be consistent with the ones
282 // used to generate AP. See calls to GetColorStringWithDefault() in
283 // CPVT_GenerateAP::Generate*AP().
284 if (pAnnotDict->GetStringFor("Subtype") == "Highlight") {
285 *R = 255;
286 *G = 255;
287 *B = 0;
288 } else {
289 *R = 0;
290 *G = 0;
291 *B = 0;
292 }
293 return true;
294 }
295 CPVT_Color color = CPVT_Color::ParseColor(*pColor);
296 switch (color.nColorType) {
297 case CPVT_Color::kRGB:
298 *R = color.fColor1 * 255.f;
299 *G = color.fColor2 * 255.f;
300 *B = color.fColor3 * 255.f;
301 break;
302 case CPVT_Color::kGray:
303 *R = 255.f * color.fColor1;
304 *G = 255.f * color.fColor1;
305 *B = 255.f * color.fColor1;
306 break;
307 case CPVT_Color::kCMYK:
308 *R = 255.f * (1 - color.fColor1) * (1 - color.fColor4);
309 *G = 255.f * (1 - color.fColor2) * (1 - color.fColor4);
310 *B = 255.f * (1 - color.fColor3) * (1 - color.fColor4);
311 break;
312 case CPVT_Color::kTransparent:
313 *R = 0;
314 *G = 0;
315 *B = 0;
316 break;
317 }
318 return true;
319}
320
321DLLEXPORT FPDF_BOOL STDCALL
322FPDFAnnot_HasAttachmentPoints(FPDF_ANNOTATION annot) {
323 if (!annot)
324 return false;
Jane Liu20eafda2017-06-07 10:33:24 -0400325
Jane Liu4fd9a472017-06-01 18:56:09 -0400326 FPDF_ANNOTATION_SUBTYPE subtype = FPDFAnnot_GetSubtype(annot);
327 return subtype == FPDF_ANNOT_LINK || subtype == FPDF_ANNOT_HIGHLIGHT ||
328 subtype == FPDF_ANNOT_UNDERLINE || subtype == FPDF_ANNOT_SQUIGGLY ||
329 subtype == FPDF_ANNOT_STRIKEOUT;
330}
331
332DLLEXPORT FPDF_BOOL STDCALL
Jane Liu20eafda2017-06-07 10:33:24 -0400333FPDFAnnot_SetAttachmentPoints(FPDF_ANNOTATION annot,
Jane Liu06462752017-06-27 16:41:14 -0400334 const FS_QUADPOINTSF* quadPoints) {
335 if (!annot || !quadPoints || !FPDFAnnot_HasAttachmentPoints(annot))
Jane Liu20eafda2017-06-07 10:33:24 -0400336 return false;
337
Jane Liue10509a2017-06-20 16:47:41 -0400338 CPDF_Dictionary* pAnnotDict =
339 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liud60e9ad2017-06-26 11:28:36 -0400340 if (!pAnnotDict)
341 return false;
342
Jane Liu06462752017-06-27 16:41:14 -0400343 // Update the "QuadPoints" entry in the annotation dictionary.
Jane Liu20eafda2017-06-07 10:33:24 -0400344 CPDF_Array* pQuadPoints = pAnnotDict->GetArrayFor("QuadPoints");
345 if (pQuadPoints)
Lei Zhang59c1ac02017-06-09 11:04:41 -0700346 pQuadPoints->Clear();
Jane Liu20eafda2017-06-07 10:33:24 -0400347 else
348 pQuadPoints = pAnnotDict->SetNewFor<CPDF_Array>("QuadPoints");
349
Jane Liu06462752017-06-27 16:41:14 -0400350 pQuadPoints->AddNew<CPDF_Number>(quadPoints->x1);
351 pQuadPoints->AddNew<CPDF_Number>(quadPoints->y1);
352 pQuadPoints->AddNew<CPDF_Number>(quadPoints->x2);
353 pQuadPoints->AddNew<CPDF_Number>(quadPoints->y2);
354 pQuadPoints->AddNew<CPDF_Number>(quadPoints->x3);
355 pQuadPoints->AddNew<CPDF_Number>(quadPoints->y3);
356 pQuadPoints->AddNew<CPDF_Number>(quadPoints->x4);
357 pQuadPoints->AddNew<CPDF_Number>(quadPoints->y4);
358
359 // If the annotation's appearance stream is defined, and the new quadpoints
360 // defines a bigger bounding box than the appearance stream currently
361 // specifies, then update the "BBox" entry in the AP dictionary too, since it
362 // comes from annotation dictionary's "QuadPoints" entry.
363 CPDF_Stream* pStream =
364 FPDFDOC_GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal);
365 if (pStream) {
366 CFX_FloatRect newRect = CPDF_Annot::RectFromQuadPoints(pAnnotDict);
367 if (newRect.Contains(pStream->GetDict()->GetRectFor("BBox")))
368 pStream->GetDict()->SetRectFor("BBox", newRect);
369 }
Jane Liu20eafda2017-06-07 10:33:24 -0400370 return true;
371}
372
Jane Liud60e9ad2017-06-26 11:28:36 -0400373DLLEXPORT FS_QUADPOINTSF STDCALL
374FPDFAnnot_GetAttachmentPoints(FPDF_ANNOTATION annot) {
375 if (!annot || !FPDFAnnot_HasAttachmentPoints(annot))
376 return FS_QUADPOINTSF();
Jane Liu20eafda2017-06-07 10:33:24 -0400377
Jane Liud60e9ad2017-06-26 11:28:36 -0400378 CPDF_Dictionary* pAnnotDict =
379 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
380 if (!pAnnotDict)
381 return FS_QUADPOINTSF();
382
Jane Liu06462752017-06-27 16:41:14 -0400383 // If the annotation's appearance stream is defined, then retrieve the
384 // quadpoints defined by the "BBox" entry in the AP dictionary, since its
385 // "BBox" entry comes from annotation dictionary's "QuadPoints" entry, but
386 // takes priority over "QuadPoints" when rendering. Otherwise, retrieve
387 // the "Quadpoints" entry from the annotation dictionary.
388 CPDF_Array* pArray;
Jane Liud60e9ad2017-06-26 11:28:36 -0400389 FS_QUADPOINTSF quadPoints;
Jane Liu06462752017-06-27 16:41:14 -0400390 CPDF_Stream* pStream =
391 FPDFDOC_GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal);
392 if (pStream) {
393 pArray = pStream->GetDict()->GetArrayFor("BBox");
394 if (!pArray)
395 return FS_QUADPOINTSF();
396
397 // Convert the BBox array into quadpoint coordinates. BBox array follows the
398 // order of a rectangle array: (left, bottom, right, up); and quadpoints
399 // follows the following order: (top-left vertex, top-right vertex, bottom-
400 // left vertex, bottom-right vertex).
401 quadPoints.x1 = pArray->GetNumberAt(0);
402 quadPoints.y1 = pArray->GetNumberAt(3);
403 quadPoints.x2 = pArray->GetNumberAt(2);
404 quadPoints.y2 = pArray->GetNumberAt(3);
405 quadPoints.x3 = pArray->GetNumberAt(0);
406 quadPoints.y3 = pArray->GetNumberAt(1);
407 quadPoints.x4 = pArray->GetNumberAt(2);
408 quadPoints.y4 = pArray->GetNumberAt(1);
409 } else {
410 pArray = pAnnotDict->GetArrayFor("QuadPoints");
411 if (!pArray)
412 return FS_QUADPOINTSF();
413
414 quadPoints.x1 = pArray->GetNumberAt(0);
415 quadPoints.y1 = pArray->GetNumberAt(1);
416 quadPoints.x2 = pArray->GetNumberAt(2);
417 quadPoints.y2 = pArray->GetNumberAt(3);
418 quadPoints.x3 = pArray->GetNumberAt(4);
419 quadPoints.y3 = pArray->GetNumberAt(5);
420 quadPoints.x4 = pArray->GetNumberAt(6);
421 quadPoints.y4 = pArray->GetNumberAt(7);
422 }
Jane Liud60e9ad2017-06-26 11:28:36 -0400423 return quadPoints;
Jane Liu4fd9a472017-06-01 18:56:09 -0400424}
425
Jane Liu20eafda2017-06-07 10:33:24 -0400426DLLEXPORT FPDF_BOOL STDCALL FPDFAnnot_SetRect(FPDF_ANNOTATION annot,
Jane Liu06462752017-06-27 16:41:14 -0400427 const FS_RECTF* rect) {
428 if (!annot || !rect)
Jane Liud60e9ad2017-06-26 11:28:36 -0400429 return false;
430
Jane Liue10509a2017-06-20 16:47:41 -0400431 CPDF_Dictionary* pAnnotDict =
432 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liu20eafda2017-06-07 10:33:24 -0400433 if (!pAnnotDict)
434 return false;
435
Jane Liu06462752017-06-27 16:41:14 -0400436 CFX_FloatRect newRect(rect->left, rect->bottom, rect->right, rect->top);
Jane Liu20eafda2017-06-07 10:33:24 -0400437
Jane Liu06462752017-06-27 16:41:14 -0400438 // Update the "Rect" entry in the annotation dictionary.
439 pAnnotDict->SetRectFor("Rect", newRect);
440
441 // If the annotation's appearance stream is defined, the annotation is of a
442 // type that does not have quadpoints, and the new rectangle is bigger than
443 // the current bounding box, then update the "BBox" entry in the AP
444 // dictionary too, since its "BBox" entry comes from annotation dictionary's
445 // "Rect" entry.
446 if (FPDFAnnot_HasAttachmentPoints(annot))
447 return true;
448
449 CPDF_Stream* pStream =
450 FPDFDOC_GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal);
451 if (pStream && newRect.Contains(pStream->GetDict()->GetRectFor("BBox")))
452 pStream->GetDict()->SetRectFor("BBox", newRect);
Jane Liu20eafda2017-06-07 10:33:24 -0400453 return true;
454}
455
Jane Liud60e9ad2017-06-26 11:28:36 -0400456DLLEXPORT FS_RECTF STDCALL FPDFAnnot_GetRect(FPDF_ANNOTATION annot) {
457 if (!annot)
458 return FS_RECTF();
459
Jane Liue10509a2017-06-20 16:47:41 -0400460 CPDF_Dictionary* pAnnotDict =
461 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liud60e9ad2017-06-26 11:28:36 -0400462 if (!pAnnotDict)
463 return FS_RECTF();
Jane Liu20eafda2017-06-07 10:33:24 -0400464
Jane Liu06462752017-06-27 16:41:14 -0400465 // If the annotation's appearance stream is defined and the annotation is of
466 // a type that does not have quadpoints, then retrieve the rectangle defined
467 // by the "BBox" entry in the AP dictionary, since its "BBox" entry comes
468 // from annotation dictionary's "Rect" entry, but takes priority over "Rect"
469 // when rendering. Otherwise, retrieve the "Rect" entry from the annotation
470 // dictionary.
471 CFX_FloatRect rt;
472 CPDF_Stream* pStream =
473 FPDFDOC_GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal);
474 if (!pStream || FPDFAnnot_HasAttachmentPoints(annot))
475 rt = pAnnotDict->GetRectFor("Rect");
476 else
477 rt = pStream->GetDict()->GetRectFor("BBox");
Jane Liu20eafda2017-06-07 10:33:24 -0400478
Jane Liud60e9ad2017-06-26 11:28:36 -0400479 FS_RECTF rect;
480 rect.left = rt.left;
481 rect.bottom = rt.bottom;
482 rect.right = rt.right;
483 rect.top = rt.top;
484 return rect;
Jane Liu4fd9a472017-06-01 18:56:09 -0400485}
486
Jane Liu20eafda2017-06-07 10:33:24 -0400487DLLEXPORT FPDF_BOOL STDCALL FPDFAnnot_SetText(FPDF_ANNOTATION annot,
488 FPDFANNOT_TEXTTYPE type,
489 FPDF_WIDESTRING text) {
Jane Liud60e9ad2017-06-26 11:28:36 -0400490 if (!annot)
491 return false;
492
Jane Liue10509a2017-06-20 16:47:41 -0400493 CPDF_Dictionary* pAnnotDict =
494 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liu20eafda2017-06-07 10:33:24 -0400495 if (!pAnnotDict)
496 return false;
497
498 CFX_ByteString key = type == FPDFANNOT_TEXTTYPE_Author ? "T" : "Contents";
499 FX_STRSIZE len = CFX_WideString::WStringLength(text);
500 CFX_WideString encodedText = CFX_WideString::FromUTF16LE(text, len);
501 pAnnotDict->SetNewFor<CPDF_String>(key, encodedText.UTF8Encode(), false);
502 return true;
503}
504
Jane Liu4fd9a472017-06-01 18:56:09 -0400505DLLEXPORT unsigned long STDCALL FPDFAnnot_GetText(FPDF_ANNOTATION annot,
506 FPDFANNOT_TEXTTYPE type,
Jane Liu262cf462017-06-09 11:36:37 -0400507 void* buffer,
Jane Liu4fd9a472017-06-01 18:56:09 -0400508 unsigned long buflen) {
Jane Liud60e9ad2017-06-26 11:28:36 -0400509 if (!annot)
510 return 0;
511
Jane Liue10509a2017-06-20 16:47:41 -0400512 CPDF_Dictionary* pAnnotDict =
513 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict();
Jane Liu4fd9a472017-06-01 18:56:09 -0400514 if (!pAnnotDict)
515 return 0;
Jane Liu20eafda2017-06-07 10:33:24 -0400516
Jane Liu4fd9a472017-06-01 18:56:09 -0400517 CFX_ByteString key = type == FPDFANNOT_TEXTTYPE_Author ? "T" : "Contents";
518 CFX_ByteString contents = pAnnotDict->GetUnicodeTextFor(key).UTF16LE_Encode();
519 unsigned long len = contents.GetLength();
520 if (buffer && buflen >= len)
521 memcpy(buffer, contents.c_str(), len);
Jane Liu20eafda2017-06-07 10:33:24 -0400522
Jane Liu4fd9a472017-06-01 18:56:09 -0400523 return len;
524}