• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "fpdfsdk/cpdfsdk_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