Merge to Master: Remove CFX_PtrArray from fx_xml.h

Original Review URL: https://codereview.chromium.org/1671473002 .
(cherry picked from commit cdac3446f26751ff5db4123d87710f8b4e15d11c)

TBR=thestig@chromium.org

Review URL: https://codereview.chromium.org/1665273002 .
diff --git a/core/include/fxcrt/fx_xml.h b/core/include/fxcrt/fx_xml.h
index eaf872c..e1255c1 100644
--- a/core/include/fxcrt/fx_xml.h
+++ b/core/include/fxcrt/fx_xml.h
@@ -7,7 +7,9 @@
 #ifndef CORE_INCLUDE_FXCRT_FX_XML_H_
 #define CORE_INCLUDE_FXCRT_FX_XML_H_
 
-#include "fx_basic.h"
+#include <vector>
+
+#include "core/include/fxcrt/fx_basic.h"
 
 class CXML_AttrItem {
  public:
@@ -15,6 +17,7 @@
   CFX_ByteString m_AttrName;
   CFX_WideString m_Value;
 };
+
 class CXML_AttrMap {
  public:
   CXML_AttrMap() { m_pMap = NULL; }
@@ -30,6 +33,7 @@
   CXML_AttrItem& GetAt(int index) const;
   CFX_ObjectArray<CXML_AttrItem>* m_pMap;
 };
+
 class CXML_Content {
  public:
   CXML_Content() : m_bCDATA(FALSE), m_Content() {}
@@ -40,8 +44,11 @@
   FX_BOOL m_bCDATA;
   CFX_WideString m_Content;
 };
+
 class CXML_Element {
  public:
+  enum ChildType { Invalid, Element, Content };
+
   static CXML_Element* Parse(const void* pBuffer,
                              size_t size,
                              FX_BOOL bSaveSpaceChars = FALSE,
@@ -52,31 +59,23 @@
   static CXML_Element* Parse(IFX_BufferRead* pBuffer,
                              FX_BOOL bSaveSpaceChars = FALSE,
                              FX_FILESIZE* pParsedSize = NULL);
+
   CXML_Element(const CFX_ByteStringC& qSpace, const CFX_ByteStringC& tagName);
   CXML_Element(const CFX_ByteStringC& qTagName);
   CXML_Element();
-
   ~CXML_Element();
 
   void Empty();
-
   CFX_ByteString GetTagName(FX_BOOL bQualified = FALSE) const;
-
   CFX_ByteString GetNamespace(FX_BOOL bQualified = FALSE) const;
-
   CFX_ByteString GetNamespaceURI(const CFX_ByteStringC& qName) const;
-
   CXML_Element* GetParent() const { return m_pParent; }
-
   FX_DWORD CountAttrs() const { return m_AttrMap.GetSize(); }
-
   void GetAttrByIndex(int index,
                       CFX_ByteString& space,
                       CFX_ByteString& name,
                       CFX_WideString& value) const;
-
   FX_BOOL HasAttr(const CFX_ByteStringC& qName) const;
-
   FX_BOOL GetAttrValue(const CFX_ByteStringC& name,
                        CFX_WideString& attribute) const;
   CFX_WideString GetAttrValue(const CFX_ByteStringC& name) const {
@@ -129,16 +128,10 @@
     return attr;
   }
 
-  FX_DWORD CountChildren() const;
-
-  enum ChildType { Invalid, Element, Content };
-
+  FX_DWORD CountChildren() const { return m_Children.size(); }
   ChildType GetChildType(FX_DWORD index) const;
-
   CFX_WideString GetContent(FX_DWORD index) const;
-
   CXML_Element* GetElement(FX_DWORD index) const;
-
   CXML_Element* GetElement(const CFX_ByteStringC& space,
                            const CFX_ByteStringC& tag) const {
     return GetElement(space, tag, 0);
@@ -146,29 +139,28 @@
 
   FX_DWORD CountElements(const CFX_ByteStringC& space,
                          const CFX_ByteStringC& tag) const;
-
   CXML_Element* GetElement(const CFX_ByteStringC& space,
                            const CFX_ByteStringC& tag,
                            int index) const;
 
   FX_DWORD FindElement(CXML_Element* pChild) const;
-
   void SetTag(const CFX_ByteStringC& qSpace, const CFX_ByteStringC& tagname);
-
   void SetTag(const CFX_ByteStringC& qTagName);
-
   void RemoveChildren();
-
   void RemoveChild(FX_DWORD index);
 
  protected:
+  struct ChildRecord {
+    ChildType type;
+    void* child;  // CXML_Element and CXML_Content lack a common ancestor.
+  };
+
   CXML_Element* m_pParent;
   CFX_ByteString m_QSpaceName;
   CFX_ByteString m_TagName;
-
   CXML_AttrMap m_AttrMap;
+  std::vector<ChildRecord> m_Children;
 
-  CFX_PtrArray m_Children;
   friend class CXML_Parser;
   friend class CXML_Composer;
 };
diff --git a/core/src/fxcrt/fx_xml_parser.cpp b/core/src/fxcrt/fx_xml_parser.cpp
index 0b71836..fb8b1db 100644
--- a/core/src/fxcrt/fx_xml_parser.cpp
+++ b/core/src/fxcrt/fx_xml_parser.cpp
@@ -467,8 +467,8 @@
               break;
             }
             pSubElement->m_pParent = pElement;
-            pElement->m_Children.Add((void*)CXML_Element::Element);
-            pElement->m_Children.Add(pSubElement);
+            pElement->m_Children.push_back(
+                {CXML_Element::Element, pSubElement});
             SkipWhiteSpaces();
           }
           break;
