Cleanup the FFWidget determination code.

This CL converts the UIType to an XFA_FFWidgetType instead of reusing
the XFA_Element type. The creation code is cleaned up to make it clearer
what's happening.

Change-Id: I5d3e4967d5c8b8a50dbb25e574b0d31fe0cf407a
Reviewed-on: https://pdfium-review.googlesource.com/24390
Reviewed-by: Ryan Harrison <rharrison@chromium.org>
Commit-Queue: dsinclair <dsinclair@chromium.org>
diff --git a/fpdfsdk/cpdfsdk_xfawidgethandler.cpp b/fpdfsdk/cpdfsdk_xfawidgethandler.cpp
index 2fca3b3..7eb5657 100644
--- a/fpdfsdk/cpdfsdk_xfawidgethandler.cpp
+++ b/fpdfsdk/cpdfsdk_xfawidgethandler.cpp
@@ -85,7 +85,7 @@
   ASSERT(node->IsWidgetReady());
 
   CFX_RectF rcBBox;
-  if (node->GetUIType() == XFA_Element::Signature)
+  if (node->GetFFWidgetType() == XFA_FFWidgetType::kSignature)
     rcBBox = pAnnot->GetXFAWidget()->GetBBox(XFA_WidgetStatus_Visible, true);
   else
     rcBBox = pAnnot->GetXFAWidget()->GetBBox(XFA_WidgetStatus_None);
diff --git a/fxjs/xfa/cjx_draw.cpp b/fxjs/xfa/cjx_draw.cpp
index 77d058f..1754506 100644
--- a/fxjs/xfa/cjx_draw.cpp
+++ b/fxjs/xfa/cjx_draw.cpp
@@ -120,7 +120,7 @@
     return;
 
   ASSERT(GetXFANode()->IsWidgetReady());
-  if (GetXFANode()->GetUIType() != XFA_Element::Text)
+  if (GetXFANode()->GetFFWidgetType() != XFA_FFWidgetType::kText)
     return;
 
   WideString wsNewValue = pValue->ToWideString();
diff --git a/fxjs/xfa/cjx_field.cpp b/fxjs/xfa/cjx_field.cpp
index 9b4364b..078def3 100644
--- a/fxjs/xfa/cjx_field.cpp
+++ b/fxjs/xfa/cjx_field.cpp
@@ -249,7 +249,8 @@
     if (pValue && !(pValue->IsNull() || pValue->IsUndefined()))
       wsNewText = pValue->ToWideString();
 
