Introduce new CXFA_FFWidget::As*() methods.

Enforce type safety at a small cost in performance since this
code has shown itself to be vulnerable to bad casting in the
historical past.

Change-Id: I6d543f446309326bac937d744c7b857fb0110e38
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/65455
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/xfa/fxfa/cxfa_ffdropdown.cpp b/xfa/fxfa/cxfa_ffdropdown.cpp
index 9d610b1..4289dc1 100644
--- a/xfa/fxfa/cxfa_ffdropdown.cpp
+++ b/xfa/fxfa/cxfa_ffdropdown.cpp
@@ -13,3 +13,7 @@
 CXFA_FFComboBox* CXFA_FFDropDown::AsComboBox() {
   return nullptr;
 }
+
+CXFA_FFDropDown* CXFA_FFDropDown::AsDropDown() {
+  return this;
+}
diff --git a/xfa/fxfa/cxfa_ffdropdown.h b/xfa/fxfa/cxfa_ffdropdown.h
index 45d30d9..b1751b4 100644
--- a/xfa/fxfa/cxfa_ffdropdown.h
+++ b/xfa/fxfa/cxfa_ffdropdown.h
@@ -16,6 +16,9 @@
  public:
   ~CXFA_FFDropDown() override;
 
+  // CXFA_FFField:
+  CXFA_FFDropDown* AsDropDown() override;
+
   virtual void InsertItem(const WideString& wsLabel, int32_t nIndex) = 0;
   virtual void DeleteItem(int32_t nIndex) = 0;
   virtual CXFA_FFComboBox* AsComboBox();
diff --git a/xfa/fxfa/cxfa_fffield.cpp b/xfa/fxfa/cxfa_fffield.cpp
index 692d13e..b031089 100644
--- a/xfa/fxfa/cxfa_fffield.cpp
+++ b/xfa/fxfa/cxfa_fffield.cpp
@@ -37,18 +37,18 @@
 #include "xfa/fxgraphics/cxfa_gecolor.h"
 #include "xfa/fxgraphics/cxfa_gepath.h"
 
-namespace {
-
-CXFA_FFField* ToField(CXFA_ContentLayoutItem* pItem) {
-  return pItem ? static_cast<CXFA_FFField*>(pItem->GetFFWidget()) : nullptr;
-}
-
-}  // namespace
-
 CXFA_FFField::CXFA_FFField(CXFA_Node* pNode) : CXFA_FFWidget(pNode) {}
 
 CXFA_FFField::~CXFA_FFField() = default;
 
+CXFA_FFDropDown* CXFA_FFField::AsDropDown() {
+  return nullptr;
+}
+
+CXFA_FFField* CXFA_FFField::AsField() {
+  return this;
+}
+
 CFX_RectF CXFA_FFField::GetBBox(FocusOption focus) {
   if (focus == kDoNotDrawFocus)
     return CXFA_FFWidget::GetBBox(kDoNotDrawFocus);
@@ -160,13 +160,15 @@
   }
 
   float fScrollOffset = 0;
-  CXFA_FFField* pPrev = ToField(GetLayoutItem()->GetPrev());
+  CXFA_ContentLayoutItem* pItem = GetLayoutItem()->GetPrev();
+  CXFA_FFField* pPrev = pItem ? ToField(pItem->GetFFWidget()) : nullptr;
   if (pPrev)
     fScrollOffset = -(m_pNode->GetUIMargin().top);
 
   while (pPrev) {
     fScrollOffset += pPrev->m_rtUI.height;
-    pPrev = ToField(pPrev->GetLayoutItem()->GetPrev());
+    pItem = pPrev->GetLayoutItem()->GetPrev();
+    pPrev = pItem ? ToField(pItem->GetFFWidget()) : nullptr;
   }
   static_cast<CFWL_Edit*>(GetNormalWidget())->SetScrollOffset(fScrollOffset);
 }
diff --git a/xfa/fxfa/cxfa_fffield.h b/xfa/fxfa/cxfa_fffield.h
index 47c0845..dd7b914 100644
--- a/xfa/fxfa/cxfa_fffield.h
+++ b/xfa/fxfa/cxfa_fffield.h
@@ -14,6 +14,7 @@
 #include "xfa/fxfa/cxfa_ffpageview.h"
 #include "xfa/fxfa/cxfa_ffwidget.h"
 
+class CXFA_FFDropDown;
 class CXFA_Node;
 
 #define XFA_MINUI_HEIGHT 4.32f
@@ -26,7 +27,10 @@
   explicit CXFA_FFField(CXFA_Node* pNode);
   ~CXFA_FFField() override;
 
