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 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