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_annotlist.h"
      8 
      9 #include <algorithm>
     10 #include <memory>
     11 #include <utility>
     12 
     13 #include "core/fpdfapi/page/cpdf_page.h"
     14 #include "core/fpdfapi/parser/cpdf_array.h"
     15 #include "core/fpdfapi/parser/cpdf_document.h"
     16 #include "core/fpdfapi/parser/cpdf_name.h"
     17 #include "core/fpdfapi/parser/cpdf_number.h"
     18 #include "core/fpdfapi/parser/cpdf_reference.h"
     19 #include "core/fpdfapi/parser/cpdf_string.h"
     20 #include "core/fpdfapi/render/cpdf_renderoptions.h"
     21 #include "core/fpdfdoc/cpdf_annot.h"
     22 #include "core/fpdfdoc/cpdf_interform.h"
     23 #include "core/fpdfdoc/cpdf_occontext.h"
     24 #include "core/fpdfdoc/cpvt_generateap.h"
     25 #include "core/fxge/cfx_renderdevice.h"
     26 #include "third_party/base/ptr_util.h"
     27 
     28 namespace {
     29 
     30 std::unique_ptr<CPDF_Annot> CreatePopupAnnot(CPDF_Annot* pAnnot,
     31                                              CPDF_Document* pDocument,
     32                                              CPDF_Page* pPage) {
     33   CPDF_Dictionary* pParentDict = pAnnot->GetAnnotDict();
     34   if (!pParentDict)
     35     return nullptr;
     36 
     37   // TODO(jaepark): We shouldn't strip BOM for some strings and not for others.
     38   // See pdfium:593.
     39   WideString sContents = pParentDict->GetUnicodeTextFor("Contents");
     40   if (sContents.IsEmpty())
     41     return nullptr;
     42 
     43   auto pAnnotDict =
     44       pdfium::MakeUnique<CPDF_Dictionary>(pDocument->GetByteStringPool());
     45   pAnnotDict->SetNewFor<CPDF_Name>("Type", "Annot");
     46   pAnnotDict->SetNewFor<CPDF_Name>("Subtype", "Popup");
     47   pAnnotDict->SetNewFor<CPDF_String>("T", pParentDict->GetStringFor("T"),
     48                                      false);
     49   pAnnotDict->SetNewFor<CPDF_String>("Contents", sContents.UTF8Encode(), false);
     50 
     51   CFX_FloatRect rect = pParentDict->GetRectFor("Rect");
     52   rect.Normalize();
     53   CFX_FloatRect popupRect(0, 0, 200, 200);
     54   // Note that if the popup can set its own dimensions, then we will need to
     55   // make sure that it isn't larger than the page size.
     56   if (rect.left + popupRect.Width() > pPage->GetPageWidth() &&
     57       rect.bottom - popupRect.Height() < 0) {
     58     // If the annotation is on the bottom-right corner of the page, then place
     59     // the popup above and to the left of the annotation.
     60     popupRect.Translate(rect.right - popupRect.Width(), rect.top);
     61   } else {
     62     // Place the popup below and to the right of the annotation without getting
     63     // clipped by page edges.
     64     popupRect.Translate(
     65         std::min(rect.left, pPage->GetPageWidth() - popupRect.Width()),
     66         std::max(rect.bottom - popupRect.Height(), 0.f));
     67   }
     68 
     69   pAnnotDict->SetRectFor("Rect", popupRect);
     70   pAnnotDict->SetNewFor<CPDF_Number>("F", 0);
     71 
     72   auto pPopupAnnot =
     73       pdfium::MakeUnique<CPDF_Annot>(std::move(pAnnotDict), pDocument);
     74   pAnnot->SetPopupAnnot(pPopupAnnot.get());
     75   return pPopupAnnot;
     76 }
     77 
     78 void GenerateAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) {
     79   if (!pAnnotDict || pAnnotDict->GetStringFor("Subtype") != "Widget")
     80     return;
     81 
     82   CPDF_Object* pFieldTypeObj = FPDF_GetFieldAttr(pAnnotDict, "FT");
     83   if (!pFieldTypeObj)
     84     return;
     85 
     86   ByteString field_type = pFieldTypeObj->GetString();
     87   if (field_type == "Tx") {
     88     CPVT_GenerateAP::GenerateFormAP(CPVT_GenerateAP::kTextField, pDoc,
     89                                     pAnnotDict);
     90     return;
     91   }
     92 
     93   CPDF_Object* pFieldFlagsObj = FPDF_GetFieldAttr(pAnnotDict, "Ff");
     94   uint32_t flags = pFieldFlagsObj ? pFieldFlagsObj->GetInteger() : 0;
     95   if (field_type == "Ch") {
     96     CPVT_GenerateAP::GenerateFormAP((flags & (1 << 17))
     97                                         ? CPVT_GenerateAP::kComboBox
     98                                         : CPVT_GenerateAP::kListBox,
     99                                     pDoc, pAnnotDict);
    100     return;
    101   }
    102 
    103   if (field_type != "Btn")
    104     return;
    105   if (flags & (1 << 16))
    106     return;
    107   if (pAnnotDict->KeyExist("AS"))
    108     return;
    109 
    110   CPDF_Dictionary* pParentDict = pAnnotDict->GetDictFor("Parent");
    111   if (!pParentDict || !pParentDict->KeyExist("AS"))
    112     return;
    113 
    114   pAnnotDict->SetNewFor<CPDF_String>("AS", pParentDict->GetStringFor("AS"),
    115                                      false);
    116   return;
    117 }
    118 
    119 }  // namespace
    120 
    121 CPDF_AnnotList::CPDF_AnnotList(CPDF_Page* pPage)
    122     : m_pDocument(pPage->m_pDocument.Get()) {
    123   if (!pPage->m_pFormDict)
    124     return;
    125 
    126   CPDF_Array* pAnnots = pPage->m_pFormDict->GetArrayFor("Annots");
    127   if (!pAnnots)
    128     return;
    129 
    130   const CPDF_Dictionary* pRoot = m_pDocument->GetRoot();
    131   CPDF_Dictionary* pAcroForm = pRoot->GetDictFor("AcroForm");
    132   bool bRegenerateAP = pAcroForm && pAcroForm->GetBooleanFor("NeedAppearances");
    133   for (size_t i = 0; i < pAnnots->GetCount(); ++i) {
    134     CPDF_Dictionary* pDict = ToDictionary(pAnnots->GetDirectObjectAt(i));
    135     if (!pDict)
    136       continue;
    137     const ByteString subtype = pDict->GetStringFor("Subtype");
    138     if (subtype == "Popup") {
    139       // Skip creating Popup annotations in the PDF document since PDFium
    140       // provides its own Popup annotations.
    141       continue;
    142     }
    143     pAnnots->ConvertToIndirectObjectAt(i, m_pDocument);
    144     m_AnnotList.push_back(pdfium::MakeUnique<CPDF_Annot>(pDict, m_pDocument));
    145     if (bRegenerateAP && subtype == "Widget" &&
    146         CPDF_InterForm::IsUpdateAPEnabled() && !pDict->GetDictFor("AP")) {
    147       GenerateAP(m_pDocument, pDict);
    148     }
    149   }
    150 
    151   size_t nAnnotListSize = m_AnnotList.size();
    152   for (size_t i = 0; i < nAnnotListSize; ++i) {
    153     std::unique_ptr<CPDF_Annot> pPopupAnnot(
    154         CreatePopupAnnot(m_AnnotList[i].get(), m_pDocument, pPage));
    155     if (pPopupAnnot)
    156       m_AnnotList.push_back(std::move(pPopupAnnot));
    157   }
    158 }
    159 
    160 CPDF_AnnotList::~CPDF_AnnotList() {}
    161 
    162 void CPDF_AnnotList::DisplayPass(CPDF_Page* pPage,
    163                                  CFX_RenderDevice* pDevice,
    164                                  CPDF_RenderContext* pContext,
    165                                  bool bPrinting,
    166                                  const CFX_Matrix* pMatrix,
    167                                  bool bWidgetPass,
    168                                  CPDF_RenderOptions* pOptions,
    169                                  FX_RECT* clip_rect) {
    170   for (const auto& pAnnot : m_AnnotList) {
    171     bool bWidget = pAnnot->GetSubtype() == CPDF_Annot::Subtype::WIDGET;
    172     if ((bWidgetPass && !bWidget) || (!bWidgetPass && bWidget))
    173       continue;
    174 
    175     uint32_t annot_flags = pAnnot->GetFlags();
    176     if (annot_flags & ANNOTFLAG_HIDDEN)
    177       continue;
    178 
    179     if (bPrinting && (annot_flags & ANNOTFLAG_PRINT) == 0)
    180       continue;
    181 
    182     if (!bPrinting && (annot_flags & ANNOTFLAG_NOVIEW))
    183       continue;
    184 
    185     if (pOptions) {
    186       CPDF_Dictionary* pAnnotDict = pAnnot->GetAnnotDict();
    187       if (pOptions->GetOCContext() && pAnnotDict &&
    188           !pOptions->GetOCContext()->CheckOCGVisible(
    189               pAnnotDict->GetDictFor("OC"))) {
    190         continue;
    191       }
    192     }
    193 
    194     CFX_Matrix matrix = *pMatrix;
    195     if (clip_rect) {
    196       FX_RECT annot_rect =
    197           matrix.TransformRect(pAnnot->GetRect()).GetOuterRect();
    198       annot_rect.Intersect(*clip_rect);
    199       if (annot_rect.IsEmpty())
    200         continue;
    201     }
    202     if (pContext) {
    203       pAnnot->DrawInContext(pPage, pContext, &matrix, CPDF_Annot::Normal);
    204     } else if (!pAnnot->DrawAppearance(pPage, pDevice, matrix,
    205                                        CPDF_Annot::Normal, pOptions)) {
    206       pAnnot->DrawBorder(pDevice, &matrix, pOptions);
    207     }
    208   }
    209 }
    210 
    211 void CPDF_AnnotList::DisplayAnnots(CPDF_Page* pPage,
    212                                    CFX_RenderDevice* pDevice,
    213                                    CPDF_RenderContext* pContext,
    214                                    bool bPrinting,
    215                                    const CFX_Matrix* pUser2Device,
    216                                    uint32_t dwAnnotFlags,
    217                                    CPDF_RenderOptions* pOptions,
    218                                    FX_RECT* pClipRect) {
    219   if (dwAnnotFlags & ANNOTFLAG_INVISIBLE) {
    220     DisplayPass(pPage, pDevice, pContext, bPrinting, pUser2Device, false,
    221                 pOptions, pClipRect);
    222   }
    223   if (dwAnnotFlags & ANNOTFLAG_HIDDEN) {
    224     DisplayPass(pPage, pDevice, pContext, bPrinting, pUser2Device, true,
    225                 pOptions, pClipRect);
    226   }
    227 }
    228 
    229 void CPDF_AnnotList::DisplayAnnots(CPDF_Page* pPage,
    230                                    CPDF_RenderContext* pContext,
    231                                    bool bPrinting,
    232                                    const CFX_Matrix* pMatrix,
    233                                    bool bShowWidget,
    234                                    CPDF_RenderOptions* pOptions) {
    235   uint32_t dwAnnotFlags = bShowWidget ? ANNOTFLAG_INVISIBLE | ANNOTFLAG_HIDDEN
    236                                       : ANNOTFLAG_INVISIBLE;
    237   DisplayAnnots(pPage, nullptr, pContext, bPrinting, pMatrix, dwAnnotFlags,
    238                 pOptions, nullptr);
    239 }
    240