1 // Copyright 2016 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 "core/fpdfdoc/cpdf_annot.h" 8 9 #include <utility> 10 11 #include "core/fpdfapi/page/cpdf_form.h" 12 #include "core/fpdfapi/page/cpdf_page.h" 13 #include "core/fpdfapi/parser/cpdf_array.h" 14 #include "core/fpdfapi/parser/cpdf_boolean.h" 15 #include "core/fpdfapi/parser/cpdf_document.h" 16 #include "core/fpdfapi/render/cpdf_rendercontext.h" 17 #include "core/fpdfapi/render/cpdf_renderoptions.h" 18 #include "core/fpdfdoc/cpvt_generateap.h" 19 #include "core/fxcrt/fx_memory.h" 20 #include "core/fxge/cfx_graphstatedata.h" 21 #include "core/fxge/cfx_pathdata.h" 22 #include "core/fxge/cfx_renderdevice.h" 23 #include "third_party/base/ptr_util.h" 24 25 namespace { 26 27 char kPDFiumKey_HasGeneratedAP[] = "PDFIUM_HasGeneratedAP"; 28 29 bool IsTextMarkupAnnotation(CPDF_Annot::Subtype type) { 30 return type == CPDF_Annot::Subtype::HIGHLIGHT || 31 type == CPDF_Annot::Subtype::SQUIGGLY || 32 type == CPDF_Annot::Subtype::STRIKEOUT || 33 type == CPDF_Annot::Subtype::UNDERLINE; 34 } 35 36 bool ShouldGenerateAPForAnnotation(CPDF_Dictionary* pAnnotDict) { 37 // If AP dictionary exists and defines an appearance for normal mode, we use 38 // the appearance defined in the existing AP dictionary. 39 CPDF_Dictionary* pAP = pAnnotDict->GetDictFor("AP"); 40 if (pAP && pAP->GetDictFor("N")) 41 return false; 42 43 return !CPDF_Annot::IsAnnotationHidden(pAnnotDict); 44 } 45 46 CPDF_Form* AnnotGetMatrix(const CPDF_Page* pPage, 47 CPDF_Annot* pAnnot, 48 CPDF_Annot::AppearanceMode mode, 49 const CFX_Matrix* pUser2Device, 50 CFX_Matrix* matrix) { 51 CPDF_Form* pForm = pAnnot->GetAPForm(pPage, mode); 52 if (!pForm) 53 return nullptr; 54 55 CFX_Matrix form_matrix = pForm->m_pFormDict->GetMatrixFor("Matrix"); 56 CFX_FloatRect form_bbox = 57 form_matrix.TransformRect(pForm->m_pFormDict->GetRectFor("BBox")); 58 matrix->MatchRect(pAnnot->GetRect(), form_bbox); 59 matrix->Concat(*pUser2Device); 60 return pForm; 61 } 62 63 CPDF_Stream* FPDFDOC_GetAnnotAPInternal(const CPDF_Dictionary* pAnnotDict, 64 CPDF_Annot::AppearanceMode eMode, 65 bool bFallbackToNormal) { 66 CPDF_Dictionary* pAP = pAnnotDict->GetDictFor("AP"); 67 if (!pAP) 68 return nullptr; 69 70 const char* ap_entry = "N"; 71 if (eMode == CPDF_Annot::Down) 72 ap_entry = "D"; 73 else if (eMode == CPDF_Annot::Rollover) 74 ap_entry = "R"; 75 if (bFallbackToNormal && !pAP->KeyExist(ap_entry)) 76 ap_entry = "N"; 77 78 CPDF_Object* psub = pAP->GetDirectObjectFor(ap_entry); 79 if (!psub) 80 return nullptr; 81 if (CPDF_Stream* pStream = psub->AsStream()) 82 return pStream; 83 84 CPDF_Dictionary* pDict = psub->AsDictionary(); 85 if (!pDict) 86 return nullptr; 87 88 ByteString as = pAnnotDict->GetStringFor("AS"); 89 if (as.IsEmpty()) { 90 ByteString value = pAnnotDict->GetStringFor("V"); 91 if (value.IsEmpty()) { 92 CPDF_Dictionary* pParentDict = pAnnotDict->GetDictFor("Parent"); 93 value = pParentDict ? pParentDict->GetStringFor("V") : ByteString(); 94 } 95 as = (!value.IsEmpty() && pDict->KeyExist(value)) ? value : "Off"; 96 } 97 return pDict->GetStreamFor(as); 98 } 99 100 } // namespace 101 102 CPDF_Annot::CPDF_Annot(std::unique_ptr<CPDF_Dictionary> pDict, 103 CPDF_Document* pDocument) 104 : m_pAnnotDict(std::move(pDict)), m_pDocument(pDocument) { 105 Init(); 106 } 107 108 CPDF_Annot::CPDF_Annot(CPDF_Dictionary* pDict, CPDF_Document* pDocument) 109 : m_pAnnotDict(pDict), m_pDocument(pDocument) { 110 Init(); 111 } 112 113 CPDF_Annot::~CPDF_Annot() { 114 ClearCachedAP(); 115 } 116 117 void CPDF_Annot::Init() { 118 m_nSubtype = StringToAnnotSubtype(m_pAnnotDict->GetStringFor("Subtype")); 119 m_bIsTextMarkupAnnotation = IsTextMarkupAnnotation(m_nSubtype); 120 m_bHasGeneratedAP = m_pAnnotDict->GetBooleanFor(kPDFiumKey_HasGeneratedAP); 121 GenerateAPIfNeeded(); 122 } 123 124 void CPDF_Annot::GenerateAPIfNeeded() { 125 if (!ShouldGenerateAPForAnnotation(m_pAnnotDict.Get())) 126 return; 127 if (!CPVT_GenerateAP::GenerateAnnotAP(m_nSubtype, m_pDocument.Get(), 128 m_pAnnotDict.Get())) { 129 return; 130 } 131 132 m_pAnnotDict->SetNewFor<CPDF_Boolean>(kPDFiumKey_HasGeneratedAP, true); 133 m_bHasGeneratedAP = true; 134 } 135 136 bool CPDF_Annot::ShouldDrawAnnotation() { 137 if (IsAnnotationHidden(m_pAnnotDict.Get())) 138 return false; 139 140 if (m_nSubtype == CPDF_Annot::Subtype::POPUP && !m_bOpenState) 141 return false; 142 143 return true; 144 } 145 146 void CPDF_Annot::ClearCachedAP() { 147 m_APMap.clear(); 148 } 149 150 CPDF_Annot::Subtype CPDF_Annot::GetSubtype() const { 151 return m_nSubtype; 152 } 153 154 CFX_FloatRect CPDF_Annot::RectForDrawing() const { 155 if (!m_pAnnotDict) 156 return CFX_FloatRect(); 157 158 bool bShouldUseQuadPointsCoords = 159 m_bIsTextMarkupAnnotation && m_bHasGeneratedAP; 160 if (bShouldUseQuadPointsCoords) 161 return RectFromQuadPoints(m_pAnnotDict.Get()); 162 163 return m_pAnnotDict->GetRectFor("Rect"); 164 } 165 166 CFX_FloatRect CPDF_Annot::GetRect() const { 167 if (!m_pAnnotDict) 168 return CFX_FloatRect(); 169 170 CFX_FloatRect rect = RectForDrawing(); 171 rect.Normalize(); 172 return rect; 173 } 174 175 uint32_t CPDF_Annot::GetFlags() const { 176 return m_pAnnotDict->GetIntegerFor("F"); 177 } 178 179 CPDF_Stream* FPDFDOC_GetAnnotAP(const CPDF_Dictionary* pAnnotDict, 180 CPDF_Annot::AppearanceMode eMode) { 181 return FPDFDOC_GetAnnotAPInternal(pAnnotDict, eMode, true); 182 } 183 184 CPDF_Stream* FPDFDOC_GetAnnotAPNoFallback(const CPDF_Dictionary* pAnnotDict, 185 CPDF_Annot::AppearanceMode eMode) { 186 return FPDFDOC_GetAnnotAPInternal(pAnnotDict, eMode, false); 187 } 188 189 CPDF_Form* CPDF_Annot::GetAPForm(const CPDF_Page* pPage, AppearanceMode mode) { 190 CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(m_pAnnotDict.Get(), mode); 191 if (!pStream) 192 return nullptr; 193 194 auto it = m_APMap.find(pStream); 195 if (it != m_APMap.end()) 196 return it->second.get(); 197 198 auto pNewForm = pdfium::MakeUnique<CPDF_Form>( 199 m_pDocument.Get(), pPage->m_pResources.Get(), pStream); 200 pNewForm->ParseContent(); 201 202 CPDF_Form* pResult = pNewForm.get(); 203 m_APMap[pStream] = std::move(pNewForm); 204 return pResult; 205 } 206 207 // Static. 208 CFX_FloatRect CPDF_Annot::RectFromQuadPoints(CPDF_Dictionary* pAnnotDict) { 209 CPDF_Array* pArray = pAnnotDict->GetArrayFor("QuadPoints"); 210 if (!pArray) 211 return CFX_FloatRect(); 212 213 // QuadPoints are defined with 4 pairs of numbers 214 // ([ pair0, pair1, pair2, pair3 ]), where 215 // pair0 = top_left 216 // pair1 = top_right 217 // pair2 = bottom_left 218 // pair3 = bottom_right 219 // 220 // On the other hand, /Rect is define as 2 pairs [pair0, pair1] where: 221 // pair0 = bottom_left 222 // pair1 = top_right. 223 return CFX_FloatRect(pArray->GetNumberAt(4), pArray->GetNumberAt(5), 224 pArray->GetNumberAt(2), pArray->GetNumberAt(3)); 225 } 226 227 // Static. 228 bool CPDF_Annot::IsAnnotationHidden(CPDF_Dictionary* pAnnotDict) { 229 return !!(pAnnotDict->GetIntegerFor("F") & ANNOTFLAG_HIDDEN); 230 } 231 232 // Static. 233 CPDF_Annot::Subtype CPDF_Annot::StringToAnnotSubtype( 234 const ByteString& sSubtype) { 235 if (sSubtype == "Text") 236 return CPDF_Annot::Subtype::TEXT; 237 if (sSubtype == "Link") 238 return CPDF_Annot::Subtype::LINK; 239 if (sSubtype == "FreeText") 240 return CPDF_Annot::Subtype::FREETEXT; 241 if (sSubtype == "Line") 242 return CPDF_Annot::Subtype::LINE; 243 if (sSubtype == "Square") 244 return CPDF_Annot::Subtype::SQUARE; 245 if (sSubtype == "Circle") 246 return CPDF_Annot::Subtype::CIRCLE; 247 if (sSubtype == "Polygon") 248 return CPDF_Annot::Subtype::POLYGON; 249 if (sSubtype == "PolyLine") 250 return CPDF_Annot::Subtype::POLYLINE; 251 if (sSubtype == "Highlight") 252 return CPDF_Annot::Subtype::HIGHLIGHT; 253 if (sSubtype == "Underline") 254 return CPDF_Annot::Subtype::UNDERLINE; 255 if (sSubtype == "Squiggly") 256 return CPDF_Annot::Subtype::SQUIGGLY; 257 if (sSubtype == "StrikeOut") 258 return CPDF_Annot::Subtype::STRIKEOUT; 259 if (sSubtype == "Stamp") 260 return CPDF_Annot::Subtype::STAMP; 261 if (sSubtype == "Caret") 262 return CPDF_Annot::Subtype::CARET; 263 if (sSubtype == "Ink") 264 return CPDF_Annot::Subtype::INK; 265 if (sSubtype == "Popup") 266 return CPDF_Annot::Subtype::POPUP; 267 if (sSubtype == "FileAttachment") 268 return CPDF_Annot::Subtype::FILEATTACHMENT; 269 if (sSubtype == "Sound") 270 return CPDF_Annot::Subtype::SOUND; 271 if (sSubtype == "Movie") 272 return CPDF_Annot::Subtype::MOVIE; 273 if (sSubtype == "Widget") 274 return CPDF_Annot::Subtype::WIDGET; 275 if (sSubtype == "Screen") 276 return CPDF_Annot::Subtype::SCREEN; 277 if (sSubtype == "PrinterMark") 278 return CPDF_Annot::Subtype::PRINTERMARK; 279 if (sSubtype == "TrapNet") 280 return CPDF_Annot::Subtype::TRAPNET; 281 if (sSubtype == "Watermark") 282 return CPDF_Annot::Subtype::WATERMARK; 283 if (sSubtype == "3D") 284 return CPDF_Annot::Subtype::THREED; 285 if (sSubtype == "RichMedia") 286 return CPDF_Annot::Subtype::RICHMEDIA; 287 if (sSubtype == "XFAWidget") 288 return CPDF_Annot::Subtype::XFAWIDGET; 289 return CPDF_Annot::Subtype::UNKNOWN; 290 } 291 292 // Static. 293 ByteString CPDF_Annot::AnnotSubtypeToString(CPDF_Annot::Subtype nSubtype) { 294 if (nSubtype == CPDF_Annot::Subtype::TEXT) 295 return "Text"; 296 if (nSubtype == CPDF_Annot::Subtype::LINK) 297 return "Link"; 298 if (nSubtype == CPDF_Annot::Subtype::FREETEXT) 299 return "FreeText"; 300 if (nSubtype == CPDF_Annot::Subtype::LINE) 301 return "Line"; 302 if (nSubtype == CPDF_Annot::Subtype::SQUARE) 303 return "Square"; 304 if (nSubtype == CPDF_Annot::Subtype::CIRCLE) 305 return "Circle"; 306 if (nSubtype == CPDF_Annot::Subtype::POLYGON) 307 return "Polygon"; 308 if (nSubtype == CPDF_Annot::Subtype::POLYLINE) 309 return "PolyLine"; 310 if (nSubtype == CPDF_Annot::Subtype::HIGHLIGHT) 311 return "Highlight"; 312 if (nSubtype == CPDF_Annot::Subtype::UNDERLINE) 313 return "Underline"; 314 if (nSubtype == CPDF_Annot::Subtype::SQUIGGLY) 315 return "Squiggly"; 316 if (nSubtype == CPDF_Annot::Subtype::STRIKEOUT) 317 return "StrikeOut"; 318 if (nSubtype == CPDF_Annot::Subtype::STAMP) 319 return "Stamp"; 320 if (nSubtype == CPDF_Annot::Subtype::CARET) 321 return "Caret"; 322 if (nSubtype == CPDF_Annot::Subtype::INK) 323 return "Ink"; 324 if (nSubtype == CPDF_Annot::Subtype::POPUP) 325 return "Popup"; 326 if (nSubtype == CPDF_Annot::Subtype::FILEATTACHMENT) 327 return "FileAttachment"; 328 if (nSubtype == CPDF_Annot::Subtype::SOUND) 329 return "Sound"; 330 if (nSubtype == CPDF_Annot::Subtype::MOVIE) 331 return "Movie"; 332 if (nSubtype == CPDF_Annot::Subtype::WIDGET) 333 return "Widget"; 334 if (nSubtype == CPDF_Annot::Subtype::SCREEN) 335 return "Screen"; 336 if (nSubtype == CPDF_Annot::Subtype::PRINTERMARK) 337 return "PrinterMark"; 338 if (nSubtype == CPDF_Annot::Subtype::TRAPNET) 339 return "TrapNet"; 340 if (nSubtype == CPDF_Annot::Subtype::WATERMARK) 341 return "Watermark"; 342 if (nSubtype == CPDF_Annot::Subtype::THREED) 343 return "3D"; 344 if (nSubtype == CPDF_Annot::Subtype::RICHMEDIA) 345 return "RichMedia"; 346 if (nSubtype == CPDF_Annot::Subtype::XFAWIDGET) 347 return "XFAWidget"; 348 return ""; 349 } 350 351 bool CPDF_Annot::DrawAppearance(CPDF_Page* pPage, 352 CFX_RenderDevice* pDevice, 353 const CFX_Matrix& mtUser2Device, 354 AppearanceMode mode, 355 const CPDF_RenderOptions* pOptions) { 356 if (!ShouldDrawAnnotation()) 357 return false; 358 359 // It might happen that by the time this annotation instance was created, 360 // it was flagged as "hidden" (e.g. /F 2), and hence CPVT_GenerateAP decided 361 // to not "generate" its AP. 362 // If for a reason the object is no longer hidden, but still does not have 363 // its "AP" generated, generate it now. 364 GenerateAPIfNeeded(); 365 366 CFX_Matrix matrix; 367 CPDF_Form* pForm = AnnotGetMatrix(pPage, this, mode, &mtUser2Device, &matrix); 368 if (!pForm) 369 return false; 370 371 CPDF_RenderContext context(pPage); 372 context.AppendLayer(pForm, &matrix); 373 context.Render(pDevice, pOptions, nullptr); 374 return true; 375 } 376 377 bool CPDF_Annot::DrawInContext(const CPDF_Page* pPage, 378 CPDF_RenderContext* pContext, 379 const CFX_Matrix* pUser2Device, 380 AppearanceMode mode) { 381 if (!ShouldDrawAnnotation()) 382 return false; 383 384 // It might happen that by the time this annotation instance was created, 385 // it was flagged as "hidden" (e.g. /F 2), and hence CPVT_GenerateAP decided 386 // to not "generate" its AP. 387 // If for a reason the object is no longer hidden, but still does not have 388 // its "AP" generated, generate it now. 389 GenerateAPIfNeeded(); 390 391 CFX_Matrix matrix; 392 CPDF_Form* pForm = AnnotGetMatrix(pPage, this, mode, pUser2Device, &matrix); 393 if (!pForm) 394 return false; 395 396 pContext->AppendLayer(pForm, &matrix); 397 return true; 398 } 399 400 void CPDF_Annot::DrawBorder(CFX_RenderDevice* pDevice, 401 const CFX_Matrix* pUser2Device, 402 const CPDF_RenderOptions* pOptions) { 403 if (GetSubtype() == CPDF_Annot::Subtype::POPUP) 404 return; 405 406 uint32_t annot_flags = GetFlags(); 407 if (annot_flags & ANNOTFLAG_HIDDEN) { 408 return; 409 } 410 bool bPrinting = pDevice->GetDeviceClass() == FXDC_PRINTER || 411 (pOptions && (pOptions->HasFlag(RENDER_PRINTPREVIEW))); 412 if (bPrinting && (annot_flags & ANNOTFLAG_PRINT) == 0) { 413 return; 414 } 415 if (!bPrinting && (annot_flags & ANNOTFLAG_NOVIEW)) { 416 return; 417 } 418 CPDF_Dictionary* pBS = m_pAnnotDict->GetDictFor("BS"); 419 char style_char; 420 float width; 421 CPDF_Array* pDashArray = nullptr; 422 if (!pBS) { 423 CPDF_Array* pBorderArray = m_pAnnotDict->GetArrayFor("Border"); 424 style_char = 'S'; 425 if (pBorderArray) { 426 width = pBorderArray->GetNumberAt(2); 427 if (pBorderArray->GetCount() == 4) { 428 pDashArray = pBorderArray->GetArrayAt(3); 429 if (!pDashArray) { 430 return; 431 } 432 size_t nLen = pDashArray->GetCount(); 433 size_t i = 0; 434 for (; i < nLen; ++i) { 435 CPDF_Object* pObj = pDashArray->GetDirectObjectAt(i); 436 if (pObj && pObj->GetInteger()) { 437 break; 438 } 439 } 440 if (i == nLen) { 441 return; 442 } 443 style_char = 'D'; 444 } 445 } else { 446 width = 1; 447 } 448 } else { 449 ByteString style = pBS->GetStringFor("S"); 450 pDashArray = pBS->GetArrayFor("D"); 451 style_char = style[1]; 452 width = pBS->GetNumberFor("W"); 453 } 454 if (width <= 0) { 455 return; 456 } 457 CPDF_Array* pColor = m_pAnnotDict->GetArrayFor("C"); 458 uint32_t argb = 0xff000000; 459 if (pColor) { 460 int R = (int32_t)(pColor->GetNumberAt(0) * 255); 461 int G = (int32_t)(pColor->GetNumberAt(1) * 255); 462 int B = (int32_t)(pColor->GetNumberAt(2) * 255); 463 argb = ArgbEncode(0xff, R, G, B); 464 } 465 CFX_GraphStateData graph_state; 466 graph_state.m_LineWidth = width; 467 if (style_char == 'D') { 468 if (pDashArray) { 469 size_t dash_count = pDashArray->GetCount(); 470 if (dash_count % 2) { 471 dash_count++; 472 } 473 graph_state.m_DashArray = FX_Alloc(float, dash_count); 474 graph_state.m_DashCount = dash_count; 475 size_t i; 476 for (i = 0; i < pDashArray->GetCount(); ++i) { 477 graph_state.m_DashArray[i] = pDashArray->GetNumberAt(i); 478 } 479 if (i < dash_count) { 480 graph_state.m_DashArray[i] = graph_state.m_DashArray[i - 1]; 481 } 482 } else { 483 graph_state.m_DashArray = FX_Alloc(float, 2); 484 graph_state.m_DashCount = 2; 485 graph_state.m_DashArray[0] = graph_state.m_DashArray[1] = 3 * 1.0f; 486 } 487 } 488 CFX_FloatRect rect = GetRect(); 489 CFX_PathData path; 490 width /= 2; 491 path.AppendRect(rect.left + width, rect.bottom + width, rect.right - width, 492 rect.top - width); 493 int fill_type = 0; 494 if (pOptions && (pOptions->HasFlag(RENDER_NOPATHSMOOTH))) 495 fill_type |= FXFILL_NOPATHSMOOTH; 496 497 pDevice->DrawPath(&path, pUser2Device, &graph_state, argb, argb, fill_type); 498 } 499