1 // Copyright 2014 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/formfiller/cffl_interactiveformfiller.h"
8
9 #include "constants/access_permissions.h"
10 #include "constants/ascii.h"
11 #include "constants/form_flags.h"
12 #include "core/fpdfapi/page/cpdf_page.h"
13 #include "core/fxcrt/autorestorer.h"
14 #include "core/fxge/cfx_drawutils.h"
15 #include "fpdfsdk/cpdfsdk_pageview.h"
16 #include "fpdfsdk/cpdfsdk_widget.h"
17 #include "fpdfsdk/formfiller/cffl_checkbox.h"
18 #include "fpdfsdk/formfiller/cffl_combobox.h"
19 #include "fpdfsdk/formfiller/cffl_formfield.h"
20 #include "fpdfsdk/formfiller/cffl_listbox.h"
21 #include "fpdfsdk/formfiller/cffl_perwindowdata.h"
22 #include "fpdfsdk/formfiller/cffl_pushbutton.h"
23 #include "fpdfsdk/formfiller/cffl_radiobutton.h"
24 #include "fpdfsdk/formfiller/cffl_textfield.h"
25 #include "public/fpdf_fwlevent.h"
26 #include "third_party/base/check.h"
27 #include "third_party/base/cxx17_backports.h"
28
CFFL_InteractiveFormFiller(CallbackIface * pCallbackIface)29 CFFL_InteractiveFormFiller::CFFL_InteractiveFormFiller(
30 CallbackIface* pCallbackIface)
31 : m_pCallbackIface(pCallbackIface) {}
32
33 CFFL_InteractiveFormFiller::~CFFL_InteractiveFormFiller() = default;
34
Annot_HitTest(const CPDFSDK_Widget * pWidget,const CFX_PointF & point)35 bool CFFL_InteractiveFormFiller::Annot_HitTest(const CPDFSDK_Widget* pWidget,
36 const CFX_PointF& point) {
37 return pWidget->GetRect().Contains(point);
38 }
39
GetViewBBox(const CPDFSDK_PageView * pPageView,CPDFSDK_Widget * pWidget)40 FX_RECT CFFL_InteractiveFormFiller::GetViewBBox(
41 const CPDFSDK_PageView* pPageView,
42 CPDFSDK_Widget* pWidget) {
43 if (CFFL_FormField* pFormField = GetFormField(pWidget))
44 return pFormField->GetViewBBox(pPageView);
45
46 DCHECK(pPageView);
47
48 CPDF_Annot* pPDFAnnot = pWidget->GetPDFAnnot();
49 CFX_FloatRect rcWin = pPDFAnnot->GetRect();
50 if (!rcWin.IsEmpty()) {
51 rcWin.Inflate(1, 1);
52 rcWin.Normalize();
53 }
54 return rcWin.GetOuterRect();
55 }
56
OnDraw(CPDFSDK_PageView * pPageView,CPDFSDK_Widget * pWidget,CFX_RenderDevice * pDevice,const CFX_Matrix & mtUser2Device)57 void CFFL_InteractiveFormFiller::OnDraw(CPDFSDK_PageView* pPageView,
58 CPDFSDK_Widget* pWidget,
59 CFX_RenderDevice* pDevice,
60 const CFX_Matrix& mtUser2Device) {
61 DCHECK(pPageView);
62 if (!IsVisible(pWidget))
63 return;
64
65 CFFL_FormField* pFormField = GetFormField(pWidget);
66 if (pFormField && pFormField->IsValid()) {
67 pFormField->OnDraw(pPageView, pWidget, pDevice, mtUser2Device);
68 if (m_pCallbackIface->GetFocusAnnot() != pWidget)
69 return;
70
71 CFX_FloatRect rcFocus = pFormField->GetFocusBox(pPageView);
72 if (rcFocus.IsEmpty())
73 return;
74
75 CFX_DrawUtils::DrawFocusRect(pDevice, mtUser2Device, rcFocus);
76
77 return;
78 }
79
80 if (pFormField) {
81 pFormField->OnDrawDeactive(pPageView, pWidget, pDevice, mtUser2Device);
82 } else {
83 pWidget->DrawAppearance(pDevice, mtUser2Device,
84 CPDF_Annot::AppearanceMode::kNormal);
85 }
86
87 if (!IsReadOnly(pWidget) && IsFillingAllowed(pWidget))
88 pWidget->DrawShadow(pDevice, pPageView);
89 }
90
OnDelete(CPDFSDK_Widget * pWidget)91 void CFFL_InteractiveFormFiller::OnDelete(CPDFSDK_Widget* pWidget) {
92 UnregisterFormField(pWidget);
93 }
94
OnMouseEnter(CPDFSDK_PageView * pPageView,ObservedPtr<CPDFSDK_Widget> & pWidget,Mask<FWL_EVENTFLAG> nFlag)95 void CFFL_InteractiveFormFiller::OnMouseEnter(
96 CPDFSDK_PageView* pPageView,
97 ObservedPtr<CPDFSDK_Widget>& pWidget,
98 Mask<FWL_EVENTFLAG> nFlag) {
99 if (!m_bNotifying) {
100 if (pWidget->GetAAction(CPDF_AAction::kCursorEnter).HasDict()) {
101 uint32_t nValueAge = pWidget->GetValueAge();
102 pWidget->ClearAppModified();
103 DCHECK(pPageView);
104 {
105 AutoRestorer<bool> restorer(&m_bNotifying);
106 m_bNotifying = true;
107
108 CFFL_FieldAction fa;
109 fa.bModifier = CPWL_Wnd::IsCTRLKeyDown(nFlag);
110 fa.bShift = CPWL_Wnd::IsSHIFTKeyDown(nFlag);
111 pWidget->OnAAction(CPDF_AAction::kCursorEnter, &fa, pPageView);
112 }
113 if (!pWidget)
114 return;
115
116 if (pWidget->IsAppModified()) {
117 CFFL_FormField* pFormField = GetFormField(pWidget.Get());
118 if (pFormField)
119 pFormField->ResetPWLWindowForValueAge(pPageView, pWidget.Get(),
120 nValueAge);
121 }
122 }
123 }
124 if (CFFL_FormField* pFormField = GetOrCreateFormField(pWidget.Get()))
125 pFormField->OnMouseEnter(pPageView);
126 }
127
OnMouseExit(CPDFSDK_PageView * pPageView,ObservedPtr<CPDFSDK_Widget> & pWidget,Mask<FWL_EVENTFLAG> nFlag)128 void CFFL_InteractiveFormFiller::OnMouseExit(
129 CPDFSDK_PageView* pPageView,
130 ObservedPtr<CPDFSDK_Widget>& pWidget,
131 Mask<FWL_EVENTFLAG> nFlag) {
132 if (!m_bNotifying) {
133 if (pWidget->GetAAction(CPDF_AAction::kCursorExit).HasDict()) {
134 uint32_t nValueAge = pWidget->GetValueAge();
135 pWidget->ClearAppModified();
136 DCHECK(pPageView);
137 {
138 AutoRestorer<bool> restorer(&m_bNotifying);
139 m_bNotifying = true;
140
141 CFFL_FieldAction fa;
142 fa.bModifier = CPWL_Wnd::IsCTRLKeyDown(nFlag);
143 fa.bShift = CPWL_Wnd::IsSHIFTKeyDown(nFlag);
144 pWidget->OnAAction(CPDF_AAction::kCursorExit, &fa, pPageView);
145 }
146 if (!pWidget)
147 return;
148
149 if (pWidget->IsAppModified()) {
150 CFFL_FormField* pFormField = GetFormField(pWidget.Get());
151 if (pFormField) {
152 pFormField->ResetPWLWindowForValueAge(pPageView, pWidget.Get(),
153 nValueAge);
154 }
155 }
156 }
157 }
158 if (CFFL_FormField* pFormField = GetFormField(pWidget.Get()))
159 pFormField->OnMouseExit(pPageView);
160 }
161
OnLButtonDown(CPDFSDK_PageView * pPageView,ObservedPtr<CPDFSDK_Widget> & pWidget,Mask<FWL_EVENTFLAG> nFlags,const CFX_PointF & point)162 bool CFFL_InteractiveFormFiller::OnLButtonDown(
163 CPDFSDK_PageView* pPageView,
164 ObservedPtr<CPDFSDK_Widget>& pWidget,
165 Mask<FWL_EVENTFLAG> nFlags,
166 const CFX_PointF& point) {
167 if (!m_bNotifying) {
168 if (Annot_HitTest(pWidget.Get(), point) &&
169 pWidget->GetAAction(CPDF_AAction::kButtonDown).HasDict()) {
170 uint32_t nValueAge = pWidget->GetValueAge();
171 pWidget->ClearAppModified();
172 DCHECK(pPageView);
173 {
174 AutoRestorer<bool> restorer(&m_bNotifying);
175 m_bNotifying = true;
176
177 CFFL_FieldAction fa;
178 fa.bModifier = CPWL_Wnd::IsCTRLKeyDown(nFlags);
179 fa.bShift = CPWL_Wnd::IsSHIFTKeyDown(nFlags);
180 pWidget->OnAAction(CPDF_AAction::kButtonDown, &fa, pPageView);
181 }
182 if (!pWidget)
183 return true;
184
185 if (!IsValidAnnot(pPageView, pWidget.Get()))
186 return true;
187
188 if (pWidget->IsAppModified()) {
189 CFFL_FormField* pFormField = GetFormField(pWidget.Get());
190 if (pFormField) {
191 pFormField->ResetPWLWindowForValueAge(pPageView, pWidget.Get(),
192 nValueAge);
193 }
194 }
195 }
196 }
197 CFFL_FormField* pFormField = GetFormField(pWidget.Get());
198 return pFormField &&
199 pFormField->OnLButtonDown(pPageView, pWidget.Get(), nFlags, point);
200 }
201
OnLButtonUp(CPDFSDK_PageView * pPageView,ObservedPtr<CPDFSDK_Widget> & pWidget,Mask<FWL_EVENTFLAG> nFlags,const CFX_PointF & point)202 bool CFFL_InteractiveFormFiller::OnLButtonUp(
203 CPDFSDK_PageView* pPageView,
204 ObservedPtr<CPDFSDK_Widget>& pWidget,
205 Mask<FWL_EVENTFLAG> nFlags,
206 const CFX_PointF& point) {
207 bool bSetFocus;
208 switch (pWidget->GetFieldType()) {
209 case FormFieldType::kPushButton:
210 case FormFieldType::kCheckBox:
211 case FormFieldType::kRadioButton: {
212 FX_RECT bbox = GetViewBBox(pPageView, pWidget.Get());
213 bSetFocus =
214 bbox.Contains(static_cast<int>(point.x), static_cast<int>(point.y));
215 break;
216 }
217 default:
218 bSetFocus = true;
219 break;
220 }
221 if (bSetFocus) {
222 ObservedPtr<CPDFSDK_Annot> pObserved(pWidget.Get());
223 m_pCallbackIface->SetFocusAnnot(pObserved);
224 }
225
226 CFFL_FormField* pFormField = GetFormField(pWidget.Get());
227 bool bRet = pFormField &&
228 pFormField->OnLButtonUp(pPageView, pWidget.Get(), nFlags, point);
229 if (m_pCallbackIface->GetFocusAnnot() != pWidget.Get())
230 return bRet;
231 if (OnButtonUp(pWidget, pPageView, nFlags) || !pWidget)
232 return true;
233 #ifdef PDF_ENABLE_XFA
234 if (OnClick(pWidget, pPageView, nFlags) || !pWidget)
235 return true;
236 #endif // PDF_ENABLE_XFA
237 return bRet;
238 }
239
OnButtonUp(ObservedPtr<CPDFSDK_Widget> & pWidget,const CPDFSDK_PageView * pPageView,Mask<FWL_EVENTFLAG> nFlag)240 bool CFFL_InteractiveFormFiller::OnButtonUp(
241 ObservedPtr<CPDFSDK_Widget>& pWidget,
242 const CPDFSDK_PageView* pPageView,
243 Mask<FWL_EVENTFLAG> nFlag) {
244 if (m_bNotifying)
245 return false;
246
247 if (!pWidget->GetAAction(CPDF_AAction::kButtonUp).HasDict())
248 return false;
249
250 uint32_t nAge = pWidget->GetAppearanceAge();
251 uint32_t nValueAge = pWidget->GetValueAge();
252 DCHECK(pPageView);
253 {
254 AutoRestorer<bool> restorer(&m_bNotifying);
255 m_bNotifying = true;
256
257 CFFL_FieldAction fa;
258 fa.bModifier = CPWL_Wnd::IsCTRLKeyDown(nFlag);
259 fa.bShift = CPWL_Wnd::IsSHIFTKeyDown(nFlag);
260 pWidget->OnAAction(CPDF_AAction::kButtonUp, &fa, pPageView);
261 }
262 if (!pWidget || !IsValidAnnot(pPageView, pWidget.Get()))
263 return true;
264 if (nAge == pWidget->GetAppearanceAge())
265 return false;
266
267 CFFL_FormField* pFormField = GetFormField(pWidget.Get());
268 if (pFormField)
269 pFormField->ResetPWLWindowForValueAge(pPageView, pWidget.Get(), nValueAge);
270 return true;
271 }
272
SetIndexSelected(ObservedPtr<CPDFSDK_Widget> & pWidget,int index,bool selected)273 bool CFFL_InteractiveFormFiller::SetIndexSelected(
274 ObservedPtr<CPDFSDK_Widget>& pWidget,
275 int index,
276 bool selected) {
277 CFFL_FormField* pFormField = GetFormField(pWidget.Get());
278 return pFormField && pFormField->SetIndexSelected(index, selected);
279 }
280
IsIndexSelected(ObservedPtr<CPDFSDK_Widget> & pWidget,int index)281 bool CFFL_InteractiveFormFiller::IsIndexSelected(
282 ObservedPtr<CPDFSDK_Widget>& pWidget,
283 int index) {
284 CFFL_FormField* pFormField = GetFormField(pWidget.Get());
285 return pFormField && pFormField->IsIndexSelected(index);
286 }
287
OnLButtonDblClk(CPDFSDK_PageView * pPageView,ObservedPtr<CPDFSDK_Widget> & pWidget,Mask<FWL_EVENTFLAG> nFlags,const CFX_PointF & point)288 bool CFFL_InteractiveFormFiller::OnLButtonDblClk(
289 CPDFSDK_PageView* pPageView,
290 ObservedPtr<CPDFSDK_Widget>& pWidget,
291 Mask<FWL_EVENTFLAG> nFlags,
292 const CFX_PointF& point) {
293 CFFL_FormField* pFormField = GetFormField(pWidget.Get());
294 return pFormField && pFormField->OnLButtonDblClk(pPageView, nFlags, point);
295 }
296
OnMouseMove(CPDFSDK_PageView * pPageView,ObservedPtr<CPDFSDK_Widget> & pWidget,Mask<FWL_EVENTFLAG> nFlags,const CFX_PointF & point)297 bool CFFL_InteractiveFormFiller::OnMouseMove(
298 CPDFSDK_PageView* pPageView,
299 ObservedPtr<CPDFSDK_Widget>& pWidget,
300 Mask<FWL_EVENTFLAG> nFlags,
301 const CFX_PointF& point) {
302 CFFL_FormField* pFormField = GetOrCreateFormField(pWidget.Get());
303 return pFormField && pFormField->OnMouseMove(pPageView, nFlags, point);
304 }
305
OnMouseWheel(CPDFSDK_PageView * pPageView,ObservedPtr<CPDFSDK_Widget> & pWidget,Mask<FWL_EVENTFLAG> nFlags,const CFX_PointF & point,const CFX_Vector & delta)306 bool CFFL_InteractiveFormFiller::OnMouseWheel(
307 CPDFSDK_PageView* pPageView,
308 ObservedPtr<CPDFSDK_Widget>& pWidget,
309 Mask<FWL_EVENTFLAG> nFlags,
310 const CFX_PointF& point,
311 const CFX_Vector& delta) {
312 CFFL_FormField* pFormField = GetFormField(pWidget.Get());
313 return pFormField &&
314 pFormField->OnMouseWheel(pPageView, nFlags, point, delta);
315 }
316
OnRButtonDown(CPDFSDK_PageView * pPageView,ObservedPtr<CPDFSDK_Widget> & pWidget,Mask<FWL_EVENTFLAG> nFlags,const CFX_PointF & point)317 bool CFFL_InteractiveFormFiller::OnRButtonDown(
318 CPDFSDK_PageView* pPageView,
319 ObservedPtr<CPDFSDK_Widget>& pWidget,
320 Mask<FWL_EVENTFLAG> nFlags,
321 const CFX_PointF& point) {
322 CFFL_FormField* pFormField = GetFormField(pWidget.Get());
323 return pFormField && pFormField->OnRButtonDown(pPageView, nFlags, point);
324 }
325
OnRButtonUp(CPDFSDK_PageView * pPageView,ObservedPtr<CPDFSDK_Widget> & pWidget,Mask<FWL_EVENTFLAG> nFlags,const CFX_PointF & point)326 bool CFFL_InteractiveFormFiller::OnRButtonUp(
327 CPDFSDK_PageView* pPageView,
328 ObservedPtr<CPDFSDK_Widget>& pWidget,
329 Mask<FWL_EVENTFLAG> nFlags,
330 const CFX_PointF& point) {
331 CFFL_FormField* pFormField = GetFormField(pWidget.Get());
332 return pFormField && pFormField->OnRButtonUp(pPageView, nFlags, point);
333 }
334
OnKeyDown(CPDFSDK_Widget * pWidget,FWL_VKEYCODE nKeyCode,Mask<FWL_EVENTFLAG> nFlags)335 bool CFFL_InteractiveFormFiller::OnKeyDown(CPDFSDK_Widget* pWidget,
336 FWL_VKEYCODE nKeyCode,
337 Mask<FWL_EVENTFLAG> nFlags) {
338 CFFL_FormField* pFormField = GetFormField(pWidget);
339 return pFormField && pFormField->OnKeyDown(nKeyCode, nFlags);
340 }
341
OnChar(CPDFSDK_Widget * pWidget,uint32_t nChar,Mask<FWL_EVENTFLAG> nFlags)342 bool CFFL_InteractiveFormFiller::OnChar(CPDFSDK_Widget* pWidget,
343 uint32_t nChar,
344 Mask<FWL_EVENTFLAG> nFlags) {
345 if (nChar == pdfium::ascii::kTab)
346 return true;
347
348 CFFL_FormField* pFormField = GetFormField(pWidget);
349 return pFormField && pFormField->OnChar(pWidget, nChar, nFlags);
350 }
351
OnSetFocus(ObservedPtr<CPDFSDK_Widget> & pWidget,Mask<FWL_EVENTFLAG> nFlag)352 bool CFFL_InteractiveFormFiller::OnSetFocus(
353 ObservedPtr<CPDFSDK_Widget>& pWidget,
354 Mask<FWL_EVENTFLAG> nFlag) {
355 if (!pWidget)
356 return false;
357
358 if (!m_bNotifying) {
359 if (pWidget->GetAAction(CPDF_AAction::kGetFocus).HasDict()) {
360 uint32_t nValueAge = pWidget->GetValueAge();
361 pWidget->ClearAppModified();
362
363 CFFL_FormField* pFormField = GetOrCreateFormField(pWidget.Get());
364 if (!pFormField)
365 return false;
366
367 CPDFSDK_PageView* pPageView = pWidget->GetPageView();
368 DCHECK(pPageView);
369 {
370 AutoRestorer<bool> restorer(&m_bNotifying);
371 m_bNotifying = true;
372
373 CFFL_FieldAction fa;
374 fa.bModifier = CPWL_Wnd::IsCTRLKeyDown(nFlag);
375 fa.bShift = CPWL_Wnd::IsSHIFTKeyDown(nFlag);
376 pFormField->GetActionData(pPageView, CPDF_AAction::kGetFocus, fa);
377 pWidget->OnAAction(CPDF_AAction::kGetFocus, &fa, pPageView);
378 }
379 if (!pWidget)
380 return false;
381
382 if (pWidget->IsAppModified()) {
383 CFFL_FormField* pFiller = GetFormField(pWidget.Get());
384 if (pFiller) {
385 pFiller->ResetPWLWindowForValueAge(pPageView, pWidget.Get(),
386 nValueAge);
387 }
388 }
389 }
390 }
391
392 if (CFFL_FormField* pFormField = GetOrCreateFormField(pWidget.Get()))
393 pFormField->SetFocusForAnnot(pWidget.Get(), nFlag);
394
395 return true;
396 }
397
OnKillFocus(ObservedPtr<CPDFSDK_Widget> & pWidget,Mask<FWL_EVENTFLAG> nFlag)398 bool CFFL_InteractiveFormFiller::OnKillFocus(
399 ObservedPtr<CPDFSDK_Widget>& pWidget,
400 Mask<FWL_EVENTFLAG> nFlag) {
401 if (!pWidget)
402 return false;
403
404 CFFL_FormField* pFormField = GetFormField(pWidget.Get());
405 if (!pFormField)
406 return true;
407
408 pFormField->KillFocusForAnnot(nFlag);
409 if (!pWidget)
410 return false;
411
412 if (m_bNotifying)
413 return true;
414
415 if (!pWidget->GetAAction(CPDF_AAction::kLoseFocus).HasDict())
416 return true;
417
418 pWidget->ClearAppModified();
419
420 CPDFSDK_PageView* pPageView = pWidget->GetPageView();
421 DCHECK(pPageView);
422 {
423 AutoRestorer<bool> restorer(&m_bNotifying);
424 m_bNotifying = true;
425
426 CFFL_FieldAction fa;
427 fa.bModifier = CPWL_Wnd::IsCTRLKeyDown(nFlag);
428 fa.bShift = CPWL_Wnd::IsSHIFTKeyDown(nFlag);
429 pFormField->GetActionData(pPageView, CPDF_AAction::kLoseFocus, fa);
430 pWidget->OnAAction(CPDF_AAction::kLoseFocus, &fa, pPageView);
431 }
432 return !!pWidget;
433 }
434
OnSetFieldInputFocus(const WideString & text)435 void CFFL_InteractiveFormFiller::OnSetFieldInputFocus(const WideString& text) {
436 m_pCallbackIface->OnSetFieldInputFocus(text);
437 }
438
Invalidate(IPDF_Page * pPage,const FX_RECT & rect)439 void CFFL_InteractiveFormFiller::Invalidate(IPDF_Page* pPage,
440 const FX_RECT& rect) {
441 m_pCallbackIface->Invalidate(pPage, rect);
442 }
443
GetOrCreatePageView(IPDF_Page * pPage)444 CPDFSDK_PageView* CFFL_InteractiveFormFiller::GetOrCreatePageView(
445 IPDF_Page* pPage) {
446 return m_pCallbackIface->GetOrCreatePageView(pPage);
447 }
448
GetPageView(IPDF_Page * pPage)449 CPDFSDK_PageView* CFFL_InteractiveFormFiller::GetPageView(IPDF_Page* pPage) {
450 return m_pCallbackIface->GetPageView(pPage);
451 }
452
GetTimerHandler()453 CFX_Timer::HandlerIface* CFFL_InteractiveFormFiller::GetTimerHandler() {
454 return m_pCallbackIface->GetTimerHandler();
455 }
456
OnChange()457 void CFFL_InteractiveFormFiller::OnChange() {
458 m_pCallbackIface->OnChange();
459 }
460
IsVisible(CPDFSDK_Widget * pWidget)461 bool CFFL_InteractiveFormFiller::IsVisible(CPDFSDK_Widget* pWidget) {
462 return pWidget->IsVisible();
463 }
464
IsReadOnly(CPDFSDK_Widget * pWidget)465 bool CFFL_InteractiveFormFiller::IsReadOnly(CPDFSDK_Widget* pWidget) {
466 int nFieldFlags = pWidget->GetFieldFlags();
467 return !!(nFieldFlags & pdfium::form_flags::kReadOnly);
468 }
469
IsFillingAllowed(CPDFSDK_Widget * pWidget) const470 bool CFFL_InteractiveFormFiller::IsFillingAllowed(
471 CPDFSDK_Widget* pWidget) const {
472 if (pWidget->GetFieldType() == FormFieldType::kPushButton)
473 return false;
474
475 return m_pCallbackIface->HasPermissions(
476 pdfium::access_permissions::kFillForm |
477 pdfium::access_permissions::kModifyAnnotation |
478 pdfium::access_permissions::kModifyContent);
479 }
480
GetFormField(CPDFSDK_Widget * pWidget)481 CFFL_FormField* CFFL_InteractiveFormFiller::GetFormField(
482 CPDFSDK_Widget* pWidget) {
483 auto it = m_Map.find(pWidget);
484 return it != m_Map.end() ? it->second.get() : nullptr;
485 }
486
GetOrCreateFormField(CPDFSDK_Widget * pWidget)487 CFFL_FormField* CFFL_InteractiveFormFiller::GetOrCreateFormField(
488 CPDFSDK_Widget* pWidget) {
489 CFFL_FormField* result = GetFormField(pWidget);
490 if (result)
491 return result;
492
493 std::unique_ptr<CFFL_FormField> pFormField;
494 switch (pWidget->GetFieldType()) {
495 case FormFieldType::kPushButton:
496 pFormField = std::make_unique<CFFL_PushButton>(this, pWidget);
497 break;
498 case FormFieldType::kCheckBox:
499 pFormField = std::make_unique<CFFL_CheckBox>(this, pWidget);
500 break;
501 case FormFieldType::kRadioButton:
502 pFormField = std::make_unique<CFFL_RadioButton>(this, pWidget);
503 break;
504 case FormFieldType::kTextField:
505 pFormField = std::make_unique<CFFL_TextField>(this, pWidget);
506 break;
507 case FormFieldType::kListBox:
508 pFormField = std::make_unique<CFFL_ListBox>(this, pWidget);
509 break;
510 case FormFieldType::kComboBox:
511 pFormField = std::make_unique<CFFL_ComboBox>(this, pWidget);
512 break;
513 case FormFieldType::kUnknown:
514 default:
515 return nullptr;
516 }
517
518 result = pFormField.get();
519 m_Map[pWidget] = std::move(pFormField);
520 return result;
521 }
522
GetText(CPDFSDK_Widget * pWidget)523 WideString CFFL_InteractiveFormFiller::GetText(CPDFSDK_Widget* pWidget) {
524 CFFL_FormField* pFormField = GetFormField(pWidget);
525 return pFormField ? pFormField->GetText() : WideString();
526 }
527
GetSelectedText(CPDFSDK_Widget * pWidget)528 WideString CFFL_InteractiveFormFiller::GetSelectedText(
529 CPDFSDK_Widget* pWidget) {
530 CFFL_FormField* pFormField = GetFormField(pWidget);
531 return pFormField ? pFormField->GetSelectedText() : WideString();
532 }
533
ReplaceAndKeepSelection(CPDFSDK_Widget * pWidget,const WideString & text)534 void CFFL_InteractiveFormFiller::ReplaceAndKeepSelection(
535 CPDFSDK_Widget* pWidget,
536 const WideString& text) {
537 CFFL_FormField* pFormField = GetFormField(pWidget);
538 if (!pFormField)
539 return;
540
541 pFormField->ReplaceAndKeepSelection(text);
542 }
543
ReplaceSelection(CPDFSDK_Widget * pWidget,const WideString & text)544 void CFFL_InteractiveFormFiller::ReplaceSelection(CPDFSDK_Widget* pWidget,
545 const WideString& text) {
546 CFFL_FormField* pFormField = GetFormField(pWidget);
547 if (!pFormField)
548 return;
549
550 pFormField->ReplaceSelection(text);
551 }
552
SelectAllText(CPDFSDK_Widget * pWidget)553 bool CFFL_InteractiveFormFiller::SelectAllText(CPDFSDK_Widget* pWidget) {
554 CFFL_FormField* pFormField = GetFormField(pWidget);
555 return pFormField && pFormField->SelectAllText();
556 }
557
CanUndo(CPDFSDK_Widget * pWidget)558 bool CFFL_InteractiveFormFiller::CanUndo(CPDFSDK_Widget* pWidget) {
559 CFFL_FormField* pFormField = GetFormField(pWidget);
560 return pFormField && pFormField->CanUndo();
561 }
562
CanRedo(CPDFSDK_Widget * pWidget)563 bool CFFL_InteractiveFormFiller::CanRedo(CPDFSDK_Widget* pWidget) {
564 CFFL_FormField* pFormField = GetFormField(pWidget);
565 return pFormField && pFormField->CanRedo();
566 }
567
Undo(CPDFSDK_Widget * pWidget)568 bool CFFL_InteractiveFormFiller::Undo(CPDFSDK_Widget* pWidget) {
569 CFFL_FormField* pFormField = GetFormField(pWidget);
570 return pFormField && pFormField->Undo();
571 }
572
Redo(CPDFSDK_Widget * pWidget)573 bool CFFL_InteractiveFormFiller::Redo(CPDFSDK_Widget* pWidget) {
574 CFFL_FormField* pFormField = GetFormField(pWidget);
575 return pFormField && pFormField->Redo();
576 }
577
UnregisterFormField(CPDFSDK_Widget * pWidget)578 void CFFL_InteractiveFormFiller::UnregisterFormField(CPDFSDK_Widget* pWidget) {
579 auto it = m_Map.find(pWidget);
580 if (it == m_Map.end())
581 return;
582
583 m_Map.erase(it);
584 }
585
InvalidateRect(PerWindowData * pWidgetData,const CFX_FloatRect & rect)586 void CFFL_InteractiveFormFiller::InvalidateRect(PerWindowData* pWidgetData,
587 const CFX_FloatRect& rect) {
588 auto* pPrivateData = static_cast<CFFL_PerWindowData*>(pWidgetData);
589 CPDFSDK_Widget* pWidget = pPrivateData->GetWidget();
590 if (!pWidget)
591 return;
592
593 m_pCallbackIface->InvalidateRect(pWidget, rect);
594 }
595
OutputSelectedRect(PerWindowData * pWidgetData,const CFX_FloatRect & rect)596 void CFFL_InteractiveFormFiller::OutputSelectedRect(PerWindowData* pWidgetData,
597 const CFX_FloatRect& rect) {
598 auto* pPrivateData = static_cast<CFFL_PerWindowData*>(pWidgetData);
599 if (!pPrivateData)
600 return;
601
602 CFFL_FormField* pFormField = pPrivateData->GetFormField();
603 if (!pFormField)
604 return;
605
606 m_pCallbackIface->OutputSelectedRect(pFormField, rect);
607 }
608
IsSelectionImplemented() const609 bool CFFL_InteractiveFormFiller::IsSelectionImplemented() const {
610 return m_pCallbackIface->IsSelectionImplemented();
611 }
612
SetCursor(CursorStyle nCursorStyle)613 void CFFL_InteractiveFormFiller::SetCursor(CursorStyle nCursorStyle) {
614 m_pCallbackIface->SetCursor(nCursorStyle);
615 }
616
QueryWherePopup(const IPWL_FillerNotify::PerWindowData * pAttached,float fPopupMin,float fPopupMax,bool * bBottom,float * fPopupRet)617 void CFFL_InteractiveFormFiller::QueryWherePopup(
618 const IPWL_FillerNotify::PerWindowData* pAttached,
619 float fPopupMin,
620 float fPopupMax,
621 bool* bBottom,
622 float* fPopupRet) {
623 auto* pData = static_cast<const CFFL_PerWindowData*>(pAttached);
624 CPDFSDK_Widget* pWidget = pData->GetWidget();
625 CPDF_Page* pPage = pWidget->GetPDFPage();
626
627 CFX_FloatRect rcPageView(0, pPage->GetPageHeight(), pPage->GetPageWidth(), 0);
628 rcPageView.Normalize();
629
630 CFX_FloatRect rcAnnot = pWidget->GetRect();
631 float fTop = 0.0f;
632 float fBottom = 0.0f;
633 switch (pWidget->GetRotate() / 90) {
634 default:
635 case 0:
636 fTop = rcPageView.top - rcAnnot.top;
637 fBottom = rcAnnot.bottom - rcPageView.bottom;
638 break;
639 case 1:
640 fTop = rcAnnot.left - rcPageView.left;
641 fBottom = rcPageView.right - rcAnnot.right;
642 break;
643 case 2:
644 fTop = rcAnnot.bottom - rcPageView.bottom;
645 fBottom = rcPageView.top - rcAnnot.top;
646 break;
647 case 3:
648 fTop = rcPageView.right - rcAnnot.right;
649 fBottom = rcAnnot.left - rcPageView.left;
650 break;
651 }
652
653 constexpr float kMaxListBoxHeight = 140;
654 const float fMaxListBoxHeight =
655 pdfium::clamp(kMaxListBoxHeight, fPopupMin, fPopupMax);
656
657 if (fBottom > fMaxListBoxHeight) {
658 *fPopupRet = fMaxListBoxHeight;
659 *bBottom = true;
660 return;
661 }
662
663 if (fTop > fMaxListBoxHeight) {
664 *fPopupRet = fMaxListBoxHeight;
665 *bBottom = false;
666 return;
667 }
668
669 if (fTop > fBottom) {
670 *fPopupRet = fTop;
671 *bBottom = false;
672 } else {
673 *fPopupRet = fBottom;
674 *bBottom = true;
675 }
676 }
677
OnKeyStrokeCommit(ObservedPtr<CPDFSDK_Widget> & pWidget,const CPDFSDK_PageView * pPageView,Mask<FWL_EVENTFLAG> nFlag)678 bool CFFL_InteractiveFormFiller::OnKeyStrokeCommit(
679 ObservedPtr<CPDFSDK_Widget>& pWidget,
680 const CPDFSDK_PageView* pPageView,
681 Mask<FWL_EVENTFLAG> nFlag) {
682 if (m_bNotifying)
683 return true;
684
685 if (!pWidget->GetAAction(CPDF_AAction::kKeyStroke).HasDict())
686 return true;
687
688 DCHECK(pPageView);
689 pWidget->ClearAppModified();
690
691 AutoRestorer<bool> restorer(&m_bNotifying);
692 m_bNotifying = true;
693
694 CFFL_FieldAction fa;
695 fa.bModifier = CPWL_Wnd::IsCTRLKeyDown(nFlag);
696 fa.bShift = CPWL_Wnd::IsSHIFTKeyDown(nFlag);
697 fa.bWillCommit = true;
698 fa.bKeyDown = true;
699 fa.bRC = true;
700
701 CFFL_FormField* pFormField = GetFormField(pWidget.Get());
702 pFormField->GetActionData(pPageView, CPDF_AAction::kKeyStroke, fa);
703 pFormField->SavePWLWindowState(pPageView);
704 pWidget->OnAAction(CPDF_AAction::kKeyStroke, &fa, pPageView);
705
706 if (!pWidget)
707 return true;
708
709 return fa.bRC;
710 }
711
OnValidate(ObservedPtr<CPDFSDK_Widget> & pWidget,const CPDFSDK_PageView * pPageView,Mask<FWL_EVENTFLAG> nFlag)712 bool CFFL_InteractiveFormFiller::OnValidate(
713 ObservedPtr<CPDFSDK_Widget>& pWidget,
714 const CPDFSDK_PageView* pPageView,
715 Mask<FWL_EVENTFLAG> nFlag) {
716 if (m_bNotifying)
717 return true;
718
719 if (!pWidget->GetAAction(CPDF_AAction::kValidate).HasDict())
720 return true;
721
722 DCHECK(pPageView);
723 pWidget->ClearAppModified();
724
725 AutoRestorer<bool> restorer(&m_bNotifying);
726 m_bNotifying = true;
727
728 CFFL_FieldAction fa;
729 fa.bModifier = CPWL_Wnd::IsCTRLKeyDown(nFlag);
730 fa.bShift = CPWL_Wnd::IsSHIFTKeyDown(nFlag);
731 fa.bKeyDown = true;
732 fa.bRC = true;
733
734 CFFL_FormField* pFormField = GetFormField(pWidget.Get());
735 pFormField->GetActionData(pPageView, CPDF_AAction::kValidate, fa);
736 pFormField->SavePWLWindowState(pPageView);
737 pWidget->OnAAction(CPDF_AAction::kValidate, &fa, pPageView);
738
739 if (!pWidget)
740 return true;
741
742 return fa.bRC;
743 }
744
OnCalculate(ObservedPtr<CPDFSDK_Widget> & pWidget)745 void CFFL_InteractiveFormFiller::OnCalculate(
746 ObservedPtr<CPDFSDK_Widget>& pWidget) {
747 if (m_bNotifying)
748 return;
749
750 ObservedPtr<CPDFSDK_Annot> pObserved(pWidget.Get());
751 m_pCallbackIface->OnCalculate(pObserved);
752 }
753
OnFormat(ObservedPtr<CPDFSDK_Widget> & pWidget)754 void CFFL_InteractiveFormFiller::OnFormat(
755 ObservedPtr<CPDFSDK_Widget>& pWidget) {
756 if (m_bNotifying)
757 return;
758
759 ObservedPtr<CPDFSDK_Annot> pObserved(pWidget.Get());
760 m_pCallbackIface->OnFormat(pObserved);
761 }
762
763 #ifdef PDF_ENABLE_XFA
OnClick(ObservedPtr<CPDFSDK_Widget> & pWidget,const CPDFSDK_PageView * pPageView,Mask<FWL_EVENTFLAG> nFlag)764 bool CFFL_InteractiveFormFiller::OnClick(ObservedPtr<CPDFSDK_Widget>& pWidget,
765 const CPDFSDK_PageView* pPageView,
766 Mask<FWL_EVENTFLAG> nFlag) {
767 if (m_bNotifying)
768 return false;
769
770 if (!pWidget->HasXFAAAction(PDFSDK_XFA_Click))
771 return false;
772
773 uint32_t nAge = pWidget->GetAppearanceAge();
774 uint32_t nValueAge = pWidget->GetValueAge();
775 {
776 AutoRestorer<bool> restorer(&m_bNotifying);
777 m_bNotifying = true;
778
779 CFFL_FieldAction fa;
780 fa.bModifier = CPWL_Wnd::IsCTRLKeyDown(nFlag);
781 fa.bShift = CPWL_Wnd::IsSHIFTKeyDown(nFlag);
782
783 pWidget->OnXFAAAction(PDFSDK_XFA_Click, &fa, pPageView);
784 }
785 if (!pWidget || !IsValidAnnot(pPageView, pWidget.Get()))
786 return true;
787 if (nAge == pWidget->GetAppearanceAge())
788 return false;
789
790 CFFL_FormField* pFormField = GetFormField(pWidget.Get());
791 if (pFormField)
792 pFormField->ResetPWLWindowForValueAge(pPageView, pWidget.Get(), nValueAge);
793 return false;
794 }
795
OnFull(ObservedPtr<CPDFSDK_Widget> & pWidget,const CPDFSDK_PageView * pPageView,Mask<FWL_EVENTFLAG> nFlag)796 bool CFFL_InteractiveFormFiller::OnFull(ObservedPtr<CPDFSDK_Widget>& pWidget,
797 const CPDFSDK_PageView* pPageView,
798 Mask<FWL_EVENTFLAG> nFlag) {
799 if (m_bNotifying)
800 return false;
801
802 if (!pWidget->HasXFAAAction(PDFSDK_XFA_Full))
803 return false;
804
805 uint32_t nAge = pWidget->GetAppearanceAge();
806 uint32_t nValueAge = pWidget->GetValueAge();
807 {
808 AutoRestorer<bool> restorer(&m_bNotifying);
809 m_bNotifying = true;
810
811 CFFL_FieldAction fa;
812 fa.bModifier = CPWL_Wnd::IsCTRLKeyDown(nFlag);
813 fa.bShift = CPWL_Wnd::IsSHIFTKeyDown(nFlag);
814 pWidget->OnXFAAAction(PDFSDK_XFA_Full, &fa, pPageView);
815 }
816 if (!pWidget || !IsValidAnnot(pPageView, pWidget.Get()))
817 return true;
818 if (nAge == pWidget->GetAppearanceAge())
819 return false;
820
821 CFFL_FormField* pFormField = GetFormField(pWidget.Get());
822 if (pFormField)
823 pFormField->ResetPWLWindowForValueAge(pPageView, pWidget.Get(), nValueAge);
824 return true;
825 }
826
OnPreOpen(ObservedPtr<CPDFSDK_Widget> & pWidget,const CPDFSDK_PageView * pPageView,Mask<FWL_EVENTFLAG> nFlag)827 bool CFFL_InteractiveFormFiller::OnPreOpen(ObservedPtr<CPDFSDK_Widget>& pWidget,
828 const CPDFSDK_PageView* pPageView,
829 Mask<FWL_EVENTFLAG> nFlag) {
830 if (m_bNotifying)
831 return false;
832
833 if (!pWidget->HasXFAAAction(PDFSDK_XFA_PreOpen))
834 return false;
835
836 uint32_t nAge = pWidget->GetAppearanceAge();
837 uint32_t nValueAge = pWidget->GetValueAge();
838 {
839 AutoRestorer<bool> restorer(&m_bNotifying);
840 m_bNotifying = true;
841
842 CFFL_FieldAction fa;
843 fa.bModifier = CPWL_Wnd::IsCTRLKeyDown(nFlag);
844 fa.bShift = CPWL_Wnd::IsSHIFTKeyDown(nFlag);
845 pWidget->OnXFAAAction(PDFSDK_XFA_PreOpen, &fa, pPageView);
846 }
847 if (!pWidget || !IsValidAnnot(pPageView, pWidget.Get()))
848 return true;
849 if (nAge == pWidget->GetAppearanceAge())
850 return false;
851
852 CFFL_FormField* pFormField = GetFormField(pWidget.Get());
853 if (pFormField)
854 pFormField->ResetPWLWindowForValueAge(pPageView, pWidget.Get(), nValueAge);
855 return true;
856 }
857
OnPostOpen(ObservedPtr<CPDFSDK_Widget> & pWidget,const CPDFSDK_PageView * pPageView,Mask<FWL_EVENTFLAG> nFlag)858 bool CFFL_InteractiveFormFiller::OnPostOpen(
859 ObservedPtr<CPDFSDK_Widget>& pWidget,
860 const CPDFSDK_PageView* pPageView,
861 Mask<FWL_EVENTFLAG> nFlag) {
862 if (m_bNotifying)
863 return false;
864
865 if (!pWidget->HasXFAAAction(PDFSDK_XFA_PostOpen))
866 return false;
867
868 uint32_t nAge = pWidget->GetAppearanceAge();
869 uint32_t nValueAge = pWidget->GetValueAge();
870 {
871 AutoRestorer<bool> restorer(&m_bNotifying);
872 m_bNotifying = true;
873
874 CFFL_FieldAction fa;
875 fa.bModifier = CPWL_Wnd::IsCTRLKeyDown(nFlag);
876 fa.bShift = CPWL_Wnd::IsSHIFTKeyDown(nFlag);
877 pWidget->OnXFAAAction(PDFSDK_XFA_PostOpen, &fa, pPageView);
878 }
879 if (!pWidget || !IsValidAnnot(pPageView, pWidget.Get()))
880 return true;
881
882 if (nAge == pWidget->GetAppearanceAge())
883 return false;
884
885 CFFL_FormField* pFormField = GetFormField(pWidget.Get());
886 if (pFormField)
887 pFormField->ResetPWLWindowForValueAge(pPageView, pWidget.Get(), nValueAge);
888 return true;
889 }
890 #endif // PDF_ENABLE_XFA
891
892 // static
IsValidAnnot(const CPDFSDK_PageView * pPageView,CPDFSDK_Widget * pWidget)893 bool CFFL_InteractiveFormFiller::IsValidAnnot(const CPDFSDK_PageView* pPageView,
894 CPDFSDK_Widget* pWidget) {
895 return pPageView && pPageView->IsValidAnnot(pWidget->GetPDFAnnot());
896 }
897
OnBeforeKeyStroke(const IPWL_FillerNotify::PerWindowData * pAttached,WideString & strChange,const WideString & strChangeEx,int nSelStart,int nSelEnd,bool bKeyDown,Mask<FWL_EVENTFLAG> nFlag)898 std::pair<bool, bool> CFFL_InteractiveFormFiller::OnBeforeKeyStroke(
899 const IPWL_FillerNotify::PerWindowData* pAttached,
900 WideString& strChange,
901 const WideString& strChangeEx,
902 int nSelStart,
903 int nSelEnd,
904 bool bKeyDown,
905 Mask<FWL_EVENTFLAG> nFlag) {
906 // Copy out of private data since the window owning it may not survive.
907 auto* pPrivateData = static_cast<const CFFL_PerWindowData*>(pAttached);
908 const CPDFSDK_PageView* pPageView = pPrivateData->GetPageView();
909 ObservedPtr<CPDFSDK_Widget> pWidget(pPrivateData->GetWidget());
910 DCHECK(pWidget);
911
912 CFFL_FormField* pFormField = GetFormField(pWidget.Get());
913
914 #ifdef PDF_ENABLE_XFA
915 if (pFormField->IsFieldFull(pPageView)) {
916 if (OnFull(pWidget, pPageView, nFlag) || !pWidget)
917 return {true, true};
918 }
919 #endif // PDF_ENABLE_XFA
920
921 if (m_bNotifying ||
922 !pWidget->GetAAction(CPDF_AAction::kKeyStroke).HasDict()) {
923 return {true, false};
924 }
925
926 AutoRestorer<bool> restorer(&m_bNotifying);
927 m_bNotifying = true;
928
929 uint32_t nAge = pWidget->GetAppearanceAge();
930 uint32_t nValueAge = pWidget->GetValueAge();
931
932 CFFL_FieldAction fa;
933 fa.bModifier = CPWL_Wnd::IsCTRLKeyDown(nFlag);
934 fa.bShift = CPWL_Wnd::IsSHIFTKeyDown(nFlag);
935 fa.sChange = strChange;
936 fa.sChangeEx = strChangeEx;
937 fa.bKeyDown = bKeyDown;
938 fa.bWillCommit = false;
939 fa.bRC = true;
940 fa.nSelStart = nSelStart;
941 fa.nSelEnd = nSelEnd;
942 pFormField->GetActionData(pPageView, CPDF_AAction::kKeyStroke, fa);
943 pFormField->SavePWLWindowState(pPageView);
944
945 bool action_status =
946 pWidget->OnAAction(CPDF_AAction::kKeyStroke, &fa, pPageView);
947
948 if (!pWidget || !IsValidAnnot(pPageView, pWidget.Get())) {
949 return {true, true};
950 }
951 if (!action_status)
952 return {true, false};
953
954 bool bExit = false;
955 if (nAge != pWidget->GetAppearanceAge()) {
956 pFormField->ResetPWLWindowForValueAge(pPageView, pWidget.Get(), nValueAge);
957 pPrivateData = pFormField->GetPerPWLWindowData(pPageView);
958 if (!pPrivateData)
959 return {true, true};
960
961 pWidget.Reset(pPrivateData->GetWidget());
962 pPageView = pPrivateData->GetPageView();
963 bExit = true;
964 }
965 if (fa.bRC) {
966 pFormField->SetActionData(pPageView, CPDF_AAction::kKeyStroke, fa);
967 } else {
968 pFormField->RecreatePWLWindowFromSavedState(pPageView);
969 }
970 if (m_pCallbackIface->GetFocusAnnot() == pWidget)
971 return {false, bExit};
972
973 pFormField->CommitData(pPageView, nFlag);
974 return {false, true};
975 }
976
OnPopupPreOpen(const IPWL_FillerNotify::PerWindowData * pAttached,Mask<FWL_EVENTFLAG> nFlag)977 bool CFFL_InteractiveFormFiller::OnPopupPreOpen(
978 const IPWL_FillerNotify::PerWindowData* pAttached,
979 Mask<FWL_EVENTFLAG> nFlag) {
980 #ifdef PDF_ENABLE_XFA
981 auto* pData = static_cast<const CFFL_PerWindowData*>(pAttached);
982 DCHECK(pData->GetWidget());
983
984 ObservedPtr<CPDFSDK_Widget> pObserved(pData->GetWidget());
985 return OnPreOpen(pObserved, pData->GetPageView(), nFlag) || !pObserved;
986 #else
987 return false;
988 #endif
989 }
990
OnPopupPostOpen(const IPWL_FillerNotify::PerWindowData * pAttached,Mask<FWL_EVENTFLAG> nFlag)991 bool CFFL_InteractiveFormFiller::OnPopupPostOpen(
992 const IPWL_FillerNotify::PerWindowData* pAttached,
993 Mask<FWL_EVENTFLAG> nFlag) {
994 #ifdef PDF_ENABLE_XFA
995 auto* pData = static_cast<const CFFL_PerWindowData*>(pAttached);
996 DCHECK(pData->GetWidget());
997
998 ObservedPtr<CPDFSDK_Widget> pObserved(pData->GetWidget());
999 return OnPostOpen(pObserved, pData->GetPageView(), nFlag) || !pObserved;
1000 #else
1001 return false;
1002 #endif
1003 }
1004