• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CPDFSDK_BAAnnot(CPDF_Annot * pAnnot,CPDFSDK_PageView * pPageView)23 CPDFSDK_BAAnnot::CPDFSDK_BAAnnot(CPDF_Annot* pAnnot,
24                                  CPDFSDK_PageView* pPageView)
25     : CPDFSDK_Annot(pPageView), m_pAnnot(pAnnot) {}
26 
~CPDFSDK_BAAnnot()27 CPDFSDK_BAAnnot::~CPDFSDK_BAAnnot() {}
28 
GetPDFAnnot() const29 CPDF_Annot* CPDFSDK_BAAnnot::GetPDFAnnot() const {
30   return m_pAnnot.Get();
31 }
32 
GetPDFPopupAnnot() const33 CPDF_Annot* CPDFSDK_BAAnnot::GetPDFPopupAnnot() const {
34   return m_pAnnot->GetPopupAnnot();
35 }
36 
GetAnnotDict() const37 CPDF_Dictionary* CPDFSDK_BAAnnot::GetAnnotDict() const {
38   return m_pAnnot->GetAnnotDict();
39 }
40 
GetAPDict() const41 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 
SetRect(const CFX_FloatRect & rect)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 
GetRect() const55 CFX_FloatRect CPDFSDK_BAAnnot::GetRect() const {
56   return m_pAnnot->GetRect();
57 }
58 
GetAnnotSubtype() const59 CPDF_Annot::Subtype CPDFSDK_BAAnnot::GetAnnotSubtype() const {
60   return m_pAnnot->GetSubtype();
61 }
62 
DrawAppearance(CFX_RenderDevice * pDevice,const CFX_Matrix & mtUser2Device,CPDF_Annot::AppearanceMode mode,const CPDF_RenderOptions * pOptions)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 
IsAppearanceValid()71 bool CPDFSDK_BAAnnot::IsAppearanceValid() {
72   return !!m_pAnnot->GetAnnotDict()->GetDictFor("AP");
73 }
74 
IsAppearanceValid(CPDF_Annot::AppearanceMode mode)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 
DrawBorder(CFX_RenderDevice * pDevice,const CFX_Matrix * pUser2Device,const CPDF_RenderOptions * pOptions)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 
ClearCachedAP()100 void CPDFSDK_BAAnnot::ClearCachedAP() {
101   m_pAnnot->ClearCachedAP();
102 }
103 
SetContents(const WideString & sContents)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 
GetContents() const113 WideString CPDFSDK_BAAnnot::GetContents() const {
114   return m_pAnnot->GetAnnotDict()->GetUnicodeTextFor("Contents");
115 }
116 
SetAnnotName(const WideString & sName)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 
GetAnnotName() const126 WideString CPDFSDK_BAAnnot::GetAnnotName() const {
127   return m_pAnnot->GetAnnotDict()->GetUnicodeTextFor("NM");
128 }
129 
SetModifiedDate(const FX_SYSTEMTIME & st)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 
GetModifiedDate() const139 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 
SetFlags(uint32_t nFlags)147 void CPDFSDK_BAAnnot::SetFlags(uint32_t nFlags) {
148   m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_Number>("F",
149                                                    static_cast<int>(nFlags));
150 }
151 
GetFlags() const152 uint32_t CPDFSDK_BAAnnot::GetFlags() const {
153   return m_pAnnot->GetAnnotDict()->GetIntegerFor("F");
154 }
155 
SetAppState(const ByteString & str)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 
GetAppState() const163 ByteString CPDFSDK_BAAnnot::GetAppState() const {
164   return m_pAnnot->GetAnnotDict()->GetStringFor("AS");
165 }
166 
SetStructParent(int key)167 void CPDFSDK_BAAnnot::SetStructParent(int key) {
168   m_pAnnot->GetAnnotDict()->SetNewFor<CPDF_Number>("StructParent", key);
169 }
170 
GetStructParent() const171 int CPDFSDK_BAAnnot::GetStructParent() const {
172   return m_pAnnot->GetAnnotDict()->GetIntegerFor("StructParent");
173 }
174 
175 // border
SetBorderWidth(int nWidth)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 
GetBorderWidth() const189 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 
SetBorderStyle(BorderStyle nStyle)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 
GetBorderStyle() const225 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 
SetColor(FX_COLORREF color)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 
RemoveColor()263 void CPDFSDK_BAAnnot::RemoveColor() {
264   m_pAnnot->GetAnnotDict()->RemoveFor("C");
265 }
266 
GetColor(FX_COLORREF & color) const267 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 
IsVisible() const303 bool CPDFSDK_BAAnnot::IsVisible() const {
304   uint32_t nFlags = GetFlags();
305   return !((nFlags & ANNOTFLAG_INVISIBLE) || (nFlags & ANNOTFLAG_HIDDEN) ||
306            (nFlags & ANNOTFLAG_NOVIEW));
307 }
308 
GetAction() const309 CPDF_Action CPDFSDK_BAAnnot::GetAction() const {
310   return CPDF_Action(m_pAnnot->GetAnnotDict()->GetDictFor("A"));
311 }
312 
SetAction(const CPDF_Action & action)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 
RemoveAction()324 void CPDFSDK_BAAnnot::RemoveAction() {
325   m_pAnnot->GetAnnotDict()->RemoveFor("A");
326 }
327 
GetAAction() const328 CPDF_AAction CPDFSDK_BAAnnot::GetAAction() const {
329   return CPDF_AAction(m_pAnnot->GetAnnotDict()->GetDictFor("AA"));
330 }
331 
SetAAction(const CPDF_AAction & aa)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 
RemoveAAction()337 void CPDFSDK_BAAnnot::RemoveAAction() {
338   m_pAnnot->GetAnnotDict()->RemoveFor("AA");
339 }
340 
GetAAction(CPDF_AAction::AActionType eAAT)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 
SetOpenState(bool bOpenState)352 void CPDFSDK_BAAnnot::SetOpenState(bool bOpenState) {
353   if (CPDF_Annot* pAnnot = m_pAnnot->GetPopupAnnot())
354     pAnnot->SetOpenState(bOpenState);
355 }
356 
GetLayoutOrder() const357 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