• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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