1 // Copyright 2016 The PDFium Authors
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 <vector>
10
11 #include "constants/annotation_common.h"
12 #include "constants/annotation_flags.h"
13 #include "constants/form_fields.h"
14 #include "core/fpdfapi/parser/cpdf_array.h"
15 #include "core/fpdfapi/parser/cpdf_dictionary.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_stream.h"
20 #include "core/fpdfapi/parser/cpdf_string.h"
21 #include "core/fpdfapi/parser/fpdf_parser_decode.h"
22 #include "core/fpdfapi/parser/fpdf_parser_utility.h"
23 #include "core/fxge/cfx_drawutils.h"
24 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
25 #include "fpdfsdk/cpdfsdk_pageview.h"
26 #include "third_party/abseil-cpp/absl/types/optional.h"
27 #include "third_party/base/check.h"
28 #include "third_party/base/containers/contains.h"
29
CPDFSDK_BAAnnot(CPDF_Annot * pAnnot,CPDFSDK_PageView * pPageView)30 CPDFSDK_BAAnnot::CPDFSDK_BAAnnot(CPDF_Annot* pAnnot,
31 CPDFSDK_PageView* pPageView)
32 : CPDFSDK_Annot(pPageView), m_pAnnot(pAnnot) {}
33
34 CPDFSDK_BAAnnot::~CPDFSDK_BAAnnot() = default;
35
AsBAAnnot()36 CPDFSDK_BAAnnot* CPDFSDK_BAAnnot::AsBAAnnot() {
37 return this;
38 }
39
GetUnsafeInputHandlers()40 CPDFSDK_Annot::UnsafeInputHandlers* CPDFSDK_BAAnnot::GetUnsafeInputHandlers() {
41 return this;
42 }
43
GetPDFAnnot() const44 CPDF_Annot* CPDFSDK_BAAnnot::GetPDFAnnot() const {
45 return m_pAnnot;
46 }
47
GetAnnotDict() const48 const CPDF_Dictionary* CPDFSDK_BAAnnot::GetAnnotDict() const {
49 return m_pAnnot->GetAnnotDict();
50 }
51
GetMutableAnnotDict()52 RetainPtr<CPDF_Dictionary> CPDFSDK_BAAnnot::GetMutableAnnotDict() {
53 return m_pAnnot->GetMutableAnnotDict();
54 }
55
GetAPDict()56 RetainPtr<CPDF_Dictionary> CPDFSDK_BAAnnot::GetAPDict() {
57 return GetMutableAnnotDict()->GetOrCreateDictFor(pdfium::annotation::kAP);
58 }
59
ClearCachedAnnotAP()60 void CPDFSDK_BAAnnot::ClearCachedAnnotAP() {
61 m_pAnnot->ClearCachedAP();
62 }
63
IsFocusableAnnot(const CPDF_Annot::Subtype & annot_type) const64 bool CPDFSDK_BAAnnot::IsFocusableAnnot(
65 const CPDF_Annot::Subtype& annot_type) const {
66 return pdfium::Contains(
67 GetPageView()->GetFormFillEnv()->GetFocusableAnnotSubtypes(), annot_type);
68 }
69
GetRect() const70 CFX_FloatRect CPDFSDK_BAAnnot::GetRect() const {
71 return m_pAnnot->GetRect();
72 }
73
GetAnnotSubtype() const74 CPDF_Annot::Subtype CPDFSDK_BAAnnot::GetAnnotSubtype() const {
75 return m_pAnnot->GetSubtype();
76 }
77
DrawAppearance(CFX_RenderDevice * pDevice,const CFX_Matrix & mtUser2Device,CPDF_Annot::AppearanceMode mode)78 void CPDFSDK_BAAnnot::DrawAppearance(CFX_RenderDevice* pDevice,
79 const CFX_Matrix& mtUser2Device,
80 CPDF_Annot::AppearanceMode mode) {
81 m_pAnnot->DrawAppearance(GetPageView()->GetPDFPage(), pDevice, mtUser2Device,
82 mode);
83 }
84
IsAppearanceValid()85 bool CPDFSDK_BAAnnot::IsAppearanceValid() {
86 return !!GetAnnotDict()->GetDictFor(pdfium::annotation::kAP);
87 }
88
SetAnnotName(const WideString & sName)89 void CPDFSDK_BAAnnot::SetAnnotName(const WideString& sName) {
90 RetainPtr<CPDF_Dictionary> pDict = GetMutableAnnotDict();
91 if (sName.IsEmpty()) {
92 pDict->RemoveFor(pdfium::annotation::kNM);
93 return;
94 }
95 pDict->SetNewFor<CPDF_String>(pdfium::annotation::kNM, sName.AsStringView());
96 }
97
GetAnnotName() const98 WideString CPDFSDK_BAAnnot::GetAnnotName() const {
99 return GetAnnotDict()->GetUnicodeTextFor(pdfium::annotation::kNM);
100 }
101
SetFlags(uint32_t nFlags)102 void CPDFSDK_BAAnnot::SetFlags(uint32_t nFlags) {
103 GetMutableAnnotDict()->SetNewFor<CPDF_Number>(pdfium::annotation::kF,
104 static_cast<int>(nFlags));
105 }
106
GetFlags() const107 uint32_t CPDFSDK_BAAnnot::GetFlags() const {
108 return GetAnnotDict()->GetIntegerFor(pdfium::annotation::kF);
109 }
110
SetAppStateOff()111 void CPDFSDK_BAAnnot::SetAppStateOff() {
112 RetainPtr<CPDF_Dictionary> pDict = GetMutableAnnotDict();
113 pDict->SetNewFor<CPDF_String>(pdfium::annotation::kAS, "Off", false);
114 }
115
GetAppState() const116 ByteString CPDFSDK_BAAnnot::GetAppState() const {
117 return GetAnnotDict()->GetByteStringFor(pdfium::annotation::kAS);
118 }
119
SetBorderWidth(int nWidth)120 void CPDFSDK_BAAnnot::SetBorderWidth(int nWidth) {
121 RetainPtr<CPDF_Dictionary> pAnnotDict = GetMutableAnnotDict();
122 RetainPtr<CPDF_Array> pBorder =
123 pAnnotDict->GetMutableArrayFor(pdfium::annotation::kBorder);
124 if (pBorder) {
125 pBorder->SetNewAt<CPDF_Number>(2, nWidth);
126 return;
127 }
128 pAnnotDict->GetOrCreateDictFor("BS")->SetNewFor<CPDF_Number>("W", nWidth);
129 }
130
GetBorderWidth() const131 int CPDFSDK_BAAnnot::GetBorderWidth() const {
132 RetainPtr<const CPDF_Array> pBorder =
133 GetAnnotDict()->GetArrayFor(pdfium::annotation::kBorder);
134 if (pBorder)
135 return pBorder->GetIntegerAt(2);
136
137 RetainPtr<const CPDF_Dictionary> pBSDict = GetAnnotDict()->GetDictFor("BS");
138 if (pBSDict)
139 return pBSDict->GetIntegerFor("W", 1);
140
141 return 1;
142 }
143
SetBorderStyle(BorderStyle nStyle)144 void CPDFSDK_BAAnnot::SetBorderStyle(BorderStyle nStyle) {
145 RetainPtr<CPDF_Dictionary> pBSDict =
146 GetMutableAnnotDict()->GetOrCreateDictFor("BS");
147 const char* name = nullptr;
148 switch (nStyle) {
149 case BorderStyle::kSolid:
150 name = "S";
151 break;
152 case BorderStyle::kDash:
153 name = "D";
154 break;
155 case BorderStyle::kBeveled:
156 name = "B";
157 break;
158 case BorderStyle::kInset:
159 name = "I";
160 break;
161 case BorderStyle::kUnderline:
162 name = "U";
163 break;
164 default:
165 return;
166 }
167 pBSDict->SetNewFor<CPDF_Name>("S", name);
168 }
169
GetBorderStyle() const170 BorderStyle CPDFSDK_BAAnnot::GetBorderStyle() const {
171 RetainPtr<const CPDF_Dictionary> pBSDict = GetAnnotDict()->GetDictFor("BS");
172 if (pBSDict) {
173 ByteString sBorderStyle = pBSDict->GetByteStringFor("S", "S");
174 if (sBorderStyle == "S")
175 return BorderStyle::kSolid;
176 if (sBorderStyle == "D")
177 return BorderStyle::kDash;
178 if (sBorderStyle == "B")
179 return BorderStyle::kBeveled;
180 if (sBorderStyle == "I")
181 return BorderStyle::kInset;
182 if (sBorderStyle == "U")
183 return BorderStyle::kUnderline;
184 }
185
186 RetainPtr<const CPDF_Array> pBorder =
187 GetAnnotDict()->GetArrayFor(pdfium::annotation::kBorder);
188 if (pBorder) {
189 if (pBorder->size() >= 4) {
190 RetainPtr<const CPDF_Array> pDP = pBorder->GetArrayAt(3);
191 if (pDP && pDP->size() > 0)
192 return BorderStyle::kDash;
193 }
194 }
195
196 return BorderStyle::kSolid;
197 }
198
IsVisible() const199 bool CPDFSDK_BAAnnot::IsVisible() const {
200 uint32_t nFlags = GetFlags();
201 return !((nFlags & pdfium::annotation_flags::kInvisible) ||
202 (nFlags & pdfium::annotation_flags::kHidden) ||
203 (nFlags & pdfium::annotation_flags::kNoView));
204 }
205
GetAction() const206 CPDF_Action CPDFSDK_BAAnnot::GetAction() const {
207 return CPDF_Action(GetAnnotDict()->GetDictFor("A"));
208 }
209
GetAAction() const210 CPDF_AAction CPDFSDK_BAAnnot::GetAAction() const {
211 return CPDF_AAction(GetAnnotDict()->GetDictFor(pdfium::form_fields::kAA));
212 }
213
GetAAction(CPDF_AAction::AActionType eAAT)214 CPDF_Action CPDFSDK_BAAnnot::GetAAction(CPDF_AAction::AActionType eAAT) {
215 CPDF_AAction AAction = GetAAction();
216 if (AAction.ActionExist(eAAT))
217 return AAction.GetAction(eAAT);
218
219 if (eAAT == CPDF_AAction::kButtonUp || eAAT == CPDF_AAction::kKeyStroke)
220 return GetAction();
221
222 return CPDF_Action(nullptr);
223 }
224
SetOpenState(bool bOpenState)225 void CPDFSDK_BAAnnot::SetOpenState(bool bOpenState) {
226 m_pAnnot->SetPopupAnnotOpenState(bOpenState);
227 }
228
UpdateAnnotRects()229 void CPDFSDK_BAAnnot::UpdateAnnotRects() {
230 std::vector<CFX_FloatRect> rects;
231 rects.push_back(GetRect());
232
233 absl::optional<CFX_FloatRect> annot_rect = m_pAnnot->GetPopupAnnotRect();
234 if (annot_rect.has_value())
235 rects.push_back(annot_rect.value());
236
237 // Make the rects round up to avoid https://crbug.com/662804
238 for (CFX_FloatRect& rect : rects)
239 rect.Inflate(1, 1);
240
241 GetPageView()->UpdateRects(rects);
242 }
243
InvalidateRect()244 void CPDFSDK_BAAnnot::InvalidateRect() {
245 CFX_FloatRect view_bounding_box = GetViewBBox();
246 if (view_bounding_box.IsEmpty())
247 return;
248
249 view_bounding_box.Inflate(1, 1);
250 view_bounding_box.Normalize();
251 FX_RECT rect = view_bounding_box.GetOuterRect();
252 GetPageView()->GetFormFillEnv()->Invalidate(GetPage(), rect);
253 }
254
GetLayoutOrder() const255 int CPDFSDK_BAAnnot::GetLayoutOrder() const {
256 if (m_pAnnot->GetSubtype() == CPDF_Annot::Subtype::POPUP)
257 return 1;
258
259 return CPDFSDK_Annot::GetLayoutOrder();
260 }
261
OnDraw(CFX_RenderDevice * pDevice,const CFX_Matrix & mtUser2Device,bool bDrawAnnots)262 void CPDFSDK_BAAnnot::OnDraw(CFX_RenderDevice* pDevice,
263 const CFX_Matrix& mtUser2Device,
264 bool bDrawAnnots) {
265 if (!IsVisible())
266 return;
267
268 const CPDF_Annot::Subtype annot_type = GetAnnotSubtype();
269 if (bDrawAnnots && annot_type == CPDF_Annot::Subtype::POPUP) {
270 DrawAppearance(pDevice, mtUser2Device, CPDF_Annot::AppearanceMode::kNormal);
271 return;
272 }
273
274 if (!is_focused_ || !IsFocusableAnnot(annot_type) ||
275 this != GetPageView()->GetFormFillEnv()->GetFocusAnnot()) {
276 return;
277 }
278
279 CFX_FloatRect view_bounding_box = GetViewBBox();
280 if (view_bounding_box.IsEmpty())
281 return;
282
283 view_bounding_box.Normalize();
284 CFX_DrawUtils::DrawFocusRect(pDevice, mtUser2Device, view_bounding_box);
285 }
286
DoHitTest(const CFX_PointF & point)287 bool CPDFSDK_BAAnnot::DoHitTest(const CFX_PointF& point) {
288 return false;
289 }
290
GetViewBBox()291 CFX_FloatRect CPDFSDK_BAAnnot::GetViewBBox() {
292 return GetRect();
293 }
294
OnMouseEnter(Mask<FWL_EVENTFLAG> nFlags)295 void CPDFSDK_BAAnnot::OnMouseEnter(Mask<FWL_EVENTFLAG> nFlags) {
296 SetOpenState(true);
297 UpdateAnnotRects();
298 }
299
OnMouseExit(Mask<FWL_EVENTFLAG> nFlags)300 void CPDFSDK_BAAnnot::OnMouseExit(Mask<FWL_EVENTFLAG> nFlags) {
301 SetOpenState(false);
302 UpdateAnnotRects();
303 }
304
OnLButtonDown(Mask<FWL_EVENTFLAG> nFlags,const CFX_PointF & point)305 bool CPDFSDK_BAAnnot::OnLButtonDown(Mask<FWL_EVENTFLAG> nFlags,
306 const CFX_PointF& point) {
307 return false;
308 }
309
OnLButtonUp(Mask<FWL_EVENTFLAG> nFlags,const CFX_PointF & point)310 bool CPDFSDK_BAAnnot::OnLButtonUp(Mask<FWL_EVENTFLAG> nFlags,
311 const CFX_PointF& point) {
312 return false;
313 }
314
OnLButtonDblClk(Mask<FWL_EVENTFLAG> nFlags,const CFX_PointF & point)315 bool CPDFSDK_BAAnnot::OnLButtonDblClk(Mask<FWL_EVENTFLAG> nFlags,
316 const CFX_PointF& point) {
317 return false;
318 }
319
OnMouseMove(Mask<FWL_EVENTFLAG> nFlags,const CFX_PointF & point)320 bool CPDFSDK_BAAnnot::OnMouseMove(Mask<FWL_EVENTFLAG> nFlags,
321 const CFX_PointF& point) {
322 return false;
323 }
324
OnMouseWheel(Mask<FWL_EVENTFLAG> nFlags,const CFX_PointF & point,const CFX_Vector & delta)325 bool CPDFSDK_BAAnnot::OnMouseWheel(Mask<FWL_EVENTFLAG> nFlags,
326 const CFX_PointF& point,
327 const CFX_Vector& delta) {
328 return false;
329 }
330
OnRButtonDown(Mask<FWL_EVENTFLAG> nFlags,const CFX_PointF & point)331 bool CPDFSDK_BAAnnot::OnRButtonDown(Mask<FWL_EVENTFLAG> nFlags,
332 const CFX_PointF& point) {
333 return false;
334 }
335
OnRButtonUp(Mask<FWL_EVENTFLAG> nFlags,const CFX_PointF & point)336 bool CPDFSDK_BAAnnot::OnRButtonUp(Mask<FWL_EVENTFLAG> nFlags,
337 const CFX_PointF& point) {
338 return false;
339 }
340
OnChar(uint32_t nChar,Mask<FWL_EVENTFLAG> nFlags)341 bool CPDFSDK_BAAnnot::OnChar(uint32_t nChar, Mask<FWL_EVENTFLAG> nFlags) {
342 return false;
343 }
344
OnKeyDown(FWL_VKEYCODE nKeyCode,Mask<FWL_EVENTFLAG> nFlags)345 bool CPDFSDK_BAAnnot::OnKeyDown(FWL_VKEYCODE nKeyCode,
346 Mask<FWL_EVENTFLAG> nFlags) {
347 // OnKeyDown() is implemented only for link annotations for now. As
348 // OnKeyDown() is implemented for other subtypes, following check should be
349 // modified.
350 if (nKeyCode != FWL_VKEY_Return ||
351 GetAnnotSubtype() != CPDF_Annot::Subtype::LINK) {
352 return false;
353 }
354
355 CPDF_Action action = GetAAction(CPDF_AAction::kKeyStroke);
356 CPDFSDK_FormFillEnvironment* env = GetPageView()->GetFormFillEnv();
357 if (action.HasDict()) {
358 return env->DoActionLink(action, CPDF_AAction::kKeyStroke, nFlags);
359 }
360
361 return env->DoActionDestination(GetDestination());
362 }
363
OnSetFocus(Mask<FWL_EVENTFLAG> nFlags)364 bool CPDFSDK_BAAnnot::OnSetFocus(Mask<FWL_EVENTFLAG> nFlags) {
365 if (!IsFocusableAnnot(GetAnnotSubtype()))
366 return false;
367
368 is_focused_ = true;
369 InvalidateRect();
370 return true;
371 }
372
OnKillFocus(Mask<FWL_EVENTFLAG> nFlags)373 bool CPDFSDK_BAAnnot::OnKillFocus(Mask<FWL_EVENTFLAG> nFlags) {
374 if (!IsFocusableAnnot(GetAnnotSubtype()))
375 return false;
376
377 is_focused_ = false;
378 InvalidateRect();
379 return true;
380 }
381
CanUndo()382 bool CPDFSDK_BAAnnot::CanUndo() {
383 return false;
384 }
385
CanRedo()386 bool CPDFSDK_BAAnnot::CanRedo() {
387 return false;
388 }
389
Undo()390 bool CPDFSDK_BAAnnot::Undo() {
391 return false;
392 }
393
Redo()394 bool CPDFSDK_BAAnnot::Redo() {
395 return false;
396 }
397
GetText()398 WideString CPDFSDK_BAAnnot::GetText() {
399 return WideString();
400 }
401
GetSelectedText()402 WideString CPDFSDK_BAAnnot::GetSelectedText() {
403 return WideString();
404 }
405
ReplaceAndKeepSelection(const WideString & text)406 void CPDFSDK_BAAnnot::ReplaceAndKeepSelection(const WideString& text) {}
407
ReplaceSelection(const WideString & text)408 void CPDFSDK_BAAnnot::ReplaceSelection(const WideString& text) {}
409
SelectAllText()410 bool CPDFSDK_BAAnnot::SelectAllText() {
411 return false;
412 }
413
SetIndexSelected(int index,bool selected)414 bool CPDFSDK_BAAnnot::SetIndexSelected(int index, bool selected) {
415 return false;
416 }
417
IsIndexSelected(int index)418 bool CPDFSDK_BAAnnot::IsIndexSelected(int index) {
419 return false;
420 }
421
GetDestination() const422 CPDF_Dest CPDFSDK_BAAnnot::GetDestination() const {
423 if (m_pAnnot->GetSubtype() != CPDF_Annot::Subtype::LINK)
424 return CPDF_Dest(nullptr);
425
426 // Link annotations can have "Dest" entry defined as an explicit array.
427 // See ISO 32000-1:2008 spec, section 12.3.2.1.
428 return CPDF_Dest::Create(GetPageView()->GetPDFDocument(),
429 GetAnnotDict()->GetDirectObjectFor("Dest"));
430 }
431