@@ -514,8 +514,7 @@
   }
   CXML_Content* pContent = new CXML_Content;
   pContent->Set(bCDATA, content);
-  pElement->m_Children.Add((void*)CXML_Element::Content);
-  pElement->m_Children.Add(pContent);
+  pElement->m_Children.push_back({CXML_Element::Content, pContent});
 }
 static CXML_Element* XML_ContinueParse(CXML_Parser& parser,
                                        FX_BOOL bSaveSpaceChars,
@@ -573,18 +572,16 @@
   RemoveChildren();
 }
 void CXML_Element::RemoveChildren() {
-  for (int i = 0; i < m_Children.GetSize(); i += 2) {
-    ChildType type = (ChildType)(uintptr_t)m_Children.GetAt(i);
-    if (type == Content) {
-      CXML_Content* content = (CXML_Content*)m_Children.GetAt(i + 1);
-      delete content;
-    } else if (type == Element) {
-      CXML_Element* child = (CXML_Element*)m_Children.GetAt(i + 1);
+  for (const ChildRecord& record : m_Children) {
+    if (record.type == Content) {
+      delete static_cast<CXML_Content*>(record.child);
+    } else if (record.type == Element) {
+      CXML_Element* child = static_cast<CXML_Element*>(record.child);
       child->RemoveChildren();
       delete child;
     }
   }
-  m_Children.RemoveAll();
+  m_Children.clear();
 }
 CFX_ByteString CXML_Element::GetTagName(FX_BOOL bQualified) const {
   if (!bQualified || m_QSpaceName.IsEmpty()) {
@@ -688,45 +685,32 @@
   }
   return FALSE;
 }
-FX_DWORD CXML_Element::CountChildren() const {
-  return m_Children.GetSize() / 2;
-}
 CXML_Element::ChildType CXML_Element::GetChildType(FX_DWORD index) const {
-  index <<= 1;
-  if (index >= (FX_DWORD)m_Children.GetSize()) {
-    return Invalid;
-  }
-  return (ChildType)(uintptr_t)m_Children.GetAt(index);
+  return index < m_Children.size() ? m_Children[index].type : Invalid;
 }
 CFX_WideString CXML_Element::GetContent(FX_DWORD index) const {
-  index <<= 1;
-  if (index >= (FX_DWORD)m_Children.GetSize() ||
-      (ChildType)(uintptr_t)m_Children.GetAt(index) != Content) {
-    return CFX_WideString();
-  }
-  CXML_Content* pContent = (CXML_Content*)m_Children.GetAt(index + 1);
-  if (pContent) {
-    return pContent->m_Content;
+  if (index < m_Children.size() && m_Children[index].type == Content) {
+    CXML_Content* pContent =
+        static_cast<CXML_Content*>(m_Children[index].child);
+    if (pContent)
+      return pContent->m_Content;
   }
   return CFX_WideString();
 }
 CXML_Element* CXML_Element::GetElement(FX_DWORD index) const {
-  index <<= 1;
-  if (index >= (FX_DWORD)m_Children.GetSize() ||
-      (ChildType)(uintptr_t)m_Children.GetAt(index) != Element) {
-    return NULL;
+  if (index < m_Children.size() && m_Children[index].type == Element) {
+    return static_cast<CXML_Element*>(m_Children[index].child);
   }
-  return (CXML_Element*)m_Children.GetAt(index + 1);
+  return nullptr;
 }
 FX_DWORD CXML_Element::CountElements(const CFX_ByteStringC& space,
                                      const CFX_ByteStringC& tag) const {
   int count = 0;
-  for (int i = 0; i < m_Children.GetSize(); i += 2) {
-    ChildType type = (ChildType)(uintptr_t)m_Children.GetAt(i);
-    if (type != Element) {
+  for (const ChildRecord& record : m_Children) {
+    if (record.type != Element)
       continue;
-    }
-    CXML_Element* pKid = (CXML_Element*)m_Children.GetAt(i + 1);
+
+    CXML_Element* pKid = static_cast<CXML_Element*>(record.child);
     if ((space.IsEmpty() || pKid->m_QSpaceName == space) &&
         pKid->m_TagName == tag) {
       count++;
@@ -737,31 +721,30 @@
 CXML_Element* CXML_Element::GetElement(const CFX_ByteStringC& space,
                                        const CFX_ByteStringC& tag,
                                        int index) const {
-  if (index < 0) {
-    return NULL;
-  }
-  for (int i = 0; i < m_Children.GetSize(); i += 2) {
-    ChildType type = (ChildType)(uintptr_t)m_Children.GetAt(i);
-    if (type != Element) {
+  if (index < 0)
+    return nullptr;
+
+  for (const ChildRecord& record : m_Children) {
+    if (record.type != Element)
       continue;
-    }
-    CXML_Element* pKid = (CXML_Element*)m_Children.GetAt(i + 1);
-    if ((!space.IsEmpty() && pKid->m_QSpaceName != space) ||
-        pKid->m_TagName != tag) {
-      continue;
-    }
-    if (index-- == 0) {
-      return pKid;
+
+    CXML_Element* pKid = static_cast<CXML_Element*>(record.child);
+    if ((space.IsEmpty() || pKid->m_QSpaceName == space) &&
+        pKid->m_TagName == tag) {
+      if (index-- == 0)
+        return pKid;
     }
   }
   return NULL;
 }
 FX_DWORD CXML_Element::FindElement(CXML_Element* pChild) const {
-  for (int i = 0; i < m_Children.GetSize(); i += 2) {
-    if ((ChildType)(uintptr_t)m_Children.GetAt(i) == Element &&
-        (CXML_Element*)m_Children.GetAt(i + 1) == pChild) {
-      return (FX_DWORD)(i >> 1);
+  int index = 0;
+  for (const ChildRecord& record : m_Children) {
+    if (record.type == Element &&
+        static_cast<CXML_Element*>(record.child) == pChild) {
+      return index;
     }
+    ++index;
   }
   return (FX_DWORD)-1;
 }