Add support for XFA specific FormField types

This adds to form field types specific types for XFA form fields to be
used instead of the generic XFA value when possible.

BUG=pdfium:952,chromium:763129,chromium:592758

Change-Id: I8d1cff6a280d71db348b7c31a251cbe2e398ec79
Reviewed-on: https://pdfium-review.googlesource.com/22677
Reviewed-by: dsinclair <dsinclair@chromium.org>
Commit-Queue: Ryan Harrison <rharrison@chromium.org>
diff --git a/core/fpdfdoc/cpdf_formfield.h b/core/fpdfdoc/cpdf_formfield.h
index 1f1205d..4f25465 100644
--- a/core/fpdfdoc/cpdf_formfield.h
+++ b/core/fpdfdoc/cpdf_formfield.h
@@ -28,26 +28,44 @@
   kTextField = 6,
   kSignature = 7,
 #ifdef PDF_ENABLE_XFA
-  kXFA = 8,  // Generic XFA field.
-#endif       // PDF_ENABLE_XFA
+  kXFA = 8,  // Generic XFA field, should use value below if possible.
+  kXFA_CheckBox = 9,
+  kXFA_ComboBox = 10,
+  kXFA_ImageField = 11,
+  kXFA_ListBox = 12,
+  kXFA_PushButton = 13,
+  kXFA_Signature = 14,
+  kXFA_TextField = 15
+#endif  // PDF_ENABLE_XFA
 };
 
 Optional<FormFieldType> IntToFormFieldType(int value);
 
 // If values are added to FormFieldType, these will need to be updated.
 #ifdef PDF_ENABLE_XFA
-constexpr size_t kFormFieldTypeCount = 9;
+constexpr size_t kFormFieldTypeCount = 16;
 #else
 constexpr size_t kFormFieldTypeCount = 8;
 #endif  // PDF_ENABLE_XFA
 
 constexpr FormFieldType kFormFieldTypes[kFormFieldTypeCount] = {
-    FormFieldType::kUnknown,   FormFieldType::kPushButton,
-    FormFieldType::kCheckBox,  FormFieldType::kRadioButton,
-    FormFieldType::kComboBox,  FormFieldType::kListBox,
-    FormFieldType::kTextField, FormFieldType::kSignature,
+    FormFieldType::kUnknown,
+    FormFieldType::kPushButton,
+    FormFieldType::kCheckBox,
+    FormFieldType::kRadioButton,
+    FormFieldType::kComboBox,
+    FormFieldType::kListBox,
+    FormFieldType::kTextField,
+    FormFieldType::kSignature,
 #ifdef PDF_ENABLE_XFA
     FormFieldType::kXFA,
+    FormFieldType::kXFA_CheckBox,
+    FormFieldType::kXFA_ComboBox,
+    FormFieldType::kXFA_ImageField,
+    FormFieldType::kXFA_ListBox,
+    FormFieldType::kXFA_PushButton,
+    FormFieldType::kXFA_Signature,
+    FormFieldType::kXFA_TextField
 #endif  // PDF_ENABLE_XFA
 };
 
diff --git a/fpdfsdk/cpdfsdk_interform.cpp b/fpdfsdk/cpdfsdk_interform.cpp
index 04ccc35..1aa1174 100644
--- a/fpdfsdk/cpdfsdk_interform.cpp
+++ b/fpdfsdk/cpdfsdk_interform.cpp
@@ -57,6 +57,24 @@
   }
 }
 
+#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
+
 }  // namespace
 
 CPDFSDK_InterForm::CPDFSDK_InterForm(CPDFSDK_FormFillEnvironment* pFormFillEnv)
@@ -691,6 +709,14 @@
   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)];
 }
 
@@ -720,5 +746,15 @@
   if (fieldType == FormFieldType::kUnknown)
     return FXSYS_RGB(255, 255, 255);
 
+#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)];
 }
