Retain layout items rather than raw widgets in CFXA_TabParam.

Prevent them from popping out of existence while we might be iterating
over them.

-- forward-declare CXFA_TabParam in header file.

Bug: chromium:1109108
Change-Id: I0e97cf3a98861e004808c124f5cfdffb3abf27fd
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/71890
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/fpdfsdk/cpdfsdk_formfillenvironment.cpp b/fpdfsdk/cpdfsdk_formfillenvironment.cpp
index d74ac22..63a5114 100644
--- a/fpdfsdk/cpdfsdk_formfillenvironment.cpp
+++ b/fpdfsdk/cpdfsdk_formfillenvironment.cpp
@@ -737,6 +737,10 @@
     return false;
   }
 
+  // Might have been destroyed by Annot_OnKillFocus().
+  if (!pFocusAnnot)
+    return false;
+
   if (pFocusAnnot->GetAnnotSubtype() == CPDF_Annot::Subtype::WIDGET) {
     CPDFSDK_Widget* pWidget = ToCPDFSDKWidget(pFocusAnnot.Get());
     FormFieldType fieldType = pWidget->GetFieldType();
diff --git a/testing/resources/javascript/xfa_specific/bug_1109108.evt b/testing/resources/javascript/xfa_specific/bug_1109108.evt
new file mode 100644
index 0000000..7d58927
--- /dev/null
+++ b/testing/resources/javascript/xfa_specific/bug_1109108.evt
@@ -0,0 +1 @@
+keycode,9
diff --git a/testing/resources/javascript/xfa_specific/bug_1109108.in b/testing/resources/javascript/xfa_specific/bug_1109108.in
new file mode 100644
index 0000000..550112e
--- /dev/null
+++ b/testing/resources/javascript/xfa_specific/bug_1109108.in
@@ -0,0 +1,64 @@
+{{header}}
+{{include ../../xfa_catalog_1_0.fragment}}
+{{include ../../xfa_object_2_0.fragment}}
+{{include ../../xfa_preamble_3_0.fragment}}
+{{include ../../xfa_config_4_0.fragment}}
+{{object 5 0}} <<
+  {{streamlen}}
+>>
+stream
+<template>
+  <subform name="s1">
+    <subform name="s5">
+      <field name="field_28">
+        <calculate>
+          <script contentType="application/x-javascript">
+            var f=xfa.resolveNode("xfa.form.s1.s5.s6.field_35");
+            f.relevant ="print";
+          </script>
+        </calculate>
+        <ui>
+          <textEdit/>
+        </ui>
+        <value>
+          <text>CLGT.</text>
+        </value>
+      </field>
+      <subform name="s6">
+        <field name="field_35">
+          <ui>
+            <choiceList open="onEntry">
+              <border>
+                <edge/>
+              </border>
+            </choiceList>
+          </ui>
+          <items save="1">
+            <text>apples</text>
+            <text>bananas</text>
+            <text>pears</text>
+          </items>
+          <value>
+            <text>apples</text>
+          </value>
+          <event activity="change">
+            <script contentType="application/x-javascript">
+              xfa.template.remerge();
+              xfa.host.openList(this);
+              app.alert('remerged');
+            </script>
+          </event>
+        </field>
+      </subform>
+    </subform>
+  </subform>
+</template>
+endstream
+endobj
+{{include ../../xfa_locale_6_0.fragment}}
+{{include ../../xfa_postamble_7_0.fragment}}
+{{include ../../xfa_pages_8_0.fragment}}
+{{xref}}
+{{trailer}}
+{{startxref}}
+%%EOF
diff --git a/testing/resources/javascript/xfa_specific/bug_1109108_expected.txt b/testing/resources/javascript/xfa_specific/bug_1109108_expected.txt
new file mode 100644
index 0000000..86c4845
--- /dev/null
+++ b/testing/resources/javascript/xfa_specific/bug_1109108_expected.txt
@@ -0,0 +1,2 @@
+Alert: remerged
+Alert: remerged
diff --git a/xfa/fxfa/cxfa_ffpageview.cpp b/xfa/fxfa/cxfa_ffpageview.cpp
index 996d8e5..47b5fdd 100644
--- a/xfa/fxfa/cxfa_ffpageview.cpp
+++ b/xfa/fxfa/cxfa_ffpageview.cpp
@@ -114,6 +114,30 @@
 
 }  // namespace
 
