Rename interform files to interactiveform.

Just rename the files in this CL.

Change-Id: I39f7fefa885977fffab6c909762b05484a1c923d
Reviewed-on: https://pdfium-review.googlesource.com/c/43814
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/fpdfsdk/cpdfsdk_interactiveform.cpp b/fpdfsdk/cpdfsdk_interactiveform.cpp
new file mode 100644
index 0000000..843d1e9
--- /dev/null
+++ b/fpdfsdk/cpdfsdk_interactiveform.cpp
@@ -0,0 +1,672 @@
+// Copyright 2016 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "fpdfsdk/cpdfsdk_interactiveform.h"
+
+#include <algorithm>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "core/fpdfapi/page/cpdf_page.h"
+#include "core/fpdfapi/parser/cfdf_document.h"
+#include "core/fpdfapi/parser/cpdf_array.h"
+#include "core/fpdfapi/parser/cpdf_dictionary.h"
+#include "core/fpdfapi/parser/cpdf_document.h"
+#include "core/fpdfapi/parser/cpdf_stream.h"
+#include "core/fpdfdoc/cpdf_actionfields.h"
+#include "core/fpdfdoc/cpdf_interactiveform.h"
+#include "core/fxcrt/autorestorer.h"
+#include "core/fxge/cfx_graphstatedata.h"
+#include "core/fxge/cfx_pathdata.h"
+#include "fpdfsdk/cpdfsdk_actionhandler.h"
+#include "fpdfsdk/cpdfsdk_annot.h"
+#include "fpdfsdk/cpdfsdk_annotiterator.h"
+#include "fpdfsdk/cpdfsdk_formfillenvironment.h"
+#include "fpdfsdk/cpdfsdk_helpers.h"
+#include "fpdfsdk/cpdfsdk_pageview.h"
+#include "fpdfsdk/cpdfsdk_widget.h"
+#include "fpdfsdk/formfiller/cffl_formfiller.h"
+#include "fpdfsdk/ipdfsdk_annothandler.h"
+#include "fxjs/ijs_event_context.h"
+#include "fxjs/ijs_runtime.h"
+#include "third_party/base/ptr_util.h"
+#include "third_party/base/stl_util.h"
+
+#ifdef PDF_ENABLE_XFA
+#include "fpdfsdk/cpdfsdk_xfawidget.h"
+#include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
+#include "fpdfsdk/fpdfxfa/cxfa_fwladaptertimermgr.h"
+#include "xfa/fxfa/cxfa_eventparam.h"
+#include "xfa/fxfa/cxfa_ffdocview.h"
+#include "xfa/fxfa/cxfa_ffwidget.h"
+#include "xfa/fxfa/cxfa_ffwidgethandler.h"
+#endif  // PDF_ENABLE_XFA
+
+namespace {
+
+constexpr uint32_t kWhiteBGR = FXSYS_BGR(255, 255, 255);
+
+bool IsFormFieldTypeComboOrText(FormFieldType fieldType) {
+  switch (fieldType) {
+    case FormFieldType::kComboBox:
+    case FormFieldType::kTextField:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#ifdef PDF_ENABLE_XFA
+bool IsFormFieldTypeXFA(FormFieldType fieldType) {
+  switch (fieldType) {
+    case FormFieldType::kXFA:
+    case FormFieldType::kXFA_CheckBox:
+    case FormFieldType::kXFA_ComboBox:
+    case FormFieldType::kXFA_ImageField:
+    case FormFieldType::kXFA_ListBox:
+    case FormFieldType::kXFA_PushButton:
+    case FormFieldType::kXFA_Signature:
+    case FormFieldType::kXFA_TextField:
+      return true;
+    default:
+      return false;
+  }
+}
+#endif  // PDF_ENABLE_XFA
+
+bool FDFToURLEncodedData(std::vector<uint8_t>* pBuffer) {
+  std::unique_ptr<CFDF_Document> pFDF = CFDF_Document::ParseMemory(*pBuffer);
+  if (!pFDF)
+    return true;
+
+  CPDF_Dictionary* pMainDict = pFDF->GetRoot()->GetDictFor("FDF");
+  if (!pMainDict)
+    return false;
+
+  CPDF_Array* pFields = pMainDict->GetArrayFor("Fields");
+  if (!pFields)
+    return false;
+
+  std::ostringstream fdfEncodedData;
+  for (uint32_t i = 0; i < pFields->GetCount(); i++) {
+    CPDF_Dictionary* pField = pFields->GetDictAt(i);
+    if (!pField)
+      continue;
+    WideString name;
+    name = pField->GetUnicodeTextFor("T");
+    ByteString name_b = name.ToDefANSI();
+    ByteString csBValue = pField->GetStringFor("V");
+    WideString csWValue = PDF_DecodeText(csBValue);
+    ByteString csValue_b = csWValue.ToDefANSI();
+    fdfEncodedData << name_b << "=" << csValue_b;
+    if (i != pFields->GetCount() - 1)
+      fdfEncodedData << "&";
+  }
+
+  size_t nBufSize = fdfEncodedData.tellp();
+  if (nBufSize <= 0)
+    return false;
+
+  pBuffer->resize(nBufSize);
+  memcpy(pBuffer->data(), fdfEncodedData.str().c_str(), nBufSize);
+  return true;
+}
+
+}  // namespace
+
+CPDFSDK_InterForm::CPDFSDK_InterForm(CPDFSDK_FormFillEnvironment* pFormFillEnv)
+    : m_pFormFillEnv(pFormFillEnv),
+      m_pInterForm(pdfium::MakeUnique<CPDF_InterForm>(
+          m_pFormFillEnv->GetPDFDocument())) {
+  ASSERT(m_pFormFillEnv);
+  m_pInterForm->SetFormNotify(this);
+  RemoveAllHighLights();
+}
+
+CPDFSDK_InterForm::~CPDFSDK_InterForm() {
+  m_Map.clear();
+#ifdef PDF_ENABLE_XFA
+  m_XFAMap.clear();
+#endif  // PDF_ENABLE_XFA
+}
+
+CPDFSDK_Widget* CPDFSDK_InterForm::GetSibling(CPDFSDK_Widget* pWidget,
+                                              bool bNext) const {
+  auto pIterator = pdfium::MakeUnique<CPDFSDK_AnnotIterator>(
+      pWidget->GetPageView(), CPDF_Annot::Subtype::WIDGET);
+
+  return ToCPDFSDKWidget(bNext ? pIterator->GetNextAnnot(pWidget)
+                               : pIterator->GetPrevAnnot(pWidget));
+}
+
+CPDFSDK_Widget* CPDFSDK_InterForm::GetWidget(CPDF_FormControl* pControl) const {
+  if (!pControl)
+    return nullptr;
+
+  CPDFSDK_Widget* pWidget = nullptr;
+  const auto it = m_Map.find(pControl);
+  if (it != m_Map.end())
+    pWidget = it->second;
+  if (pWidget)
+    return pWidget;
+
+  CPDF_Dictionary* pControlDict = pControl->GetWidget();
+  CPDF_Document* pDocument = m_pFormFillEnv->GetPDFDocument();
+  CPDFSDK_PageView* pPage = nullptr;
+
+  if (CPDF_Dictionary* pPageDict = pControlDict->GetDictFor("P")) {
+    int nPageIndex = pDocument->GetPageIndex(pPageDict->GetObjNum());
+    if (nPageIndex >= 0)
+      pPage = m_pFormFillEnv->GetPageView(nPageIndex);
+  }
+
+  if (!pPage) {
+    int nPageIndex = GetPageIndexByAnnotDict(pDocument, pControlDict);
+    if (nPageIndex >= 0)
+      pPage = m_pFormFillEnv->GetPageView(nPageIndex);
+  }
+
+  return pPage ? ToCPDFSDKWidget(pPage->GetAnnotByDict(pControlDict)) : nullptr;
+}
+
+void CPDFSDK_InterForm::GetWidgets(
+    const WideString& sFieldName,
+    std::vector<CPDFSDK_Annot::ObservedPtr>* widgets) const {
+  for (int i = 0, sz = m_pInterForm->CountFields(sFieldName); i < sz; ++i) {
+    CPDF_FormField* pFormField = m_pInterForm->GetField(i, sFieldName);
+    ASSERT(pFormField);
+    GetWidgets(pFormField, widgets);
+  }
+}
+
+void CPDFSDK_InterForm::GetWidgets(
+    CPDF_FormField* pField,
+    std::vector<CPDFSDK_Annot::ObservedPtr>* widgets) const {
+  for (int i = 0, sz = pField->CountControls(); i < sz; ++i) {
+    CPDF_FormControl* pFormCtrl = pField->GetControl(i);
+    ASSERT(pFormCtrl);
+    CPDFSDK_Widget* pWidget = GetWidget(pFormCtrl);
+    if (pWidget)
+      widgets->emplace_back(pWidget);
+  }
+}
+
+int CPDFSDK_InterForm::GetPageIndexByAnnotDict(
+    CPDF_Document* pDocument,
+    CPDF_Dictionary* pAnnotDict) const {
+  ASSERT(pAnnotDict);
+
+  for (int i = 0, sz = pDocument->GetPageCount(); i < sz; i++) {
+    if (CPDF_Dictionary* pPageDict = pDocument->GetPageDictionary(i)) {
+      if (CPDF_Array* pAnnots = pPageDict->GetArrayFor("Annots")) {
+        for (int j = 0, jsz = pAnnots->GetCount(); j < jsz; j++) {
+          CPDF_Object* pDict = pAnnots->GetDirectObjectAt(j);
+          if (pAnnotDict == pDict)
+            return i;
+        }
+      }
+    }
+  }
+
+  return -1;
+}
+
+void CPDFSDK_InterForm::AddMap(CPDF_FormControl* pControl,
+                               CPDFSDK_Widget* pWidget) {
+  m_Map[pControl] = pWidget;
+}
+
+void CPDFSDK_InterForm::RemoveMap(CPDF_FormControl* pControl) {
+  m_Map.erase(pControl);
+}
+
+void CPDFSDK_InterForm::EnableCalculate(bool bEnabled) {
+  m_bCalculate = bEnabled;
+}
+
+bool CPDFSDK_InterForm::IsCalculateEnabled() const {
+  return m_bCalculate;
+}
+
+#ifdef PDF_ENABLE_XFA
+void CPDFSDK_InterForm::AddXFAMap(CXFA_FFWidget* hWidget,
+                                  CPDFSDK_XFAWidget* pWidget) {
+  ASSERT(hWidget);
+  m_XFAMap[hWidget] = pWidget;
+}
+
+void CPDFSDK_InterForm::RemoveXFAMap(CXFA_FFWidget* hWidget) {
+  ASSERT(hWidget);
+  m_XFAMap.erase(hWidget);
+}
+
+CPDFSDK_XFAWidget* CPDFSDK_InterForm::GetXFAWidget(CXFA_FFWidget* hWidget) {
+  ASSERT(hWidget);
+  auto it = m_XFAMap.find(hWidget);
+  return it != m_XFAMap.end() ? it->second : nullptr;
+}
+
+void CPDFSDK_InterForm::XfaEnableCalculate(bool bEnabled) {
+  m_bXfaCalculate = bEnabled;
+}
+bool CPDFSDK_InterForm::IsXfaCalculateEnabled() const {
+  return m_bXfaCalculate;
+}
+
+bool CPDFSDK_InterForm::IsXfaValidationsEnabled() {
+  return m_bXfaValidationsEnabled;
+}
+void CPDFSDK_InterForm::XfaSetValidationsEnabled(bool bEnabled) {
+  m_bXfaValidationsEnabled = bEnabled;
+}
+
+void CPDFSDK_InterForm::SynchronizeField(CPDF_FormField* pFormField) {
+  for (int i = 0, sz = pFormField->CountControls(); i < sz; i++) {
+    CPDF_FormControl* pFormCtrl = pFormField->GetControl(i);
+    if (CPDFSDK_Widget* pWidget = GetWidget(pFormCtrl))
+      pWidget->Synchronize(false);
+  }
+}
+#endif  // PDF_ENABLE_XFA
+
+void CPDFSDK_InterForm::OnCalculate(CPDF_FormField* pFormField) {
+  if (!m_pFormFillEnv->IsJSPlatformPresent())
+    return;
+
+  if (m_bBusy)
+    return;
+
+  AutoRestorer<bool> restorer(&m_bBusy);
+  m_bBusy = true;
+
+  if (!IsCalculateEnabled())
+    return;
+
+  IJS_Runtime* pRuntime = m_pFormFillEnv->GetIJSRuntime();
+  int nSize = m_pInterForm->CountFieldsInCalculationOrder();
+  for (int i = 0; i < nSize; i++) {
+    CPDF_FormField* pField = m_pInterForm->GetFieldInCalculationOrder(i);
+    if (!pField)
+      continue;
+
+    FormFieldType fieldType = pField->GetFieldType();
+    if (!IsFormFieldTypeComboOrText(fieldType))
+      continue;
+
+    CPDF_AAction aAction = pField->GetAdditionalAction();
+    if (!aAction.GetDict() || !aAction.ActionExist(CPDF_AAction::Calculate))
+      continue;
+
+    CPDF_Action action = aAction.GetAction(CPDF_AAction::Calculate);
+    if (!action.GetDict())
+      continue;
+
+    WideString csJS = action.GetJavaScript();
+    if (csJS.IsEmpty())
+      continue;
+
+    WideString sOldValue = pField->GetValue();
+    WideString sValue = sOldValue;
+    bool bRC = true;
+    IJS_Runtime::ScopedEventContext pContext(pRuntime);
+    pContext->OnField_Calculate(pFormField, pField, &sValue, &bRC);
+
+    Optional<IJS_Runtime::JS_Error> err = pContext->RunScript(csJS);
+    if (!err && bRC && sValue.Compare(sOldValue) != 0)
+      pField->SetValue(sValue, NotificationOption::kNotify);
+  }
+}
+
+Optional<WideString> CPDFSDK_InterForm::OnFormat(CPDF_FormField* pFormField) {
+  if (!m_pFormFillEnv->IsJSPlatformPresent())
+    return {};
+
+  WideString sValue = pFormField->GetValue();
+  IJS_Runtime* pRuntime = m_pFormFillEnv->GetIJSRuntime();
+  if (pFormField->GetFieldType() == FormFieldType::kComboBox &&
+      pFormField->CountSelectedItems() > 0) {
+    int index = pFormField->GetSelectedIndex(0);
+    if (index >= 0)
+      sValue = pFormField->GetOptionLabel(index);
+  }
+
+  CPDF_AAction aAction = pFormField->GetAdditionalAction();
+  if (aAction.GetDict() && aAction.ActionExist(CPDF_AAction::Format)) {
+    CPDF_Action action = aAction.GetAction(CPDF_AAction::Format);
+    if (action.GetDict()) {
+      WideString script = action.GetJavaScript();
+      if (!script.IsEmpty()) {
+        IJS_Runtime::ScopedEventContext pContext(pRuntime);
+        pContext->OnField_Format(pFormField, &sValue, true);
+        Optional<IJS_Runtime::JS_Error> err = pContext->RunScript(script);
+        if (!err)
+          return sValue;
+      }
+    }
+  }
+  return {};
+}
+
+void CPDFSDK_InterForm::ResetFieldAppearance(CPDF_FormField* pFormField,
+                                             Optional<WideString> sValue,
+                                             bool bValueChanged) {
+  for (int i = 0, sz = pFormField->CountControls(); i < sz; i++) {
+    CPDF_FormControl* pFormCtrl = pFormField->GetControl(i);
+    ASSERT(pFormCtrl);
+    if (CPDFSDK_Widget* pWidget = GetWidget(pFormCtrl))
+      pWidget->ResetAppearance(sValue, bValueChanged);
+  }
+}
+
+void CPDFSDK_InterForm::UpdateField(CPDF_FormField* pFormField) {
+  auto* formfiller = m_pFormFillEnv->GetInteractiveFormFiller();
+  for (int i = 0, sz = pFormField->CountControls(); i < sz; i++) {
+    CPDF_FormControl* pFormCtrl = pFormField->GetControl(i);
+    ASSERT(pFormCtrl);
+
+    CPDFSDK_Widget* pWidget = GetWidget(pFormCtrl);
+    if (!pWidget)
+      continue;
+
+    IPDF_Page* pPage = pWidget->GetPage();
+    FX_RECT rect = formfiller->GetViewBBox(
+        m_pFormFillEnv->GetPageView(pPage, false), pWidget);
+    m_pFormFillEnv->Invalidate(pPage, rect);
+  }
+}
+
+bool CPDFSDK_InterForm::OnKeyStrokeCommit(CPDF_FormField* pFormField,
+                                          const WideString& csValue) {
+  CPDF_AAction aAction = pFormField->GetAdditionalAction();
+  if (!aAction.GetDict() || !aAction.ActionExist(CPDF_AAction::KeyStroke))
+    return true;
+
+  CPDF_Action action = aAction.GetAction(CPDF_AAction::KeyStroke);
+  if (!action.GetDict())
+    return true;
+
+  CPDFSDK_FieldAction fa;
+  fa.bModifier = false;
+  fa.bShift = false;
+  fa.sValue = csValue;
+  m_pFormFillEnv->GetActionHandler()->DoAction_FieldJavaScript(
+      action, CPDF_AAction::KeyStroke, m_pFormFillEnv.Get(), pFormField, &fa);
+  return fa.bRC;
+}
+
+bool CPDFSDK_InterForm::OnValidate(CPDF_FormField* pFormField,
+                                   const WideString& csValue) {
+  CPDF_AAction aAction = pFormField->GetAdditionalAction();
+  if (!aAction.GetDict() || !aAction.ActionExist(CPDF_AAction::Validate))
+    return true;
+
+  CPDF_Action action = aAction.GetAction(CPDF_AAction::Validate);
+  if (!action.GetDict())
+    return true;
+
+  CPDFSDK_FieldAction fa;
+  fa.bModifier = false;
+  fa.bShift = false;
+  fa.sValue = csValue;
+  m_pFormFillEnv->GetActionHandler()->DoAction_FieldJavaScript(
+      action, CPDF_AAction::Validate, m_pFormFillEnv.Get(), pFormField, &fa);
+  return fa.bRC;
+}
+
+bool CPDFSDK_InterForm::DoAction_Hide(const CPDF_Action& action) {
+  ASSERT(action.GetDict());
+
+  CPDF_ActionFields af(&action);
+  std::vector<const CPDF_Object*> fieldObjects = af.GetAllFields();
+  std::vector<CPDF_FormField*> fields = GetFieldFromObjects(fieldObjects);
+
+  bool bHide = action.GetHideStatus();
+  bool bChanged = false;
+
+  for (CPDF_FormField* pField : fields) {
+    for (int i = 0, sz = pField->CountControls(); i < sz; ++i) {
+      CPDF_FormControl* pControl = pField->GetControl(i);
+      ASSERT(pControl);
+
+      if (CPDFSDK_Widget* pWidget = GetWidget(pControl)) {
+        uint32_t nFlags = pWidget->GetFlags();
+        nFlags &= ~ANNOTFLAG_INVISIBLE;
+        nFlags &= ~ANNOTFLAG_NOVIEW;
+        if (bHide)
+          nFlags |= ANNOTFLAG_HIDDEN;
+        else
+          nFlags &= ~ANNOTFLAG_HIDDEN;
+        pWidget->SetFlags(nFlags);
+        pWidget->GetPageView()->UpdateView(pWidget);
+        bChanged = true;
+      }
+    }
+  }
+
+  return bChanged;
+}
+
+bool CPDFSDK_InterForm::DoAction_SubmitForm(const CPDF_Action& action) {
+  WideString sDestination = action.GetFilePath();
+  if (sDestination.IsEmpty())
+    return false;
+
+  const CPDF_Dictionary* pActionDict = action.GetDict();
+  if (pActionDict->KeyExist("Fields")) {
+    CPDF_ActionFields af(&action);
+    uint32_t dwFlags = action.GetFlags();
+    std::vector<const CPDF_Object*> fieldObjects = af.GetAllFields();
+    std::vector<CPDF_FormField*> fields = GetFieldFromObjects(fieldObjects);
+    if (!fields.empty()) {
+      bool bIncludeOrExclude = !(dwFlags & 0x01);
+      if (!m_pInterForm->CheckRequiredFields(&fields, bIncludeOrExclude))
+        return false;
+
+      return SubmitFields(sDestination, fields, bIncludeOrExclude, false);
+    }
+  }
+  if (!m_pInterForm->CheckRequiredFields(nullptr, true))
+    return false;
+
+  return SubmitForm(sDestination, false);
+}
+
+bool CPDFSDK_InterForm::SubmitFields(const WideString& csDestination,
+                                     const std::vector<CPDF_FormField*>& fields,
+                                     bool bIncludeOrExclude,
+                                     bool bUrlEncoded) {
+  ByteString textBuf = ExportFieldsToFDFTextBuf(fields, bIncludeOrExclude);
+  if (textBuf.IsEmpty())
+    return false;
+
+  std::vector<uint8_t> buffer(textBuf.begin(), textBuf.end());
+  if (bUrlEncoded && !FDFToURLEncodedData(&buffer))
+    return false;
+
+  m_pFormFillEnv->JS_docSubmitForm(buffer.data(), buffer.size(), csDestination);
+  return true;
+}
+
+ByteString CPDFSDK_InterForm::ExportFieldsToFDFTextBuf(
+    const std::vector<CPDF_FormField*>& fields,
+    bool bIncludeOrExclude) {
+  std::unique_ptr<CFDF_Document> pFDF = m_pInterForm->ExportToFDF(
+      m_pFormFillEnv->JS_docGetFilePath(), fields, bIncludeOrExclude, false);
+
+  return pFDF ? pFDF->WriteToString() : ByteString();
+}
+
+bool CPDFSDK_InterForm::SubmitForm(const WideString& sDestination,
+                                   bool bUrlEncoded) {
+  if (sDestination.IsEmpty())
+    return false;
+
+  std::unique_ptr<CFDF_Document> pFDFDoc =
+      m_pInterForm->ExportToFDF(m_pFormFillEnv->JS_docGetFilePath(), false);
+  if (!pFDFDoc)
+    return false;
+
+  ByteString fdfBuffer = pFDFDoc->WriteToString();
+  if (fdfBuffer.IsEmpty())
+    return false;
+
+  std::vector<uint8_t> buffer(fdfBuffer.begin(), fdfBuffer.end());
+  if (bUrlEncoded && !FDFToURLEncodedData(&buffer))
+    return false;
+
+  m_pFormFillEnv->JS_docSubmitForm(buffer.data(), buffer.size(), sDestination);
+  return true;
+}
+
+ByteString CPDFSDK_InterForm::ExportFormToFDFTextBuf() {
+  std::unique_ptr<CFDF_Document> pFDF =
+      m_pInterForm->ExportToFDF(m_pFormFillEnv->JS_docGetFilePath(), false);
+
+  return pFDF ? pFDF->WriteToString() : ByteString();
+}
+
+void CPDFSDK_InterForm::DoAction_ResetForm(const CPDF_Action& action) {
+  ASSERT(action.GetDict());
+  const CPDF_Dictionary* pActionDict = action.GetDict();
+  if (!pActionDict->KeyExist("Fields")) {
+    m_pInterForm->ResetForm(NotificationOption::kNotify);
+    return;
+  }
+  CPDF_ActionFields af(&action);
+  uint32_t dwFlags = action.GetFlags();
+  std::vector<const CPDF_Object*> fieldObjects = af.GetAllFields();
+  std::vector<CPDF_FormField*> fields = GetFieldFromObjects(fieldObjects);
+  m_pInterForm->ResetForm(fields, !(dwFlags & 0x01),
+                          NotificationOption::kNotify);
+}
+
+std::vector<CPDF_FormField*> CPDFSDK_InterForm::GetFieldFromObjects(
+    const std::vector<const CPDF_Object*>& objects) const {
+  std::vector<CPDF_FormField*> fields;
+  for (const CPDF_Object* pObject : objects) {
+    if (!pObject || !pObject->IsString())
+      continue;
+
+    WideString csName = pObject->GetUnicodeText();
+    CPDF_FormField* pField = m_pInterForm->GetField(0, csName);
+    if (pField)
+      fields.push_back(pField);
+  }
+  return fields;
+}
+
+bool CPDFSDK_InterForm::BeforeValueChange(CPDF_FormField* pField,
+                                          const WideString& csValue) {
+  FormFieldType fieldType = pField->GetFieldType();
+  if (!IsFormFieldTypeComboOrText(fieldType))
+    return true;
+  if (!OnKeyStrokeCommit(pField, csValue))
+    return false;
+  return OnValidate(pField, csValue);
+}
+
+void CPDFSDK_InterForm::AfterValueChange(CPDF_FormField* pField) {
+#ifdef PDF_ENABLE_XFA
+  SynchronizeField(pField);
+#endif  // PDF_ENABLE_XFA
+
+  FormFieldType fieldType = pField->GetFieldType();
+  if (!IsFormFieldTypeComboOrText(fieldType))
+    return;
+
+  OnCalculate(pField);
+  ResetFieldAppearance(pField, OnFormat(pField), true);
+  UpdateField(pField);
+}
+
+bool CPDFSDK_InterForm::BeforeSelectionChange(CPDF_FormField* pField,
+                                              const WideString& csValue) {
+  if (pField->GetFieldType() != FormFieldType::kListBox)
+    return true;
+  if (!OnKeyStrokeCommit(pField, csValue))
+    return false;
+  return OnValidate(pField, csValue);
+}
+
+void CPDFSDK_InterForm::AfterSelectionChange(CPDF_FormField* pField) {
+  if (pField->GetFieldType() != FormFieldType::kListBox)
+    return;
+
+  OnCalculate(pField);
+  ResetFieldAppearance(pField, pdfium::nullopt, true);
+  UpdateField(pField);
+}
+
+void CPDFSDK_InterForm::AfterCheckedStatusChange(CPDF_FormField* pField) {
+  FormFieldType fieldType = pField->GetFieldType();
+  if (fieldType != FormFieldType::kCheckBox &&
+      fieldType != FormFieldType::kRadioButton)
+    return;
+
+  OnCalculate(pField);
+  UpdateField(pField);
+}
+
+void CPDFSDK_InterForm::AfterFormReset(CPDF_InterForm* pForm) {
+  OnCalculate(nullptr);
+}
+
+bool CPDFSDK_InterForm::IsNeedHighLight(FormFieldType fieldType) const {
+  if (fieldType == FormFieldType::kUnknown)
+    return false;
+
+#ifdef PDF_ENABLE_XFA
+  // For the XFA fields, we need to return if the specific field type has
+  // highlight enabled or if the general XFA field type has it enabled.
+  if (IsFormFieldTypeXFA(fieldType)) {
+    if (!m_NeedsHighlight[static_cast<size_t>(fieldType)])
+      return m_NeedsHighlight[static_cast<size_t>(FormFieldType::kXFA)];
+  }
+#endif  // PDF_ENABLE_XFA
+  return m_NeedsHighlight[static_cast<size_t>(fieldType)];
+}
+
+void CPDFSDK_InterForm::RemoveAllHighLights() {
+  std::fill(m_HighlightColor, m_HighlightColor + kFormFieldTypeCount,
+            kWhiteBGR);
+  std::fill(m_NeedsHighlight, m_NeedsHighlight + kFormFieldTypeCount, false);
+}
+
+void CPDFSDK_InterForm::SetHighlightColor(FX_COLORREF clr,
+                                          FormFieldType fieldType) {
+  if (fieldType == FormFieldType::kUnknown)
+    return;
+
+  m_HighlightColor[static_cast<size_t>(fieldType)] = clr;
+  m_NeedsHighlight[static_cast<size_t>(fieldType)] = true;
+}
+
+void CPDFSDK_InterForm::SetAllHighlightColors(FX_COLORREF clr) {
+  for (auto type : kFormFieldTypes) {
+    m_HighlightColor[static_cast<size_t>(type)] = clr;
+    m_NeedsHighlight[static_cast<size_t>(type)] = true;
+  }
+}
+
+FX_COLORREF CPDFSDK_InterForm::GetHighlightColor(FormFieldType fieldType) {
+  if (fieldType == FormFieldType::kUnknown)
+    return kWhiteBGR;
+
+#ifdef PDF_ENABLE_XFA
+  // For the XFA fields, we need to return the specific field type highlight
+  // colour or the general XFA field type colour if present.
+  if (IsFormFieldTypeXFA(fieldType)) {
+    if (!m_NeedsHighlight[static_cast<size_t>(fieldType)] &&
+        m_NeedsHighlight[static_cast<size_t>(FormFieldType::kXFA)]) {
+      return m_HighlightColor[static_cast<size_t>(FormFieldType::kXFA)];
+    }
+  }
+#endif  // PDF_ENABLE_XFA
+  return m_HighlightColor[static_cast<size_t>(fieldType)];
+}