diff --git a/fpdfsdk/fpdfformfill.cpp b/fpdfsdk/fpdfformfill.cpp
index cc2861f..10aecb3 100644
--- a/fpdfsdk/fpdfformfill.cpp
+++ b/fpdfsdk/fpdfformfill.cpp
@@ -71,6 +71,27 @@
 #ifdef PDF_ENABLE_XFA
 static_assert(static_cast<int>(FormFieldType::kXFA) == FPDF_FORMFIELD_XFA,
               "XFA form field types must match");
+static_assert(static_cast<int>(FormFieldType::kXFA_CheckBox) ==
+                  FPDF_FORMFIELD_XFA_CHECKBOX,
+              "XFA CheckBox form field types must match");
+static_assert(static_cast<int>(FormFieldType::kXFA_ComboBox) ==
+                  FPDF_FORMFIELD_XFA_COMBOBOX,
+              "XFA ComboBox form field types must match");
+static_assert(static_cast<int>(FormFieldType::kXFA_ImageField) ==
+                  FPDF_FORMFIELD_XFA_IMAGEFIELD,
+              "XFA ImageField form field types must match");
+static_assert(static_cast<int>(FormFieldType::kXFA_ListBox) ==
+                  FPDF_FORMFIELD_XFA_LISTBOX,
+              "XFA ListBox form field types must match");
+static_assert(static_cast<int>(FormFieldType::kXFA_PushButton) ==
+                  FPDF_FORMFIELD_XFA_PUSHBUTTON,
+              "XFA PushButton form field types must match");
+static_assert(static_cast<int>(FormFieldType::kXFA_Signature) ==
+                  FPDF_FORMFIELD_XFA_SIGNATURE,
+              "XFA Signature form field types must match");
+static_assert(static_cast<int>(FormFieldType::kXFA_TextField) ==
+                  FPDF_FORMFIELD_XFA_TEXTFIELD,
+              "XFA TextField form field types must match");
 #endif  // PDF_ENABLE_XFA
 static_assert(kFormFieldTypeCount == FPDF_FORMFIELD_COUNT,
               "Number of form field types must match");
@@ -238,7 +259,7 @@
     rcWidget.Inflate(1.0f, 1.0f);
     if (rcWidget.Contains(CFX_PointF(static_cast<float>(page_x),
                                      static_cast<float>(page_y)))) {
-      return static_cast<int>(FormFieldType::kXFA);
+      return static_cast<int>(pXFAAnnot->GetFormFieldType());
     }
   }
 #endif  // PDF_ENABLE_XFA
@@ -698,7 +719,7 @@
     return;
 
   Optional<FormFieldType> cast_input = IntToFormFieldType(fieldType);
