Home | History | Annotate | Download | only in fpdfsdk
      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 "fpdfsdk/cpdfsdk_baannot.h"
      8 
      9 #include <algorithm>
     10 #include <utility>
     11 
     12 #include "core/fpdfapi/parser/cpdf_array.h"
     13 #include "core/fpdfapi/parser/cpdf_document.h"
     14 #include "core/fpdfapi/parser/cpdf_name.h"
     15 #include "core/fpdfapi/parser/cpdf_number.h"
     16 #include "core/fpdfapi/parser/cpdf_reference.h"
     17 #include "core/fpdfapi/parser/cpdf_stream.h"
     18 #include "core/fpdfapi/parser/cpdf_string.h"
     19 #include "core/fpdfapi/parser/fpdf_parser_decode.h"
     20 #include "fpdfsdk/cpdfsdk_datetime.h"
     21 #include "fpdfsdk/cpdfsdk_pageview.h"
     22 
     23 CPDFSDK_BAAnnot::CPDFSDK_BAAnnot(CPDF_Annot* pAnnot,
     24                                  CPDFSDK_PageView* pPageView)
     25     : CPDFSDK_Annot(pPageView), m_pAnnot(pAnnot) {}
     26 
     27 CPDFSDK_BAAnnot::~CPDFSDK_BAAnnot() {}
     28 
     29 CPDF_Annot* CPDFSDK_BAAnnot::GetPDFAnnot() const {
     30   return m_pAnnot.Get();
     31 }
     32 
     33 CPDF_Annot* CPDFSDK_BAAnnot::GetPDFPopupAnnot() const {
     34   return m_pAnnot->GetPopupAnnot();
     35 }
     36 
     37 CPDF_Dictionary* CPDFSDK_BAAnnot::GetAnnotDict() const {
     38   return m_pAnnot->GetAnnotDict();
     39 }
     40 
     41 CPDF_Dictionary* CPDFSDK_BAAnnot::GetAPDict() const {
     42   CPDF_Dictionary* pAPDict = m_pAnnot->GetAnnotDict()->GetDictFor("AP");
     43   if (!pAPDict)
     44     pAPDict = m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_Dictionary>("AP");
     45   return pAPDict;
     46 }
     47 
     48 void CPDFSDK_BAAnnot::SetRect(const CFX_FloatRect& rect) {
     49   ASSERT(rect.right - rect.left >= GetMinWidth());
     50   ASSERT(rect.top - rect.bottom >= GetMinHeight());
     51 
     52   m_pAnnot->GetAnnotDict()->SetRectFor("Rect", rect);
     53 }
     54 
     55 CFX_FloatRect CPDFSDK_BAAnnot::GetRect() const {
     56   return m_pAnnot->GetRect();
     57 }
     58 
     59 CPDF_Annot::Subtype CPDFSDK_BAAnnot::GetAnnotSubtype() const {
     60   return m_pAnnot->GetSubtype();
     61 }
     62 
     63 void CPDFSDK_BAAnnot::DrawAppearance(CFX_RenderDevice* pDevice,
     64                                      const CFX_Matrix& mtUser2Device,
     65                                      CPDF_Annot::AppearanceMode mode,
     66                                      const CPDF_RenderOptions* pOptions) {
     67   m_pAnnot->DrawAppearance(m_pPageView->GetPDFPage(), pDevice, mtUser2Device,
     68                            mode, pOptions);
     69 }
     70 
     71 bool CPDFSDK_BAAnnot::IsAppearanceValid() {
     72   return !!m_pAnnot->GetAnnotDict()->GetDictFor("AP");
     73 }
     74 
     75 bool CPDFSDK_BAAnnot::IsAppearanceValid(CPDF_Annot::AppearanceMode mode) {
     76   CPDF_Dictionary* pAP = m_pAnnot->GetAnnotDict()->GetDictFor("AP");
     77   if (!pAP)
     78     return false;
     79 
     80   // Choose the right sub-ap
     81   const char* ap_entry = "N";
     82   if (mode == CPDF_Annot::Down)
     83     ap_entry = "D";
     84   else if (mode == CPDF_Annot::Rollover)
     85     ap_entry = "R";
     86   if (!pAP->KeyExist(ap_entry))
     87     ap_entry = "N";
     88 
     89   // Get the AP stream or subdirectory
     90   CPDF_Object* psub = pAP->GetDirectObjectFor(ap_entry);
     91   return !!psub;
     92 }
     93 
     94 void CPDFSDK_BAAnnot::DrawBorder(CFX_RenderDevice* pDevice,
     95                                  const CFX_Matrix* pUser2Device,
     96                                  const CPDF_RenderOptions* pOptions) {
     97   m_pAnnot->DrawBorder(pDevice, pUser2Device, pOptions);
     98 }
     99 
    100 void CPDFSDK_BAAnnot::ClearCachedAP() {
    101   m_pAnnot->ClearCachedAP();
    102 }
    103 
    104 void CPDFSDK_BAAnnot::SetContents(const WideString& sContents) {
    105   if (sContents.IsEmpty()) {
    106     m_pAnnot->GetAnnotDict()->RemoveFor("Contents");
    107   } else {
    108     m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_String>(
    109         "Contents", PDF_EncodeText(sContents), false);
    110   }
    111 }
    112 
    113 WideString CPDFSDK_BAAnnot::GetContents() const {
    114   return m_pAnnot->GetAnnotDict()->GetUnicodeTextFor("Contents");
    115 }
    116 
    117 void CPDFSDK_BAAnnot::SetAnnotName(const WideString& sName) {
    118   if (sName.IsEmpty()) {
    119     m_pAnnot->GetAnnotDict()->RemoveFor("NM");
    120   } else {
    121     m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_String>(
    122         "NM", PDF_EncodeText(sName), false);
    123   }
    124 }
    125 
    126 WideString CPDFSDK_BAAnnot::GetAnnotName() const {
    127   return m_pAnnot->GetAnnotDict()->GetUnicodeTextFor("NM");
    128 }
    129 
    130 void CPDFSDK_BAAnnot::SetModifiedDate(const FX_SYSTEMTIME& st) {
    131   CPDFSDK_DateTime dt(st);
    132   ByteString str = dt.ToPDFDateTimeString();
    133   if (str.IsEmpty())
    134     m_pAnnot->GetAnnotDict()->RemoveFor("M");
    135   else
    136     m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_String>("M", str, false);
    137 }
    138 
    139 FX_SYSTEMTIME CPDFSDK_BAAnnot::GetModifiedDate() const {
    140   FX_SYSTEMTIME systime;
    141   ByteString str = m_pAnnot->GetAnnotDict()->GetStringFor("M");
    142   CPDFSDK_DateTime dt(str);
    143   dt.ToSystemTime(systime);
    144   return systime;
    145 }
    146 
    147 void CPDFSDK_BAAnnot::SetFlags(uint32_t nFlags) {
    148   m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_Number>("F",
    149                                                    static_cast<int>(nFlags));
    150 }
    151 
    152 uint32_t CPDFSDK_BAAnnot::GetFlags() const {
    153   return m_pAnnot->GetAnnotDict()->GetIntegerFor("F");
    154 }
    155 
    156 void CPDFSDK_BAAnnot::SetAppState(const ByteString& str) {
    157   if (str.IsEmpty())
    158     m_pAnnot->GetAnnotDict()->RemoveFor("AS");
    159   else
    160     m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_String>("AS", str, false);
    161 }
    162 
    163 ByteString CPDFSDK_BAAnnot::GetAppState() const {
    164   return m_pAnnot->GetAnnotDict()->GetStringFor("AS");
    165 }
    166 
    167 void CPDFSDK_BAAnnot::SetStructParent(int key) {
    168   m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_Number>("StructParent", key);
    169 }
    170 
    171 int CPDFSDK_BAAnnot::GetStructParent() const {
    172   return m_pAnnot->GetAnnotDict()->GetIntegerFor("StructParent");
    173 }
    174 
    175 // border
    176 void CPDFSDK_BAAnnot::SetBorderWidth(int nWidth) {
    177   CPDF_Array* pBorder = m_pAnnot->GetAnnotDict()->GetArrayFor("Border");
    178   if (pBorder) {
    179     pBorder->SetNewAt<CPDF_Number>(2, nWidth);
    180   } else {
    181     CPDF_Dictionary* pBSDict = m_pAnnot->GetAnnotDict()->GetDictFor("BS");
    182     if (!pBSDict)
    183       pBSDict = m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_Dictionary>("BS");
    184 
    185     pBSDict->SetNewFor<CPDF_Number>("W", nWidth);
    186   }
    187 }
    188 
    189 int CPDFSDK_BAAnnot::GetBorderWidth() const {
    190   if (CPDF_Array* pBorder = m_pAnnot->GetAnnotDict()->GetArrayFor("Border"))
    191     return pBorder->GetIntegerAt(2);
    192 
    193   if (CPDF_Dictionary* pBSDict = m_pAnnot->GetAnnotDict()->GetDictFor("BS"))
    194     return pBSDict->GetIntegerFor("W", 1);
    195 
    196   return 1;
    197 }
    198 
    199 void CPDFSDK_BAAnnot::SetBorderStyle(BorderStyle nStyle) {
    200   CPDF_Dictionary* pBSDict = m_pAnnot->GetAnnotDict()->GetDictFor("BS");
    201   if (!pBSDict)
    202     pBSDict = m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_Dictionary>("BS");
    203 
    204   switch (nStyle) {
    205     case BorderStyle::SOLID:
    206       pBSDict->SetNewFor<CPDF_Name>("S", "S");
    207       break;
    208     case BorderStyle::DASH:
    209       pBSDict->SetNewFor<CPDF_Name>("S", "D");
    210       break;
    211     case BorderStyle::BEVELED:
    212       pBSDict->SetNewFor<CPDF_Name>("S", "B");
    213       break;
    214     case BorderStyle::INSET:
    215       pBSDict->SetNewFor<CPDF_Name>("S", "I");
    216       break;
    217     case BorderStyle::UNDERLINE:
    218       pBSDict->SetNewFor<CPDF_Name>("S", "U");
    219       break;
    220     default:
    221       break;
    222   }
    223 }
    224 
    225 BorderStyle CPDFSDK_BAAnnot::GetBorderStyle() const {
    226   CPDF_Dictionary* pBSDict = m_pAnnot->GetAnnotDict()->GetDictFor("BS");
    227   if (pBSDict) {
    228     ByteString sBorderStyle = pBSDict->GetStringFor("S", "S");
    229     if (sBorderStyle == "S")
    230       return BorderStyle::SOLID;
    231     if (sBorderStyle == "D")
    232       return BorderStyle::DASH;
    233     if (sBorderStyle == "B")
    234       return BorderStyle::BEVELED;
    235     if (sBorderStyle == "I")
    236       return BorderStyle::INSET;
    237     if (sBorderStyle == "U")
    238       return BorderStyle::UNDERLINE;
    239   }
    240 
    241   CPDF_Array* pBorder = m_pAnnot->GetAnnotDict()->GetArrayFor("Border");
    242   if (pBorder) {
    243     if (pBorder->GetCount() >= 4) {
    244       CPDF_Array* pDP = pBorder->GetArrayAt(3);
    245       if (pDP && pDP->GetCount() > 0)
    246         return BorderStyle::DASH;
    247     }
    248   }
    249 
    250   return BorderStyle::SOLID;
    251 }
    252 
    253 void CPDFSDK_BAAnnot::SetColor(FX_COLORREF color) {
    254   CPDF_Array* pArray = m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_Array>("C");
    255   pArray->AddNew<CPDF_Number>(static_cast<float>(FXSYS_GetRValue(color)) /
    256                               255.0f);
    257   pArray->AddNew<CPDF_Number>(static_cast<float>(FXSYS_GetGValue(color)) /
    258                               255.0f);
    259   pArray->AddNew<CPDF_Number>(static_cast<float>(FXSYS_GetBValue(color)) /
    260                               255.0f);
    261 }
    262 
    263 void CPDFSDK_BAAnnot::RemoveColor() {
    264   m_pAnnot->GetAnnotDict()->RemoveFor("C");
    265 }
    266 
    267 bool CPDFSDK_BAAnnot::GetColor(FX_COLORREF& color) const {
    268   if (CPDF_Array* pEntry = m_pAnnot->GetAnnotDict()->GetArrayFor("C")) {
    269     size_t nCount = pEntry->GetCount();
    270     if (nCount == 1) {
    271       float g = pEntry->GetNumberAt(0) * 255;
    272 
    273       color = FXSYS_RGB((int)g, (int)g, (int)g);
    274 
    275       return true;
    276     } else if (nCount == 3) {
    277       float r = pEntry->GetNumberAt(0) * 255;
    278       float g = pEntry->GetNumberAt(1) * 255;
    279       float b = pEntry->GetNumberAt(2) * 255;
    280 
    281       color = FXSYS_RGB((int)r, (int)g, (int)b);
    282 
    283       return true;
    284     } else if (nCount == 4) {
    285       float c = pEntry->GetNumberAt(0);
    286       float m = pEntry->GetNumberAt(1);
    287       float y = pEntry->GetNumberAt(2);
    288       float k = pEntry->GetNumberAt(3);
    289 
    290       float r = 1.0f - std::min(1.0f, c + k);
    291       float g = 1.0f - std::min(1.0f, m + k);
    292       float b = 1.0f - std::min(1.0f, y + k);
    293 
    294       color = FXSYS_RGB((int)(r * 255), (int)(g * 255), (int)(b * 255));
    295 
    296       return true;
    297     }
    298   }
    299 
    300   return false;
    301 }
    302 
    303 bool CPDFSDK_BAAnnot::IsVisible() const {
    304   uint32_t nFlags = GetFlags();
    305   return !((nFlags & ANNOTFLAG_INVISIBLE) || (nFlags & ANNOTFLAG_HIDDEN) ||
    306            (nFlags & ANNOTFLAG_NOVIEW));
    307 }
    308 
    309 CPDF_Action CPDFSDK_BAAnnot::GetAction() const {
    310   return CPDF_Action(m_pAnnot->GetAnnotDict()->GetDictFor("A"));
    311 }
    312 
    313 void CPDFSDK_BAAnnot::SetAction(const CPDF_Action& action) {
    314   CPDF_Dictionary* pDict = action.GetDict();
    315   if (pDict != m_pAnnot->GetAnnotDict()->GetDictFor("A")) {
    316     CPDF_Document* pDoc = m_pPageView->GetPDFDocument();
    317     if (pDict->IsInline())
    318       pDict = pDoc->AddIndirectObject(pDict->Clone())->AsDictionary();
    319     m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_Reference>("A", pDoc,
    320                                                         pDict->GetObjNum());
    321   }
    322 }
    323 
    324 void CPDFSDK_BAAnnot::RemoveAction() {
    325   m_pAnnot->GetAnnotDict()->RemoveFor("A");
    326 }
    327 
    328 CPDF_AAction CPDFSDK_BAAnnot::GetAAction() const {
    329   return CPDF_AAction(m_pAnnot->GetAnnotDict()->GetDictFor("AA"));
    330 }
    331 
    332 void CPDFSDK_BAAnnot::SetAAction(const CPDF_AAction& aa) {
    333   if (aa.GetDict() != m_pAnnot->GetAnnotDict()->GetDictFor("AA"))
    334     m_pAnnot->GetAnnotDict()->SetFor("AA", pdfium::WrapUnique(aa.GetDict()));
    335 }
    336 
    337 void CPDFSDK_BAAnnot::RemoveAAction() {
    338   m_pAnnot->GetAnnotDict()->RemoveFor("AA");
    339 }
    340 
    341 CPDF_Action CPDFSDK_BAAnnot::GetAAction(CPDF_AAction::AActionType eAAT) {
    342   CPDF_AAction AAction = GetAAction();
    343   if (AAction.ActionExist(eAAT))
    344     return AAction.GetAction(eAAT);
    345 
    346   if (eAAT == CPDF_AAction::ButtonUp)
    347     return GetAction();
    348 
    349   return CPDF_Action(nullptr);
    350 }
    351 
    352 void CPDFSDK_BAAnnot::SetOpenState(bool bOpenState) {
    353   if (CPDF_Annot* pAnnot = m_pAnnot->GetPopupAnnot())
    354     pAnnot->SetOpenState(bOpenState);
    355 }
    356 
    357 int CPDFSDK_BAAnnot::GetLayoutOrder() const {
    358   if (m_pAnnot->GetSubtype() == CPDF_Annot::Subtype::POPUP)
    359     return 1;
    360 
    361   return CPDFSDK_Annot::GetLayoutOrder();
    362 }
    363