-    if (xfaNode->GetUIChild()->GetElementType() == XFA_Element::NumericEdit) {
+    if (xfaNode->GetUIChildNode()->GetElementType() ==
+        XFA_Element::NumericEdit) {
       wsNewText = xfaNode->NumericLimit(wsNewText, xfaNode->GetLeadDigits(),
                                         xfaNode->GetFracDigits());
     }
@@ -272,7 +273,8 @@
   CXFA_Node* formValue = xfaNode->GetFormValueIfExists();
   CXFA_Node* pNode = formValue ? formValue->GetFirstChild() : nullptr;
   if (pNode && pNode->GetElementType() == XFA_Element::Decimal) {
-    if (xfaNode->GetUIChild()->GetElementType() == XFA_Element::NumericEdit &&
+    if (xfaNode->GetUIChildNode()->GetElementType() ==
+            XFA_Element::NumericEdit &&
         (pNode->JSObject()->GetInteger(XFA_Attribute::FracDigits) == -1)) {
       pValue->SetString(content.UTF8Encode().AsStringView());
     } else {
diff --git a/fxjs/xfa/cjx_node.cpp b/fxjs/xfa/cjx_node.cpp
index 1d6e022..0508651 100644
--- a/fxjs/xfa/cjx_node.cpp
+++ b/fxjs/xfa/cjx_node.cpp
@@ -505,21 +505,18 @@
     case EventAppliesToo::kSignature: {
       if (!GetXFANode()->IsWidgetReady())
         return XFA_EVENTERROR_NotExist;
-
-      CXFA_Node* pUINode = GetXFANode()->GetUIChild();
-      if (pUINode->GetElementType() != XFA_Element::Signature)
+      if (GetXFANode()->GetUIChildNode()->GetElementType() !=
+          XFA_Element::Signature) {
         return XFA_EVENTERROR_NotExist;
-
+      }
       return pNotify->ExecEventByDeepFirst(
           GetXFANode(), eventParaInfo->m_eventType, false, false);
     }
     case EventAppliesToo::kChoiceList: {
       if (!GetXFANode()->IsWidgetReady())
         return XFA_EVENTERROR_NotExist;
-
-      CXFA_Node* pUINode = GetXFANode()->GetUIChild();
-      if (pUINode->GetElementType() != XFA_Element::ChoiceList ||
-          GetXFANode()->IsListBox()) {
+      if (GetXFANode()->GetUIChildNode()->GetElementType() !=
+          XFA_Element::ChoiceList) {
         return XFA_EVENTERROR_NotExist;
       }
       return pNotify->ExecEventByDeepFirst(
diff --git a/xfa/fxfa/cxfa_fffield.cpp b/xfa/fxfa/cxfa_fffield.cpp
index 05319b3..2238648 100644
--- a/xfa/fxfa/cxfa_fffield.cpp
+++ b/xfa/fxfa/cxfa_fffield.cpp
@@ -49,14 +49,16 @@
   if (!bDrawFocus)
     return CXFA_FFWidget::GetBBox(dwStatus);
 
-  XFA_Element type = m_pNode->GetUIType();
-  if (type != XFA_Element::Button && type != XFA_Element::CheckButton &&
-      type != XFA_Element::ImageEdit && type != XFA_Element::Signature &&
-      type != XFA_Element::ChoiceList) {
-    return CFX_RectF();
+  switch (m_pNode->GetFFWidgetType()) {
+    case XFA_FFWidgetType::kButton:
+    case XFA_FFWidgetType::kCheckButton:
+    case XFA_FFWidgetType::kImageEdit:
+    case XFA_FFWidgetType::kSignature:
+    case XFA_FFWidgetType::kChoiceList:
+      return GetRotateMatrix().TransformRect(m_rtUI);
+    default:
+      return CFX_RectF();
   }
-
-  return GetRotateMatrix().TransformRect(m_rtUI);
 }
 
 void CXFA_FFField::RenderWidget(CXFA_Graphics* pGS,
@@ -136,9 +138,10 @@
 }
 
 void CXFA_FFField::SetEditScrollOffset() {
-  XFA_Element eType = m_pNode->GetUIType();
-  if (eType != XFA_Element::TextEdit && eType != XFA_Element::NumericEdit &&
-      eType != XFA_Element::PasswordEdit) {
+  XFA_FFWidgetType eType = m_pNode->GetFFWidgetType();
+  if (eType != XFA_FFWidgetType::kTextEdit &&
+      eType != XFA_FFWidgetType::kNumericEdit &&
+      eType != XFA_FFWidgetType::kPasswordEdit) {
     return;
   }
 
@@ -333,7 +336,7 @@
 }
 
 uint32_t CXFA_FFField::UpdateUIProperty() {
-  CXFA_Node* pUiNode = m_pNode->GetUIChild();
+  CXFA_Node* pUiNode = m_pNode->GetUIChildNode();
   if (pUiNode && pUiNode->GetElementType() == XFA_Element::DefaultUi)
     return FWL_STYLEEXT_EDT_ReadOnly;
   return 0;
diff --git a/xfa/fxfa/cxfa_ffnotify.cpp b/xfa/fxfa/cxfa_ffnotify.cpp
index 588df5b..d4834f0 100644
--- a/xfa/fxfa/cxfa_ffnotify.cpp
+++ b/xfa/fxfa/cxfa_ffnotify.cpp
@@ -65,7 +65,7 @@
                                           const wchar_t* pLabel,
                                           const wchar_t* pValue,
                                           int32_t iIndex) {
-  if (pSender->GetUIType() != XFA_Element::ChoiceList)
+  if (pSender->GetFFWidgetType() != XFA_FFWidgetType::kChoiceList)
     return;
 
   CXFA_FFWidget* pWidget = m_pDoc->GetDocView()->GetWidgetForNode(pSender);
@@ -81,7 +81,7 @@
 
 void CXFA_FFNotify::OnWidgetListItemRemoved(CXFA_Node* pSender,
                                             int32_t iIndex) {
-  if (pSender->GetUIType() != XFA_Element::ChoiceList)
+  if (pSender->GetFFWidgetType() != XFA_FFWidgetType::kChoiceList)
     return;
 
   CXFA_FFWidget* pWidget = m_pDoc->GetDocView()->GetWidgetForNode(pSender);
@@ -116,72 +116,70 @@
   if (!pNode->HasCreatedUIWidget())
     return new CXFA_ContentLayoutItem(pNode);
 
-  CXFA_FFWidget* pWidget;
-  switch (pNode->GetUIType()) {
-    case XFA_Element::Barcode:
+  CXFA_FFWidget* pWidget = nullptr;
+  switch (pNode->GetFFWidgetType()) {
+    case XFA_FFWidgetType::kBarcode:
       pWidget = new CXFA_FFBarcode(pNode);
       break;
-    case XFA_Element::Button:
+    case XFA_FFWidgetType::kButton:
       pWidget = new CXFA_FFPushButton(pNode);
       break;
-    case XFA_Element::CheckButton:
+    case XFA_FFWidgetType::kCheckButton:
       pWidget = new CXFA_FFCheckButton(pNode);
       break;
-    case XFA_Element::ChoiceList: {
+    case XFA_FFWidgetType::kChoiceList: {
       if (pNode->IsListBox())
         pWidget = new CXFA_FFListBox(pNode);
       else
         pWidget = new CXFA_FFComboBox(pNode);
     } break;
-    case XFA_Element::DateTimeEdit:
+    case XFA_FFWidgetType::kDateTimeEdit:
       pWidget = new CXFA_FFDateTimeEdit(pNode);
       break;
-    case XFA_Element::ImageEdit:
+    case XFA_FFWidgetType::kImageEdit:
       pWidget = new CXFA_FFImageEdit(pNode);
       break;
-    case XFA_Element::NumericEdit:
+    case XFA_FFWidgetType::kNumericEdit:
       pWidget = new CXFA_FFNumericEdit(pNode);
       break;
-    case XFA_Element::PasswordEdit:
+    case XFA_FFWidgetType::kPasswordEdit:
       pWidget = new CXFA_FFPasswordEdit(pNode);
       break;
-    case XFA_Element::Signature:
+    case XFA_FFWidgetType::kSignature:
       pWidget = new CXFA_FFSignature(pNode);
       break;
-    case XFA_Element::TextEdit:
+    case XFA_FFWidgetType::kTextEdit:
       pWidget = new CXFA_FFTextEdit(pNode);
       break;
-    case XFA_Element::Arc:
+    case XFA_FFWidgetType::kArc:
       pWidget = new CXFA_FFArc(pNode);
       break;
-    case XFA_Element::Line:
+    case XFA_FFWidgetType::kLine:
       pWidget = new CXFA_FFLine(pNode);
       break;
-    case XFA_Element::Rectangle:
+    case XFA_FFWidgetType::kRectangle:
       pWidget = new CXFA_FFRectangle(pNode);
       break;
-    case XFA_Element::Text:
+    case XFA_FFWidgetType::kText:
       pWidget = new CXFA_FFText(pNode);
       break;
-    case XFA_Element::Image:
+    case XFA_FFWidgetType::kImage:
       pWidget = new CXFA_FFImage(pNode);
       break;
-    case XFA_Element::Subform:
+    case XFA_FFWidgetType::kSubform:
       pWidget = new CXFA_FFWidget(pNode);
       break;
-    case XFA_Element::ExclGroup:
+    case XFA_FFWidgetType::kExclGroup:
       pWidget = new CXFA_FFExclGroup(pNode);
       break;
-    case XFA_Element::DefaultUi:
-    default:
-      pWidget = nullptr;
-      break;
+    case XFA_FFWidgetType::kNone:
+      return nullptr;
   }
+  ASSERT(pWidget);
 
-  if (pWidget) {
-    CXFA_LayoutProcessor* pLayout = m_pDoc->GetXFADoc()->GetDocLayout();
-    pWidget->SetDocView(m_pDoc->GetDocView(pLayout));
-  }
+  CXFA_LayoutProcessor* pLayout = m_pDoc->GetXFADoc()->GetDocLayout();
+  pWidget->SetDocView(m_pDoc->GetDocView(pLayout));
+
   return pWidget;
 }
 
@@ -247,7 +245,7 @@
 }
 
 void CXFA_FFNotify::OpenDropDownList(CXFA_FFWidget* hWidget) {
-  if (hWidget->GetNode()->GetUIType() != XFA_Element::ChoiceList)
+  if (hWidget->GetNode()->GetFFWidgetType() != XFA_FFWidgetType::kChoiceList)
     return;
 
   CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
diff --git a/xfa/fxfa/cxfa_ffpageview.cpp b/xfa/fxfa/cxfa_ffpageview.cpp
index 72fe3f4..fa68cb7 100644
--- a/xfa/fxfa/cxfa_ffpageview.cpp
+++ b/xfa/fxfa/cxfa_ffpageview.cpp
@@ -345,7 +345,7 @@
     if (!pdfium::ContainsValue(m_TabOrderWidgetArray, hWidget)) {
       m_TabOrderWidgetArray.push_back(hWidget);
       CXFA_Node* pNode = hWidget->GetNode();
-      if (pNode->GetUIType() == XFA_Element::ExclGroup) {
+      if (pNode->GetFFWidgetType() == XFA_FFWidgetType::kExclGroup) {
         auto it = std::find(SpaceOrderWidgetArray.begin(),
                             SpaceOrderWidgetArray.end(), hWidget);
         int32_t iWidgetIndex = it != SpaceOrderWidgetArray.end()
diff --git a/xfa/fxfa/cxfa_fftextedit.cpp b/xfa/fxfa/cxfa_fftextedit.cpp
index d3c6fa6..ad03b52 100644
--- a/xfa/fxfa/cxfa_fftextedit.cpp
+++ b/xfa/fxfa/cxfa_fftextedit.cpp
@@ -192,7 +192,7 @@
 }
 
 void CXFA_FFTextEdit::ValidateNumberField(const WideString& wsText) {
-  if (GetNode()->GetUIType() != XFA_Element::NumericEdit)
+  if (GetNode()->GetFFWidgetType() != XFA_FFWidgetType::kNumericEdit)
     return;
 
   IXFA_AppProvider* pAppProvider = GetApp()->GetAppProvider();
@@ -258,7 +258,7 @@
     eType = XFA_VALUEPICTURE_Edit;
 
   bool bUpdate = false;
-  if (m_pNode->GetUIType() == XFA_Element::TextEdit &&
+  if (m_pNode->GetFFWidgetType() == XFA_FFWidgetType::kTextEdit &&
       !m_pNode->GetNumberOfCells()) {
     XFA_Element elementType;
     int32_t iMaxChars;
@@ -269,7 +269,7 @@
       pEdit->SetLimit(iMaxChars);
       bUpdate = true;
     }
-  } else if (m_pNode->GetUIType() == XFA_Element::Barcode) {
+  } else if (m_pNode->GetFFWidgetType() == XFA_FFWidgetType::kBarcode) {
     int32_t nDataLen = 0;
     if (eType == XFA_VALUEPICTURE_Edit)
       nDataLen = m_pNode->GetBarcodeAttribute_DataLength().value_or(0);
@@ -300,7 +300,7 @@
   eParam.m_pTarget = m_pNode.Get();
   eParam.m_wsPrevText = wsPrevText;
   CFWL_Edit* pEdit = static_cast<CFWL_Edit*>(m_pNormalWidget.get());
-  if (m_pNode->GetUIType() == XFA_Element::DateTimeEdit) {
+  if (m_pNode->GetFFWidgetType() == XFA_FFWidgetType::kDateTimeEdit) {
     CFWL_DateTimePicker* pDateTime = (CFWL_DateTimePicker*)pEdit;
     eParam.m_wsNewText = pDateTime->GetEditText();
     if (pDateTime->HasSelection()) {
@@ -324,7 +324,8 @@
 }
 
 bool CXFA_FFTextEdit::CheckWord(const ByteStringView& sWord) {
-  return sWord.IsEmpty() || m_pNode->GetUIType() != XFA_Element::TextEdit;
+  return sWord.IsEmpty() ||
+         m_pNode->GetFFWidgetType() != XFA_FFWidgetType::kTextEdit;
 }
 
 void CXFA_FFTextEdit::OnProcessMessage(CFWL_Message* pMessage) {
diff --git a/xfa/fxfa/cxfa_ffwidget.h b/xfa/fxfa/cxfa_ffwidget.h
index 0a9c906..24f236e 100644
--- a/xfa/fxfa/cxfa_ffwidget.h
+++ b/xfa/fxfa/cxfa_ffwidget.h
@@ -63,6 +63,27 @@
   int32_t m_iRefCount;
 };
 
+enum class XFA_FFWidgetType {
+  kNone = 0,
+  kBarcode,
+  kButton,
+  kCheckButton,
+  kChoiceList,
+  kDateTimeEdit,
+  kImageEdit,
+  kNumericEdit,
+  kPasswordEdit,
+  kSignature,
+  kTextEdit,
+  kArc,
+  kLine,
+  kRectangle,
+  kText,
+  kImage,
+  kSubform,
+  kExclGroup
+};
+
 class CXFA_FFWidget : public CXFA_ContentLayoutItem {
  public:
   explicit CXFA_FFWidget(CXFA_Node* pNode);
diff --git a/xfa/fxfa/cxfa_textprovider.cpp b/xfa/fxfa/cxfa_textprovider.cpp
index 0d3c777..cbb01a9 100644
--- a/xfa/fxfa/cxfa_textprovider.cpp
+++ b/xfa/fxfa/cxfa_textprovider.cpp
@@ -134,8 +134,7 @@
 }
 
 bool CXFA_TextProvider::IsCheckButtonAndAutoWidth() {
-  XFA_Element eType = m_pNode->GetUIType();
-  if (eType != XFA_Element::CheckButton)
+  if (m_pNode->GetFFWidgetType() != XFA_FFWidgetType::kCheckButton)
     return false;
   return !m_pNode->TryWidth();
 }
diff --git a/xfa/fxfa/parser/cxfa_barcode.cpp b/xfa/fxfa/parser/cxfa_barcode.cpp
index d692291..8c77c57 100644
--- a/xfa/fxfa/parser/cxfa_barcode.cpp
+++ b/xfa/fxfa/parser/cxfa_barcode.cpp
@@ -55,3 +55,7 @@
                 pdfium::MakeUnique<CJX_Barcode>(this)) {}
 
 CXFA_Barcode::~CXFA_Barcode() {}
+
+XFA_FFWidgetType CXFA_Barcode::GetDefaultFFWidgetType() const {
+  return XFA_FFWidgetType::kBarcode;
+}
diff --git a/xfa/fxfa/parser/cxfa_barcode.h b/xfa/fxfa/parser/cxfa_barcode.h
index 469889b..056196f 100644
--- a/xfa/fxfa/parser/cxfa_barcode.h
+++ b/xfa/fxfa/parser/cxfa_barcode.h
@@ -13,6 +13,8 @@
  public:
   CXFA_Barcode(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Barcode() override;
+
+  XFA_FFWidgetType GetDefaultFFWidgetType() const override;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_BARCODE_H_
diff --git a/xfa/fxfa/parser/cxfa_button.cpp b/xfa/fxfa/parser/cxfa_button.cpp
index 2b62efb..7b56d2b 100644
--- a/xfa/fxfa/parser/cxfa_button.cpp
+++ b/xfa/fxfa/parser/cxfa_button.cpp
@@ -37,3 +37,7 @@
                 pdfium::MakeUnique<CJX_Button>(this)) {}
 
 CXFA_Button::~CXFA_Button() {}
+
+XFA_FFWidgetType CXFA_Button::GetDefaultFFWidgetType() const {
+  return XFA_FFWidgetType::kButton;
+}
diff --git a/xfa/fxfa/parser/cxfa_button.h b/xfa/fxfa/parser/cxfa_button.h
index 86ffb52..75d62a6 100644
--- a/xfa/fxfa/parser/cxfa_button.h
+++ b/xfa/fxfa/parser/cxfa_button.h
@@ -13,6 +13,8 @@
  public:
   CXFA_Button(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Button() override;
+
+  XFA_FFWidgetType GetDefaultFFWidgetType() const override;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_BUTTON_H_
diff --git a/xfa/fxfa/parser/cxfa_checkbutton.cpp b/xfa/fxfa/parser/cxfa_checkbutton.cpp
index 00f3993..0e40e57 100644
--- a/xfa/fxfa/parser/cxfa_checkbutton.cpp
+++ b/xfa/fxfa/parser/cxfa_checkbutton.cpp
@@ -43,3 +43,7 @@
                 pdfium::MakeUnique<CJX_CheckButton>(this)) {}
 
 CXFA_CheckButton::~CXFA_CheckButton() {}
+
+XFA_FFWidgetType CXFA_CheckButton::GetDefaultFFWidgetType() const {
+  return XFA_FFWidgetType::kCheckButton;
+}
diff --git a/xfa/fxfa/parser/cxfa_checkbutton.h b/xfa/fxfa/parser/cxfa_checkbutton.h
index dbfb4bb..f107de3 100644
--- a/xfa/fxfa/parser/cxfa_checkbutton.h
+++ b/xfa/fxfa/parser/cxfa_checkbutton.h
@@ -13,6 +13,8 @@
  public:
   CXFA_CheckButton(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_CheckButton() override;
+
+  XFA_FFWidgetType GetDefaultFFWidgetType() const override;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_CHECKBUTTON_H_
diff --git a/xfa/fxfa/parser/cxfa_choicelist.cpp b/xfa/fxfa/parser/cxfa_choicelist.cpp
index 4bd8387..bf95ef9 100644
--- a/xfa/fxfa/parser/cxfa_choicelist.cpp
+++ b/xfa/fxfa/parser/cxfa_choicelist.cpp
@@ -49,3 +49,7 @@
              ? XFA_Element::ExData
              : XFA_Element::Text;
 }
+
+XFA_FFWidgetType CXFA_ChoiceList::GetDefaultFFWidgetType() const {
+  return XFA_FFWidgetType::kChoiceList;
+}
diff --git a/xfa/fxfa/parser/cxfa_choicelist.h b/xfa/fxfa/parser/cxfa_choicelist.h
index b3384cb..d621d8a 100644
--- a/xfa/fxfa/parser/cxfa_choicelist.h
+++ b/xfa/fxfa/parser/cxfa_choicelist.h
@@ -15,6 +15,7 @@
   ~CXFA_ChoiceList() override;
 
   XFA_Element GetValueNodeType() const override;
+  XFA_FFWidgetType GetDefaultFFWidgetType() const override;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_CHOICELIST_H_
diff --git a/xfa/fxfa/parser/cxfa_datetimeedit.cpp b/xfa/fxfa/parser/cxfa_datetimeedit.cpp
index 0869ce5..65b4ba3 100644
--- a/xfa/fxfa/parser/cxfa_datetimeedit.cpp
+++ b/xfa/fxfa/parser/cxfa_datetimeedit.cpp
@@ -46,3 +46,7 @@
 XFA_Element CXFA_DateTimeEdit::GetValueNodeType() const {
   return XFA_Element::DateTime;
 }
+
+XFA_FFWidgetType CXFA_DateTimeEdit::GetDefaultFFWidgetType() const {
+  return XFA_FFWidgetType::kDateTimeEdit;
+}
diff --git a/xfa/fxfa/parser/cxfa_datetimeedit.h b/xfa/fxfa/parser/cxfa_datetimeedit.h
index 802ff77..662a1ef 100644
--- a/xfa/fxfa/parser/cxfa_datetimeedit.h
+++ b/xfa/fxfa/parser/cxfa_datetimeedit.h
@@ -15,6 +15,7 @@
   ~CXFA_DateTimeEdit() override;
 
   XFA_Element GetValueNodeType() const override;
+  XFA_FFWidgetType GetDefaultFFWidgetType() const override;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_DATETIMEEDIT_H_
diff --git a/xfa/fxfa/parser/cxfa_defaultui.cpp b/xfa/fxfa/parser/cxfa_defaultui.cpp
index a940084..42bf0d0 100644
--- a/xfa/fxfa/parser/cxfa_defaultui.cpp
+++ b/xfa/fxfa/parser/cxfa_defaultui.cpp
@@ -34,3 +34,7 @@
                 kName) {}
 
 CXFA_DefaultUi::~CXFA_DefaultUi() {}
+
+XFA_FFWidgetType CXFA_DefaultUi::GetDefaultFFWidgetType() const {
+  return XFA_FFWidgetType::kTextEdit;
+}
diff --git a/xfa/fxfa/parser/cxfa_defaultui.h b/xfa/fxfa/parser/cxfa_defaultui.h
index ce14941..5c20370 100644
--- a/xfa/fxfa/parser/cxfa_defaultui.h
+++ b/xfa/fxfa/parser/cxfa_defaultui.h
@@ -13,6 +13,8 @@
  public:
   CXFA_DefaultUi(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_DefaultUi() override;
+
+  XFA_FFWidgetType GetDefaultFFWidgetType() const override;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_DEFAULTUI_H_
diff --git a/xfa/fxfa/parser/cxfa_imageedit.cpp b/xfa/fxfa/parser/cxfa_imageedit.cpp
index f8c56cb..f7f89e1 100644
--- a/xfa/fxfa/parser/cxfa_imageedit.cpp
+++ b/xfa/fxfa/parser/cxfa_imageedit.cpp
@@ -43,3 +43,7 @@
 XFA_Element CXFA_ImageEdit::GetValueNodeType() const {
   return XFA_Element::Image;
 }
+
+XFA_FFWidgetType CXFA_ImageEdit::GetDefaultFFWidgetType() const {
+  return XFA_FFWidgetType::kImageEdit;
+}
diff --git a/xfa/fxfa/parser/cxfa_imageedit.h b/xfa/fxfa/parser/cxfa_imageedit.h
index c41d4d3..0a950d8 100644
--- a/xfa/fxfa/parser/cxfa_imageedit.h
+++ b/xfa/fxfa/parser/cxfa_imageedit.h
@@ -15,6 +15,7 @@
   ~CXFA_ImageEdit() override;
 
   XFA_Element GetValueNodeType() const override;
+  XFA_FFWidgetType GetDefaultFFWidgetType() const override;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_IMAGEEDIT_H_
diff --git a/xfa/fxfa/parser/cxfa_node.cpp b/xfa/fxfa/parser/cxfa_node.cpp
index 9312b6d..5b04700 100644
--- a/xfa/fxfa/parser/cxfa_node.cpp
+++ b/xfa/fxfa/parser/cxfa_node.cpp
@@ -2372,7 +2372,7 @@
 }
 
 WideString CXFA_Node::GetBarcodeType() {
-  CXFA_Node* pUIChild = GetUIChild();
+  CXFA_Node* pUIChild = GetUIChildNode();
   return pUIChild
              ? WideString(pUIChild->JSObject()->GetCData(XFA_Attribute::Type))
              : WideString();
@@ -2380,7 +2380,7 @@
 
 Optional<BC_CHAR_ENCODING> CXFA_Node::GetBarcodeAttribute_CharEncoding() {
   Optional<WideString> wsCharEncoding =
-      GetUIChild()->JSObject()->TryCData(XFA_Attribute::CharEncoding, true);
+      GetUIChildNode()->JSObject()->TryCData(XFA_Attribute::CharEncoding, true);
   if (!wsCharEncoding)
     return {};
   if (wsCharEncoding->CompareNoCase(L"UTF-16"))
@@ -2392,7 +2392,7 @@
 
 Optional<bool> CXFA_Node::GetBarcodeAttribute_Checksum() {
   Optional<XFA_AttributeEnum> checksum =
-      GetUIChild()->JSObject()->TryEnum(XFA_Attribute::Checksum, true);
+      GetUIChildNode()->JSObject()->TryEnum(XFA_Attribute::Checksum, true);
   if (!checksum)
     return {};
 
@@ -2412,7 +2412,7 @@
 
 Optional<int32_t> CXFA_Node::GetBarcodeAttribute_DataLength() {
   Optional<WideString> wsDataLength =
-      GetUIChild()->JSObject()->TryCData(XFA_Attribute::DataLength, true);
+      GetUIChildNode()->JSObject()->TryCData(XFA_Attribute::DataLength, true);
   if (!wsDataLength)
     return {};
 
@@ -2421,7 +2421,7 @@
 
 Optional<char> CXFA_Node::GetBarcodeAttribute_StartChar() {
   Optional<WideString> wsStartEndChar =
-      GetUIChild()->JSObject()->TryCData(XFA_Attribute::StartChar, true);
+      GetUIChildNode()->JSObject()->TryCData(XFA_Attribute::StartChar, true);
   if (!wsStartEndChar || wsStartEndChar->IsEmpty())
     return {};
 
@@ -2430,7 +2430,7 @@
 
 Optional<char> CXFA_Node::GetBarcodeAttribute_EndChar() {
   Optional<WideString> wsStartEndChar =
-      GetUIChild()->JSObject()->TryCData(XFA_Attribute::EndChar, true);
+      GetUIChildNode()->JSObject()->TryCData(XFA_Attribute::EndChar, true);
   if (!wsStartEndChar || wsStartEndChar->IsEmpty())
     return {};
 
@@ -2438,7 +2438,7 @@
 }
 
 Optional<int32_t> CXFA_Node::GetBarcodeAttribute_ECLevel() {
-  Optional<WideString> wsECLevel = GetUIChild()->JSObject()->TryCData(
+  Optional<WideString> wsECLevel = GetUIChildNode()->JSObject()->TryCData(
       XFA_Attribute::ErrorCorrectionLevel, true);
   if (!wsECLevel)
     return {};
@@ -2447,7 +2447,8 @@
 
 Optional<int32_t> CXFA_Node::GetBarcodeAttribute_ModuleWidth() {
   Optional<CXFA_Measurement> moduleWidthHeight =
-      GetUIChild()->JSObject()->TryMeasure(XFA_Attribute::ModuleWidth, true);
+      GetUIChildNode()->JSObject()->TryMeasure(XFA_Attribute::ModuleWidth,
+                                               true);
   if (!moduleWidthHeight)
     return {};
 
@@ -2456,7 +2457,8 @@
 
 Optional<int32_t> CXFA_Node::GetBarcodeAttribute_ModuleHeight() {
   Optional<CXFA_Measurement> moduleWidthHeight =
-      GetUIChild()->JSObject()->TryMeasure(XFA_Attribute::ModuleHeight, true);
+      GetUIChildNode()->JSObject()->TryMeasure(XFA_Attribute::ModuleHeight,
+                                               true);
   if (!moduleWidthHeight)
     return {};
 
@@ -2464,13 +2466,13 @@
 }
 
 Optional<bool> CXFA_Node::GetBarcodeAttribute_PrintChecksum() {
-  return GetUIChild()->JSObject()->TryBoolean(XFA_Attribute::PrintCheckDigit,
-                                              true);
+  return GetUIChildNode()->JSObject()->TryBoolean(
+      XFA_Attribute::PrintCheckDigit, true);
 }
 
 Optional<BC_TEXT_LOC> CXFA_Node::GetBarcodeAttribute_TextLocation() {
   Optional<XFA_AttributeEnum> textLocation =
-      GetUIChild()->JSObject()->TryEnum(XFA_Attribute::TextLocation, true);
+      GetUIChildNode()->JSObject()->TryEnum(XFA_Attribute::TextLocation, true);
   if (!textLocation)
     return {};
 
@@ -2492,12 +2494,14 @@
 }
 
 Optional<bool> CXFA_Node::GetBarcodeAttribute_Truncate() {
-  return GetUIChild()->JSObject()->TryBoolean(XFA_Attribute::Truncate, true);
+  return GetUIChildNode()->JSObject()->TryBoolean(XFA_Attribute::Truncate,
+                                                  true);
 }
 
 Optional<int8_t> CXFA_Node::GetBarcodeAttribute_WideNarrowRatio() {
   Optional<WideString> wsWideNarrowRatio =
-      GetUIChild()->JSObject()->TryCData(XFA_Attribute::WideNarrowRatio, true);
+      GetUIChildNode()->JSObject()->TryCData(XFA_Attribute::WideNarrowRatio,
+                                             true);
   if (!wsWideNarrowRatio)
     return {};
 
@@ -2516,7 +2520,8 @@
   return {static_cast<int8_t>(result)};
 }
 
-std::pair<XFA_Element, CXFA_Node*> CXFA_Node::CreateUIChild() {
+std::pair<XFA_FFWidgetType, CXFA_Ui*>
+CXFA_Node::CreateChildUIAndValueNodesIfNeeded() {
   XFA_Element eType = GetElementType();
   ASSERT(eType == XFA_Element::Field || eType == XFA_Element::Draw);
 
@@ -2536,8 +2541,10 @@
     }
   }
 
-  XFA_Element eWidgetType = XFA_Element::Unknown;
-  XFA_Element valueNodeType = XFA_Element::Unknown;
+  XFA_FFWidgetType ff_widget_type =
+      pUIChild ? pUIChild->GetDefaultFFWidgetType() : XFA_FFWidgetType::kNone;
+  XFA_Element ui_child_type =
+      pUIChild ? pUIChild->GetElementType() : XFA_Element::Unknown;
 
   // Both Field and Draw nodes have a Value child. So, we should either always
   // have it, or always create it. If we don't get the Value child for some
@@ -2550,73 +2557,91 @@
   // that child must be the type we want to use.
   CXFA_Node* child = value->GetFirstChild();
   if (child) {
+    XFA_FFWidgetType tmp_widget_type = XFA_FFWidgetType::kNone;
     switch (child->GetElementType()) {
       case XFA_Element::Boolean:
-        valueNodeType = XFA_Element::CheckButton;
+        ui_child_type = XFA_Element::CheckButton;
+        tmp_widget_type = XFA_FFWidgetType::kCheckButton;
         break;
       case XFA_Element::Integer:
       case XFA_Element::Decimal:
       case XFA_Element::Float:
-        valueNodeType = XFA_Element::NumericEdit;
+        ui_child_type = XFA_Element::NumericEdit;
+        tmp_widget_type = XFA_FFWidgetType::kNumericEdit;
         break;
       case XFA_Element::ExData:
       case XFA_Element::Text:
-        valueNodeType = XFA_Element::TextEdit;
-        eWidgetType = XFA_Element::Text;
+        ui_child_type = XFA_Element::TextEdit;
+        tmp_widget_type = XFA_FFWidgetType::kTextEdit;
         break;
       case XFA_Element::Date:
       case XFA_Element::Time:
       case XFA_Element::DateTime:
-        valueNodeType = XFA_Element::DateTimeEdit;
+        ui_child_type = XFA_Element::DateTimeEdit;
+        tmp_widget_type = XFA_FFWidgetType::kDateTimeEdit;
         break;
       case XFA_Element::Image:
-        valueNodeType = XFA_Element::ImageEdit;
-        eWidgetType = XFA_Element::Image;
+        ui_child_type = XFA_Element::ImageEdit;
+        tmp_widget_type = XFA_FFWidgetType::kImageEdit;
         break;
       case XFA_Element::Arc:
+        ui_child_type = XFA_Element::DefaultUi;
+        tmp_widget_type = XFA_FFWidgetType::kArc;
+        break;
       case XFA_Element::Line:
+        ui_child_type = XFA_Element::DefaultUi;
+        tmp_widget_type = XFA_FFWidgetType::kLine;
+        break;
       case XFA_Element::Rectangle:
-        valueNodeType = XFA_Element::DefaultUi;
-        eWidgetType = child->GetElementType();
+        ui_child_type = XFA_Element::DefaultUi;
+        tmp_widget_type = XFA_FFWidgetType::kRectangle;
         break;
       default:
         NOTREACHED();
         break;
     }
-  }
 
-  if (eType == XFA_Element::Draw) {
-    if (pUIChild && pUIChild->GetElementType() == XFA_Element::TextEdit) {
-      eWidgetType = XFA_Element::Text;
-    } else if (pUIChild &&
-               pUIChild->GetElementType() == XFA_Element::ImageEdit) {
-      eWidgetType = XFA_Element::Image;
-    } else if (eWidgetType == XFA_Element::Unknown) {
-      eWidgetType = XFA_Element::Text;
-    }
-  } else if (eType == XFA_Element::Field) {
-    if (pUIChild && pUIChild->GetElementType() == XFA_Element::DefaultUi) {
-      eWidgetType = XFA_Element::TextEdit;
-    } else if (pUIChild) {
-      eWidgetType = pUIChild->GetElementType();
-    } else if (valueNodeType == XFA_Element::Unknown) {
-      eWidgetType = XFA_Element::TextEdit;
-    } else {
-      eWidgetType = valueNodeType;
-    }
-  } else {
-    NOTREACHED();
+    // Only set the FFWidget if we didn't already set it from the UI child.
+    if (ff_widget_type == XFA_FFWidgetType::kNone)
+      ff_widget_type = tmp_widget_type;
   }
 
   if (!pUIChild) {
-    if (valueNodeType == XFA_Element::Unknown)
-      valueNodeType = XFA_Element::TextEdit;
-    pUIChild =
-        pUI->JSObject()->GetOrCreateProperty<CXFA_Node>(0, valueNodeType);
+    if (ui_child_type == XFA_Element::Unknown)
+      ui_child_type = XFA_Element::TextEdit;
+
+    pUIChild = CreateUINodeIfNeeded(pUI, ui_child_type);
+    if (ff_widget_type == XFA_FFWidgetType::kNone)
+      ff_widget_type = pUIChild->GetDefaultFFWidgetType();
   }
 
+  // When handling draw children, change the image and text edit items to
+  // be non-edit.
+  if (eType == XFA_Element::Draw) {
+    switch (pUIChild->GetElementType()) {
+      case XFA_Element::TextEdit:
+        ff_widget_type = XFA_FFWidgetType::kText;
+        break;
+      case XFA_Element::ImageEdit:
+        ff_widget_type = XFA_FFWidgetType::kImage;
+        break;
+      default:
+        break;
+    }
+  }
+  ASSERT(ff_widget_type != XFA_FFWidgetType::kNone);
+
   CreateValueNodeIfNeeded(value, pUIChild);
-  return {eWidgetType, pUIChild};
+  return {ff_widget_type, pUI};
+}
+
+XFA_FFWidgetType CXFA_Node::GetDefaultFFWidgetType() const {
+  NOTREACHED();
+  return XFA_FFWidgetType::kNone;
+}
+
+CXFA_Node* CXFA_Node::CreateUINodeIfNeeded(CXFA_Ui* ui, XFA_Element type) {
+  return ui->JSObject()->GetOrCreateProperty<CXFA_Node>(0, type);
 }
 
 void CXFA_Node::CreateValueNodeIfNeeded(CXFA_Value* value,
@@ -2643,34 +2668,39 @@
   return XFA_Element::Text;
 }
 
-CXFA_Node* CXFA_Node::GetUIChild() {
-  if (m_eUIType != XFA_Element::Unknown)
-    return m_pUiChildNode;
+CXFA_Node* CXFA_Node::GetUIChildNode() {
+  ASSERT(HasCreatedUIWidget());
+
+  if (ff_widget_type_ != XFA_FFWidgetType::kNone)
+    return ui_ ? ui_->GetFirstChild() : nullptr;
 
   XFA_Element type = GetElementType();
   if (type == XFA_Element::Field || type == XFA_Element::Draw) {
-    std::tie(m_eUIType, m_pUiChildNode) = CreateUIChild();
+    std::tie(ff_widget_type_, ui_) = CreateChildUIAndValueNodesIfNeeded();
+  } else if (type == XFA_Element::Subform) {
+    ff_widget_type_ = XFA_FFWidgetType::kSubform;
+  } else if (type == XFA_Element::ExclGroup) {
+    ff_widget_type_ = XFA_FFWidgetType::kExclGroup;
   } else {
-    m_eUIType = GetElementType();
-    m_pUiChildNode = nullptr;
+    NOTREACHED();
   }
-  return m_pUiChildNode;
+  return ui_ ? ui_->GetFirstChild() : nullptr;
 }
 
-XFA_Element CXFA_Node::GetUIType() {
-  GetUIChild();
-  return m_eUIType;
+XFA_FFWidgetType CXFA_Node::GetFFWidgetType() {
+  GetUIChildNode();
+  return ff_widget_type_;
 }
 
 CXFA_Border* CXFA_Node::GetUIBorder() {
-  CXFA_Node* pUIChild = GetUIChild();
+  CXFA_Node* pUIChild = GetUIChildNode();
   return pUIChild ? pUIChild->JSObject()->GetProperty<CXFA_Border>(
                         0, XFA_Element::Border)
                   : nullptr;
 }
 
 CFX_RectF CXFA_Node::GetUIMargin() {
-  CXFA_Node* pUIChild = GetUIChild();
+  CXFA_Node* pUIChild = GetUIChildNode();
   if (!pUIChild)
     return CFX_RectF();
 
@@ -2737,8 +2767,8 @@
 
 void CXFA_Node::ResetData() {
   WideString wsValue;
-  switch (GetUIType()) {
-    case XFA_Element::ImageEdit: {
+  switch (GetFFWidgetType()) {
+    case XFA_FFWidgetType::kImageEdit: {
       CXFA_Value* imageValue = GetDefaultValueIfExists();
       CXFA_Image* image = imageValue ? imageValue->GetImageIfExists() : nullptr;
       WideString wsContentType, wsHref;
@@ -2750,7 +2780,7 @@
       SetImageEdit(wsContentType, wsHref, wsValue);
       break;
     }
-    case XFA_Element::ExclGroup: {
+    case XFA_FFWidgetType::kExclGroup: {
       CXFA_Node* pNextChild = GetFirstContainerChild();
       while (pNextChild) {
         CXFA_Node* pChild = pNextChild;
@@ -2786,7 +2816,7 @@
       }
       break;
     }
-    case XFA_Element::ChoiceList:
+    case XFA_FFWidgetType::kChoiceList:
       ClearAllSelections();
     default: {
       CXFA_Value* defValue = GetDefaultValueIfExists();
@@ -2838,7 +2868,8 @@
   CXFA_FFWidget* pWidget = docView->GetWidgetForNode(this);
   for (; pWidget; pWidget = GetNextWidget(pWidget)) {
     if (pWidget == pExcept || !pWidget->IsLoaded() ||
-        (GetUIType() != XFA_Element::CheckButton && pWidget->IsFocused())) {
+        (GetFFWidgetType() != XFA_FFWidgetType::kCheckButton &&
+         pWidget->IsFocused())) {
       continue;
     }
     pWidget->UpdateFWLData();
@@ -2853,7 +2884,6 @@
 
   LoadCaption(doc);
 
-  XFA_Element eUIType = GetUIType();
   XFA_AttributeEnum iCapPlacement = caption->GetPlacementType();
   float fCapReserve = caption->GetReserve();
   const bool bVert = iCapPlacement == XFA_AttributeEnum::Top ||
@@ -2863,7 +2893,7 @@
       static_cast<CXFA_FieldLayoutData*>(m_pLayoutData.get())
           ->m_pCapTextLayout.get();
   if (pCapTextLayout) {
-    if (!bVert && eUIType != XFA_Element::Button)
+    if (!bVert && GetFFWidgetType() != XFA_FFWidgetType::kButton)
       szCap.width = fCapReserve;
 
     CFX_SizeF minSize;
@@ -3000,7 +3030,7 @@
 
     FDE_TextStyle dwStyles;
     dwStyles.last_line_height_ = true;
-    if (GetUIType() == XFA_Element::TextEdit && IsMultiLine())
+    if (GetFFWidgetType() == XFA_FFWidgetType::kTextEdit && IsMultiLine())
       dwStyles.line_wrap_ = true;
 
     pTextOut->SetStyles(dwStyles);
@@ -3215,8 +3245,7 @@
                                   float& fCalcHeight) {
   InitLayoutData();
 
-  XFA_Element eUIType = GetUIType();
-  if (eUIType == XFA_Element::Text) {
+  if (GetFFWidgetType() == XFA_FFWidgetType::kText) {
     m_pLayoutData->m_fWidgetHeight = TryHeight().value_or(-1);
     StartTextLayout(doc, fCalcWidth, fCalcHeight);
     return;
@@ -3231,7 +3260,7 @@
     if (height)
       fCalcHeight = *height;
     else
-      CalculateAccWidthAndHeight(doc, eUIType, fCalcWidth, fCalcHeight);
+      CalculateAccWidthAndHeight(doc, fCalcWidth, fCalcHeight);
 
     m_pLayoutData->m_fWidgetHeight = fCalcHeight;
     return;
@@ -3247,7 +3276,7 @@
         fCalcHeight = *height;
     }
     if (!width || !height)
-      CalculateAccWidthAndHeight(doc, eUIType, fWidth, fCalcHeight);
+      CalculateAccWidthAndHeight(doc, fWidth, fCalcHeight);
 
     fCalcWidth = fWidth;
   }
@@ -3255,44 +3284,45 @@
 }
 
 void CXFA_Node::CalculateAccWidthAndHeight(CXFA_FFDoc* doc,
-                                           XFA_Element eUIType,
                                            float& fWidth,
                                            float& fCalcHeight) {
   CFX_SizeF sz(fWidth, m_pLayoutData->m_fWidgetHeight);
-  switch (eUIType) {
-    case XFA_Element::Barcode:
-    case XFA_Element::ChoiceList:
-    case XFA_Element::Signature:
+  switch (GetFFWidgetType()) {
+    case XFA_FFWidgetType::kBarcode:
+    case XFA_FFWidgetType::kChoiceList:
+    case XFA_FFWidgetType::kSignature:
       CalculateFieldAutoSize(doc, sz);
       break;
-    case XFA_Element::ImageEdit:
+    case XFA_FFWidgetType::kImageEdit:
       CalculateImageEditAutoSize(doc, sz);
       break;
-    case XFA_Element::Button:
+    case XFA_FFWidgetType::kButton:
       CalculatePushButtonAutoSize(doc, sz);
       break;
-    case XFA_Element::CheckButton:
+    case XFA_FFWidgetType::kCheckButton:
       CalculateCheckButtonAutoSize(doc, sz);
       break;
-    case XFA_Element::DateTimeEdit:
-    case XFA_Element::NumericEdit:
-    case XFA_Element::PasswordEdit:
-    case XFA_Element::TextEdit:
+    case XFA_FFWidgetType::kDateTimeEdit:
+    case XFA_FFWidgetType::kNumericEdit:
+    case XFA_FFWidgetType::kPasswordEdit:
+    case XFA_FFWidgetType::kTextEdit:
       CalculateTextEditAutoSize(doc, sz);
       break;
-    case XFA_Element::Image:
+    case XFA_FFWidgetType::kImage:
       CalculateImageAutoSize(doc, sz);
       break;
-    case XFA_Element::Arc:
-    case XFA_Element::Line:
-    case XFA_Element::Rectangle:
-    case XFA_Element::Subform:
-    case XFA_Element::ExclGroup:
+    case XFA_FFWidgetType::kArc:
+    case XFA_FFWidgetType::kLine:
+    case XFA_FFWidgetType::kRectangle:
+    case XFA_FFWidgetType::kSubform:
+    case XFA_FFWidgetType::kExclGroup:
       CalculateWidgetAutoSize(sz);
       break;
-    default:
+    case XFA_FFWidgetType::kText:
+    case XFA_FFWidgetType::kNone:
       break;
   }
+
   fWidth = sz.width;
   m_pLayoutData->m_fWidgetHeight = sz.height;
   fCalcHeight = sz.height;
@@ -3301,15 +3331,18 @@
 bool CXFA_Node::FindSplitPos(CXFA_FFDocView* docView,
                              int32_t iBlockIndex,
                              float& fCalcHeight) {
-  XFA_Element eUIType = GetUIType();
-  if (eUIType == XFA_Element::Subform)
+  if (GetFFWidgetType() == XFA_FFWidgetType::kSubform)
     return false;
 
-  if (eUIType != XFA_Element::Text && eUIType != XFA_Element::TextEdit &&
-      eUIType != XFA_Element::NumericEdit &&
-      eUIType != XFA_Element::PasswordEdit) {
-    fCalcHeight = 0;
-    return true;
+  switch (GetFFWidgetType()) {
+    case XFA_FFWidgetType::kText:
+    case XFA_FFWidgetType::kTextEdit:
+    case XFA_FFWidgetType::kNumericEdit:
+    case XFA_FFWidgetType::kPasswordEdit:
+      break;
+    default:
+      fCalcHeight = 0;
+      return true;
   }
 
   float fTopInset = 0;
@@ -3325,7 +3358,7 @@
     fTopInset += rtUIMargin.top;
     fBottomInset += rtUIMargin.width;
   }
-  if (eUIType == XFA_Element::Text) {
+  if (GetFFWidgetType() == XFA_FFWidgetType::kText) {
     float fHeight = fCalcHeight;
     if (iBlockIndex == 0) {
       fCalcHeight = fCalcHeight - fTopInset;
@@ -3346,6 +3379,7 @@
     }
     return true;
   }
+
   XFA_AttributeEnum iCapPlacement = XFA_AttributeEnum::Unknown;
   float fCapReserve = 0;
   if (iBlockIndex == 0) {
@@ -3378,7 +3412,7 @@
       // TODO(dsinclair): Inline fWidth when the 2nd param of
       // CalculateAccWidthAndHeight isn't a ref-param.
       float fWidth = TryWidth().value_or(0);
-      CalculateAccWidthAndHeight(docView->GetDoc(), eUIType, fWidth, fHeight);
+      CalculateAccWidthAndHeight(docView->GetDoc(), fWidth, fHeight);
     }
     iLinesCount = pFieldData->m_pTextOut->GetTotalLines();
   }
@@ -3531,17 +3565,17 @@
   if (m_pLayoutData)
     return;
 
-  switch (GetUIType()) {
-    case XFA_Element::Text:
+  switch (GetFFWidgetType()) {
+    case XFA_FFWidgetType::kText:
       m_pLayoutData = pdfium::MakeUnique<CXFA_TextLayoutData>();
       return;
-    case XFA_Element::TextEdit:
+    case XFA_FFWidgetType::kTextEdit:
       m_pLayoutData = pdfium::MakeUnique<CXFA_TextEditData>();
       return;
-    case XFA_Element::Image:
+    case XFA_FFWidgetType::kImage:
       m_pLayoutData = pdfium::MakeUnique<CXFA_ImageLayoutData>();
       return;
-    case XFA_Element::ImageEdit:
+    case XFA_FFWidgetType::kImageEdit:
       m_pLayoutData = pdfium::MakeUnique<CXFA_ImageEditData>();
       return;
     default:
@@ -3659,7 +3693,7 @@
 }
 
 XFA_AttributeEnum CXFA_Node::GetButtonHighlight() {
-  CXFA_Node* pUIChild = GetUIChild();
+  CXFA_Node* pUIChild = GetUIChildNode();
   if (pUIChild)
     return pUIChild->JSObject()->GetEnum(XFA_Attribute::Highlight);
   return XFA_AttributeEnum::Inverted;
@@ -3692,7 +3726,7 @@
 }
 
 bool CXFA_Node::IsCheckButtonRound() {
-  CXFA_Node* pUIChild = GetUIChild();
+  CXFA_Node* pUIChild = GetUIChildNode();
   if (pUIChild)
     return pUIChild->JSObject()->GetEnum(XFA_Attribute::Shape) ==
            XFA_AttributeEnum::Round;
@@ -3700,7 +3734,7 @@
 }
 
 XFA_AttributeEnum CXFA_Node::GetCheckButtonMark() {
-  CXFA_Node* pUIChild = GetUIChild();
+  CXFA_Node* pUIChild = GetUIChildNode();
   if (pUIChild)
     return pUIChild->JSObject()->GetEnum(XFA_Attribute::Mark);
   return XFA_AttributeEnum::Default;
@@ -3712,7 +3746,7 @@
 }
 
 float CXFA_Node::GetCheckButtonSize() {
-  CXFA_Node* pUIChild = GetUIChild();
+  CXFA_Node* pUIChild = GetUIChildNode();
   if (pUIChild) {
     return pUIChild->JSObject()
         ->GetMeasure(XFA_Attribute::Size)
@@ -3722,7 +3756,7 @@
 }
 
 bool CXFA_Node::IsAllowNeutral() {
-  CXFA_Node* pUIChild = GetUIChild();
+  CXFA_Node* pUIChild = GetUIChildNode();
   return pUIChild &&
          pUIChild->JSObject()->GetBoolean(XFA_Attribute::AllowNeutral);
 }
@@ -3900,7 +3934,7 @@
 }
 
 bool CXFA_Node::IsChoiceListCommitOnSelect() {
-  CXFA_Node* pUIChild = GetUIChild();
+  CXFA_Node* pUIChild = GetUIChildNode();
   if (pUIChild) {
     return pUIChild->JSObject()->GetEnum(XFA_Attribute::CommitOn) ==
            XFA_AttributeEnum::Select;
@@ -3909,12 +3943,12 @@
 }
 
 bool CXFA_Node::IsChoiceListAllowTextEntry() {
-  CXFA_Node* pUIChild = GetUIChild();
+  CXFA_Node* pUIChild = GetUIChildNode();
   return pUIChild && pUIChild->JSObject()->GetBoolean(XFA_Attribute::TextEntry);
 }
 
 bool CXFA_Node::IsChoiceListMultiSelect() {
-  CXFA_Node* pUIChild = GetUIChild();
+  CXFA_Node* pUIChild = GetUIChildNode();
   if (pUIChild) {
     return pUIChild->JSObject()->GetEnum(XFA_Attribute::Open) ==
            XFA_AttributeEnum::MultiSelect;
@@ -3923,7 +3957,7 @@
 }
 
 bool CXFA_Node::IsListBox() {
-  CXFA_Node* pUIChild = GetUIChild();
+  CXFA_Node* pUIChild = GetUIChildNode();
   if (!pUIChild)
     return false;
 
@@ -4355,7 +4389,7 @@
 }
 
 bool CXFA_Node::IsHorizontalScrollPolicyOff() {
-  CXFA_Node* pUIChild = GetUIChild();
+  CXFA_Node* pUIChild = GetUIChildNode();
   if (pUIChild) {
     return pUIChild->JSObject()->GetEnum(XFA_Attribute::HScrollPolicy) ==
            XFA_AttributeEnum::Off;
@@ -4364,7 +4398,7 @@
 }
 
 bool CXFA_Node::IsVerticalScrollPolicyOff() {
-  CXFA_Node* pUIChild = GetUIChild();
+  CXFA_Node* pUIChild = GetUIChildNode();
   if (pUIChild) {
     return pUIChild->JSObject()->GetEnum(XFA_Attribute::VScrollPolicy) ==
            XFA_AttributeEnum::Off;
@@ -4373,7 +4407,7 @@
 }
 
 Optional<int32_t> CXFA_Node::GetNumberOfCells() {
-  CXFA_Node* pUIChild = GetUIChild();
+  CXFA_Node* pUIChild = GetUIChildNode();
   if (!pUIChild)
     return {};
   if (CXFA_Comb* pNode =
@@ -4383,13 +4417,13 @@
 }
 
 WideString CXFA_Node::GetPasswordChar() {
-  CXFA_Node* pUIChild = GetUIChild();
+  CXFA_Node* pUIChild = GetUIChildNode();
   return pUIChild ? pUIChild->JSObject()->GetCData(XFA_Attribute::PasswordChar)
                   : L"*";
 }
 
 bool CXFA_Node::IsMultiLine() {
-  CXFA_Node* pUIChild = GetUIChild();
+  CXFA_Node* pUIChild = GetUIChildNode();
   return pUIChild && pUIChild->JSObject()->GetBoolean(XFA_Attribute::MultiLine);
 }
 
@@ -4457,7 +4491,7 @@
   WideString wsPicture = GetPictureContent(eValueType);
   bool bValidate = true;
   bool bSyncData = false;
-  CXFA_Node* pNode = GetUIChild();
+  CXFA_Node* pNode = GetUIChildNode();
   if (!pNode)
     return true;
 
@@ -4578,11 +4612,11 @@
     GetItemLabel(wsValue.AsStringView(), wsValue);
 
   WideString wsPicture = GetPictureContent(eValueType);
-  CXFA_Node* pNode = GetUIChild();
+  CXFA_Node* pNode = GetUIChildNode();
   if (!pNode)
     return wsValue;
 
-  switch (GetUIChild()->GetElementType()) {
+  switch (GetUIChildNode()->GetElementType()) {
     case XFA_Element::ChoiceList: {
       if (eValueType == XFA_VALUEPICTURE_Display) {
         int32_t iSelItemIndex = GetSelectedItem(0);
diff --git a/xfa/fxfa/parser/cxfa_node.h b/xfa/fxfa/parser/cxfa_node.h
index 5e1a31c..ae7f4ba 100644
--- a/xfa/fxfa/parser/cxfa_node.h
+++ b/xfa/fxfa/parser/cxfa_node.h
@@ -16,6 +16,7 @@
 #include "core/fxge/fx_dib.h"
 #include "fxbarcode/BC_Library.h"
 #include "third_party/base/optional.h"
+#include "xfa/fxfa/cxfa_ffwidget.h"
 #include "xfa/fxfa/parser/cxfa_object.h"
 
 class CFGAS_GEFont;
@@ -36,6 +37,7 @@
 class CXFA_Para;
 class CXFA_Script;
 class CXFA_TextLayout;
+class CXFA_Ui;
 class CXFA_Validate;
 class CXFA_Value;
 class CXFA_WidgetLayoutData;
@@ -312,8 +314,9 @@
   Optional<bool> GetBarcodeAttribute_Truncate();
   Optional<int8_t> GetBarcodeAttribute_WideNarrowRatio();
 
-  CXFA_Node* GetUIChild();
-  XFA_Element GetUIType();
+  CXFA_Node* GetUIChildNode();
+  XFA_FFWidgetType GetFFWidgetType();
+
   CFX_RectF GetUIMargin();
   CXFA_Border* GetUIBorder();
 
@@ -438,6 +441,7 @@
                           int32_t iTread) const;
 
   virtual XFA_Element GetValueNodeType() const;
+  virtual XFA_FFWidgetType GetDefaultFFWidgetType() const;
 
  protected:
   CXFA_Node(CXFA_Document* pDoc,
@@ -505,7 +509,6 @@
   float GetHeightWithoutMargin(float fHeightCalc);
   void CalculateTextContentSize(CXFA_FFDoc* doc, CFX_SizeF& size);
   void CalculateAccWidthAndHeight(CXFA_FFDoc* doc,
-                                  XFA_Element eUIType,
                                   float& fWidth,
                                   float& fCalcHeight);
   void InitLayoutData();
@@ -516,8 +519,10 @@
                           int32_t nIndex);
   WideString FormatNumStr(const WideString& wsValue, IFX_Locale* pLocale);
   void GetItemLabel(const WideStringView& wsValue, WideString& wsLabel);
-  std::pair<XFA_Element, CXFA_Node*> CreateUIChild();
+
+  std::pair<XFA_FFWidgetType, CXFA_Ui*> CreateChildUIAndValueNodesIfNeeded();
   void CreateValueNodeIfNeeded(CXFA_Value* value, CXFA_Node* pUIChild);
+  CXFA_Node* CreateUINodeIfNeeded(CXFA_Ui* ui, XFA_Element type);
 
   const PropertyData* const m_Properties;
   const AttributeData* const m_Attributes;
@@ -533,12 +538,13 @@
   uint32_t m_dwNameHash;
   CXFA_Node* m_pAuxNode;
   std::vector<UnownedPtr<CXFA_Node>> binding_nodes_;
-  CXFA_Node* m_pUiChildNode = nullptr;
-  XFA_Element m_eUIType = XFA_Element::Unknown;
   bool m_bIsNull = true;
   bool m_bPreNull = true;
   bool is_widget_ready_ = false;
   std::unique_ptr<CXFA_WidgetLayoutData> m_pLayoutData;
+
+  CXFA_Ui* ui_ = nullptr;
+  XFA_FFWidgetType ff_widget_type_ = XFA_FFWidgetType::kNone;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_NODE_H_
diff --git a/xfa/fxfa/parser/cxfa_numericedit.cpp b/xfa/fxfa/parser/cxfa_numericedit.cpp
index 0c282db..ff26c44 100644
--- a/xfa/fxfa/parser/cxfa_numericedit.cpp
+++ b/xfa/fxfa/parser/cxfa_numericedit.cpp
@@ -44,3 +44,7 @@
 XFA_Element CXFA_NumericEdit::GetValueNodeType() const {
   return XFA_Element::Float;
 }
+
+XFA_FFWidgetType CXFA_NumericEdit::GetDefaultFFWidgetType() const {
+  return XFA_FFWidgetType::kNumericEdit;
+}
diff --git a/xfa/fxfa/parser/cxfa_numericedit.h b/xfa/fxfa/parser/cxfa_numericedit.h
index a2a10eb..1a96f46 100644
--- a/xfa/fxfa/parser/cxfa_numericedit.h
+++ b/xfa/fxfa/parser/cxfa_numericedit.h
@@ -15,6 +15,7 @@
   ~CXFA_NumericEdit() override;
 
   XFA_Element GetValueNodeType() const override;
+  XFA_FFWidgetType GetDefaultFFWidgetType() const override;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_NUMERICEDIT_H_
diff --git a/xfa/fxfa/parser/cxfa_passwordedit.cpp b/xfa/fxfa/parser/cxfa_passwordedit.cpp
index e86cd13..68267af 100644
--- a/xfa/fxfa/parser/cxfa_passwordedit.cpp
+++ b/xfa/fxfa/parser/cxfa_passwordedit.cpp
@@ -39,3 +39,7 @@
                 kName) {}
 
 CXFA_PasswordEdit::~CXFA_PasswordEdit() {}
+
+XFA_FFWidgetType CXFA_PasswordEdit::GetDefaultFFWidgetType() const {
+  return XFA_FFWidgetType::kPasswordEdit;
+}
diff --git a/xfa/fxfa/parser/cxfa_passwordedit.h b/xfa/fxfa/parser/cxfa_passwordedit.h
index 2db05ba..e390aaa 100644
--- a/xfa/fxfa/parser/cxfa_passwordedit.h
+++ b/xfa/fxfa/parser/cxfa_passwordedit.h
@@ -13,6 +13,8 @@
  public:
   CXFA_PasswordEdit(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_PasswordEdit() override;
+
+  XFA_FFWidgetType GetDefaultFFWidgetType() const override;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_PASSWORDEDIT_H_
diff --git a/xfa/fxfa/parser/cxfa_signature.cpp b/xfa/fxfa/parser/cxfa_signature.cpp
index baee044..ebb8f28 100644
--- a/xfa/fxfa/parser/cxfa_signature.cpp
+++ b/xfa/fxfa/parser/cxfa_signature.cpp
@@ -39,3 +39,7 @@
                 pdfium::MakeUnique<CJX_Signature>(this)) {}
 
 CXFA_Signature::~CXFA_Signature() {}
+
+XFA_FFWidgetType CXFA_Signature::GetDefaultFFWidgetType() const {
+  return XFA_FFWidgetType::kSignature;
+}
diff --git a/xfa/fxfa/parser/cxfa_signature.h b/xfa/fxfa/parser/cxfa_signature.h
index f55ce5a..3491a1e 100644
--- a/xfa/fxfa/parser/cxfa_signature.h
+++ b/xfa/fxfa/parser/cxfa_signature.h
@@ -13,6 +13,8 @@
  public:
   CXFA_Signature(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Signature() override;
+
+  XFA_FFWidgetType GetDefaultFFWidgetType() const override;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_SIGNATURE_H_
diff --git a/xfa/fxfa/parser/cxfa_textedit.cpp b/xfa/fxfa/parser/cxfa_textedit.cpp
index 3b2767a..2527777 100644
--- a/xfa/fxfa/parser/cxfa_textedit.cpp
+++ b/xfa/fxfa/parser/cxfa_textedit.cpp
@@ -44,3 +44,7 @@
                 pdfium::MakeUnique<CJX_TextEdit>(this)) {}
 
 CXFA_TextEdit::~CXFA_TextEdit() {}
+
+XFA_FFWidgetType CXFA_TextEdit::GetDefaultFFWidgetType() const {
+  return XFA_FFWidgetType::kTextEdit;
+}
diff --git a/xfa/fxfa/parser/cxfa_textedit.h b/xfa/fxfa/parser/cxfa_textedit.h
index 972ede4..97c9764 100644
--- a/xfa/fxfa/parser/cxfa_textedit.h
+++ b/xfa/fxfa/parser/cxfa_textedit.h
@@ -13,6 +13,8 @@
  public:
   CXFA_TextEdit(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_TextEdit() override;
+
+  XFA_FFWidgetType GetDefaultFFWidgetType() const override;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_TEXTEDIT_H_
diff --git a/xfa/fxfa/parser/xfa_document_datamerger_imp.cpp b/xfa/fxfa/parser/xfa_document_datamerger_imp.cpp
index 7875ff8..5b098cc 100644
--- a/xfa/fxfa/parser/xfa_document_datamerger_imp.cpp
+++ b/xfa/fxfa/parser/xfa_document_datamerger_imp.cpp
@@ -71,8 +71,8 @@
 
 void FormValueNode_MatchNoneCreateChild(CXFA_Node* pFormNode) {
   ASSERT(pFormNode->IsWidgetReady());
-  // GetUIChild has the side effect of creating the UI child.
-  pFormNode->GetUIChild();
+  // GetUIChildNode has the side effect of creating the UI child.
+  pFormNode->GetUIChildNode();
 }
 
 bool FormValueNode_SetChildContent(CXFA_Node* pValueNode,
@@ -137,8 +137,8 @@
       0, XFA_Element::Value);
   if (!bDataToForm) {
     WideString wsValue;
-    switch (pFormNode->GetUIType()) {
-      case XFA_Element::ImageEdit: {
+    switch (pFormNode->GetFFWidgetType()) {
+      case XFA_FFWidgetType::kImageEdit: {
         CXFA_Image* image = defValue ? defValue->GetImageIfExists() : nullptr;
         WideString wsContentType;
         WideString wsHref;
@@ -160,7 +160,7 @@
 
         break;
       }
-      case XFA_Element::ChoiceList:
+      case XFA_FFWidgetType::kChoiceList:
         wsValue = defValue ? defValue->GetChildValueContent() : L"";
         if (pFormNode->IsChoiceListMultiSelect()) {
           std::vector<WideString> wsSelTextArray =
@@ -187,7 +187,7 @@
               wsValue, pFormNode->GetFormatDataValue(wsValue), false, false);
         }
         break;
-      case XFA_Element::CheckButton:
+      case XFA_FFWidgetType::kCheckButton:
         wsValue = defValue ? defValue->GetChildValueContent() : L"";
         if (wsValue.IsEmpty())
           break;
@@ -195,7 +195,7 @@
         pDataNode->JSObject()->SetAttributeValue(
             wsValue, pFormNode->GetFormatDataValue(wsValue), false, false);
         break;
-      case XFA_Element::ExclGroup: {
+      case XFA_FFWidgetType::kExclGroup: {
         CXFA_Node* pChecked = nullptr;
         CXFA_Node* pChild = pFormNode->GetFirstChild();
         for (; pChild; pChild = pChild->GetNextSibling()) {
@@ -257,7 +257,7 @@
         }
         break;
       }
-      case XFA_Element::NumericEdit: {
+      case XFA_FFWidgetType::kNumericEdit: {
         wsValue = defValue ? defValue->GetChildValueContent() : L"";
         if (wsValue.IsEmpty())
           break;
@@ -288,8 +288,8 @@
 
   pDataNode->JSObject()->SetAttributeValue(wsNormalizeValue, wsXMLValue, false,
                                            false);
-  switch (pFormNode->GetUIType()) {
-    case XFA_Element::ImageEdit: {
+  switch (pFormNode->GetFFWidgetType()) {
+    case XFA_FFWidgetType::kImageEdit: {
       FormValueNode_SetChildContent(defValue, wsNormalizeValue,
                                     XFA_Element::Image);
       CXFA_Image* image = defValue ? defValue->GetImageIfExists() : nullptr;
@@ -312,7 +312,7 @@
       }
       break;
     }
-    case XFA_Element::ChoiceList:
+    case XFA_FFWidgetType::kChoiceList:
       if (pFormNode->IsChoiceListMultiSelect()) {
         std::vector<CXFA_Node*> items = pDataNode->GetNodeList(
             XFA_NODEFILTER_Children | XFA_NODEFILTER_Properties,
@@ -341,20 +341,16 @@
                                       XFA_Element::Text);
       }
       break;
-    case XFA_Element::CheckButton:
-      FormValueNode_SetChildContent(defValue, wsNormalizeValue,
-                                    XFA_Element::Text);
-      break;
-    case XFA_Element::ExclGroup: {
+    case XFA_FFWidgetType::kExclGroup: {
       pFormNode->SetSelectedMemberByValue(wsNormalizeValue.AsStringView(),
                                           false, false, false);
       break;
     }
-    case XFA_Element::DateTimeEdit:
+    case XFA_FFWidgetType::kDateTimeEdit:
       FormValueNode_SetChildContent(defValue, wsNormalizeValue,
                                     XFA_Element::DateTime);
       break;
-    case XFA_Element::NumericEdit: {
+    case XFA_FFWidgetType::kNumericEdit: {
       WideString wsPicture =
           pFormNode->GetPictureContent(XFA_VALUEPICTURE_DataBind);
       if (wsPicture.IsEmpty())
@@ -364,11 +360,6 @@
                                     XFA_Element::Float);
       break;
     }
-    case XFA_Element::Barcode:
-    case XFA_Element::Button:
-    case XFA_Element::PasswordEdit:
-    case XFA_Element::Signature:
-    case XFA_Element::TextEdit:
     default:
       FormValueNode_SetChildContent(defValue, wsNormalizeValue,
                                     XFA_Element::Text);
diff --git a/xfa/fxfa/parser/xfa_utils.cpp b/xfa/fxfa/parser/xfa_utils.cpp
index 226aaed..785119b 100644
--- a/xfa/fxfa/parser/xfa_utils.cpp
+++ b/xfa/fxfa/parser/xfa_utils.cpp
@@ -144,7 +144,7 @@
     return true;
   if (!pGrandParentNode->GetBindData())
     return false;
-  if (pGrandParentNode->GetUIType() == XFA_Element::PasswordEdit)
+  if (pGrandParentNode->GetFFWidgetType() == XFA_FFWidgetType::kPasswordEdit)
     return false;
   return true;
 }