Use more UnownedPtr in CPDF_FormControl.

To make this work, remove an UnownedPtr vector in CPDF_FormField and
make CPDF_InteractiveForm manage it instead.

Also simplify some code within CPDF_FormControl and
CPDF_InteractiveForm.

Change-Id: Ifc3a979dcdb992376a48db7a40840d2e76078500
Reviewed-on: https://pdfium-review.googlesource.com/c/43938
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfdoc/cpdf_formcontrol.cpp b/core/fpdfdoc/cpdf_formcontrol.cpp
index a1f1f8f..edd5fe5 100644
--- a/core/fpdfdoc/cpdf_formcontrol.cpp
+++ b/core/fpdfdoc/cpdf_formcontrol.cpp
@@ -71,10 +71,8 @@
          GetType() == CPDF_FormField::kRadioButton);
   ByteString csOn = GetOnStateName();
   CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pField->GetDict(), "Opt"));
-  if (pArray) {
-    int iIndex = m_pField->GetControlIndex(this);
-    csOn = pArray->GetStringAt(iIndex);
-  }
+  if (pArray)
+    csOn = pArray->GetStringAt(m_pField->GetControlIndex(this));
   if (csOn.IsEmpty())
     csOn = "Yes";
   return PDF_DecodeText(csOn);
@@ -196,9 +194,9 @@
     return CPDF_DefaultAppearance(m_pWidgetDict->GetStringFor("DA"));
 
   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pField->GetDict(), "DA");
-  if (pObj)
-    return CPDF_DefaultAppearance(pObj->GetString());
-  return m_pField->GetForm()->GetDefaultAppearance();
+  if (!pObj)
+    return m_pForm->GetDefaultAppearance();
+  return CPDF_DefaultAppearance(pObj->GetString());
 }
 
 CPDF_Font* CPDF_FormControl::GetDefaultControlFont() {
@@ -214,14 +212,13 @@
     if (pFonts) {
       CPDF_Dictionary* pElement = pFonts->GetDictFor(*csFontNameTag);
       if (pElement) {
-        CPDF_Font* pFont =
-            m_pField->GetForm()->GetDocument()->LoadFont(pElement);
+        CPDF_Font* pFont = m_pForm->GetDocument()->LoadFont(pElement);
         if (pFont)
           return pFont;
       }
     }
   }
-  if (CPDF_Font* pFormFont = m_pField->GetForm()->GetFormFont(*csFontNameTag))
+  if (CPDF_Font* pFormFont = m_pForm->GetFormFont(*csFontNameTag))
     return pFormFont;
 
   CPDF_Dictionary* pPageDict = m_pWidgetDict->GetDictFor("P");
@@ -231,8 +228,7 @@
     if (pFonts) {
       CPDF_Dictionary* pElement = pFonts->GetDictFor(*csFontNameTag);
       if (pElement) {
-        CPDF_Font* pFont =
-            m_pField->GetForm()->GetDocument()->LoadFont(pElement);
+        CPDF_Font* pFont = m_pForm->GetDocument()->LoadFont(pElement);
         if (pFont)
           return pFont;
       }
@@ -250,5 +246,5 @@
   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pField->GetDict(), "Q");
   if (pObj)
     return pObj->GetInteger();
-  return m_pField->GetForm()->GetFormAlignment();
+  return m_pForm->GetFormAlignment();
 }
diff --git a/core/fpdfdoc/cpdf_formcontrol.h b/core/fpdfdoc/cpdf_formcontrol.h
index 7288651..d66ae0a 100644
--- a/core/fpdfdoc/cpdf_formcontrol.h
+++ b/core/fpdfdoc/cpdf_formcontrol.h
@@ -48,7 +48,7 @@
   const CPDF_InteractiveForm* GetInteractiveForm() const {
     return m_pForm.Get();
   }
-  CPDF_FormField* GetField() const { return m_pField; }
+  CPDF_FormField* GetField() const { return m_pField.Get(); }
   CPDF_Dictionary* GetWidget() const { return m_pWidgetDict.Get(); }
   CFX_FloatRect GetRect() const;
 
@@ -115,7 +115,7 @@
   CPDF_Stream* GetIcon(const ByteString& csEntry);
   CPDF_ApSettings GetMK() const;
 