-  if (!cast_input.has_value())
+  if (!cast_input)
     return;
 
   if (cast_input.value() == FormFieldType::kUnknown) {
diff --git a/public/fpdf_formfill.h b/public/fpdf_formfill.h
index e4cdaee..c2e2bd5 100644
--- a/public/fpdf_formfill.h
+++ b/public/fpdf_formfill.h
@@ -1453,13 +1453,31 @@
 #define FPDF_FORMFIELD_TEXTFIELD 6    // text field type.
 #define FPDF_FORMFIELD_SIGNATURE 7    // text field type.
 #ifdef PDF_ENABLE_XFA
-#define FPDF_FORMFIELD_XFA 8  // Generic XFA type.
-#endif                        // PDF_ENABLE_XFA
+#define FPDF_FORMFIELD_XFA 8              // Generic XFA type.
+#define FPDF_FORMFIELD_XFA_CHECKBOX 9     // XFA check box type.
+#define FPDF_FORMFIELD_XFA_COMBOBOX 10    // XFA combo box type.
+#define FPDF_FORMFIELD_XFA_IMAGEFIELD 11  // XFA image field type.
+#define FPDF_FORMFIELD_XFA_LISTBOX 12     // XFA list box type.
+#define FPDF_FORMFIELD_XFA_PUSHBUTTON 13  // XFA push button type.
+#define FPDF_FORMFIELD_XFA_SIGNATURE 14   // XFA signture field type.
+#define FPDF_FORMFIELD_XFA_TEXTFIELD 15   // XFA text field type.
+#endif                                    // PDF_ENABLE_XFA
 
 #ifndef PDF_ENABLE_XFA
 #define FPDF_FORMFIELD_COUNT 8
 #else
-#define FPDF_FORMFIELD_COUNT 9
+#define FPDF_FORMFIELD_COUNT 16
+#endif  // PDF_ENABLE_XFA
+
+#ifdef PDF_ENABLE_XFA
+#define IS_XFA_FORMFIELD(type)                                              \
+  ((type == FPDF_FORMFIELD_XFA) || (type == FPDF_FORMFIELD_XFA_CHECKBOX) || \
+   (type == FPDF_FORMFIELD_XFA_COMBOBOX) ||                                 \
+   (type == FPDF_FORMFIELD_XFA_IMAGEFIELD) ||                               \
+   (type == FPDF_FORMFIELD_XFA_LISTBOX) ||                                  \
+   (type == FPDF_FORMFIELD_XFA_PUSHBUTTON) ||                               \
+   (type == FPDF_FORMFIELD_XFA_SIGNATURE) ||                                \
+   (type == FPDF_FORMFIELD_XFA_TEXTFIELD))
 #endif  // PDF_ENABLE_XFA
 
 /**
diff --git a/xfa/fxfa/cxfa_ffcheckbutton.cpp b/xfa/fxfa/cxfa_ffcheckbutton.cpp
index 699f3fe..69b5d6f 100644
--- a/xfa/fxfa/cxfa_ffcheckbutton.cpp
+++ b/xfa/fxfa/cxfa_ffcheckbutton.cpp
@@ -344,3 +344,7 @@
                                       const CFX_Matrix& matrix) {
   m_pOldDelegate->OnDrawWidget(pGraphics, matrix);
 }
+
+FormFieldType CXFA_FFCheckButton::GetFormFieldType() {
+  return FormFieldType::kXFA_CheckBox;
+}
diff --git a/xfa/fxfa/cxfa_ffcheckbutton.h b/xfa/fxfa/cxfa_ffcheckbutton.h
index 9b469bd..f841d78 100644
--- a/xfa/fxfa/cxfa_ffcheckbutton.h
+++ b/xfa/fxfa/cxfa_ffcheckbutton.h
@@ -29,6 +29,7 @@
   void OnProcessEvent(CFWL_Event* pEvent) override;
   void OnDrawWidget(CXFA_Graphics* pGraphics,
                     const CFX_Matrix& matrix) override;
+  FormFieldType GetFormFieldType() override;
 
   void SetFWLCheckState(XFA_CHECKSTATE eCheckState);
 
diff --git a/xfa/fxfa/cxfa_ffcombobox.cpp b/xfa/fxfa/cxfa_ffcombobox.cpp
index 5d0792b..4c024fb 100644
--- a/xfa/fxfa/cxfa_ffcombobox.cpp
+++ b/xfa/fxfa/cxfa_ffcombobox.cpp
@@ -266,6 +266,10 @@
   ToComboBox(m_pNormalWidget.get())->EditDeSelect();
 }
 
+FormFieldType CXFA_FFComboBox::GetFormFieldType() {
+  return FormFieldType::kXFA_ComboBox;
+}
+
 void CXFA_FFComboBox::SetItemState(int32_t nIndex, bool bSelected) {
   ToComboBox(m_pNormalWidget.get())->SetCurSel(bSelected ? nIndex : -1);
   m_pNormalWidget->Update();
diff --git a/xfa/fxfa/cxfa_ffcombobox.h b/xfa/fxfa/cxfa_ffcombobox.h
index c4bf6e9..a20319e 100644
--- a/xfa/fxfa/cxfa_ffcombobox.h
+++ b/xfa/fxfa/cxfa_ffcombobox.h
@@ -35,6 +35,7 @@
   void SelectAll() override;
   void Delete() override;
   void DeSelect() override;
+  FormFieldType GetFormFieldType() override;
 
   // IFWL_WidgetDelegate
   void OnProcessMessage(CFWL_Message* pMessage) override;
diff --git a/xfa/fxfa/cxfa_ffimageedit.cpp b/xfa/fxfa/cxfa_ffimageedit.cpp
index 681370e..0e97559 100644
--- a/xfa/fxfa/cxfa_ffimageedit.cpp
+++ b/xfa/fxfa/cxfa_ffimageedit.cpp
@@ -147,3 +147,7 @@
                                     const CFX_Matrix& matrix) {
   m_pOldDelegate->OnDrawWidget(pGraphics, matrix);
 }
+
+FormFieldType CXFA_FFImageEdit::GetFormFieldType() {
+  return FormFieldType::kXFA_ImageField;
+}
diff --git a/xfa/fxfa/cxfa_ffimageedit.h b/xfa/fxfa/cxfa_ffimageedit.h
index 436435d..a7ef6a8 100644
--- a/xfa/fxfa/cxfa_ffimageedit.h
+++ b/xfa/fxfa/cxfa_ffimageedit.h
@@ -25,6 +25,7 @@
   void OnProcessEvent(CFWL_Event* pEvent) override;
   void OnDrawWidget(CXFA_Graphics* pGraphics,
                     const CFX_Matrix& matrix) override;
+  FormFieldType GetFormFieldType() override;
 
  private:
   void SetFWLRect() override;
diff --git a/xfa/fxfa/cxfa_fflistbox.cpp b/xfa/fxfa/cxfa_fflistbox.cpp
index 1a7b11b..ce9198a 100644
--- a/xfa/fxfa/cxfa_fflistbox.cpp
+++ b/xfa/fxfa/cxfa_fflistbox.cpp
@@ -208,3 +208,7 @@
                                   const CFX_Matrix& matrix) {
   m_pOldDelegate->OnDrawWidget(pGraphics, matrix);
 }
+
+FormFieldType CXFA_FFListBox::GetFormFieldType() {
+  return FormFieldType::kXFA_ListBox;
+}
diff --git a/xfa/fxfa/cxfa_fflistbox.h b/xfa/fxfa/cxfa_fflistbox.h
index 11c7761..27f1cdb 100644
--- a/xfa/fxfa/cxfa_fflistbox.h
+++ b/xfa/fxfa/cxfa_fflistbox.h
@@ -21,6 +21,7 @@
   void OnProcessEvent(CFWL_Event* pEvent) override;
   void OnDrawWidget(CXFA_Graphics* pGraphics,
                     const CFX_Matrix& matrix) override;
+  FormFieldType GetFormFieldType() override;
 
   void OnSelectChanged(CFWL_Widget* pWidget);
   void SetItemState(int32_t nIndex, bool bSelected);
diff --git a/xfa/fxfa/cxfa_ffpushbutton.cpp b/xfa/fxfa/cxfa_ffpushbutton.cpp
index 97078a6..fdf7512 100644
--- a/xfa/fxfa/cxfa_ffpushbutton.cpp
+++ b/xfa/fxfa/cxfa_ffpushbutton.cpp
@@ -239,3 +239,7 @@
     }
   }
 }
+
+FormFieldType CXFA_FFPushButton::GetFormFieldType() {
+  return FormFieldType::kXFA_PushButton;
+}
diff --git a/xfa/fxfa/cxfa_ffpushbutton.h b/xfa/fxfa/cxfa_ffpushbutton.h
index ba2d023..9b2a0ee 100644
--- a/xfa/fxfa/cxfa_ffpushbutton.h
+++ b/xfa/fxfa/cxfa_ffpushbutton.h
@@ -34,6 +34,7 @@
   void OnProcessEvent(CFWL_Event* pEvent) override;
   void OnDrawWidget(CXFA_Graphics* pGraphics,
                     const CFX_Matrix& matrix) override;
+  FormFieldType GetFormFieldType() override;
 
  private:
   void LoadHighlightCaption();
diff --git a/xfa/fxfa/cxfa_ffsignature.cpp b/xfa/fxfa/cxfa_ffsignature.cpp
index 3b373a9..6e56b38 100644
--- a/xfa/fxfa/cxfa_ffsignature.cpp
+++ b/xfa/fxfa/cxfa_ffsignature.cpp
@@ -110,3 +110,7 @@
 bool CXFA_FFSignature::OnSetCursor(const CFX_PointF& point) {
   return false;
 }
+
+FormFieldType CXFA_FFSignature::GetFormFieldType() {
+  return FormFieldType::kXFA_Signature;
+}
diff --git a/xfa/fxfa/cxfa_ffsignature.h b/xfa/fxfa/cxfa_ffsignature.h
index af26004..bd09576 100644
--- a/xfa/fxfa/cxfa_ffsignature.h
+++ b/xfa/fxfa/cxfa_ffsignature.h
@@ -37,6 +37,7 @@
   bool OnChar(uint32_t dwChar, uint32_t dwFlags) override;
   FWL_WidgetHit OnHitTest(const CFX_PointF& point) override;
   bool OnSetCursor(const CFX_PointF& point) override;
+  FormFieldType GetFormFieldType() override;
 };
 
 #endif  // XFA_FXFA_CXFA_FFSIGNATURE_H_
diff --git a/xfa/fxfa/cxfa_fftextedit.cpp b/xfa/fxfa/cxfa_fftextedit.cpp
index 3429d97..fad9a9b 100644
--- a/xfa/fxfa/cxfa_fftextedit.cpp
+++ b/xfa/fxfa/cxfa_fftextedit.cpp
@@ -423,3 +423,7 @@
 void CXFA_FFTextEdit::DeSelect() {
   ToEdit(m_pNormalWidget.get())->ClearSelection();
 }
+
+FormFieldType CXFA_FFTextEdit::GetFormFieldType() {
+  return FormFieldType::kXFA_TextField;
+}
diff --git a/xfa/fxfa/cxfa_fftextedit.h b/xfa/fxfa/cxfa_fftextedit.h
index d6bc131..e8edb46 100644
--- a/xfa/fxfa/cxfa_fftextedit.h
+++ b/xfa/fxfa/cxfa_fftextedit.h
@@ -57,6 +57,7 @@
   void SelectAll() override;
   void Delete() override;
   void DeSelect() override;
+  FormFieldType GetFormFieldType() override;
 
  protected:
   uint32_t GetAlignment();
diff --git a/xfa/fxfa/cxfa_ffwidget.cpp b/xfa/fxfa/cxfa_ffwidget.cpp
index e28aa43..1024004 100644
--- a/xfa/fxfa/cxfa_ffwidget.cpp
+++ b/xfa/fxfa/cxfa_ffwidget.cpp
@@ -1187,6 +1187,10 @@
 
 void CXFA_FFWidget::DeSelect() {}
 
+FormFieldType CXFA_FFWidget::GetFormFieldType() {
+  return FormFieldType::kXFA;
+}
+
 void CXFA_FFWidget::GetSuggestWords(CFX_PointF pointf,
                                     std::vector<ByteString>* pWords) {
   pWords->clear();
diff --git a/xfa/fxfa/cxfa_ffwidget.h b/xfa/fxfa/cxfa_ffwidget.h
index 50b5406..7c21903 100644
--- a/xfa/fxfa/cxfa_ffwidget.h
+++ b/xfa/fxfa/cxfa_ffwidget.h
@@ -9,6 +9,7 @@
 
 #include <vector>
 
+#include "core/fpdfdoc/cpdf_formfield.h"
 #include "core/fxcodec/fx_codec_def.h"
 #include "core/fxge/cfx_graphstatedata.h"
 #include "xfa/fwl/cfwl_app.h"
@@ -134,6 +135,8 @@
   virtual void Delete();
   virtual void DeSelect();
 
+  virtual FormFieldType GetFormFieldType();
+
   // TODO(tsepez): Implement or remove.
   void GetSuggestWords(CFX_PointF pointf, std::vector<ByteString>* pWords);
   bool ReplaceSpellCheckWord(CFX_PointF pointf,