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_interactiveform.h"
8
9 #include <stdint.h>
10
11 #include <algorithm>
12 #include <memory>
13 #include <sstream>
14 #include <utility>
15 #include <vector>
16
17 #include "constants/annotation_flags.h"
18 #include "core/fpdfapi/page/cpdf_page.h"
19 #include "core/fpdfapi/parser/cfdf_document.h"
20 #include "core/fpdfapi/parser/cpdf_array.h"
21 #include "core/fpdfapi/parser/cpdf_dictionary.h"
22 #include "core/fpdfapi/parser/cpdf_document.h"
23 #include "core/fpdfapi/parser/cpdf_stream.h"
24 #include "core/fpdfdoc/cpdf_action.h"
25 #include "core/fpdfdoc/cpdf_formcontrol.h"
26 #include "core/fpdfdoc/cpdf_interactiveform.h"
27 #include "core/fxcrt/autorestorer.h"
28 #include "core/fxcrt/fx_string_wrappers.h"
29 #include "core/fxcrt/stl_util.h"
30 #include "core/fxge/cfx_graphstatedata.h"
31 #include "core/fxge/cfx_path.h"
32 #include "fpdfsdk/cpdfsdk_annot.h"
33 #include "fpdfsdk/cpdfsdk_annotiterator.h"
34 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
35 #include "fpdfsdk/cpdfsdk_pageview.h"
36 #include "fpdfsdk/cpdfsdk_widget.h"
37 #include "fpdfsdk/formfiller/cffl_formfield.h"
38 #include "fxjs/ijs_event_context.h"
39 #include "fxjs/ijs_runtime.h"
40 #include "third_party/base/check.h"
41
42 namespace {
43
44 constexpr uint32_t kWhiteBGR = FXSYS_BGR(255, 255, 255);
45
IsFormFieldTypeComboOrText(FormFieldType fieldType)46 bool IsFormFieldTypeComboOrText(FormFieldType fieldType) {
47 switch (fieldType) {
48 case FormFieldType::kComboBox:
49 case FormFieldType::kTextField:
50 return true;
51 default:
52 return false;
53 }
54 }
55
56 #ifdef PDF_ENABLE_XFA
IsFormFieldTypeXFA(FormFieldType fieldType)57 bool IsFormFieldTypeXFA(FormFieldType fieldType) {
58 switch (fieldType) {
59 case FormFieldType::kXFA:
60 case FormFieldType::kXFA_CheckBox:
61 case FormFieldType::kXFA_ComboBox:
62 case FormFieldType::kXFA_ImageField:
63 case FormFieldType::kXFA_ListBox:
64 case FormFieldType::kXFA_PushButton:
65 case FormFieldType::kXFA_Signature:
66 case FormFieldType::kXFA_TextField:
67 return true;
68 default:
69 return false;
70 }
71 }
72 #endif // PDF_ENABLE_XFA
73
FDFToURLEncodedData(ByteString buffer)74 ByteString FDFToURLEncodedData(ByteString buffer) {
75 std::unique_ptr<CFDF_Document> pFDF =
76 CFDF_Document::ParseMemory(buffer.raw_span());
77 if (!pFDF)
78 return buffer;
79
80 RetainPtr<const CPDF_Dictionary> pMainDict =
81 pFDF->GetRoot()->GetDictFor("FDF");
82 if (!pMainDict)
83 return ByteString();
84
85 RetainPtr<const CPDF_Array> pFields = pMainDict->GetArrayFor("Fields");
86 if (!pFields)
87 return ByteString();
88
89 fxcrt::ostringstream encoded_data;
90 for (uint32_t i = 0; i < pFields->size(); i++) {
91 RetainPtr<const CPDF_Dictionary> pField = pFields->GetDictAt(i);
92 if (!pField)
93 continue;
94 WideString name = pField->GetUnicodeTextFor("T");
95 ByteString name_b = name.ToDefANSI();
96 ByteString csBValue = pField->GetByteStringFor("V");
97 WideString csWValue = PDF_DecodeText(csBValue.raw_span());
98 ByteString csValue_b = csWValue.ToDefANSI();
99 encoded_data << name_b << "=" << csValue_b;
100 if (i != pFields->size() - 1)
101 encoded_data << "&";
102 }
103
104 return ByteString(encoded_data);
105 }
106
107 } // namespace
108
CPDFSDK_InteractiveForm(CPDFSDK_FormFillEnvironment * pFormFillEnv)109 CPDFSDK_InteractiveForm::CPDFSDK_InteractiveForm(
110 CPDFSDK_FormFillEnvironment* pFormFillEnv)
111 : m_pFormFillEnv(pFormFillEnv),
112 m_pInteractiveForm(std::make_unique<CPDF_InteractiveForm>(
113 m_pFormFillEnv->GetPDFDocument())) {
114 m_pInteractiveForm->SetNotifierIface(this);
115 RemoveAllHighLights();
116 }
117
118 CPDFSDK_InteractiveForm::~CPDFSDK_InteractiveForm() = default;
119
GetWidget(CPDF_FormControl * pControl) const120 CPDFSDK_Widget* CPDFSDK_InteractiveForm::GetWidget(
121 CPDF_FormControl* pControl) const {
122 if (!pControl)
123 return nullptr;
124
125 CPDFSDK_Widget* pWidget = nullptr;
126 const auto it = m_Map.find(pControl);
127 if (it != m_Map.end())
128 pWidget = it->second;
129 if (pWidget)
130 return pWidget;
131
132 CPDF_Document* pDocument = m_pFormFillEnv->GetPDFDocument();
133 CPDFSDK_PageView* pPage = nullptr;
134 RetainPtr<const CPDF_Dictionary> pControlDict = pControl->GetWidgetDict();
135 RetainPtr<const CPDF_Dictionary> pPageDict = pControlDict->GetDictFor("P");
136 if (pPageDict) {
137 int nPageIndex = pDocument->GetPageIndex(pPageDict->GetObjNum());
138 if (nPageIndex >= 0)
139 pPage = m_pFormFillEnv->GetPageViewAtIndex(nPageIndex);
140 }
141
142 if (!pPage) {
143 int nPageIndex = GetPageIndexByAnnotDict(pDocument, pControlDict);
144 if (nPageIndex >= 0)
145 pPage = m_pFormFillEnv->GetPageViewAtIndex(nPageIndex);
146 }
147
148 return pPage ? ToCPDFSDKWidget(pPage->GetAnnotByDict(pControlDict)) : nullptr;
149 }
150
GetWidgets(const WideString & sFieldName,std::vector<ObservedPtr<CPDFSDK_Widget>> * widgets) const151 void CPDFSDK_InteractiveForm::GetWidgets(
152 const WideString& sFieldName,
153 std::vector<ObservedPtr<CPDFSDK_Widget>>* widgets) const {
154 for (size_t i = 0, sz = m_pInteractiveForm->CountFields(sFieldName); i < sz;
155 ++i) {
156 CPDF_FormField* pFormField = m_pInteractiveForm->GetField(i, sFieldName);
157 DCHECK(pFormField);
158 GetWidgets(pFormField, widgets);
159 }
160 }
161
GetWidgets(CPDF_FormField * pField,std::vector<ObservedPtr<CPDFSDK_Widget>> * widgets) const162 void CPDFSDK_InteractiveForm::GetWidgets(
163 CPDF_FormField* pField,
164 std::vector<ObservedPtr<CPDFSDK_Widget>>* widgets) const {
165 for (int i = 0, sz = pField->CountControls(); i < sz; ++i) {
166 CPDF_FormControl* pFormCtrl = pField->GetControl(i);
167 DCHECK(pFormCtrl);
168 CPDFSDK_Widget* pWidget = GetWidget(pFormCtrl);
169 if (pWidget)
170 widgets->emplace_back(pWidget);
171 }
172 }
173
GetPageIndexByAnnotDict(CPDF_Document * pDocument,const CPDF_Dictionary * pAnnotDict) const174 int CPDFSDK_InteractiveForm::GetPageIndexByAnnotDict(
175 CPDF_Document* pDocument,
176 const CPDF_Dictionary* pAnnotDict) const {
177 DCHECK(pAnnotDict);
178
179 for (int i = 0, sz = pDocument->GetPageCount(); i < sz; i++) {
180 RetainPtr<const CPDF_Dictionary> pPageDict =
181 pDocument->GetPageDictionary(i);
182 if (!pPageDict)
183 continue;
184
185 RetainPtr<const CPDF_Array> pAnnots = pPageDict->GetArrayFor("Annots");
186 if (!pAnnots)
187 continue;
188
189 for (size_t j = 0, jsz = pAnnots->size(); j < jsz; j++) {
190 RetainPtr<const CPDF_Object> pDict = pAnnots->GetDirectObjectAt(j);
191 if (pAnnotDict == pDict)
192 return i;
193 }
194 }
195 return -1;
196 }
197
AddMap(CPDF_FormControl * pControl,CPDFSDK_Widget * pWidget)198 void CPDFSDK_InteractiveForm::AddMap(CPDF_FormControl* pControl,
199 CPDFSDK_Widget* pWidget) {
200 m_Map[pdfium::WrapUnowned(pControl)] = pWidget;
201 }
202
RemoveMap(CPDF_FormControl * pControl)203 void CPDFSDK_InteractiveForm::RemoveMap(CPDF_FormControl* pControl) {
204 auto it = m_Map.find(pControl);
205 if (it != m_Map.end())
206 m_Map.erase(it);
207 }
208
EnableCalculate(bool bEnabled)209 void CPDFSDK_InteractiveForm::EnableCalculate(bool bEnabled) {
210 m_bCalculate = bEnabled;
211 }
212
IsCalculateEnabled() const213 bool CPDFSDK_InteractiveForm::IsCalculateEnabled() const {
214 return m_bCalculate;
215 }
216
217 #ifdef PDF_ENABLE_XFA
XfaEnableCalculate(bool bEnabled)218 void CPDFSDK_InteractiveForm::XfaEnableCalculate(bool bEnabled) {
219 m_bXfaCalculate = bEnabled;
220 }
221
IsXfaCalculateEnabled() const222 bool CPDFSDK_InteractiveForm::IsXfaCalculateEnabled() const {
223 return m_bXfaCalculate;
224 }
225
IsXfaValidationsEnabled()226 bool CPDFSDK_InteractiveForm::IsXfaValidationsEnabled() {
227 return m_bXfaValidationsEnabled;
228 }
XfaSetValidationsEnabled(bool bEnabled)229 void CPDFSDK_InteractiveForm::XfaSetValidationsEnabled(bool bEnabled) {
230 m_bXfaValidationsEnabled = bEnabled;
231 }
232
SynchronizeField(CPDF_FormField * pFormField)233 void CPDFSDK_InteractiveForm::SynchronizeField(CPDF_FormField* pFormField) {
234 for (int i = 0, sz = pFormField->CountControls(); i < sz; i++) {
235 CPDF_FormControl* pFormCtrl = pFormField->GetControl(i);
236 if (CPDFSDK_Widget* pWidget = GetWidget(pFormCtrl))
237 pWidget->Synchronize(false);
238 }
239 }
240 #endif // PDF_ENABLE_XFA
241
OnCalculate(CPDF_FormField * pFormField)242 void CPDFSDK_InteractiveForm::OnCalculate(CPDF_FormField* pFormField) {
243 if (!m_pFormFillEnv->IsJSPlatformPresent())
244 return;
245
246 if (m_bBusy)
247 return;
248
249 AutoRestorer<bool> restorer(&m_bBusy);
250 m_bBusy = true;
251
252 if (!IsCalculateEnabled())
253 return;
254
255 IJS_Runtime* pRuntime = m_pFormFillEnv->GetIJSRuntime();
256 int nSize = m_pInteractiveForm->CountFieldsInCalculationOrder();
257 for (int i = 0; i < nSize; i++) {
258 CPDF_FormField* pField = m_pInteractiveForm->GetFieldInCalculationOrder(i);
259 if (!pField)
260 continue;
261
262 FormFieldType fieldType = pField->GetFieldType();
263 if (!IsFormFieldTypeComboOrText(fieldType))
264 continue;
265
266 CPDF_AAction aAction = pField->GetAdditionalAction();
267 if (!aAction.ActionExist(CPDF_AAction::kCalculate))
268 continue;
269
270 CPDF_Action action = aAction.GetAction(CPDF_AAction::kCalculate);
271 if (!action.HasDict())
272 continue;
273
274 WideString csJS = action.GetJavaScript();
275 if (csJS.IsEmpty())
276 continue;
277
278 WideString sOldValue = pField->GetValue();
279 WideString sValue = sOldValue;
280 bool bRC = true;
281 IJS_Runtime::ScopedEventContext pContext(pRuntime);
282 pContext->OnField_Calculate(pFormField, pField, &sValue, &bRC);
283
284 absl::optional<IJS_Runtime::JS_Error> err = pContext->RunScript(csJS);
285 if (!err.has_value() && bRC && sValue != sOldValue)
286 pField->SetValue(sValue, NotificationOption::kNotify);
287 }
288 }
289
OnFormat(CPDF_FormField * pFormField)290 absl::optional<WideString> CPDFSDK_InteractiveForm::OnFormat(
291 CPDF_FormField* pFormField) {
292 if (!m_pFormFillEnv->IsJSPlatformPresent())
293 return absl::nullopt;
294
295 WideString sValue = pFormField->GetValue();
296 IJS_Runtime* pRuntime = m_pFormFillEnv->GetIJSRuntime();
297 if (pFormField->GetFieldType() == FormFieldType::kComboBox &&
298 pFormField->CountSelectedItems() > 0) {
299 int index = pFormField->GetSelectedIndex(0);
300 if (index >= 0)
301 sValue = pFormField->GetOptionLabel(index);
302 }
303
304 CPDF_AAction aAction = pFormField->GetAdditionalAction();
305 if (aAction.ActionExist(CPDF_AAction::kFormat)) {
306 CPDF_Action action = aAction.GetAction(CPDF_AAction::kFormat);
307 if (action.HasDict()) {
308 WideString script = action.GetJavaScript();
309 if (!script.IsEmpty()) {
310 IJS_Runtime::ScopedEventContext pContext(pRuntime);
311 pContext->OnField_Format(pFormField, &sValue);
312 absl::optional<IJS_Runtime::JS_Error> err = pContext->RunScript(script);
313 if (!err.has_value())
314 return sValue;
315 }
316 }
317 }
318 return absl::nullopt;
319 }
320
ResetFieldAppearance(CPDF_FormField * pFormField,absl::optional<WideString> sValue)321 void CPDFSDK_InteractiveForm::ResetFieldAppearance(
322 CPDF_FormField* pFormField,
323 absl::optional<WideString> sValue) {
324 for (int i = 0, sz = pFormField->CountControls(); i < sz; i++) {
325 CPDF_FormControl* pFormCtrl = pFormField->GetControl(i);
326 DCHECK(pFormCtrl);
327 if (CPDFSDK_Widget* pWidget = GetWidget(pFormCtrl))
328 pWidget->ResetAppearance(sValue, CPDFSDK_Widget::kValueChanged);
329 }
330 }
331
UpdateField(CPDF_FormField * pFormField)332 void CPDFSDK_InteractiveForm::UpdateField(CPDF_FormField* pFormField) {
333 auto* formfiller = m_pFormFillEnv->GetInteractiveFormFiller();
334 for (int i = 0, sz = pFormField->CountControls(); i < sz; i++) {
335 CPDF_FormControl* pFormCtrl = pFormField->GetControl(i);
336 DCHECK(pFormCtrl);
337
338 CPDFSDK_Widget* pWidget = GetWidget(pFormCtrl);
339 if (!pWidget)
340 continue;
341
342 IPDF_Page* pPage = pWidget->GetPage();
343 FX_RECT rect =
344 formfiller->GetViewBBox(m_pFormFillEnv->GetPageView(pPage), pWidget);
345 m_pFormFillEnv->Invalidate(pPage, rect);
346 }
347 }
348
OnKeyStrokeCommit(CPDF_FormField * pFormField,const WideString & csValue)349 bool CPDFSDK_InteractiveForm::OnKeyStrokeCommit(CPDF_FormField* pFormField,
350 const WideString& csValue) {
351 CPDF_AAction aAction = pFormField->GetAdditionalAction();
352 if (!aAction.ActionExist(CPDF_AAction::kKeyStroke))
353 return true;
354
355 CPDF_Action action = aAction.GetAction(CPDF_AAction::kKeyStroke);
356 if (!action.HasDict())
357 return true;
358
359 CFFL_FieldAction fa;
360 fa.bModifier = false;
361 fa.bShift = false;
362 fa.sValue = csValue;
363 m_pFormFillEnv->DoActionFieldJavaScript(action, CPDF_AAction::kKeyStroke,
364 pFormField, &fa);
365 return fa.bRC;
366 }
367
OnValidate(CPDF_FormField * pFormField,const WideString & csValue)368 bool CPDFSDK_InteractiveForm::OnValidate(CPDF_FormField* pFormField,
369 const WideString& csValue) {
370 CPDF_AAction aAction = pFormField->GetAdditionalAction();
371 if (!aAction.ActionExist(CPDF_AAction::kValidate))
372 return true;
373
374 CPDF_Action action = aAction.GetAction(CPDF_AAction::kValidate);
375 if (!action.HasDict())
376 return true;
377
378 CFFL_FieldAction fa;
379 fa.bModifier = false;
380 fa.bShift = false;
381 fa.sValue = csValue;
382 m_pFormFillEnv->DoActionFieldJavaScript(action, CPDF_AAction::kValidate,
383 pFormField, &fa);
384 return fa.bRC;
385 }
386
DoAction_Hide(const CPDF_Action & action)387 bool CPDFSDK_InteractiveForm::DoAction_Hide(const CPDF_Action& action) {
388 DCHECK(action.GetDict());
389 std::vector<CPDF_FormField*> fields =
390 GetFieldFromObjects(action.GetAllFields());
391 bool bHide = action.GetHideStatus();
392 bool bChanged = false;
393
394 for (CPDF_FormField* pField : fields) {
395 for (int i = 0, sz = pField->CountControls(); i < sz; ++i) {
396 CPDF_FormControl* pControl = pField->GetControl(i);
397 DCHECK(pControl);
398
399 if (CPDFSDK_Widget* pWidget = GetWidget(pControl)) {
400 uint32_t nFlags = pWidget->GetFlags();
401 nFlags &= ~pdfium::annotation_flags::kInvisible;
402 nFlags &= ~pdfium::annotation_flags::kNoView;
403 if (bHide)
404 nFlags |= pdfium::annotation_flags::kHidden;
405 else
406 nFlags &= ~pdfium::annotation_flags::kHidden;
407 pWidget->SetFlags(nFlags);
408 pWidget->GetPageView()->UpdateView(pWidget);
409 bChanged = true;
410 }
411 }
412 }
413
414 return bChanged;
415 }
416
DoAction_SubmitForm(const CPDF_Action & action)417 bool CPDFSDK_InteractiveForm::DoAction_SubmitForm(const CPDF_Action& action) {
418 WideString sDestination = action.GetFilePath();
419 if (sDestination.IsEmpty())
420 return false;
421
422 if (action.HasFields()) {
423 uint32_t dwFlags = action.GetFlags();
424 std::vector<CPDF_FormField*> fields =
425 GetFieldFromObjects(action.GetAllFields());
426 if (!fields.empty()) {
427 bool bIncludeOrExclude = !(dwFlags & 0x01);
428 if (!m_pInteractiveForm->CheckRequiredFields(&fields, bIncludeOrExclude))
429 return false;
430
431 return SubmitFields(sDestination, fields, bIncludeOrExclude, false);
432 }
433 }
434 if (!m_pInteractiveForm->CheckRequiredFields(nullptr, true))
435 return false;
436
437 return SubmitForm(sDestination);
438 }
439
SubmitFields(const WideString & csDestination,const std::vector<CPDF_FormField * > & fields,bool bIncludeOrExclude,bool bUrlEncoded)440 bool CPDFSDK_InteractiveForm::SubmitFields(
441 const WideString& csDestination,
442 const std::vector<CPDF_FormField*>& fields,
443 bool bIncludeOrExclude,
444 bool bUrlEncoded) {
445 ByteString text_buf = ExportFieldsToFDFTextBuf(fields, bIncludeOrExclude);
446 if (text_buf.IsEmpty())
447 return false;
448
449 if (bUrlEncoded) {
450 text_buf = FDFToURLEncodedData(text_buf);
451 if (text_buf.IsEmpty())
452 return false;
453 }
454
455 m_pFormFillEnv->SubmitForm(text_buf.raw_span(), csDestination);
456 return true;
457 }
458
ExportFieldsToFDFTextBuf(const std::vector<CPDF_FormField * > & fields,bool bIncludeOrExclude)459 ByteString CPDFSDK_InteractiveForm::ExportFieldsToFDFTextBuf(
460 const std::vector<CPDF_FormField*>& fields,
461 bool bIncludeOrExclude) {
462 std::unique_ptr<CFDF_Document> pFDF = m_pInteractiveForm->ExportToFDF(
463 m_pFormFillEnv->GetFilePath(), fields, bIncludeOrExclude);
464
465 return pFDF ? pFDF->WriteToString() : ByteString();
466 }
467
SubmitForm(const WideString & sDestination)468 bool CPDFSDK_InteractiveForm::SubmitForm(const WideString& sDestination) {
469 if (sDestination.IsEmpty())
470 return false;
471
472 std::unique_ptr<CFDF_Document> pFDFDoc =
473 m_pInteractiveForm->ExportToFDF(m_pFormFillEnv->GetFilePath());
474 if (!pFDFDoc)
475 return false;
476
477 ByteString fdf_buffer = pFDFDoc->WriteToString();
478 if (fdf_buffer.IsEmpty())
479 return false;
480
481 m_pFormFillEnv->SubmitForm(fdf_buffer.raw_span(), sDestination);
482 return true;
483 }
484
ExportFormToFDFTextBuf()485 ByteString CPDFSDK_InteractiveForm::ExportFormToFDFTextBuf() {
486 std::unique_ptr<CFDF_Document> pFDF =
487 m_pInteractiveForm->ExportToFDF(m_pFormFillEnv->GetFilePath());
488
489 return pFDF ? pFDF->WriteToString() : ByteString();
490 }
491
DoAction_ResetForm(const CPDF_Action & action)492 void CPDFSDK_InteractiveForm::DoAction_ResetForm(const CPDF_Action& action) {
493 DCHECK(action.GetDict());
494 if (!action.HasFields()) {
495 m_pInteractiveForm->ResetForm();
496 return;
497 }
498 uint32_t dwFlags = action.GetFlags();
499 std::vector<CPDF_FormField*> fields =
500 GetFieldFromObjects(action.GetAllFields());
501 m_pInteractiveForm->ResetForm(fields, !(dwFlags & 0x01));
502 }
503
GetFieldFromObjects(const std::vector<RetainPtr<const CPDF_Object>> & objects) const504 std::vector<CPDF_FormField*> CPDFSDK_InteractiveForm::GetFieldFromObjects(
505 const std::vector<RetainPtr<const CPDF_Object>>& objects) const {
506 std::vector<CPDF_FormField*> fields;
507 for (const CPDF_Object* pObject : objects) {
508 if (!pObject || !pObject->IsString())
509 continue;
510
511 WideString csName = pObject->GetUnicodeText();
512 CPDF_FormField* pField = m_pInteractiveForm->GetField(0, csName);
513 if (pField)
514 fields.push_back(pField);
515 }
516 return fields;
517 }
518
BeforeValueChange(CPDF_FormField * pField,const WideString & csValue)519 bool CPDFSDK_InteractiveForm::BeforeValueChange(CPDF_FormField* pField,
520 const WideString& csValue) {
521 FormFieldType fieldType = pField->GetFieldType();
522 if (!IsFormFieldTypeComboOrText(fieldType))
523 return true;
524 if (!OnKeyStrokeCommit(pField, csValue))
525 return false;
526 return OnValidate(pField, csValue);
527 }
528
AfterValueChange(CPDF_FormField * pField)529 void CPDFSDK_InteractiveForm::AfterValueChange(CPDF_FormField* pField) {
530 #ifdef PDF_ENABLE_XFA
531 SynchronizeField(pField);
532 #endif // PDF_ENABLE_XFA
533
534 FormFieldType fieldType = pField->GetFieldType();
535 if (!IsFormFieldTypeComboOrText(fieldType))
536 return;
537
538 OnCalculate(pField);
539 ResetFieldAppearance(pField, OnFormat(pField));
540 UpdateField(pField);
541 }
542
BeforeSelectionChange(CPDF_FormField * pField,const WideString & csValue)543 bool CPDFSDK_InteractiveForm::BeforeSelectionChange(CPDF_FormField* pField,
544 const WideString& csValue) {
545 if (pField->GetFieldType() != FormFieldType::kListBox)
546 return true;
547 if (!OnKeyStrokeCommit(pField, csValue))
548 return false;
549 return OnValidate(pField, csValue);
550 }
551
AfterSelectionChange(CPDF_FormField * pField)552 void CPDFSDK_InteractiveForm::AfterSelectionChange(CPDF_FormField* pField) {
553 if (pField->GetFieldType() != FormFieldType::kListBox)
554 return;
555
556 OnCalculate(pField);
557 ResetFieldAppearance(pField, absl::nullopt);
558 UpdateField(pField);
559 }
560
AfterCheckedStatusChange(CPDF_FormField * pField)561 void CPDFSDK_InteractiveForm::AfterCheckedStatusChange(CPDF_FormField* pField) {
562 FormFieldType fieldType = pField->GetFieldType();
563 if (fieldType != FormFieldType::kCheckBox &&
564 fieldType != FormFieldType::kRadioButton)
565 return;
566
567 OnCalculate(pField);
568 UpdateField(pField);
569 }
570
AfterFormReset(CPDF_InteractiveForm * pForm)571 void CPDFSDK_InteractiveForm::AfterFormReset(CPDF_InteractiveForm* pForm) {
572 OnCalculate(nullptr);
573 }
574
IsNeedHighLight(FormFieldType fieldType) const575 bool CPDFSDK_InteractiveForm::IsNeedHighLight(FormFieldType fieldType) const {
576 if (fieldType == FormFieldType::kUnknown)
577 return false;
578
579 #ifdef PDF_ENABLE_XFA
580 // For the XFA fields, we need to return if the specific field type has
581 // highlight enabled or if the general XFA field type has it enabled.
582 if (IsFormFieldTypeXFA(fieldType)) {
583 if (!m_NeedsHighlight[static_cast<size_t>(fieldType)])
584 return m_NeedsHighlight[static_cast<size_t>(FormFieldType::kXFA)];
585 }
586 #endif // PDF_ENABLE_XFA
587 return m_NeedsHighlight[static_cast<size_t>(fieldType)];
588 }
589
RemoveAllHighLights()590 void CPDFSDK_InteractiveForm::RemoveAllHighLights() {
591 std::fill(std::begin(m_HighlightColor), std::end(m_HighlightColor),
592 kWhiteBGR);
593 std::fill(std::begin(m_NeedsHighlight), std::end(m_NeedsHighlight), false);
594 }
595
SetHighlightColor(FX_COLORREF clr,FormFieldType fieldType)596 void CPDFSDK_InteractiveForm::SetHighlightColor(FX_COLORREF clr,
597 FormFieldType fieldType) {
598 if (fieldType == FormFieldType::kUnknown)
599 return;
600
601 m_HighlightColor[static_cast<size_t>(fieldType)] = clr;
602 m_NeedsHighlight[static_cast<size_t>(fieldType)] = true;
603 }
604
SetAllHighlightColors(FX_COLORREF clr)605 void CPDFSDK_InteractiveForm::SetAllHighlightColors(FX_COLORREF clr) {
606 for (size_t i = 0; i < kFormFieldTypeCount; ++i) {
607 m_HighlightColor[i] = clr;
608 m_NeedsHighlight[i] = true;
609 }
610 }
611
GetHighlightColor(FormFieldType fieldType)612 FX_COLORREF CPDFSDK_InteractiveForm::GetHighlightColor(
613 FormFieldType fieldType) {
614 if (fieldType == FormFieldType::kUnknown)
615 return kWhiteBGR;
616
617 #ifdef PDF_ENABLE_XFA
618 // For the XFA fields, we need to return the specific field type highlight
619 // colour or the general XFA field type colour if present.
620 if (IsFormFieldTypeXFA(fieldType)) {
621 if (!m_NeedsHighlight[static_cast<size_t>(fieldType)] &&
622 m_NeedsHighlight[static_cast<size_t>(FormFieldType::kXFA)]) {
623 return m_HighlightColor[static_cast<size_t>(FormFieldType::kXFA)];
624 }
625 }
626 #endif // PDF_ENABLE_XFA
627 return m_HighlightColor[static_cast<size_t>(fieldType)];
628 }
629