1 // Copyright 2017 PDFium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "public/fpdf_annot.h" 6 7 #include <memory> 8 #include <utility> 9 10 #include "core/fpdfapi/edit/cpdf_pagecontentgenerator.h" 11 #include "core/fpdfapi/page/cpdf_form.h" 12 #include "core/fpdfapi/page/cpdf_page.h" 13 #include "core/fpdfapi/page/cpdf_pageobject.h" 14 #include "core/fpdfapi/parser/cpdf_array.h" 15 #include "core/fpdfapi/parser/cpdf_dictionary.h" 16 #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" 20 #include "core/fpdfdoc/cpdf_annot.h" 21 #include "core/fpdfdoc/cpdf_formfield.h" 22 #include "core/fpdfdoc/cpdf_interform.h" 23 #include "core/fpdfdoc/cpvt_generateap.h" 24 #include "core/fxge/cfx_color.h" 25 #include "fpdfsdk/fsdk_define.h" 26 27 namespace { 28 29 // These checks ensure the consistency of annotation subtype values across core/ 30 // and public. 31 static_assert(static_cast<int>(CPDF_Annot::Subtype::UNKNOWN) == 32 FPDF_ANNOT_UNKNOWN, 33 "CPDF_Annot::UNKNOWN value mismatch"); 34 static_assert(static_cast<int>(CPDF_Annot::Subtype::TEXT) == FPDF_ANNOT_TEXT, 35 "CPDF_Annot::TEXT value mismatch"); 36 static_assert(static_cast<int>(CPDF_Annot::Subtype::LINK) == FPDF_ANNOT_LINK, 37 "CPDF_Annot::LINK value mismatch"); 38 static_assert(static_cast<int>(CPDF_Annot::Subtype::FREETEXT) == 39 FPDF_ANNOT_FREETEXT, 40 "CPDF_Annot::FREETEXT value mismatch"); 41 static_assert(static_cast<int>(CPDF_Annot::Subtype::LINE) == FPDF_ANNOT_LINE, 42 "CPDF_Annot::LINE value mismatch"); 43 static_assert(static_cast<int>(CPDF_Annot::Subtype::SQUARE) == 44 FPDF_ANNOT_SQUARE, 45 "CPDF_Annot::SQUARE value mismatch"); 46 static_assert(static_cast<int>(CPDF_Annot::Subtype::CIRCLE) == 47 FPDF_ANNOT_CIRCLE, 48 "CPDF_Annot::CIRCLE value mismatch"); 49 static_assert(static_cast<int>(CPDF_Annot::Subtype::POLYGON) == 50 FPDF_ANNOT_POLYGON, 51 "CPDF_Annot::POLYGON value mismatch"); 52 static_assert(static_cast<int>(CPDF_Annot::Subtype::POLYLINE) == 53 FPDF_ANNOT_POLYLINE, 54 "CPDF_Annot::POLYLINE value mismatch"); 55 static_assert(static_cast<int>(CPDF_Annot::Subtype::HIGHLIGHT) == 56 FPDF_ANNOT_HIGHLIGHT, 57 "CPDF_Annot::HIGHLIGHT value mismatch"); 58 static_assert(static_cast<int>(CPDF_Annot::Subtype::UNDERLINE) == 59 FPDF_ANNOT_UNDERLINE, 60 "CPDF_Annot::UNDERLINE value mismatch"); 61 static_assert(static_cast<int>(CPDF_Annot::Subtype::SQUIGGLY) == 62 FPDF_ANNOT_SQUIGGLY, 63 "CPDF_Annot::SQUIGGLY value mismatch"); 64 static_assert(static_cast<int>(CPDF_Annot::Subtype::STRIKEOUT) == 65 FPDF_ANNOT_STRIKEOUT, 66 "CPDF_Annot::STRIKEOUT value mismatch"); 67 static_assert(static_cast<int>(CPDF_Annot::Subtype::STAMP) == FPDF_ANNOT_STAMP, 68 "CPDF_Annot::STAMP value mismatch"); 69 static_assert(static_cast<int>(CPDF_Annot::Subtype::CARET) == FPDF_ANNOT_CARET, 70 "CPDF_Annot::CARET value mismatch"); 71 static_assert(static_cast<int>(CPDF_Annot::Subtype::INK) == FPDF_ANNOT_INK, 72 "CPDF_Annot::INK value mismatch"); 73 static_assert(static_cast<int>(CPDF_Annot::Subtype::POPUP) == FPDF_ANNOT_POPUP, 74 "CPDF_Annot::POPUP value mismatch"); 75 static_assert(static_cast<int>(CPDF_Annot::Subtype::FILEATTACHMENT) == 76 FPDF_ANNOT_FILEATTACHMENT, 77 "CPDF_Annot::FILEATTACHMENT value mismatch"); 78 static_assert(static_cast<int>(CPDF_Annot::Subtype::SOUND) == FPDF_ANNOT_SOUND, 79 "CPDF_Annot::SOUND value mismatch"); 80 static_assert(static_cast<int>(CPDF_Annot::Subtype::MOVIE) == FPDF_ANNOT_MOVIE, 81 "CPDF_Annot::MOVIE value mismatch"); 82 static_assert(static_cast<int>(CPDF_Annot::Subtype::WIDGET) == 83 FPDF_ANNOT_WIDGET, 84 "CPDF_Annot::WIDGET value mismatch"); 85 static_assert(static_cast<int>(CPDF_Annot::Subtype::SCREEN) == 86 FPDF_ANNOT_SCREEN, 87 "CPDF_Annot::SCREEN value mismatch"); 88 static_assert(static_cast<int>(CPDF_Annot::Subtype::PRINTERMARK) == 89 FPDF_ANNOT_PRINTERMARK, 90 "CPDF_Annot::PRINTERMARK value mismatch"); 91 static_assert(static_cast<int>(CPDF_Annot::Subtype::TRAPNET) == 92 FPDF_ANNOT_TRAPNET, 93 "CPDF_Annot::TRAPNET value mismatch"); 94 static_assert(static_cast<int>(CPDF_Annot::Subtype::WATERMARK) == 95 FPDF_ANNOT_WATERMARK, 96 "CPDF_Annot::WATERMARK value mismatch"); 97 static_assert(static_cast<int>(CPDF_Annot::Subtype::THREED) == 98 FPDF_ANNOT_THREED, 99 "CPDF_Annot::THREED value mismatch"); 100 static_assert(static_cast<int>(CPDF_Annot::Subtype::RICHMEDIA) == 101 FPDF_ANNOT_RICHMEDIA, 102 "CPDF_Annot::RICHMEDIA value mismatch"); 103 static_assert(static_cast<int>(CPDF_Annot::Subtype::XFAWIDGET) == 104 FPDF_ANNOT_XFAWIDGET, 105 "CPDF_Annot::XFAWIDGET value mismatch"); 106 107 // These checks ensure the consistency of annotation appearance mode values 108 // across core/ and public. 109 static_assert(static_cast<int>(CPDF_Annot::AppearanceMode::Normal) == 110 FPDF_ANNOT_APPEARANCEMODE_NORMAL, 111 "CPDF_Annot::AppearanceMode::Normal value mismatch"); 112 static_assert(static_cast<int>(CPDF_Annot::AppearanceMode::Rollover) == 113 FPDF_ANNOT_APPEARANCEMODE_ROLLOVER, 114 "CPDF_Annot::AppearanceMode::Rollover value mismatch"); 115 static_assert(static_cast<int>(CPDF_Annot::AppearanceMode::Down) == 116 FPDF_ANNOT_APPEARANCEMODE_DOWN, 117 "CPDF_Annot::AppearanceMode::Down value mismatch"); 118 119 // These checks ensure the consistency of dictionary value types across core/ 120 // and public/. 121 static_assert(static_cast<int>(CPDF_Object::Type::BOOLEAN) == 122 FPDF_OBJECT_BOOLEAN, 123 "CPDF_Object::BOOLEAN value mismatch"); 124 static_assert(static_cast<int>(CPDF_Object::Type::NUMBER) == FPDF_OBJECT_NUMBER, 125 "CPDF_Object::NUMBER value mismatch"); 126 static_assert(static_cast<int>(CPDF_Object::Type::STRING) == FPDF_OBJECT_STRING, 127 "CPDF_Object::STRING value mismatch"); 128 static_assert(static_cast<int>(CPDF_Object::Type::NAME) == FPDF_OBJECT_NAME, 129 "CPDF_Object::NAME value mismatch"); 130 static_assert(static_cast<int>(CPDF_Object::Type::ARRAY) == FPDF_OBJECT_ARRAY, 131 "CPDF_Object::ARRAY value mismatch"); 132 static_assert(static_cast<int>(CPDF_Object::Type::DICTIONARY) == 133 FPDF_OBJECT_DICTIONARY, 134 "CPDF_Object::DICTIONARY value mismatch"); 135 static_assert(static_cast<int>(CPDF_Object::Type::STREAM) == FPDF_OBJECT_STREAM, 136 "CPDF_Object::STREAM value mismatch"); 137 static_assert(static_cast<int>(CPDF_Object::Type::NULLOBJ) == 138 FPDF_OBJECT_NULLOBJ, 139 "CPDF_Object::NULLOBJ value mismatch"); 140 static_assert(static_cast<int>(CPDF_Object::Type::REFERENCE) == 141 FPDF_OBJECT_REFERENCE, 142 "CPDF_Object::REFERENCE value mismatch"); 143 144 class CPDF_AnnotContext { 145 public: 146 CPDF_AnnotContext(CPDF_Dictionary* pAnnotDict, 147 CPDF_Page* pPage, 148 CPDF_Stream* pStream) 149 : m_pAnnotDict(pAnnotDict), m_pPage(pPage) { 150 SetForm(pStream); 151 } 152 ~CPDF_AnnotContext() {} 153 154 bool HasForm() const { return !!m_pAnnotForm; } 155 156 void SetForm(CPDF_Stream* pStream) { 157 if (!pStream) 158 return; 159 160 // Reset the annotation matrix to be the identity matrix, since the 161 // appearance stream already takes matrix into account. 162 pStream->GetDict()->SetMatrixFor("Matrix", CFX_Matrix()); 163 164 m_pAnnotForm = pdfium::MakeUnique<CPDF_Form>( 165 m_pPage->m_pDocument.Get(), m_pPage->m_pResources.Get(), pStream); 166 m_pAnnotForm->ParseContent(); 167 } 168 169 CPDF_Form* GetForm() const { return m_pAnnotForm.get(); } 170 CPDF_Dictionary* GetAnnotDict() const { return m_pAnnotDict.Get(); } 171 CPDF_Page* GetPage() const { return m_pPage.Get(); } 172 173 private: 174 std::unique_ptr<CPDF_Form> m_pAnnotForm; 175 UnownedPtr<CPDF_Dictionary> m_pAnnotDict; 176 UnownedPtr<CPDF_Page> m_pPage; 177 }; 178 179 CPDF_AnnotContext* CPDFAnnotContextFromFPDFAnnotation(FPDF_ANNOTATION annot) { 180 return static_cast<CPDF_AnnotContext*>(annot); 181 } 182 183 bool HasAPStream(const CPDF_Dictionary* pAnnotDict) { 184 return !!FPDFDOC_GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal); 185 } 186 187 void UpdateContentStream(CPDF_Form* pForm, CPDF_Stream* pStream) { 188 ASSERT(pForm); 189 ASSERT(pStream); 190 191 CPDF_PageContentGenerator generator(pForm); 192 std::ostringstream buf; 193 generator.ProcessPageObjects(&buf); 194 pStream->SetDataAndRemoveFilter(&buf); 195 } 196 197 } // namespace 198 199 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV 200 FPDFAnnot_IsSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype) { 201 // The supported subtypes must also be communicated in the user doc. 202 return subtype == FPDF_ANNOT_CIRCLE || subtype == FPDF_ANNOT_HIGHLIGHT || 203 subtype == FPDF_ANNOT_INK || subtype == FPDF_ANNOT_POPUP || 204 subtype == FPDF_ANNOT_SQUARE || subtype == FPDF_ANNOT_SQUIGGLY || 205 subtype == FPDF_ANNOT_STAMP || subtype == FPDF_ANNOT_STRIKEOUT || 206 subtype == FPDF_ANNOT_TEXT || subtype == FPDF_ANNOT_UNDERLINE; 207 } 208 209 FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV 210 FPDFPage_CreateAnnot(FPDF_PAGE page, FPDF_ANNOTATION_SUBTYPE subtype) { 211 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); 212 if (!pPage || !FPDFAnnot_IsSupportedSubtype(subtype)) 213 return nullptr; 214 215 auto pDict = pdfium::MakeUnique<CPDF_Dictionary>( 216 pPage->m_pDocument->GetByteStringPool()); 217 pDict->SetNewFor<CPDF_Name>("Type", "Annot"); 218 pDict->SetNewFor<CPDF_Name>("Subtype", 219 CPDF_Annot::AnnotSubtypeToString( 220 static_cast<CPDF_Annot::Subtype>(subtype))); 221 auto pNewAnnot = 222 pdfium::MakeUnique<CPDF_AnnotContext>(pDict.get(), pPage, nullptr); 223 224 CPDF_Array* pAnnotList = pPage->m_pFormDict->GetArrayFor("Annots"); 225 if (!pAnnotList) 226 pAnnotList = pPage->m_pFormDict->SetNewFor<CPDF_Array>("Annots"); 227 228 pAnnotList->Add(std::move(pDict)); 229 return pNewAnnot.release(); 230 } 231 232 FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetAnnotCount(FPDF_PAGE page) { 233 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); 234 if (!pPage || !pPage->m_pFormDict) 235 return 0; 236 237 CPDF_Array* pAnnots = pPage->m_pFormDict->GetArrayFor("Annots"); 238 return pAnnots ? pAnnots->GetCount() : 0; 239 } 240 241 FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFPage_GetAnnot(FPDF_PAGE page, 242 int index) { 243 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); 244 if (!pPage || !pPage->m_pFormDict || index < 0) 245 return nullptr; 246 247 CPDF_Array* pAnnots = pPage->m_pFormDict->GetArrayFor("Annots"); 248 if (!pAnnots || static_cast<size_t>(index) >= pAnnots->GetCount()) 249 return nullptr; 250 251 CPDF_Dictionary* pDict = ToDictionary(pAnnots->GetDirectObjectAt(index)); 252 auto pNewAnnot = pdfium::MakeUnique<CPDF_AnnotContext>(pDict, pPage, nullptr); 253 return pNewAnnot.release(); 254 } 255 256 FPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetAnnotIndex(FPDF_PAGE page, 257 FPDF_ANNOTATION annot) { 258 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); 259 CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot); 260 if (!pPage || !pPage->m_pFormDict || !pAnnot || !pAnnot->GetAnnotDict()) 261 return -1; 262 263 CPDF_Array* pAnnots = pPage->m_pFormDict->GetArrayFor("Annots"); 264 if (!pAnnots) 265 return -1; 266 267 CPDF_Dictionary* pDict = pAnnot->GetAnnotDict(); 268 auto it = 269 std::find_if(pAnnots->begin(), pAnnots->end(), 270 [pDict](const std::unique_ptr<CPDF_Object>& candidate) { 271 return candidate->GetDirect() == pDict; 272 }); 273 274 if (it == pAnnots->end()) 275 return -1; 276 277 return it - pAnnots->begin(); 278 } 279 280 FPDF_EXPORT void FPDF_CALLCONV FPDFPage_CloseAnnot(FPDF_ANNOTATION annot) { 281 delete CPDFAnnotContextFromFPDFAnnotation(annot); 282 } 283 284 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_RemoveAnnot(FPDF_PAGE page, 285 int index) { 286 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); 287 if (!pPage || !pPage->m_pFormDict || index < 0) 288 return false; 289 290 CPDF_Array* pAnnots = pPage->m_pFormDict->GetArrayFor("Annots"); 291 if (!pAnnots || static_cast<size_t>(index) >= pAnnots->GetCount()) 292 return false; 293 294 pAnnots->RemoveAt(index); 295 return true; 296 } 297 298 FPDF_EXPORT FPDF_ANNOTATION_SUBTYPE FPDF_CALLCONV 299 FPDFAnnot_GetSubtype(FPDF_ANNOTATION annot) { 300 if (!annot) 301 return FPDF_ANNOT_UNKNOWN; 302 303 CPDF_Dictionary* pAnnotDict = 304 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict(); 305 if (!pAnnotDict) 306 return FPDF_ANNOT_UNKNOWN; 307 308 return static_cast<FPDF_ANNOTATION_SUBTYPE>( 309 CPDF_Annot::StringToAnnotSubtype(pAnnotDict->GetStringFor("Subtype"))); 310 } 311 312 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV 313 FPDFAnnot_IsObjectSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype) { 314 // The supported subtypes must also be communicated in the user doc. 315 return subtype == FPDF_ANNOT_INK || subtype == FPDF_ANNOT_STAMP; 316 } 317 318 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV 319 FPDFAnnot_UpdateObject(FPDF_ANNOTATION annot, FPDF_PAGEOBJECT obj) { 320 CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot); 321 CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(obj); 322 if (!pAnnot || !pAnnot->GetAnnotDict() || !pAnnot->HasForm() || !pObj) 323 return false; 324 325 // Check that the annotation type is supported by this method. 326 if (!FPDFAnnot_IsObjectSupportedSubtype(FPDFAnnot_GetSubtype(annot))) 327 return false; 328 329 // Check that the annotation already has an appearance stream, since an 330 // existing object is to be updated. 331 CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(pAnnot->GetAnnotDict(), 332 CPDF_Annot::AppearanceMode::Normal); 333 if (!pStream) 334 return false; 335 336 // Check that the object is already in this annotation's object list. 337 CPDF_Form* pForm = pAnnot->GetForm(); 338 CPDF_PageObjectList* pObjList = pForm->GetPageObjectList(); 339 auto it = 340 std::find_if(pObjList->begin(), pObjList->end(), 341 [pObj](const std::unique_ptr<CPDF_PageObject>& candidate) { 342 return candidate.get() == pObj; 343 }); 344 if (it == pObjList->end()) 345 return false; 346 347 // Update the content stream data in the annotation's AP stream. 348 UpdateContentStream(pForm, pStream); 349 return true; 350 } 351 352 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV 353 FPDFAnnot_AppendObject(FPDF_ANNOTATION annot, FPDF_PAGEOBJECT obj) { 354 CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot); 355 CPDF_PageObject* pObj = CPDFPageObjectFromFPDFPageObject(obj); 356 if (!pAnnot || !pObj) 357 return false; 358 359 CPDF_Dictionary* pAnnotDict = pAnnot->GetAnnotDict(); 360 CPDF_Page* pPage = pAnnot->GetPage(); 361 if (!pAnnotDict || !pPage) 362 return false; 363 364 // Check that the annotation type is supported by this method. 365 if (!FPDFAnnot_IsObjectSupportedSubtype(FPDFAnnot_GetSubtype(annot))) 366 return false; 367 368 // If the annotation does not have an AP stream yet, generate and set it. 369 CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(pAnnot->GetAnnotDict(), 370 CPDF_Annot::AppearanceMode::Normal); 371 if (!pStream) { 372 CPVT_GenerateAP::GenerateEmptyAP(pPage->m_pDocument.Get(), pAnnotDict); 373 pStream = 374 FPDFDOC_GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal); 375 if (!pStream) 376 return false; 377 } 378 379 // Get the annotation's corresponding form object for parsing its AP stream. 380 if (!pAnnot->HasForm()) 381 pAnnot->SetForm(pStream); 382 383 // Check that the object did not come from the same annotation. If this check 384 // succeeds, then it is assumed that the object came from 385 // FPDFPageObj_CreateNew{Path|Rect}() or FPDFPageObj_New{Text|Image}Obj(). 386 // Note that an object that came from a different annotation must not be 387 // passed here, since an object cannot belong to more than one annotation. 388 CPDF_Form* pForm = pAnnot->GetForm(); 389 CPDF_PageObjectList* pObjList = pForm->GetPageObjectList(); 390 auto it = 391 std::find_if(pObjList->begin(), pObjList->end(), 392 [pObj](const std::unique_ptr<CPDF_PageObject>& candidate) { 393 return candidate.get() == pObj; 394 }); 395 if (it != pObjList->end()) 396 return false; 397 398 // Append the object to the object list. 399 std::unique_ptr<CPDF_PageObject> pPageObjHolder(pObj); 400 pObjList->push_back(std::move(pPageObjHolder)); 401 402 // Set the content stream data in the annotation's AP stream. 403 UpdateContentStream(pForm, pStream); 404 return true; 405 } 406 407 FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetObjectCount(FPDF_ANNOTATION annot) { 408 CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot); 409 if (!pAnnot || !pAnnot->GetAnnotDict()) 410 return 0; 411 412 if (!pAnnot->HasForm()) { 413 CPDF_Stream* pStream = FPDFDOC_GetAnnotAP( 414 pAnnot->GetAnnotDict(), CPDF_Annot::AppearanceMode::Normal); 415 if (!pStream) 416 return 0; 417 418 pAnnot->SetForm(pStream); 419 } 420 return pdfium::CollectionSize<int>(*pAnnot->GetForm()->GetPageObjectList()); 421 } 422 423 FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV 424 FPDFAnnot_GetObject(FPDF_ANNOTATION annot, int index) { 425 CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot); 426 if (!pAnnot || !pAnnot->GetAnnotDict() || index < 0) 427 return nullptr; 428 429 if (!pAnnot->HasForm()) { 430 CPDF_Stream* pStream = FPDFDOC_GetAnnotAP( 431 pAnnot->GetAnnotDict(), CPDF_Annot::AppearanceMode::Normal); 432 if (!pStream) 433 return nullptr; 434 435 pAnnot->SetForm(pStream); 436 } 437 438 return pAnnot->GetForm()->GetPageObjectList()->GetPageObjectByIndex(index); 439 } 440 441 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV 442 FPDFAnnot_RemoveObject(FPDF_ANNOTATION annot, int index) { 443 CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot); 444 if (!pAnnot || !pAnnot->GetAnnotDict() || !pAnnot->HasForm() || index < 0) 445 return false; 446 447 // Check that the annotation type is supported by this method. 448 if (!FPDFAnnot_IsObjectSupportedSubtype(FPDFAnnot_GetSubtype(annot))) 449 return false; 450 451 // Check that the annotation already has an appearance stream, since an 452 // existing object is to be deleted. 453 CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(pAnnot->GetAnnotDict(), 454 CPDF_Annot::AppearanceMode::Normal); 455 if (!pStream) 456 return false; 457 458 CPDF_PageObjectList* pObjList = pAnnot->GetForm()->GetPageObjectList(); 459 if (static_cast<size_t>(index) >= pObjList->size()) 460 return false; 461 462 pObjList->erase(pObjList->begin() + index); 463 UpdateContentStream(pAnnot->GetForm(), pStream); 464 return true; 465 } 466 467 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetColor(FPDF_ANNOTATION annot, 468 FPDFANNOT_COLORTYPE type, 469 unsigned int R, 470 unsigned int G, 471 unsigned int B, 472 unsigned int A) { 473 if (!annot || R > 255 || G > 255 || B > 255 || A > 255) 474 return false; 475 476 CPDF_Dictionary* pAnnotDict = 477 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict(); 478 if (!pAnnotDict) 479 return false; 480 481 // For annotations with their appearance streams already defined, the path 482 // stream's own color definitions take priority over the annotation color 483 // definitions set by this method, hence this method will simply fail. 484 if (HasAPStream(pAnnotDict)) 485 return false; 486 487 // Set the opacity of the annotation. 488 pAnnotDict->SetNewFor<CPDF_Number>("CA", A / 255.f); 489 490 // Set the color of the annotation. 491 ByteString key = type == FPDFANNOT_COLORTYPE_InteriorColor ? "IC" : "C"; 492 CPDF_Array* pColor = pAnnotDict->GetArrayFor(key); 493 if (pColor) 494 pColor->Clear(); 495 else 496 pColor = pAnnotDict->SetNewFor<CPDF_Array>(key); 497 498 pColor->AddNew<CPDF_Number>(R / 255.f); 499 pColor->AddNew<CPDF_Number>(G / 255.f); 500 pColor->AddNew<CPDF_Number>(B / 255.f); 501 502 return true; 503 } 504 505 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetColor(FPDF_ANNOTATION annot, 506 FPDFANNOT_COLORTYPE type, 507 unsigned int* R, 508 unsigned int* G, 509 unsigned int* B, 510 unsigned int* A) { 511 if (!annot || !R || !G || !B || !A) 512 return false; 513 514 CPDF_Dictionary* pAnnotDict = 515 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict(); 516 if (!pAnnotDict) 517 return false; 518 519 // For annotations with their appearance streams already defined, the path 520 // stream's own color definitions take priority over the annotation color 521 // definitions retrieved by this method, hence this method will simply fail. 522 if (HasAPStream(pAnnotDict)) 523 return false; 524 525 CPDF_Array* pColor = pAnnotDict->GetArrayFor( 526 type == FPDFANNOT_COLORTYPE_InteriorColor ? "IC" : "C"); 527 *A = 528 (pAnnotDict->KeyExist("CA") ? pAnnotDict->GetNumberFor("CA") : 1) * 255.f; 529 if (!pColor) { 530 // Use default color. The default colors must be consistent with the ones 531 // used to generate AP. See calls to GetColorStringWithDefault() in 532 // CPVT_GenerateAP::Generate*AP(). 533 if (pAnnotDict->GetStringFor("Subtype") == "Highlight") { 534 *R = 255; 535 *G = 255; 536 *B = 0; 537 } else { 538 *R = 0; 539 *G = 0; 540 *B = 0; 541 } 542 return true; 543 } 544 545 CFX_Color color = CFX_Color::ParseColor(*pColor); 546 switch (color.nColorType) { 547 case CFX_Color::kRGB: 548 *R = color.fColor1 * 255.f; 549 *G = color.fColor2 * 255.f; 550 *B = color.fColor3 * 255.f; 551 break; 552 case CFX_Color::kGray: 553 *R = 255.f * color.fColor1; 554 *G = 255.f * color.fColor1; 555 *B = 255.f * color.fColor1; 556 break; 557 case CFX_Color::kCMYK: 558 *R = 255.f * (1 - color.fColor1) * (1 - color.fColor4); 559 *G = 255.f * (1 - color.fColor2) * (1 - color.fColor4); 560 *B = 255.f * (1 - color.fColor3) * (1 - color.fColor4); 561 break; 562 case CFX_Color::kTransparent: 563 *R = 0; 564 *G = 0; 565 *B = 0; 566 break; 567 } 568 return true; 569 } 570 571 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV 572 FPDFAnnot_HasAttachmentPoints(FPDF_ANNOTATION annot) { 573 if (!annot) 574 return false; 575 576 FPDF_ANNOTATION_SUBTYPE subtype = FPDFAnnot_GetSubtype(annot); 577 return subtype == FPDF_ANNOT_LINK || subtype == FPDF_ANNOT_HIGHLIGHT || 578 subtype == FPDF_ANNOT_UNDERLINE || subtype == FPDF_ANNOT_SQUIGGLY || 579 subtype == FPDF_ANNOT_STRIKEOUT; 580 } 581 582 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV 583 FPDFAnnot_SetAttachmentPoints(FPDF_ANNOTATION annot, 584 const FS_QUADPOINTSF* quadPoints) { 585 if (!annot || !quadPoints || !FPDFAnnot_HasAttachmentPoints(annot)) 586 return false; 587 588 CPDF_Dictionary* pAnnotDict = 589 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict(); 590 if (!pAnnotDict) 591 return false; 592 593 // Update the "QuadPoints" entry in the annotation dictionary. 594 CPDF_Array* pQuadPoints = pAnnotDict->GetArrayFor("QuadPoints"); 595 if (pQuadPoints) 596 pQuadPoints->Clear(); 597 else 598 pQuadPoints = pAnnotDict->SetNewFor<CPDF_Array>("QuadPoints"); 599 600 pQuadPoints->AddNew<CPDF_Number>(quadPoints->x1); 601 pQuadPoints->AddNew<CPDF_Number>(quadPoints->y1); 602 pQuadPoints->AddNew<CPDF_Number>(quadPoints->x2); 603 pQuadPoints->AddNew<CPDF_Number>(quadPoints->y2); 604 pQuadPoints->AddNew<CPDF_Number>(quadPoints->x3); 605 pQuadPoints->AddNew<CPDF_Number>(quadPoints->y3); 606 pQuadPoints->AddNew<CPDF_Number>(quadPoints->x4); 607 pQuadPoints->AddNew<CPDF_Number>(quadPoints->y4); 608 609 // If the annotation's appearance stream is defined, and the new quadpoints 610 // defines a bigger bounding box than the appearance stream currently 611 // specifies, then update the "BBox" entry in the AP dictionary too, since it 612 // comes from annotation dictionary's "QuadPoints" entry. 613 CPDF_Stream* pStream = 614 FPDFDOC_GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal); 615 if (pStream) { 616 CFX_FloatRect newRect = CPDF_Annot::RectFromQuadPoints(pAnnotDict); 617 if (newRect.Contains(pStream->GetDict()->GetRectFor("BBox"))) 618 pStream->GetDict()->SetRectFor("BBox", newRect); 619 } 620 return true; 621 } 622 623 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV 624 FPDFAnnot_GetAttachmentPoints(FPDF_ANNOTATION annot, 625 FS_QUADPOINTSF* quadPoints) { 626 if (!annot || !FPDFAnnot_HasAttachmentPoints(annot) || !quadPoints) 627 return false; 628 629 CPDF_Dictionary* pAnnotDict = 630 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict(); 631 if (!pAnnotDict) 632 return false; 633 634 CPDF_Array* pArray = pAnnotDict->GetArrayFor("QuadPoints"); 635 if (!pArray) 636 return false; 637 638 quadPoints->x1 = pArray->GetNumberAt(0); 639 quadPoints->y1 = pArray->GetNumberAt(1); 640 quadPoints->x2 = pArray->GetNumberAt(2); 641 quadPoints->y2 = pArray->GetNumberAt(3); 642 quadPoints->x3 = pArray->GetNumberAt(4); 643 quadPoints->y3 = pArray->GetNumberAt(5); 644 quadPoints->x4 = pArray->GetNumberAt(6); 645 quadPoints->y4 = pArray->GetNumberAt(7); 646 return true; 647 } 648 649 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetRect(FPDF_ANNOTATION annot, 650 const FS_RECTF* rect) { 651 if (!annot || !rect) 652 return false; 653 654 CPDF_Dictionary* pAnnotDict = 655 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict(); 656 if (!pAnnotDict) 657 return false; 658 659 CFX_FloatRect newRect = CFXFloatRectFromFSRECTF(*rect); 660 661 // Update the "Rect" entry in the annotation dictionary. 662 pAnnotDict->SetRectFor("Rect", newRect); 663 664 // If the annotation's appearance stream is defined, the annotation is of a 665 // type that does not have quadpoints, and the new rectangle is bigger than 666 // the current bounding box, then update the "BBox" entry in the AP 667 // dictionary too, since its "BBox" entry comes from annotation dictionary's 668 // "Rect" entry. 669 if (FPDFAnnot_HasAttachmentPoints(annot)) 670 return true; 671 672 CPDF_Stream* pStream = 673 FPDFDOC_GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal); 674 if (pStream && newRect.Contains(pStream->GetDict()->GetRectFor("BBox"))) 675 pStream->GetDict()->SetRectFor("BBox", newRect); 676 return true; 677 } 678 679 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetRect(FPDF_ANNOTATION annot, 680 FS_RECTF* rect) { 681 if (!annot || !rect) 682 return false; 683 684 CPDF_Dictionary* pAnnotDict = 685 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict(); 686 if (!pAnnotDict) 687 return false; 688 689 FSRECTFFromCFXFloatRect(pAnnotDict->GetRectFor("Rect"), rect); 690 return true; 691 } 692 693 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_HasKey(FPDF_ANNOTATION annot, 694 FPDF_BYTESTRING key) { 695 if (!annot) 696 return false; 697 698 CPDF_Dictionary* pAnnotDict = 699 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict(); 700 if (!pAnnotDict) 701 return false; 702 703 return pAnnotDict->KeyExist(key); 704 } 705 706 FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV 707 FPDFAnnot_GetValueType(FPDF_ANNOTATION annot, FPDF_BYTESTRING key) { 708 if (!FPDFAnnot_HasKey(annot, key)) 709 return FPDF_OBJECT_UNKNOWN; 710 711 auto* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot); 712 CPDF_Object* pObj = pAnnot->GetAnnotDict()->GetObjectFor(key); 713 return pObj ? pObj->GetType() : FPDF_OBJECT_UNKNOWN; 714 } 715 716 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV 717 FPDFAnnot_SetStringValue(FPDF_ANNOTATION annot, 718 FPDF_BYTESTRING key, 719 FPDF_WIDESTRING value) { 720 if (!annot) 721 return false; 722 723 CPDF_Dictionary* pAnnotDict = 724 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict(); 725 if (!pAnnotDict) 726 return false; 727 728 pAnnotDict->SetNewFor<CPDF_String>( 729 key, CFXByteStringFromFPDFWideString(value), false); 730 return true; 731 } 732 733 FPDF_EXPORT unsigned long FPDF_CALLCONV 734 FPDFAnnot_GetStringValue(FPDF_ANNOTATION annot, 735 FPDF_BYTESTRING key, 736 void* buffer, 737 unsigned long buflen) { 738 if (!annot) 739 return 0; 740 741 CPDF_Dictionary* pAnnotDict = 742 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict(); 743 if (!pAnnotDict) 744 return 0; 745 746 return Utf16EncodeMaybeCopyAndReturnLength(pAnnotDict->GetUnicodeTextFor(key), 747 buffer, buflen); 748 } 749 750 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV 751 FPDFAnnot_SetAP(FPDF_ANNOTATION annot, 752 FPDF_ANNOT_APPEARANCEMODE appearanceMode, 753 FPDF_WIDESTRING value) { 754 if (appearanceMode < 0 || appearanceMode >= FPDF_ANNOT_APPEARANCEMODE_COUNT) 755 return false; 756 757 if (!annot) 758 return false; 759 760 CPDF_Dictionary* pAnnotDict = 761 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict(); 762 if (!pAnnotDict) 763 return false; 764 765 constexpr const char* modeKeyForMode[] = {"N", "R", "D"}; 766 static_assert(FX_ArraySize(modeKeyForMode) == FPDF_ANNOT_APPEARANCEMODE_COUNT, 767 "length of modeKeyForMode should be equal to " 768 "FPDF_ANNOT_APPEARANCEMODE_COUNT"); 769 const char* modeKey = modeKeyForMode[appearanceMode]; 770 771 CPDF_Dictionary* pApDict = pAnnotDict->GetDictFor("AP"); 772 773 // If value is null, we're in remove mode. Otherwise, we're in add/update 774 // mode. 775 if (value) { 776 if (!pApDict) 777 pApDict = pAnnotDict->SetNewFor<CPDF_Dictionary>("AP"); 778 779 ByteString newValue = CFXByteStringFromFPDFWideString(value); 780 auto pNewApStream = pdfium::MakeUnique<CPDF_Stream>(); 781 pNewApStream->SetData(newValue.raw_str(), newValue.GetLength()); 782 pApDict->SetFor(modeKey, std::move(pNewApStream)); 783 } else { 784 if (pApDict) { 785 if (appearanceMode == FPDF_ANNOT_APPEARANCEMODE_NORMAL) 786 pAnnotDict->RemoveFor("AP"); 787 else 788 pApDict->RemoveFor(modeKey); 789 } 790 } 791 792 return true; 793 } 794 795 FPDF_EXPORT unsigned long FPDF_CALLCONV 796 FPDFAnnot_GetAP(FPDF_ANNOTATION annot, 797 FPDF_ANNOT_APPEARANCEMODE appearanceMode, 798 void* buffer, 799 unsigned long buflen) { 800 if (appearanceMode < 0 || appearanceMode >= FPDF_ANNOT_APPEARANCEMODE_COUNT) 801 return 0; 802 803 if (!annot) 804 return 0; 805 806 CPDF_Dictionary* pAnnotDict = 807 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict(); 808 if (!pAnnotDict) 809 return 0; 810 811 CPDF_Annot::AppearanceMode mode = 812 static_cast<CPDF_Annot::AppearanceMode>(appearanceMode); 813 814 CPDF_Stream* pStream = FPDFDOC_GetAnnotAPNoFallback(pAnnotDict, mode); 815 return Utf16EncodeMaybeCopyAndReturnLength( 816 pStream ? pStream->GetUnicodeText() : L"", buffer, buflen); 817 } 818 819 FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV 820 FPDFAnnot_GetLinkedAnnot(FPDF_ANNOTATION annot, FPDF_BYTESTRING key) { 821 CPDF_AnnotContext* pAnnot = CPDFAnnotContextFromFPDFAnnotation(annot); 822 if (!pAnnot || !pAnnot->GetAnnotDict()) 823 return nullptr; 824 825 CPDF_Dictionary* pLinkedDict = pAnnot->GetAnnotDict()->GetDictFor(key); 826 if (!pLinkedDict || pLinkedDict->GetStringFor("Type") != "Annot") 827 return nullptr; 828 829 auto pLinkedAnnot = pdfium::MakeUnique<CPDF_AnnotContext>( 830 pLinkedDict, pAnnot->GetPage(), nullptr); 831 return pLinkedAnnot.release(); 832 } 833 834 FPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFlags(FPDF_ANNOTATION annot) { 835 if (!annot) 836 return FPDF_ANNOT_FLAG_NONE; 837 838 CPDF_Dictionary* pAnnotDict = 839 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict(); 840 return pAnnotDict ? pAnnotDict->GetIntegerFor("F") : FPDF_ANNOT_FLAG_NONE; 841 } 842 843 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetFlags(FPDF_ANNOTATION annot, 844 int flags) { 845 if (!annot) 846 return false; 847 848 CPDF_Dictionary* pAnnotDict = 849 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict(); 850 if (!pAnnotDict) 851 return false; 852 853 pAnnotDict->SetNewFor<CPDF_Number>("F", flags); 854 return true; 855 } 856 857 FPDF_EXPORT int FPDF_CALLCONV 858 FPDFAnnot_GetFormFieldFlags(FPDF_PAGE page, FPDF_ANNOTATION annot) { 859 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); 860 if (!pPage || !annot) 861 return FPDF_FORMFLAG_NONE; 862 863 CPDF_Dictionary* pAnnotDict = 864 CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict(); 865 if (!pAnnotDict) 866 return FPDF_FORMFLAG_NONE; 867 868 CPDF_InterForm interform(pPage->m_pDocument.Get()); 869 CPDF_FormField* pFormField = interform.GetFieldByDict(pAnnotDict); 870 return pFormField ? pFormField->GetFieldFlags() : FPDF_FORMFLAG_NONE; 871 } 872 873 FPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV 874 FPDFAnnot_GetFormFieldAtPoint(FPDF_FORMHANDLE hHandle, 875 FPDF_PAGE page, 876 double page_x, 877 double page_y) { 878 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); 879 if (!hHandle || !pPage) 880 return nullptr; 881 882 CPDF_InterForm interform(pPage->m_pDocument.Get()); 883 int annot_index = -1; 884 CPDF_FormControl* pFormCtrl = interform.GetControlAtPoint( 885 pPage, CFX_PointF(static_cast<float>(page_x), static_cast<float>(page_y)), 886 &annot_index); 887 if (!pFormCtrl || annot_index == -1) 888 return nullptr; 889 return FPDFPage_GetAnnot(page, annot_index); 890 } 891