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