-  CPDF_FormField* const m_pField;
+  UnownedPtr<CPDF_FormField> const m_pField;
   UnownedPtr<CPDF_Dictionary> const m_pWidgetDict;
   UnownedPtr<const CPDF_InteractiveForm> const m_pForm;
 };
diff --git a/core/fpdfdoc/cpdf_formfield.cpp b/core/fpdfdoc/cpdf_formfield.cpp
index 4cb9496..2b06161 100644
--- a/core/fpdfdoc/cpdf_formfield.cpp
+++ b/core/fpdfdoc/cpdf_formfield.cpp
@@ -251,15 +251,20 @@
 }
 
 int CPDF_FormField::CountControls() const {
-  return pdfium::CollectionSize<int>(m_ControlList);
+  return pdfium::CollectionSize<int>(GetControls());
+}
+
+CPDF_FormControl* CPDF_FormField::GetControl(int index) const {
+  return GetControls()[index].Get();
 }
 
 int CPDF_FormField::GetControlIndex(const CPDF_FormControl* pControl) const {
   if (!pControl)
     return -1;
 
-  auto it = std::find(m_ControlList.begin(), m_ControlList.end(), pControl);
-  return it != m_ControlList.end() ? it - m_ControlList.begin() : -1;
+  const auto& controls = GetControls();
+  auto it = std::find(controls.begin(), controls.end(), pControl);
+  return it != controls.end() ? it - controls.begin() : -1;
 }
 
 FormFieldType CPDF_FormField::GetFieldType() const {
@@ -426,10 +431,11 @@
   if (const CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict.Get(), "MaxLen"))
     return pObj->GetInteger();
 
-  for (auto& pControl : m_ControlList) {
+  for (auto& pControl : GetControls()) {
     if (!pControl)
       continue;
-    CPDF_Dictionary* pWidgetDict = pControl->GetWidget();
+
+    const CPDF_Dictionary* pWidgetDict = pControl->GetWidget();
     if (pWidgetDict->KeyExist("MaxLen"))
       return pWidgetDict->GetIntegerFor("MaxLen");
   }
@@ -931,3 +937,8 @@
       break;
   }
 }
+
+const std::vector<UnownedPtr<CPDF_FormControl>>& CPDF_FormField::GetControls()
+    const {
+  return m_pForm->GetControlsForField(this);
+}
diff --git a/core/fpdfdoc/cpdf_formfield.h b/core/fpdfdoc/cpdf_formfield.h
index ce12169..2c525cb 100644
--- a/core/fpdfdoc/cpdf_formfield.h
+++ b/core/fpdfdoc/cpdf_formfield.h
@@ -111,9 +111,7 @@
 
   int CountControls() const;
 
-  CPDF_FormControl* GetControl(int index) const {
-    return m_ControlList[index].Get();
-  }
+  CPDF_FormControl* GetControl(int index) const;
 
   int GetControlIndex(const CPDF_FormControl* pControl) const;
   FormFieldType GetFieldType() const;
@@ -172,10 +170,6 @@
 
   WideString GetCheckValue(bool bDefault) const;
 
-  void AddFormControl(CPDF_FormControl* pFormControl) {
-    m_ControlList.emplace_back(pFormControl);
-  }
-
   void SetOpt(std::unique_ptr<CPDF_Object> pOpt);
 
  private:
@@ -197,6 +191,8 @@
   bool NotifyListOrComboBoxBeforeChange(const WideString& value);
   void NotifyListOrComboBoxAfterChange();
 
+  const std::vector<UnownedPtr<CPDF_FormControl>>& GetControls() const;
+
   CPDF_FormField::Type m_Type = kUnknown;
   uint32_t m_Flags = 0;
   bool m_bReadOnly = false;
@@ -205,8 +201,6 @@
 
   UnownedPtr<CPDF_InteractiveForm> const m_pForm;
   UnownedPtr<CPDF_Dictionary> const m_pDict;
-  // Owned by InteractiveForm parent.
-  std::vector<UnownedPtr<CPDF_FormControl>> m_ControlList;
   float m_FontSize = 0;
   UnownedPtr<CPDF_Font> m_pFont;
 };
