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