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