Home | History | Annotate | Download | only in fpdfsdk
      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_interform.h"
      8 
      9 #include <algorithm>
     10 #include <memory>
     11 #include <sstream>
     12 #include <string>
     13 #include <vector>
     14 
     15 #include "core/fpdfapi/page/cpdf_page.h"
     16 #include "core/fpdfapi/parser/cfdf_document.h"
     17 #include "core/fpdfapi/parser/cpdf_array.h"
     18 #include "core/fpdfapi/parser/cpdf_document.h"
     19 #include "core/fpdfapi/parser/cpdf_stream.h"
     20 #include "core/fpdfdoc/cpdf_actionfields.h"
     21 #include "core/fpdfdoc/cpdf_interform.h"
     22 #include "core/fxge/cfx_graphstatedata.h"
     23 #include "core/fxge/cfx_pathdata.h"
     24 #include "fpdfsdk/cba_annotiterator.h"
     25 #include "fpdfsdk/cpdfsdk_annot.h"
     26 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
     27 #include "fpdfsdk/cpdfsdk_pageview.h"
     28 #include "fpdfsdk/cpdfsdk_widget.h"
     29 #include "fpdfsdk/formfiller/cffl_formfiller.h"
     30 #include "fpdfsdk/fsdk_actionhandler.h"
     31 #include "fpdfsdk/fsdk_define.h"
     32 #include "fpdfsdk/ipdfsdk_annothandler.h"
     33 #include "fxjs/ijs_event_context.h"
     34 #include "fxjs/ijs_runtime.h"
     35 #include "third_party/base/stl_util.h"
     36 
     37 #ifdef PDF_ENABLE_XFA
     38 #include "fpdfsdk/cpdfsdk_xfawidget.h"
     39 #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
     40 #include "fpdfsdk/fpdfxfa/cxfa_fwladaptertimermgr.h"
     41 #include "xfa/fxfa/cxfa_eventparam.h"
     42 #include "xfa/fxfa/cxfa_ffdocview.h"
     43 #include "xfa/fxfa/cxfa_ffwidget.h"
     44 #include "xfa/fxfa/cxfa_ffwidgethandler.h"
     45 #endif  // PDF_ENABLE_XFA
     46 
     47 namespace {
     48 
     49 bool IsFormFieldTypeComboOrText(FormFieldType fieldType) {
     50   switch (fieldType) {
     51     case FormFieldType::kComboBox:
     52     case FormFieldType::kTextField:
     53       return true;
     54     default:
     55       return false;
     56   }
     57 }
     58 
     59 #ifdef PDF_ENABLE_XFA
     60 bool IsFormFieldTypeXFA(FormFieldType fieldType) {
     61   switch (fieldType) {
     62     case FormFieldType::kXFA:
     63     case FormFieldType::kXFA_CheckBox:
     64     case FormFieldType::kXFA_ComboBox:
     65     case FormFieldType::kXFA_ImageField:
     66     case FormFieldType::kXFA_ListBox:
     67     case FormFieldType::kXFA_PushButton:
     68     case FormFieldType::kXFA_Signature:
     69     case FormFieldType::kXFA_TextField:
     70       return true;
     71     default:
     72       return false;
     73   }
     74 }
     75 #endif  // PDF_ENABLE_XFA
     76 
     77 }  // namespace
     78 
     79 CPDFSDK_InterForm::CPDFSDK_InterForm(CPDFSDK_FormFillEnvironment* pFormFillEnv)
     80     : m_pFormFillEnv(pFormFillEnv),
     81       m_pInterForm(
     82           pdfium::MakeUnique<CPDF_InterForm>(m_pFormFillEnv->GetPDFDocument())),
     83 #ifdef PDF_ENABLE_XFA
     84       m_bXfaCalculate(true),
     85       m_bXfaValidationsEnabled(true),
     86 #endif  // PDF_ENABLE_XFA
     87       m_bCalculate(true),
     88       m_bBusy(false),
     89       m_HighlightAlpha(0) {
     90   m_pInterForm->SetFormNotify(this);
     91   RemoveAllHighLights();
     92 }
     93 
     94 CPDFSDK_InterForm::~CPDFSDK_InterForm() {
     95   m_Map.clear();
     96 #ifdef PDF_ENABLE_XFA
     97   m_XFAMap.clear();
     98 #endif  // PDF_ENABLE_XFA
     99 }
    100 
    101 bool CPDFSDK_InterForm::HighlightWidgets() {
    102   return false;
    103 }
    104 
    105 CPDFSDK_Widget* CPDFSDK_InterForm::GetSibling(CPDFSDK_Widget* pWidget,
    106                                               bool bNext) const {
    107   auto pIterator = pdfium::MakeUnique<CBA_AnnotIterator>(
    108       pWidget->GetPageView(), CPDF_Annot::Subtype::WIDGET);
    109 
    110   if (bNext)
    111     return static_cast<CPDFSDK_Widget*>(pIterator->GetNextAnnot(pWidget));
    112 
    113   return static_cast<CPDFSDK_Widget*>(pIterator->GetPrevAnnot(pWidget));
    114 }
    115 
    116 CPDFSDK_Widget* CPDFSDK_InterForm::GetWidget(CPDF_FormControl* pControl) const {
    117   if (!pControl || !m_pInterForm)
    118     return nullptr;
    119 
    120   CPDFSDK_Widget* pWidget = nullptr;
    121   const auto it = m_Map.find(pControl);
    122   if (it != m_Map.end())
    123     pWidget = it->second;
    124   if (pWidget)
    125     return pWidget;
    126 
    127   CPDF_Dictionary* pControlDict = pControl->GetWidget();
    128   CPDF_Document* pDocument = m_pFormFillEnv->GetPDFDocument();
    129   CPDFSDK_PageView* pPage = nullptr;
    130 
    131   if (CPDF_Dictionary* pPageDict = pControlDict->GetDictFor("P")) {
    132     int nPageIndex = pDocument->GetPageIndex(pPageDict->GetObjNum());
    133     if (nPageIndex >= 0)
    134       pPage = m_pFormFillEnv->GetPageView(nPageIndex);
    135   }
    136 
    137   if (!pPage) {
    138     int nPageIndex = GetPageIndexByAnnotDict(pDocument, pControlDict);
    139     if (nPageIndex >= 0)
    140       pPage = m_pFormFillEnv->GetPageView(nPageIndex);
    141   }
    142 
    143   if (!pPage)
    144     return nullptr;
    145 
    146   return static_cast<CPDFSDK_Widget*>(pPage->GetAnnotByDict(pControlDict));
    147 }
    148 
    149 void CPDFSDK_InterForm::GetWidgets(
    150     const WideString& sFieldName,
    151     std::vector<CPDFSDK_Annot::ObservedPtr>* widgets) const {
    152   for (int i = 0, sz = m_pInterForm->CountFields(sFieldName); i < sz; ++i) {
    153     CPDF_FormField* pFormField = m_pInterForm->GetField(i, sFieldName);
    154     ASSERT(pFormField);
    155     GetWidgets(pFormField, widgets);
    156   }
    157 }
    158 
    159 void CPDFSDK_InterForm::GetWidgets(
    160     CPDF_FormField* pField,
    161     std::vector<CPDFSDK_Annot::ObservedPtr>* widgets) const {
    162   for (int i = 0, sz = pField->CountControls(); i < sz; ++i) {
    163     CPDF_FormControl* pFormCtrl = pField->GetControl(i);
    164     ASSERT(pFormCtrl);
    165     CPDFSDK_Widget* pWidget = GetWidget(pFormCtrl);
    166     if (pWidget)
    167       widgets->emplace_back(pWidget);
    168   }
    169 }
    170 
    171 int CPDFSDK_InterForm::GetPageIndexByAnnotDict(
    172     CPDF_Document* pDocument,
    173     CPDF_Dictionary* pAnnotDict) const {
    174   ASSERT(pAnnotDict);
    175 
    176   for (int i = 0, sz = pDocument->GetPageCount(); i < sz; i++) {
    177     if (CPDF_Dictionary* pPageDict = pDocument->GetPage(i)) {
    178       if (CPDF_Array* pAnnots = pPageDict->GetArrayFor("Annots")) {
    179         for (int j = 0, jsz = pAnnots->GetCount(); j < jsz; j++) {
    180           CPDF_Object* pDict = pAnnots->GetDirectObjectAt(j);
    181           if (pAnnotDict == pDict)
    182             return i;
    183         }
    184       }
    185     }
    186   }
    187 
    188   return -1;
    189 }
    190 
    191 void CPDFSDK_InterForm::AddMap(CPDF_FormControl* pControl,
    192                                CPDFSDK_Widget* pWidget) {
    193   m_Map[pControl] = pWidget;
    194 }
    195 
    196 void CPDFSDK_InterForm::RemoveMap(CPDF_FormControl* pControl) {
    197   m_Map.erase(pControl);
    198 }
    199 
    200 void CPDFSDK_InterForm::EnableCalculate(bool bEnabled) {
    201   m_bCalculate = bEnabled;
    202 }
    203 
    204 bool CPDFSDK_InterForm::IsCalculateEnabled() const {
    205   return m_bCalculate;
    206 }
    207 
    208 #ifdef PDF_ENABLE_XFA
    209 void CPDFSDK_InterForm::AddXFAMap(CXFA_FFWidget* hWidget,
    210                                   CPDFSDK_XFAWidget* pWidget) {
    211   ASSERT(hWidget);
    212   m_XFAMap[hWidget] = pWidget;
    213 }
    214 
    215 void CPDFSDK_InterForm::RemoveXFAMap(CXFA_FFWidget* hWidget) {
    216   ASSERT(hWidget);
    217   m_XFAMap.erase(hWidget);
    218 }
    219 
    220 CPDFSDK_XFAWidget* CPDFSDK_InterForm::GetXFAWidget(CXFA_FFWidget* hWidget) {
    221   ASSERT(hWidget);
    222   auto it = m_XFAMap.find(hWidget);
    223   return it != m_XFAMap.end() ? it->second : nullptr;
    224 }
    225 
    226 void CPDFSDK_InterForm::XfaEnableCalculate(bool bEnabled) {
    227   m_bXfaCalculate = bEnabled;
    228 }
    229 bool CPDFSDK_InterForm::IsXfaCalculateEnabled() const {
    230   return m_bXfaCalculate;
    231 }
    232 
    233 bool CPDFSDK_InterForm::IsXfaValidationsEnabled() {
    234   return m_bXfaValidationsEnabled;
    235 }
    236 void CPDFSDK_InterForm::XfaSetValidationsEnabled(bool bEnabled) {
    237   m_bXfaValidationsEnabled = bEnabled;
    238 }
    239 
    240 void CPDFSDK_InterForm::SynchronizeField(CPDF_FormField* pFormField,
    241                                          bool bSynchronizeElse) {
    242   for (int i = 0, sz = pFormField->CountControls(); i < sz; i++) {
    243     CPDF_FormControl* pFormCtrl = pFormField->GetControl(i);
    244     if (CPDFSDK_Widget* pWidget = GetWidget(pFormCtrl))
    245       pWidget->Synchronize(bSynchronizeElse);
    246   }
    247 }
    248 #endif  // PDF_ENABLE_XFA
    249 
    250 void CPDFSDK_InterForm::OnCalculate(CPDF_FormField* pFormField) {
    251   if (!m_pFormFillEnv->IsJSInitiated())
    252     return;
    253 
    254   if (m_bBusy)
    255     return;
    256 
    257   m_bBusy = true;
    258 
    259   if (!IsCalculateEnabled()) {
    260     m_bBusy = false;
    261     return;
    262   }
    263 
    264   IJS_Runtime* pRuntime = m_pFormFillEnv->GetJSRuntime();
    265   int nSize = m_pInterForm->CountFieldsInCalculationOrder();
    266   for (int i = 0; i < nSize; i++) {
    267     CPDF_FormField* pField = m_pInterForm->GetFieldInCalculationOrder(i);
    268     if (!pField)
    269       continue;
    270 
    271     FormFieldType fieldType = pField->GetFieldType();
    272     if (!IsFormFieldTypeComboOrText(fieldType))
    273       continue;
    274 
    275     CPDF_AAction aAction = pField->GetAdditionalAction();
    276     if (!aAction.GetDict() || !aAction.ActionExist(CPDF_AAction::Calculate))
    277       continue;
    278 
    279     CPDF_Action action = aAction.GetAction(CPDF_AAction::Calculate);
    280     if (!action.GetDict())
    281       continue;
    282 
    283     WideString csJS = action.GetJavaScript();
    284     if (csJS.IsEmpty())
    285       continue;
    286 
    287     IJS_EventContext* pContext = pRuntime->NewEventContext();
    288     WideString sOldValue = pField->GetValue();
    289     WideString sValue = sOldValue;
    290     bool bRC = true;
    291     pContext->OnField_Calculate(pFormField, pField, sValue, bRC);
    292 
    293     WideString sInfo;
    294     bool bRet = pContext->RunScript(csJS, &sInfo);
    295     pRuntime->ReleaseEventContext(pContext);
    296     if (bRet && bRC && sValue.Compare(sOldValue) != 0)
    297       pField->SetValue(sValue, true);
    298   }
    299   m_bBusy = false;
    300 }
    301 
    302 WideString CPDFSDK_InterForm::OnFormat(CPDF_FormField* pFormField,
    303                                        bool& bFormatted) {
    304   WideString sValue = pFormField->GetValue();
    305   if (!m_pFormFillEnv->IsJSInitiated()) {
    306     bFormatted = false;
    307     return sValue;
    308   }
    309 
    310   IJS_Runtime* pRuntime = m_pFormFillEnv->GetJSRuntime();
    311   if (pFormField->GetFieldType() == FormFieldType::kComboBox &&
    312       pFormField->CountSelectedItems() > 0) {
    313     int index = pFormField->GetSelectedIndex(0);
    314     if (index >= 0)
    315       sValue = pFormField->GetOptionLabel(index);
    316   }
    317 
    318   bFormatted = false;
    319 
    320   CPDF_AAction aAction = pFormField->GetAdditionalAction();
    321   if (aAction.GetDict() && aAction.ActionExist(CPDF_AAction::Format)) {
    322     CPDF_Action action = aAction.GetAction(CPDF_AAction::Format);
    323     if (action.GetDict()) {
    324       WideString script = action.GetJavaScript();
    325       if (!script.IsEmpty()) {
    326         WideString Value = sValue;
    327 
    328         IJS_EventContext* pContext = pRuntime->NewEventContext();
    329         pContext->OnField_Format(pFormField, Value, true);
    330         WideString sInfo;
    331         bool bRet = pContext->RunScript(script, &sInfo);
    332         pRuntime->ReleaseEventContext(pContext);
    333         if (bRet) {
    334           sValue = Value;
    335           bFormatted = true;
    336         }
    337       }
    338     }
    339   }
    340   return sValue;
    341 }
    342 
    343 void CPDFSDK_InterForm::ResetFieldAppearance(CPDF_FormField* pFormField,
    344                                              const WideString* sValue,
    345                                              bool bValueChanged) {
    346   for (int i = 0, sz = pFormField->CountControls(); i < sz; i++) {
    347     CPDF_FormControl* pFormCtrl = pFormField->GetControl(i);
    348     ASSERT(pFormCtrl);
    349     if (CPDFSDK_Widget* pWidget = GetWidget(pFormCtrl))
    350       pWidget->ResetAppearance(sValue, bValueChanged);
    351   }
    352 }
    353 
    354 void CPDFSDK_InterForm::UpdateField(CPDF_FormField* pFormField) {
    355   auto* formfiller = m_pFormFillEnv->GetInteractiveFormFiller();
    356   for (int i = 0, sz = pFormField->CountControls(); i < sz; i++) {
    357     CPDF_FormControl* pFormCtrl = pFormField->GetControl(i);
    358     ASSERT(pFormCtrl);
    359 
    360     CPDFSDK_Widget* pWidget = GetWidget(pFormCtrl);
    361     if (!pWidget)
    362       continue;
    363 
    364     UnderlyingPageType* pPage = pWidget->GetUnderlyingPage();
    365     FX_RECT rect = formfiller->GetViewBBox(
    366         m_pFormFillEnv->GetPageView(pPage, false), pWidget);
    367     m_pFormFillEnv->Invalidate(pPage, rect);
    368   }
    369 }
    370 
    371 bool CPDFSDK_InterForm::OnKeyStrokeCommit(CPDF_FormField* pFormField,
    372                                           const WideString& csValue) {
    373   CPDF_AAction aAction = pFormField->GetAdditionalAction();
    374   if (!aAction.GetDict() || !aAction.ActionExist(CPDF_AAction::KeyStroke))
    375     return true;
    376 
    377   CPDF_Action action = aAction.GetAction(CPDF_AAction::KeyStroke);
    378   if (!action.GetDict())
    379     return true;
    380 
    381   CPDFSDK_ActionHandler* pActionHandler = m_pFormFillEnv->GetActionHandler();
    382   PDFSDK_FieldAction fa;
    383   fa.bModifier = false;
    384   fa.bShift = false;
    385   fa.sValue = csValue;
    386   pActionHandler->DoAction_FieldJavaScript(
    387       action, CPDF_AAction::KeyStroke, m_pFormFillEnv.Get(), pFormField, fa);
    388   return fa.bRC;
    389 }
    390 
    391 bool CPDFSDK_InterForm::OnValidate(CPDF_FormField* pFormField,
    392                                    const WideString& csValue) {
    393   CPDF_AAction aAction = pFormField->GetAdditionalAction();
    394   if (!aAction.GetDict() || !aAction.ActionExist(CPDF_AAction::Validate))
    395     return true;
    396 
    397   CPDF_Action action = aAction.GetAction(CPDF_AAction::Validate);
    398   if (!action.GetDict())
    399     return true;
    400 
    401   CPDFSDK_ActionHandler* pActionHandler = m_pFormFillEnv->GetActionHandler();
    402   PDFSDK_FieldAction fa;
    403   fa.bModifier = false;
    404   fa.bShift = false;
    405   fa.sValue = csValue;
    406   pActionHandler->DoAction_FieldJavaScript(
    407       action, CPDF_AAction::Validate, m_pFormFillEnv.Get(), pFormField, fa);
    408   return fa.bRC;
    409 }
    410 
    411 bool CPDFSDK_InterForm::DoAction_Hide(const CPDF_Action& action) {
    412   ASSERT(action.GetDict());
    413 
    414   CPDF_ActionFields af(&action);
    415   std::vector<CPDF_Object*> fieldObjects = af.GetAllFields();
    416   std::vector<CPDF_FormField*> fields = GetFieldFromObjects(fieldObjects);
    417 
    418   bool bHide = action.GetHideStatus();
    419   bool bChanged = false;
    420 
    421   for (CPDF_FormField* pField : fields) {
    422     for (int i = 0, sz = pField->CountControls(); i < sz; ++i) {
    423       CPDF_FormControl* pControl = pField->GetControl(i);
    424       ASSERT(pControl);
    425 
    426       if (CPDFSDK_Widget* pWidget = GetWidget(pControl)) {
    427         uint32_t nFlags = pWidget->GetFlags();
    428         nFlags &= ~ANNOTFLAG_INVISIBLE;
    429         nFlags &= ~ANNOTFLAG_NOVIEW;
    430         if (bHide)
    431           nFlags |= ANNOTFLAG_HIDDEN;
    432         else
    433           nFlags &= ~ANNOTFLAG_HIDDEN;
    434         pWidget->SetFlags(nFlags);
    435         pWidget->GetPageView()->UpdateView(pWidget);
    436         bChanged = true;
    437       }
    438     }
    439   }
    440 
    441   return bChanged;
    442 }
    443 
    444 bool CPDFSDK_InterForm::DoAction_SubmitForm(const CPDF_Action& action) {
    445   WideString sDestination = action.GetFilePath();
    446   if (sDestination.IsEmpty())
    447     return false;
    448 
    449   CPDF_Dictionary* pActionDict = action.GetDict();
    450   if (pActionDict->KeyExist("Fields")) {
    451     CPDF_ActionFields af(&action);
    452     uint32_t dwFlags = action.GetFlags();
    453     std::vector<CPDF_Object*> fieldObjects = af.GetAllFields();
    454     std::vector<CPDF_FormField*> fields = GetFieldFromObjects(fieldObjects);
    455     if (!fields.empty()) {
    456       bool bIncludeOrExclude = !(dwFlags & 0x01);
    457       if (!m_pInterForm->CheckRequiredFields(&fields, bIncludeOrExclude))
    458         return false;
    459 
    460       return SubmitFields(sDestination, fields, bIncludeOrExclude, false);
    461     }
    462   }
    463   if (!m_pInterForm->CheckRequiredFields(nullptr, true))
    464     return false;
    465 
    466   return SubmitForm(sDestination, false);
    467 }
    468 
    469 bool CPDFSDK_InterForm::SubmitFields(const WideString& csDestination,
    470                                      const std::vector<CPDF_FormField*>& fields,
    471                                      bool bIncludeOrExclude,
    472                                      bool bUrlEncoded) {
    473   ByteString textBuf = ExportFieldsToFDFTextBuf(fields, bIncludeOrExclude);
    474 
    475   size_t nBufSize = textBuf.GetLength();
    476   if (nBufSize == 0)
    477     return false;
    478 
    479   uint8_t* pLocalBuffer = FX_Alloc(uint8_t, nBufSize);
    480   memcpy(pLocalBuffer, textBuf.c_str(), nBufSize);
    481   uint8_t* pBuffer = pLocalBuffer;
    482 
    483   if (bUrlEncoded && !FDFToURLEncodedData(pBuffer, nBufSize)) {
    484     FX_Free(pLocalBuffer);
    485     return false;
    486   }
    487 
    488   m_pFormFillEnv->JS_docSubmitForm(pBuffer, nBufSize, csDestination.c_str());
    489 
    490   if (pBuffer != pLocalBuffer)
    491     FX_Free(pBuffer);
    492 
    493   FX_Free(pLocalBuffer);
    494 
    495   return true;
    496 }
    497 
    498 bool CPDFSDK_InterForm::FDFToURLEncodedData(uint8_t*& pBuf, size_t& nBufSize) {
    499   std::unique_ptr<CFDF_Document> pFDF =
    500       CFDF_Document::ParseMemory(pBuf, nBufSize);
    501   if (!pFDF)
    502     return true;
    503 
    504   CPDF_Dictionary* pMainDict = pFDF->GetRoot()->GetDictFor("FDF");
    505   if (!pMainDict)
    506     return false;
    507 
    508   CPDF_Array* pFields = pMainDict->GetArrayFor("Fields");
    509   if (!pFields)
    510     return false;
    511 
    512   std::ostringstream fdfEncodedData;
    513   for (uint32_t i = 0; i < pFields->GetCount(); i++) {
    514     CPDF_Dictionary* pField = pFields->GetDictAt(i);
    515     if (!pField)
    516       continue;
    517     WideString name;
    518     name = pField->GetUnicodeTextFor("T");
    519     ByteString name_b = ByteString::FromUnicode(name);
    520     ByteString csBValue = pField->GetStringFor("V");
    521     WideString csWValue = PDF_DecodeText(csBValue);
    522     ByteString csValue_b = ByteString::FromUnicode(csWValue);
    523 
    524     fdfEncodedData << name_b.GetBuffer(name_b.GetLength());
    525     name_b.ReleaseBuffer(name_b.GetStringLength());
    526     fdfEncodedData << "=";
    527     fdfEncodedData << csValue_b.GetBuffer(csValue_b.GetLength());
    528     csValue_b.ReleaseBuffer(csValue_b.GetStringLength());
    529     if (i != pFields->GetCount() - 1)
    530       fdfEncodedData << "&";
    531   }
    532 
    533   nBufSize = fdfEncodedData.tellp();
    534   if (nBufSize == 0)
    535     return false;
    536 
    537   pBuf = FX_Alloc(uint8_t, nBufSize);
    538   memcpy(pBuf, fdfEncodedData.str().c_str(), nBufSize);
    539   return true;
    540 }
    541 
    542 ByteString CPDFSDK_InterForm::ExportFieldsToFDFTextBuf(
    543     const std::vector<CPDF_FormField*>& fields,
    544     bool bIncludeOrExclude) {
    545   std::unique_ptr<CFDF_Document> pFDF = m_pInterForm->ExportToFDF(
    546       m_pFormFillEnv->JS_docGetFilePath(), fields, bIncludeOrExclude, false);
    547 
    548   return pFDF ? pFDF->WriteToString() : ByteString();
    549 }
    550 
    551 bool CPDFSDK_InterForm::SubmitForm(const WideString& sDestination,
    552                                    bool bUrlEncoded) {
    553   if (sDestination.IsEmpty())
    554     return false;
    555 
    556   if (!m_pFormFillEnv || !m_pInterForm)
    557     return false;
    558 
    559   std::unique_ptr<CFDF_Document> pFDFDoc =
    560       m_pInterForm->ExportToFDF(m_pFormFillEnv->JS_docGetFilePath(), false);
    561   if (!pFDFDoc)
    562     return false;
    563 
    564   ByteString fdfBuffer = pFDFDoc->WriteToString();
    565 
    566   if (fdfBuffer.IsEmpty())
    567     return false;
    568 
    569   uint8_t* pLocalBuffer = FX_Alloc(uint8_t, fdfBuffer.GetLength());
    570   memcpy(pLocalBuffer, fdfBuffer.c_str(), fdfBuffer.GetLength());
    571   uint8_t* pBuffer = pLocalBuffer;
    572 
    573   size_t nBufSize = fdfBuffer.GetLength();
    574   if (bUrlEncoded && !FDFToURLEncodedData(pBuffer, nBufSize)) {
    575     FX_Free(pLocalBuffer);
    576     return false;
    577   }
    578 
    579   m_pFormFillEnv->JS_docSubmitForm(pBuffer, nBufSize, sDestination.c_str());
    580 
    581   if (pBuffer != pLocalBuffer)
    582     FX_Free(pBuffer);
    583 
    584   FX_Free(pLocalBuffer);
    585 
    586   return true;
    587 }
    588 
    589 ByteString CPDFSDK_InterForm::ExportFormToFDFTextBuf() {
    590   std::unique_ptr<CFDF_Document> pFDF =
    591       m_pInterForm->ExportToFDF(m_pFormFillEnv->JS_docGetFilePath(), false);
    592 
    593   return pFDF ? pFDF->WriteToString() : ByteString();
    594 }
    595 
    596 bool CPDFSDK_InterForm::DoAction_ResetForm(const CPDF_Action& action) {
    597   ASSERT(action.GetDict());
    598 
    599   CPDF_Dictionary* pActionDict = action.GetDict();
    600   if (!pActionDict->KeyExist("Fields"))
    601     return m_pInterForm->ResetForm(true);
    602 
    603   CPDF_ActionFields af(&action);
    604   uint32_t dwFlags = action.GetFlags();
    605 
    606   std::vector<CPDF_Object*> fieldObjects = af.GetAllFields();
    607   std::vector<CPDF_FormField*> fields = GetFieldFromObjects(fieldObjects);
    608   return m_pInterForm->ResetForm(fields, !(dwFlags & 0x01), true);
    609 }
    610 
    611 bool CPDFSDK_InterForm::DoAction_ImportData(const CPDF_Action& action) {
    612   return false;
    613 }
    614 
    615 std::vector<CPDF_FormField*> CPDFSDK_InterForm::GetFieldFromObjects(
    616     const std::vector<CPDF_Object*>& objects) const {
    617   std::vector<CPDF_FormField*> fields;
    618   for (CPDF_Object* pObject : objects) {
    619     if (pObject && pObject->IsString()) {
    620       WideString csName = pObject->GetUnicodeText();
    621       CPDF_FormField* pField = m_pInterForm->GetField(0, csName);
    622       if (pField)
    623         fields.push_back(pField);
    624     }
    625   }
    626   return fields;
    627 }
    628 
    629 int CPDFSDK_InterForm::BeforeValueChange(CPDF_FormField* pField,
    630                                          const WideString& csValue) {
    631   FormFieldType fieldType = pField->GetFieldType();
    632   if (!IsFormFieldTypeComboOrText(fieldType))
    633     return 0;
    634 
    635   if (!OnKeyStrokeCommit(pField, csValue))
    636     return -1;
    637 
    638   if (!OnValidate(pField, csValue))
    639     return -1;
    640 
    641   return 1;
    642 }
    643 
    644 void CPDFSDK_InterForm::AfterValueChange(CPDF_FormField* pField) {
    645 #ifdef PDF_ENABLE_XFA
    646   SynchronizeField(pField, false);
    647 #endif  // PDF_ENABLE_XFA
    648   FormFieldType fieldType = pField->GetFieldType();
    649   if (IsFormFieldTypeComboOrText(fieldType)) {
    650     OnCalculate(pField);
    651     bool bFormatted = false;
    652     WideString sValue = OnFormat(pField, bFormatted);
    653     ResetFieldAppearance(pField, bFormatted ? &sValue : nullptr, true);
    654     UpdateField(pField);
    655   }
    656 }
    657 
    658 int CPDFSDK_InterForm::BeforeSelectionChange(CPDF_FormField* pField,
    659                                              const WideString& csValue) {
    660   if (pField->GetFieldType() != FormFieldType::kListBox)
    661     return 0;
    662 
    663   if (!OnKeyStrokeCommit(pField, csValue))
    664     return -1;
    665 
    666   if (!OnValidate(pField, csValue))
    667     return -1;
    668 
    669   return 1;
    670 }
    671 
    672 void CPDFSDK_InterForm::AfterSelectionChange(CPDF_FormField* pField) {
    673   if (pField->GetFieldType() != FormFieldType::kListBox)
    674     return;
    675 
    676   OnCalculate(pField);
    677   ResetFieldAppearance(pField, nullptr, true);
    678   UpdateField(pField);
    679 }
    680 
    681 void CPDFSDK_InterForm::AfterCheckedStatusChange(CPDF_FormField* pField) {
    682   FormFieldType fieldType = pField->GetFieldType();
    683   if (fieldType != FormFieldType::kCheckBox &&
    684       fieldType != FormFieldType::kRadioButton)
    685     return;
    686 
    687   OnCalculate(pField);
    688   UpdateField(pField);
    689 }
    690 
    691 int CPDFSDK_InterForm::BeforeFormReset(CPDF_InterForm* pForm) {
    692   return 0;
    693 }
    694 
    695 void CPDFSDK_InterForm::AfterFormReset(CPDF_InterForm* pForm) {
    696   OnCalculate(nullptr);
    697 }
    698 
    699 int CPDFSDK_InterForm::BeforeFormImportData(CPDF_InterForm* pForm) {
    700   return 0;
    701 }
    702 
    703 void CPDFSDK_InterForm::AfterFormImportData(CPDF_InterForm* pForm) {
    704   OnCalculate(nullptr);
    705 }
    706 
    707 bool CPDFSDK_InterForm::IsNeedHighLight(FormFieldType fieldType) {
    708   if (fieldType == FormFieldType::kUnknown)
    709     return false;
    710 
    711 #ifdef PDF_ENABLE_XFA
    712   // For the XFA fields, we need to return if the specific field type has
    713   // highlight enabled or if the general XFA field type has it enabled.
    714   if (IsFormFieldTypeXFA(fieldType)) {
    715     if (!m_NeedsHighlight[static_cast<size_t>(fieldType)])
    716       return m_NeedsHighlight[static_cast<size_t>(FormFieldType::kXFA)];
    717   }
    718 #endif  // PDF_ENABLE_XFA
    719   return m_NeedsHighlight[static_cast<size_t>(fieldType)];
    720 }
    721 
    722 void CPDFSDK_InterForm::RemoveAllHighLights() {
    723   std::fill(m_HighlightColor, m_HighlightColor + kFormFieldTypeCount,
    724             FXSYS_RGB(255, 255, 255));
    725   std::fill(m_NeedsHighlight, m_NeedsHighlight + kFormFieldTypeCount, false);
    726 }
    727 
    728 void CPDFSDK_InterForm::SetHighlightColor(FX_COLORREF clr,
    729                                           FormFieldType fieldType) {
    730   if (fieldType == FormFieldType::kUnknown)
    731     return;
    732 
    733   m_HighlightColor[static_cast<size_t>(fieldType)] = clr;
    734   m_NeedsHighlight[static_cast<size_t>(fieldType)] = true;
    735 }
    736 
    737 void CPDFSDK_InterForm::SetAllHighlightColors(FX_COLORREF clr) {
    738   for (auto type : kFormFieldTypes) {
    739     m_HighlightColor[static_cast<size_t>(type)] = clr;
    740     m_NeedsHighlight[static_cast<size_t>(type)] = true;
    741   }
    742 }
    743 
    744 FX_COLORREF CPDFSDK_InterForm::GetHighlightColor(FormFieldType fieldType) {
    745   if (fieldType == FormFieldType::kUnknown)
    746     return FXSYS_RGB(255, 255, 255);
    747 
    748 #ifdef PDF_ENABLE_XFA
    749   // For the XFA fields, we need to return the specific field type highlight
    750   // colour or the general XFA field type colour if present.
    751   if (IsFormFieldTypeXFA(fieldType)) {
    752     if (!m_NeedsHighlight[static_cast<size_t>(fieldType)] &&
    753         m_NeedsHighlight[static_cast<size_t>(FormFieldType::kXFA)]) {
    754       return m_HighlightColor[static_cast<size_t>(FormFieldType::kXFA)];
    755     }
    756   }
    757 #endif  // PDF_ENABLE_XFA
    758   return m_HighlightColor[static_cast<size_t>(fieldType)];
    759 }
    760