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