Convert |CXFA_FFDocView::m_IndexChangedSubforms| to a deque.

Pop off items one at a time to safely iterate through it. Add a set to
keep track of seen notes to prevent infinite loops.

BUG=chromium:932900

Change-Id: I74eb29262e8ba29097638f7103ef427799a06fc5
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/52971
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/xfa/fxfa/cxfa_ffdocview.cpp b/xfa/fxfa/cxfa_ffdocview.cpp
index 587bcfa..0b069f6 100644
--- a/xfa/fxfa/cxfa_ffdocview.cpp
+++ b/xfa/fxfa/cxfa_ffdocview.cpp
@@ -6,6 +6,7 @@
 
 #include "xfa/fxfa/cxfa_ffdocview.h"
 
+#include <set>
 #include <utility>
 
 #include "core/fxcrt/fx_extension.h"
@@ -463,8 +464,12 @@
 }
 
 void CXFA_FFDocView::RunSubformIndexChange() {
-  for (CXFA_Node* pSubformNode : m_IndexChangedSubforms) {
-    if (!pSubformNode->IsWidgetReady())
+  std::set<CXFA_Node*> seen;
+  while (!m_IndexChangedSubforms.empty()) {
+    CXFA_Node* pSubformNode = m_IndexChangedSubforms.front();
+    m_IndexChangedSubforms.pop_front();
+    bool bInserted = seen.insert(pSubformNode).second;
+    if (!bInserted || !pSubformNode->IsWidgetReady())
       continue;
 
     CXFA_EventParam eParam;
@@ -472,7 +477,6 @@
     eParam.m_pTarget = pSubformNode;
     pSubformNode->ProcessEvent(this, XFA_AttributeValue::IndexChange, &eParam);
   }
-  m_IndexChangedSubforms.clear();
 }
 
 void CXFA_FFDocView::AddNewFormNode(CXFA_Node* pNode) {
@@ -482,7 +486,8 @@
 
 void CXFA_FFDocView::AddIndexChangedSubform(CXFA_Node* pNode) {
   ASSERT(pNode->GetElementType() == XFA_Element::Subform);
-  m_IndexChangedSubforms.push_back(pNode);
+  if (!pdfium::ContainsValue(m_IndexChangedSubforms, pNode))
+    m_IndexChangedSubforms.push_back(pNode);
 }
 
 void CXFA_FFDocView::RunDocClose() {
diff --git a/xfa/fxfa/cxfa_ffdocview.h b/xfa/fxfa/cxfa_ffdocview.h
index b2debf3..91aae15 100644
--- a/xfa/fxfa/cxfa_ffdocview.h
+++ b/xfa/fxfa/cxfa_ffdocview.h
@@ -124,7 +124,7 @@
   std::vector<CXFA_Node*> m_CalculateNodes;
   std::vector<CXFA_BindItems*> m_BindItems;
   std::deque<CXFA_Node*> m_NewAddedNodes;
-  std::vector<CXFA_Node*> m_IndexChangedSubforms;
+  std::deque<CXFA_Node*> m_IndexChangedSubforms;
   XFA_DOCVIEW_LAYOUTSTATUS m_iStatus = XFA_DOCVIEW_LAYOUTSTATUS_None;
   int32_t m_iLock = 0;
 };