diff --git a/core/fpdfdoc/cpdf_interactiveform.cpp b/core/fpdfdoc/cpdf_interactiveform.cpp
index 347fd55..754737c 100644
--- a/core/fpdfdoc/cpdf_interactiveform.cpp
+++ b/core/fpdfdoc/cpdf_interactiveform.cpp
@@ -390,10 +390,10 @@
  public:
   class Node {
    public:
-    Node() : m_pField(nullptr), m_level(0) {}
+    Node() : m_level(0) {}
     Node(const WideString& short_name, int level)
         : m_ShortName(short_name), m_level(level) {}
-    ~Node() {}
+    ~Node() = default;
 
     void AddChildNode(std::unique_ptr<Node> pNode) {
       m_Children.push_back(std::move(pNode));
@@ -466,9 +466,9 @@
   Node m_Root;
 };
 
-CFieldTree::CFieldTree() {}
+CFieldTree::CFieldTree() = default;
 
-CFieldTree::~CFieldTree() {}
+CFieldTree::~CFieldTree() = default;
 
 CFieldTree::Node* CFieldTree::AddChild(Node* pParent,
                                        const WideString& short_name) {
@@ -717,7 +717,7 @@
 
   for (size_t i = pAnnotList->size(); i > 0; --i) {
     size_t annot_index = i - 1;
-    CPDF_Dictionary* pAnnot = pAnnotList->GetDictAt(annot_index);
+    const CPDF_Dictionary* pAnnot = pAnnotList->GetDictAt(annot_index);
     if (!pAnnot)
       continue;
 
@@ -826,6 +826,13 @@
     m_pFormNotify->AfterFormReset(this);
 }
 
+const std::vector<UnownedPtr<CPDF_FormControl>>&
+CPDF_InteractiveForm::GetControlsForField(const CPDF_FormField* pField) const {
+  const auto& it = m_ControlLists.find(pField);
+  ASSERT(it != m_ControlLists.end());
+  return it->second;
+}
+
 void CPDF_InteractiveForm::LoadField(CPDF_Dictionary* pFieldDict, int nLevel) {
   if (nLevel > nMaxRecursion)
     return;
@@ -955,7 +962,7 @@
   auto pNew = pdfium::MakeUnique<CPDF_FormControl>(pField, pWidgetDict);
   CPDF_FormControl* pControl = pNew.get();
   m_ControlMap[pWidgetDict] = std::move(pNew);
-  pField->AddFormControl(pControl);
+  m_ControlLists[pField].emplace_back(pControl);
   return pControl;
 }
 
diff --git a/core/fpdfdoc/cpdf_interactiveform.h b/core/fpdfdoc/cpdf_interactiveform.h
index 1b68852..7a89320 100644
--- a/core/fpdfdoc/cpdf_interactiveform.h
+++ b/core/fpdfdoc/cpdf_interactiveform.h
@@ -91,6 +91,9 @@
   CPDF_Document* GetDocument() const { return m_pDocument.Get(); }
   CPDF_Dictionary* GetFormDict() const { return m_pFormDict.Get(); }
 
+  const std::vector<UnownedPtr<CPDF_FormControl>>& GetControlsForField(
+      const CPDF_FormField* pField) const;
+
  private:
   void LoadField(CPDF_Dictionary* pFieldDict, int nLevel);
   void AddTerminalField(CPDF_Dictionary* pFieldDict);
@@ -99,12 +102,15 @@
 
   static bool s_bUpdateAP;
 
+  ByteString m_bsEncoding;
   UnownedPtr<CPDF_Document> const m_pDocument;
   UnownedPtr<CPDF_Dictionary> m_pFormDict;
+  std::unique_ptr<CFieldTree> m_pFieldTree;
   std::map<const CPDF_Dictionary*, std::unique_ptr<CPDF_FormControl>>
       m_ControlMap;
-  std::unique_ptr<CFieldTree> m_pFieldTree;
-  ByteString m_bsEncoding;
+  // Points into |m_ControlMap|.
+  std::map<const CPDF_FormField*, std::vector<UnownedPtr<CPDF_FormControl>>>
+      m_ControlLists;
   UnownedPtr<IPDF_FormNotify> m_pFormNotify;
 };