+class CXFA_TabParam {
+ public:
+  CXFA_TabParam() = default;
+  explicit CXFA_TabParam(CXFA_FFWidget* pWidget)
+      : m_pItem(pWidget->GetLayoutItem()) {}
+
+  ~CXFA_TabParam() = default;
+
+  CXFA_FFWidget* GetWidget() const { return m_pItem->GetFFWidget(); }
+  const std::vector<RetainPtr<CXFA_ContentLayoutItem>>& GetChildren() const {
+    return m_Children;
+  }
+  void ClearChildren() { m_Children.clear(); }
+  void AppendTabParam(CXFA_TabParam* pParam) {
+    m_Children.push_back(pParam->m_pItem);
+    m_Children.insert(m_Children.end(), pParam->m_Children.begin(),
+                      pParam->m_Children.end());
+  }
+
+ private:
+  RetainPtr<CXFA_ContentLayoutItem> m_pItem;
+  std::vector<RetainPtr<CXFA_ContentLayoutItem>> m_Children;
+};
+
 CXFA_FFPageView::CXFA_FFPageView(CXFA_FFDocView* pDocView, CXFA_Node* pPageArea)
     : m_pPageArea(pPageArea), m_pDocView(pDocView) {}
 
@@ -225,16 +249,6 @@
   return pWidget;
 }
 
-void CXFA_TabParam::AppendTabParam(CXFA_TabParam* pParam) {
-  m_Children.push_back(pParam->GetWidget());
-  m_Children.insert(m_Children.end(), pParam->GetChildren().begin(),
-                    pParam->GetChildren().end());
-}
-
-void CXFA_TabParam::ClearChildren() {
-  m_Children.clear();
-}
-
 CXFA_FFTabOrderPageWidgetIterator::CXFA_FFTabOrderPageWidgetIterator(
     CXFA_FFPageView* pPageView,
     uint32_t dwFilter)
@@ -434,14 +448,14 @@
 CXFA_FFTabOrderPageWidgetIterator::CreateSpaceOrderLayoutItems() {
   std::vector<RetainPtr<CXFA_ContentLayoutItem>> items;
   CXFA_LayoutItemIterator sIterator(m_pPageViewLayout.Get());
-  auto pParam = std::make_unique<CXFA_TabParam>(nullptr);
+  auto pParam = std::make_unique<CXFA_TabParam>();
   bool bCurrentItem = false;
   bool bContentArea = false;
   OrderContainer(&sIterator, nullptr, pParam.get(), &bCurrentItem,
                  &bContentArea, false);
   items.reserve(pParam->GetChildren().size());
-  for (CXFA_FFWidget* widget : pParam->GetChildren())
-    items.emplace_back(widget->GetLayoutItem());
+  for (const auto& layout_item : pParam->GetChildren())
+    items.push_back(layout_item);
 
   sIterator.Reset();
   bCurrentItem = false;
@@ -449,8 +463,9 @@
   pParam->ClearChildren();
   OrderContainer(&sIterator, nullptr, pParam.get(), &bCurrentItem,
                  &bContentArea, true);
-  for (CXFA_FFWidget* widget : pParam->GetChildren())
-    items.emplace_back(widget->GetLayoutItem());
+  for (const auto& layout_item : pParam->GetChildren())
+    items.push_back(layout_item);
+
   return items;
 }
 
@@ -466,7 +481,3 @@
   }
   return pWidget;
 }
-
-CXFA_TabParam::CXFA_TabParam(CXFA_FFWidget* pWidget) : m_pWidget(pWidget) {}
-
-CXFA_TabParam::~CXFA_TabParam() = default;
diff --git a/xfa/fxfa/cxfa_ffpageview.h b/xfa/fxfa/cxfa_ffpageview.h
index f2fab62..ed22572 100644
--- a/xfa/fxfa/cxfa_ffpageview.h
+++ b/xfa/fxfa/cxfa_ffpageview.h
@@ -19,6 +19,7 @@
 
 class CXFA_FFWidget;
 class CXFA_FFDocView;
+class CXFA_TabParam;
 
 class CXFA_FFPageView : public Observable {
  public:
@@ -65,21 +66,6 @@
   const bool m_bIgnoreRelevant;
 };
 
-class CXFA_TabParam {
- public:
-  explicit CXFA_TabParam(CXFA_FFWidget* pWidget);
-  ~CXFA_TabParam();
-
-  void AppendTabParam(CXFA_TabParam* pParam);
-  void ClearChildren();
-  CXFA_FFWidget* GetWidget() const { return m_pWidget.Get(); }
-  const std::vector<CXFA_FFWidget*>& GetChildren() const { return m_Children; }
-
- private:
-  UnownedPtr<CXFA_FFWidget> const m_pWidget;
-  std::vector<CXFA_FFWidget*> m_Children;
-};
-
 class CXFA_FFTabOrderPageWidgetIterator final : public IXFA_WidgetIterator {
  public:
   CXFA_FFTabOrderPageWidgetIterator(CXFA_FFPageView* pPageView,