-  // CXFA_FFWidget
+  virtual CXFA_FFDropDown* AsDropDown();
+
+  // CXFA_FFWidget:
+  CXFA_FFField* AsField() override;
   CFX_RectF GetBBox(FocusOption focus) override;
   void RenderWidget(CXFA_Graphics* pGS,
                     const CFX_Matrix& matrix,
@@ -57,7 +61,7 @@
   bool OnSetCursor(const CFX_PointF& point) override;
   FWL_WidgetHit HitTest(const CFX_PointF& point) override;
 
-  // IFWL_WidgetDelegate
+  // IFWL_WidgetDelegate:
   void OnProcessMessage(CFWL_Message* pMessage) override;
   void OnProcessEvent(CFWL_Event* pEvent) override;
   void OnDrawWidget(CXFA_Graphics* pGraphics,
@@ -105,4 +109,8 @@
   std::unique_ptr<CFWL_Widget> m_pNormalWidget;
 };
 
+inline CXFA_FFDropDown* ToDropDown(CXFA_FFField* field) {
+  return field ? field->AsDropDown() : nullptr;
+}
+
 #endif  // XFA_FXFA_CXFA_FFFIELD_H_
diff --git a/xfa/fxfa/cxfa_ffnotify.cpp b/xfa/fxfa/cxfa_ffnotify.cpp
index 4a9bfd3..fc70e6b 100644
--- a/xfa/fxfa/cxfa_ffnotify.cpp
+++ b/xfa/fxfa/cxfa_ffnotify.cpp
@@ -43,14 +43,6 @@
 #include "xfa/fxfa/parser/cxfa_node.h"
 #include "xfa/fxfa/parser/cxfa_passwordedit.h"
 
-namespace {
-
-CXFA_FFDropDown* ToDropDown(CXFA_FFWidget* widget) {
-  return static_cast<CXFA_FFDropDown*>(widget);
-}
-
-}  // namespace
-
 CXFA_FFNotify::CXFA_FFNotify(CXFA_FFDoc* pDoc) : m_pDoc(pDoc) {}
 
 CXFA_FFNotify::~CXFA_FFNotify() {}
@@ -71,7 +63,7 @@
   CXFA_FFWidget* pWidget = m_pDoc->GetDocView()->GetWidgetForNode(pSender);
   for (; pWidget; pWidget = pWidget->GetNextFFWidget()) {
     if (pWidget->IsLoaded())
-      ToDropDown(pWidget)->InsertItem(wsLabel, iIndex);
+      ToDropDown(ToField(pWidget))->InsertItem(wsLabel, iIndex);
   }
 }
 
@@ -83,7 +75,7 @@
   CXFA_FFWidget* pWidget = m_pDoc->GetDocView()->GetWidgetForNode(pSender);
   for (; pWidget; pWidget = pWidget->GetNextFFWidget()) {
     if (pWidget->IsLoaded())
-      ToDropDown(pWidget)->DeleteItem(iIndex);
+      ToDropDown(ToField(pWidget))->DeleteItem(iIndex);
   }
 }
 
@@ -268,7 +260,7 @@
   if (!hWidget->IsLoaded())
     return;
 
-  CXFA_FFDropDown* pDropDown = ToDropDown(hWidget);  // Safe if kChoiceList.
+  CXFA_FFDropDown* pDropDown = ToDropDown(ToField(hWidget));
   CXFA_FFComboBox* pComboBox = ToComboBox(pDropDown);
   if (!pComboBox)
     return;
diff --git a/xfa/fxfa/cxfa_ffwidget.cpp b/xfa/fxfa/cxfa_ffwidget.cpp
index b743a6e..881218c 100644
--- a/xfa/fxfa/cxfa_ffwidget.cpp
+++ b/xfa/fxfa/cxfa_ffwidget.cpp
@@ -288,6 +288,10 @@
   GetLayoutItem()->SetStatusBits(dwAdded);
 }
 
+CXFA_FFField* CXFA_FFWidget::AsField() {
+  return nullptr;
+}
+
 CFX_RectF CXFA_FFWidget::GetBBox(FocusOption focus) {
   if (focus == kDrawFocus || !m_pPageView)
     return CFX_RectF();
diff --git a/xfa/fxfa/cxfa_ffwidget.h b/xfa/fxfa/cxfa_ffwidget.h
index c173f59..4c362c1 100644
--- a/xfa/fxfa/cxfa_ffwidget.h
+++ b/xfa/fxfa/cxfa_ffwidget.h
@@ -25,6 +25,7 @@
 class CXFA_FFApp;
 class CXFA_FFDoc;
 class CXFA_FFDocView;
+class CXFA_FFField;
 class CXFA_FFPageView;
 class CXFA_FFWidgetHandler;
 class CXFA_Graphics;
@@ -77,6 +78,8 @@
   void DisplayCaret(bool bVisible, const CFX_RectF* pRtAnchor) override;
   void GetBorderColorAndThickness(FX_ARGB* cr, float* fWidth) override;
 
+  virtual CXFA_FFField* AsField();
+
   virtual CFX_RectF GetBBox(FocusOption focus);
   virtual void RenderWidget(CXFA_Graphics* pGS,
                             const CFX_Matrix& matrix,
@@ -196,4 +199,8 @@
   mutable CFX_RectF m_rtWidget;
 };
 
+inline CXFA_FFField* ToField(CXFA_FFWidget* widget) {
+  return widget ? widget->AsField() : nullptr;
+}
+
 #endif  // XFA_FXFA_CXFA_FFWIDGET_H_