xref: /aosp_15_r20/external/pdfium/fpdfsdk/cpdfsdk_baannot.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
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   }
165   pBSDict->SetNewFor<CPDF_Name>("S", name);
166 }
167 
GetBorderStyle() const168 BorderStyle CPDFSDK_BAAnnot::GetBorderStyle() const {
169   RetainPtr<const CPDF_Dictionary> pBSDict = GetAnnotDict()->GetDictFor("BS");
170   if (pBSDict) {
171     ByteString sBorderStyle = pBSDict->GetByteStringFor("S", "S");
172     if (sBorderStyle == "S")
173       return BorderStyle::kSolid;
174     if (sBorderStyle == "D")
175       return BorderStyle::kDash;
176     if (sBorderStyle == "B")
177       return BorderStyle::kBeveled;
178     if (sBorderStyle == "I")
179       return BorderStyle::kInset;
180     if (sBorderStyle == "U")
181       return BorderStyle::kUnderline;
182   }
183 
184   RetainPtr<const CPDF_Array> pBorder =
185       GetAnnotDict()->GetArrayFor(pdfium::annotation::kBorder);
186   if (pBorder) {
187     if (pBorder->size() >= 4) {
188       RetainPtr<const CPDF_Array> pDP = pBorder->GetArrayAt(3);
189       if (pDP && pDP->size() > 0)
190         return BorderStyle::kDash;
191     }
192   }
193 
194   return BorderStyle::kSolid;
195 }
196 
IsVisible() const197 bool CPDFSDK_BAAnnot::IsVisible() const {
198   uint32_t nFlags = GetFlags();
199   return !((nFlags & pdfium::annotation_flags::kInvisible) ||
200            (nFlags & pdfium::annotation_flags::kHidden) ||
201            (nFlags & pdfium::annotation_flags::kNoView));
202 }
203 
GetAction() const204 CPDF_Action CPDFSDK_BAAnnot::GetAction() const {
205   return CPDF_Action(GetAnnotDict()->GetDictFor("A"));
206 }
207 
GetAAction() const208 CPDF_AAction CPDFSDK_BAAnnot::GetAAction() const {
209   return CPDF_AAction(GetAnnotDict()->GetDictFor(pdfium::form_fields::kAA));
210 }
211 
GetAAction(CPDF_AAction::AActionType eAAT)212 CPDF_Action CPDFSDK_BAAnnot::GetAAction(CPDF_AAction::AActionType eAAT) {
213   CPDF_AAction AAction = GetAAction();
214   if (AAction.ActionExist(eAAT))
215     return AAction.GetAction(eAAT);
216 
217   if (eAAT == CPDF_AAction::kButtonUp || eAAT == CPDF_AAction::kKeyStroke)
218     return GetAction();
219 
220   return CPDF_Action(nullptr);
221 }
222 
SetOpenState(bool bOpenState)223 void CPDFSDK_BAAnnot::SetOpenState(bool bOpenState) {
224   m_pAnnot->SetPopupAnnotOpenState(bOpenState);
225 }
226 
UpdateAnnotRects()227 void CPDFSDK_BAAnnot::UpdateAnnotRects() {
228   std::vector<CFX_FloatRect> rects;
229   rects.push_back(GetRect());
230 
231   absl::optional<CFX_FloatRect> annot_rect = m_pAnnot->GetPopupAnnotRect();
232   if (annot_rect.has_value())
233     rects.push_back(annot_rect.value());
234 
235   // Make the rects round up to avoid https://crbug.com/662804
236   for (CFX_FloatRect& rect : rects)
237     rect.Inflate(1, 1);
238 
239   GetPageView()->UpdateRects(rects);
240 }
241 
InvalidateRect()242 void CPDFSDK_BAAnnot::InvalidateRect() {
243   CFX_FloatRect view_bounding_box = GetViewBBox();
244   if (view_bounding_box.IsEmpty())
245     return;
246 
247   view_bounding_box.Inflate(1, 1);
248   view_bounding_box.Normalize();
249   FX_RECT rect = view_bounding_box.GetOuterRect();
250   GetPageView()->GetFormFillEnv()->Invalidate(GetPage(), rect);
251 }
252 
GetLayoutOrder() const253 int CPDFSDK_BAAnnot::GetLayoutOrder() const {
254   if (m_pAnnot->GetSubtype() == CPDF_Annot::Subtype::POPUP)
255     return 1;
256 
257   return CPDFSDK_Annot::GetLayoutOrder();
258 }
259 
OnDraw(CFX_RenderDevice * pDevice,const CFX_Matrix & mtUser2Device,bool bDrawAnnots)260 void CPDFSDK_BAAnnot::OnDraw(CFX_RenderDevice* pDevice,
261                              const CFX_Matrix& mtUser2Device,
262                              bool bDrawAnnots) {
263   if (!IsVisible())
264     return;
265 
266   const CPDF_Annot::Subtype annot_type = GetAnnotSubtype();
267   if (bDrawAnnots && annot_type == CPDF_Annot::Subtype::POPUP) {
268     DrawAppearance(pDevice, mtUser2Device, CPDF_Annot::AppearanceMode::kNormal);
269     return;
270   }
271 
272   if (!is_focused_ || !IsFocusableAnnot(annot_type) ||
273       this != GetPageView()->GetFormFillEnv()->GetFocusAnnot()) {
274     return;
275   }
276 
277   CFX_FloatRect view_bounding_box = GetViewBBox();
278   if (view_bounding_box.IsEmpty())
279     return;
280 
281   view_bounding_box.Normalize();
282   CFX_DrawUtils::DrawFocusRect(pDevice, mtUser2Device, view_bounding_box);
283 }
284 
DoHitTest(const CFX_PointF & point)285 bool CPDFSDK_BAAnnot::DoHitTest(const CFX_PointF& point) {
286   return false;
287 }
288 
GetViewBBox()289 CFX_FloatRect CPDFSDK_BAAnnot::GetViewBBox() {
290   return GetRect();
291 }
292 
OnMouseEnter(Mask<FWL_EVENTFLAG> nFlags)293 void CPDFSDK_BAAnnot::OnMouseEnter(Mask<FWL_EVENTFLAG> nFlags) {
294   SetOpenState(true);
295   UpdateAnnotRects();
296 }
297 
OnMouseExit(Mask<FWL_EVENTFLAG> nFlags)298 void CPDFSDK_BAAnnot::OnMouseExit(Mask<FWL_EVENTFLAG> nFlags) {
299   SetOpenState(false);
300   UpdateAnnotRects();
301 }
302 
OnLButtonDown(Mask<FWL_EVENTFLAG> nFlags,const CFX_PointF & point)303 bool CPDFSDK_BAAnnot::OnLButtonDown(Mask<FWL_EVENTFLAG> nFlags,
304                                     const CFX_PointF& point) {
305   return false;
306 }
307 
OnLButtonUp(Mask<FWL_EVENTFLAG> nFlags,const CFX_PointF & point)308 bool CPDFSDK_BAAnnot::OnLButtonUp(Mask<FWL_EVENTFLAG> nFlags,
309                                   const CFX_PointF& point) {
310   return false;
311 }
312 
OnLButtonDblClk(Mask<FWL_EVENTFLAG> nFlags,const CFX_PointF & point)313 bool CPDFSDK_BAAnnot::OnLButtonDblClk(Mask<FWL_EVENTFLAG> nFlags,
314                                       const CFX_PointF& point) {
315   return false;
316 }
317 
OnMouseMove(Mask<FWL_EVENTFLAG> nFlags,const CFX_PointF & point)318 bool CPDFSDK_BAAnnot::OnMouseMove(Mask<FWL_EVENTFLAG> nFlags,
319                                   const CFX_PointF& point) {
320   return false;
321 }
322 
OnMouseWheel(Mask<FWL_EVENTFLAG> nFlags,const CFX_PointF & point,const CFX_Vector & delta)323 bool CPDFSDK_BAAnnot::OnMouseWheel(Mask<FWL_EVENTFLAG> nFlags,
324                                    const CFX_PointF& point,
325                                    const CFX_Vector& delta) {
326   return false;
327 }
328 
OnRButtonDown(Mask<FWL_EVENTFLAG> nFlags,const CFX_PointF & point)329 bool CPDFSDK_BAAnnot::OnRButtonDown(Mask<FWL_EVENTFLAG> nFlags,
330                                     const CFX_PointF& point) {
331   return false;
332 }
333 
OnRButtonUp(Mask<FWL_EVENTFLAG> nFlags,const CFX_PointF & point)334 bool CPDFSDK_BAAnnot::OnRButtonUp(Mask<FWL_EVENTFLAG> nFlags,
335                                   const CFX_PointF& point) {
336   return false;
337 }
338 
OnChar(uint32_t nChar,Mask<FWL_EVENTFLAG> nFlags)339 bool CPDFSDK_BAAnnot::OnChar(uint32_t nChar, Mask<FWL_EVENTFLAG> nFlags) {
340   return false;
341 }
342 
OnKeyDown(FWL_VKEYCODE nKeyCode,Mask<FWL_EVENTFLAG> nFlags)343 bool CPDFSDK_BAAnnot::OnKeyDown(FWL_VKEYCODE nKeyCode,
344                                 Mask<FWL_EVENTFLAG> nFlags) {
345   // OnKeyDown() is implemented only for link annotations for now. As
346   // OnKeyDown() is implemented for other subtypes, following check should be
347   // modified.
348   if (nKeyCode != FWL_VKEY_Return ||
349       GetAnnotSubtype() != CPDF_Annot::Subtype::LINK) {
350     return false;
351   }
352 
353   CPDF_Action action = GetAAction(CPDF_AAction::kKeyStroke);
354   CPDFSDK_FormFillEnvironment* env = GetPageView()->GetFormFillEnv();
355   if (action.HasDict()) {
356     return env->DoActionLink(action, CPDF_AAction::kKeyStroke, nFlags);
357   }
358 
359   return env->DoActionDestination(GetDestination());
360 }
361 
OnSetFocus(Mask<FWL_EVENTFLAG> nFlags)362 bool CPDFSDK_BAAnnot::OnSetFocus(Mask<FWL_EVENTFLAG> nFlags) {
363   if (!IsFocusableAnnot(GetAnnotSubtype()))
364     return false;
365 
366   is_focused_ = true;
367   InvalidateRect();
368   return true;
369 }
370 
OnKillFocus(Mask<FWL_EVENTFLAG> nFlags)371 bool CPDFSDK_BAAnnot::OnKillFocus(Mask<FWL_EVENTFLAG> nFlags) {
372   if (!IsFocusableAnnot(GetAnnotSubtype()))
373     return false;
374 
375   is_focused_ = false;
376   InvalidateRect();
377   return true;
378 }
379 
CanUndo()380 bool CPDFSDK_BAAnnot::CanUndo() {
381   return false;
382 }
383 
CanRedo()384 bool CPDFSDK_BAAnnot::CanRedo() {
385   return false;
386 }
387 
Undo()388 bool CPDFSDK_BAAnnot::Undo() {
389   return false;
390 }
391 
Redo()392 bool CPDFSDK_BAAnnot::Redo() {
393   return false;
394 }
395 
GetText()396 WideString CPDFSDK_BAAnnot::GetText() {
397   return WideString();
398 }
399 
GetSelectedText()400 WideString CPDFSDK_BAAnnot::GetSelectedText() {
401   return WideString();
402 }
403 
ReplaceAndKeepSelection(const WideString & text)404 void CPDFSDK_BAAnnot::ReplaceAndKeepSelection(const WideString& text) {}
405 
ReplaceSelection(const WideString & text)406 void CPDFSDK_BAAnnot::ReplaceSelection(const WideString& text) {}
407 
SelectAllText()408 bool CPDFSDK_BAAnnot::SelectAllText() {
409   return false;
410 }
411 
SetIndexSelected(int index,bool selected)412 bool CPDFSDK_BAAnnot::SetIndexSelected(int index, bool selected) {
413   return false;
414 }
415 
IsIndexSelected(int index)416 bool CPDFSDK_BAAnnot::IsIndexSelected(int index) {
417   return false;
418 }
419 
GetDestination() const420 CPDF_Dest CPDFSDK_BAAnnot::GetDestination() const {
421   if (m_pAnnot->GetSubtype() != CPDF_Annot::Subtype::LINK)
422     return CPDF_Dest(nullptr);
423 
424   // Link annotations can have "Dest" entry defined as an explicit array.
425   // See ISO 32000-1:2008 spec, section 12.3.2.1.
426   return CPDF_Dest::Create(GetPageView()->GetPDFDocument(),
427                            GetAnnotDict()->GetDirectObjectFor("Dest"));
428 }
429