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.Get();
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->GetPageViewAtIndex(nPageIndex);
144   }
145 
146   if (!pPage) {
147     int nPageIndex = GetPageIndexByAnnotDict(pDocument, pControlDict);
148     if (nPageIndex >= 0)
149       pPage = m_pFormFillEnv->GetPageViewAtIndex(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