Use std::vector<std::unique_ptr<CPVT_WordInfo>> as word array.

We never push nullptrs into this array, so remove some checks for
nullness, but be really careful about bounds checking.

Change-Id: I79960a4cc9a729b3d5985f297aea8c4b03ceb601
Reviewed-on: https://pdfium-review.googlesource.com/3103
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfdoc/cpdf_variabletext.cpp b/core/fpdfdoc/cpdf_variabletext.cpp
index dcd3a07..d5746b1 100644
--- a/core/fpdfdoc/cpdf_variabletext.cpp
+++ b/core/fpdfdoc/cpdf_variabletext.cpp
@@ -170,16 +170,12 @@
 bool CPDF_VariableText::Iterator::GetWord(CPVT_Word& word) const {
   word.WordPlace = m_CurPos;
   CSection* pSection = m_pVT->m_SectionArray.GetAt(m_CurPos.nSecIndex);
-  if (!pSection)
+  if (!pSection ||
+      !pdfium::IndexInBounds(pSection->m_LineArray, m_CurPos.nLineIndex) ||
+      !pdfium::IndexInBounds(pSection->m_WordArray, m_CurPos.nWordIndex)) {
     return false;
-
-  if (!pdfium::IndexInBounds(pSection->m_LineArray, m_CurPos.nLineIndex))
-    return false;
-
-  CPVT_WordInfo* pWord = pSection->m_WordArray.GetAt(m_CurPos.nWordIndex);
-  if (!pWord)
-    return false;
-
+  }
+  CPVT_WordInfo* pWord = pSection->m_WordArray[m_CurPos.nWordIndex].get();
   word.Word = pWord->Word;
   word.nCharset = pWord->nCharset;
   word.fWidth = m_pVT->GetWordWidth(*pWord);
@@ -197,13 +193,11 @@
 
 bool CPDF_VariableText::Iterator::SetWord(const CPVT_Word& word) {
   CSection* pSection = m_pVT->m_SectionArray.GetAt(m_CurPos.nSecIndex);
-  if (!pSection)
+  if (!pSection ||
+      !pdfium::IndexInBounds(pSection->m_WordArray, m_CurPos.nWordIndex)) {
     return false;
-
-  CPVT_WordInfo* pWord = pSection->m_WordArray.GetAt(m_CurPos.nWordIndex);
-  if (!pWord)
-    return false;
-
+  }
+  CPVT_WordInfo* pWord = pSection->m_WordArray[m_CurPos.nWordIndex].get();
   if (pWord->pWordProps)
     *pWord->pWordProps = word.WordProps;
   return true;
@@ -329,25 +323,22 @@
 
   CPVT_WordPlace wordplace = place;
   UpdateWordPlace(wordplace);
-  CPVT_WordPlace newplace = place;
+  CPVT_WordPlace result = place;
   if (CSection* pSection = m_SectionArray.GetAt(wordplace.nSecIndex)) {
     CPVT_WordPlace NewPlace(wordplace.nSecIndex + 1, 0, -1);
     CPVT_SectionInfo secinfo;
     AddSection(NewPlace, secinfo);
-    newplace = NewPlace;
+    result = NewPlace;
     if (CSection* pNewSection = m_SectionArray.GetAt(NewPlace.nSecIndex)) {
-      for (int32_t w = wordplace.nWordIndex + 1,
-                   sz = pSection->m_WordArray.GetSize();
-           w < sz; w++) {
-        if (CPVT_WordInfo* pWord = pSection->m_WordArray.GetAt(w)) {
-          NewPlace.nWordIndex++;
-          pNewSection->AddWord(NewPlace, *pWord);
-        }
+      for (int32_t w = wordplace.nWordIndex + 1;
+           w < pdfium::CollectionSize<int32_t>(pSection->m_WordArray); ++w) {
+        NewPlace.nWordIndex++;
+        pNewSection->AddWord(NewPlace, *pSection->m_WordArray[w]);
       }
     }
     ClearSectionRightWords(wordplace);
   }
-  return newplace;
+  return result;
 }
 
 CPVT_WordPlace CPDF_VariableText::InsertText(const CPVT_WordPlace& place,
@@ -478,7 +469,7 @@
   for (i = 0, sz = m_SectionArray.GetSize(); i < sz && i < newplace.nSecIndex;
        i++) {
     if (CSection* pSection = m_SectionArray.GetAt(i)) {
-      nIndex += pSection->m_WordArray.GetSize();
+      nIndex += pdfium::CollectionSize<int32_t>(pSection->m_WordArray);
       if (i != m_SectionArray.GetSize() - 1)
         nIndex += kReturnLength;
     }
@@ -494,7 +485,7 @@
   bool bFind = false;
   for (int32_t i = 0, sz = m_SectionArray.GetSize(); i < sz; i++) {
     if (CSection* pSection = m_SectionArray.GetAt(i)) {
-      nIndex += pSection->m_WordArray.GetSize();
+      nIndex += pdfium::CollectionSize<int32_t>(pSection->m_WordArray);
       if (nIndex == index) {
         place = pSection->GetEndWordPlace();
         bFind = true;
@@ -679,10 +670,11 @@
 int32_t CPDF_VariableText::GetTotalWords() const {
   int32_t nTotal = 0;
   for (int32_t i = 0, sz = m_SectionArray.GetSize(); i < sz; i++) {
-    if (CSection* pSection = m_SectionArray.GetAt(i))
-      nTotal += (pSection->m_WordArray.GetSize() + kReturnLength);
+    if (CSection* pSection = m_SectionArray.GetAt(i)) {
+      nTotal += pdfium::CollectionSize<int32_t>(pSection->m_WordArray) +
+                kReturnLength;
+    }
   }
-
   return nTotal - kReturnLength;
 }
 
@@ -735,24 +727,24 @@
 
 bool CPDF_VariableText::GetWordInfo(const CPVT_WordPlace& place,
                                     CPVT_WordInfo& wordinfo) {
-  if (CSection* pSection = m_SectionArray.GetAt(place.nSecIndex)) {
-    if (CPVT_WordInfo* pWord = pSection->m_WordArray.GetAt(place.nWordIndex)) {
-      wordinfo = *pWord;
-      return true;
-    }
+  CSection* pSection = m_SectionArray.GetAt(place.nSecIndex);
+  if (!pSection ||
+      !pdfium::IndexInBounds(pSection->m_WordArray, place.nWordIndex)) {
+    return false;
   }
-  return false;
+  wordinfo = *pSection->m_WordArray[place.nWordIndex];
+  return true;
 }
 
 bool CPDF_VariableText::SetWordInfo(const CPVT_WordPlace& place,
                                     const CPVT_WordInfo& wordinfo) {
-  if (CSection* pSection = m_SectionArray.GetAt(place.nSecIndex)) {
-    if (CPVT_WordInfo* pWord = pSection->m_WordArray.GetAt(place.nWordIndex)) {
-      *pWord = wordinfo;
-      return true;
-    }
+  CSection* pSection = m_SectionArray.GetAt(place.nSecIndex);
+  if (!pSection ||
+      !pdfium::IndexInBounds(pSection->m_WordArray, place.nWordIndex)) {
+    return false;
   }
-  return false;
+  *pSection->m_WordArray[place.nWordIndex] = wordinfo;
+  return true;
 }
 
 bool CPDF_VariableText::GetLineInfo(const CPVT_WordPlace& place,
@@ -876,13 +868,14 @@
 
 void CPDF_VariableText::ClearSectionRightWords(const CPVT_WordPlace& place) {
   CPVT_WordPlace wordplace = AdjustLineHeader(place, true);
-  if (CSection* pSection = m_SectionArray.GetAt(place.nSecIndex)) {
-    for (int32_t w = pSection->m_WordArray.GetSize() - 1;
-         w > wordplace.nWordIndex; w--) {
-      delete pSection->m_WordArray.GetAt(w);
-      pSection->m_WordArray.RemoveAt(w);
-    }
+  CSection* pSection = m_SectionArray.GetAt(place.nSecIndex);
+  if (!pSection ||
+      !pdfium::IndexInBounds(pSection->m_WordArray, wordplace.nWordIndex + 1)) {
+    return;
   }
+  pSection->m_WordArray.erase(
+      pSection->m_WordArray.begin() + wordplace.nWordIndex + 1,
+      pSection->m_WordArray.end());
 }
 
 CPVT_WordPlace CPDF_VariableText::AdjustLineHeader(const CPVT_WordPlace& place,
@@ -895,14 +888,14 @@
 bool CPDF_VariableText::ClearEmptySection(const CPVT_WordPlace& place) {
   if (place.nSecIndex == 0 && m_SectionArray.GetSize() == 1)
     return false;
-  if (CSection* pSection = m_SectionArray.GetAt(place.nSecIndex)) {
-    if (pSection->m_WordArray.GetSize() == 0) {
-      delete pSection;
-      m_SectionArray.RemoveAt(place.nSecIndex);
-      return true;
-    }
-  }
-  return false;
+
+  CSection* pSection = m_SectionArray.GetAt(place.nSecIndex);
+  if (!pSection || !pSection->m_WordArray.empty())
+    return false;
+
+  delete pSection;
+  m_SectionArray.RemoveAt(place.nSecIndex);
+  return true;
 }
 
 void CPDF_VariableText::ClearEmptySections(const CPVT_WordRange& PlaceRange) {
@@ -918,12 +911,9 @@
   CPVT_WordPlace oldplace = AdjustLineHeader(place, true);
   if (CSection* pNextSection = m_SectionArray.GetAt(place.nSecIndex + 1)) {
     if (CSection* pSection = m_SectionArray.GetAt(oldplace.nSecIndex)) {
-      for (int32_t w = 0, sz = pNextSection->m_WordArray.GetSize(); w < sz;
-           w++) {
-        if (CPVT_WordInfo* pWord = pNextSection->m_WordArray.GetAt(w)) {
-          oldplace.nWordIndex++;
-          pSection->AddWord(oldplace, *pWord);
-        }
+      for (auto& pWord : pNextSection->m_WordArray) {
+        oldplace.nWordIndex++;
+        pSection->AddWord(oldplace, *pWord);
       }
     }
     delete pNextSection;
@@ -943,21 +933,23 @@
 }
 
 CPVT_WordPlace CPDF_VariableText::ClearLeftWord(const CPVT_WordPlace& place) {
-  if (CSection* pSection = m_SectionArray.GetAt(place.nSecIndex)) {
-    CPVT_WordPlace leftplace = GetPrevWordPlace(place);
-    if (leftplace != place) {
-      if (leftplace.nSecIndex != place.nSecIndex) {
-        if (pSection->m_WordArray.GetSize() == 0)
-          ClearEmptySection(place);
-        else
-          LinkLatterSection(leftplace);
-      } else {
-        pSection->ClearWord(place);
-      }
-    }
-    return leftplace;
+  CSection* pSection = m_SectionArray.GetAt(place.nSecIndex);
+  if (!pSection)
+    return place;
+
+  CPVT_WordPlace leftplace = GetPrevWordPlace(place);
+  if (leftplace == place)
+    return place;
+
+  if (leftplace.nSecIndex != place.nSecIndex) {
+    if (pSection->m_WordArray.empty())
+      ClearEmptySection(place);
+    else
+      LinkLatterSection(leftplace);
+  } else {
+    pSection->ClearWord(place);
   }
-  return place;
+  return leftplace;
 }
 
 CPVT_WordPlace CPDF_VariableText::ClearRightWord(const CPVT_WordPlace& place) {
diff --git a/core/fpdfdoc/csection.cpp b/core/fpdfdoc/csection.cpp
index 0c78255..6198d78 100644
--- a/core/fpdfdoc/csection.cpp
+++ b/core/fpdfdoc/csection.cpp
@@ -15,25 +15,13 @@
 
 CSection::CSection(CPDF_VariableText* pVT) : m_pVT(pVT) {}
 
-CSection::~CSection() {
-  ResetAll();
-}
+CSection::~CSection() {}
 
 void CSection::ResetAll() {
-  ResetWordArray();
-  ResetLineArray();
-}
-
-void CSection::ResetLineArray() {
+  m_WordArray.clear();
   m_LineArray.clear();
 }
 
-void CSection::ResetWordArray() {
-  for (int32_t i = 0, sz = m_WordArray.GetSize(); i < sz; i++)
-    delete m_WordArray.GetAt(i);
-  m_WordArray.RemoveAll();
-}
-
 void CSection::ResetLinePlace() {
   int32_t i = 0;
   for (auto& pLine : m_LineArray) {
@@ -44,13 +32,10 @@
 
 CPVT_WordPlace CSection::AddWord(const CPVT_WordPlace& place,
                                  const CPVT_WordInfo& wordinfo) {
-  CPVT_WordInfo* pWord = new CPVT_WordInfo(wordinfo);
-  int32_t nWordIndex =
-      pdfium::clamp(place.nWordIndex, 0, m_WordArray.GetSize());
-  if (nWordIndex == m_WordArray.GetSize())
-    m_WordArray.Add(pWord);
-  else
-    m_WordArray.InsertAt(nWordIndex, pWord);
+  int32_t nWordIndex = pdfium::clamp(
+      place.nWordIndex, 0, pdfium::CollectionSize<int32_t>(m_WordArray));
+  m_WordArray.insert(m_WordArray.begin() + nWordIndex,
+                     pdfium::MakeUnique<CPVT_WordInfo>(wordinfo));
   return place;
 }
 
@@ -202,54 +187,50 @@
   int32_t nRight = range.EndPos.nWordIndex + 1;
   int32_t nMid = (nLeft + nRight) / 2;
   while (nLeft < nRight) {
-    if (nMid == nLeft) {
+    if (nMid == nLeft)
       break;
-    }
     if (nMid == nRight) {
       nMid--;
       break;
     }
-    if (CPVT_WordInfo* pWord = m_WordArray.GetAt(nMid)) {
-      if (fx >
-          pWord->fWordX + m_pVT->GetWordWidth(*pWord) * VARIABLETEXT_HALF) {
-        nLeft = nMid;
-        nMid = (nLeft + nRight) / 2;
-        continue;
-      } else {
-        nRight = nMid;
-        nMid = (nLeft + nRight) / 2;
-        continue;
-      }
-    } else {
+    if (!pdfium::IndexInBounds(m_WordArray, nMid))
       break;
-    }
-  }
-  if (CPVT_WordInfo* pWord = m_WordArray.GetAt(nMid)) {
+    CPVT_WordInfo* pWord = m_WordArray[nMid].get();
     if (fx > pWord->fWordX + m_pVT->GetWordWidth(*pWord) * VARIABLETEXT_HALF) {
-      wordplace.nWordIndex = nMid;
+      nLeft = nMid;
+      nMid = (nLeft + nRight) / 2;
+      continue;
     }
+    nRight = nMid;
+    nMid = (nLeft + nRight) / 2;
+  }
+  if (pdfium::IndexInBounds(m_WordArray, nMid)) {
+    CPVT_WordInfo* pWord = m_WordArray[nMid].get();
+    if (fx > pWord->fWordX + m_pVT->GetWordWidth(*pWord) * VARIABLETEXT_HALF)
+      wordplace.nWordIndex = nMid;
   }
   return wordplace;
 }
 
 void CSection::ClearLeftWords(int32_t nWordIndex) {
   for (int32_t i = nWordIndex; i >= 0; i--) {
-    delete m_WordArray.GetAt(i);
-    m_WordArray.RemoveAt(i);
+    if (pdfium::IndexInBounds(m_WordArray, i))
+      m_WordArray.erase(m_WordArray.begin() + i);
   }
 }
 
 void CSection::ClearRightWords(int32_t nWordIndex) {
-  for (int32_t i = m_WordArray.GetSize() - 1; i > nWordIndex; i--) {
-    delete m_WordArray.GetAt(i);
-    m_WordArray.RemoveAt(i);
+  int32_t sz = pdfium::CollectionSize<int32_t>(m_WordArray);
+  for (int32_t i = sz - 1; i > nWordIndex; i--) {
+    if (pdfium::IndexInBounds(m_WordArray, i))
+      m_WordArray.erase(m_WordArray.begin() + i);
   }
 }
 
 void CSection::ClearMidWords(int32_t nBeginIndex, int32_t nEndIndex) {
   for (int32_t i = nEndIndex; i > nBeginIndex; i--) {
-    delete m_WordArray.GetAt(i);
-    m_WordArray.RemoveAt(i);
+    if (pdfium::IndexInBounds(m_WordArray, i))
+      m_WordArray.erase(m_WordArray.begin() + i);
   }
 }
 
@@ -266,11 +247,11 @@
   } else if (PlaceRange.EndPos.WordCmp(SecEndPos) <= 0) {
     ClearLeftWords(PlaceRange.EndPos.nWordIndex);
   } else {
-    ResetWordArray();
+    m_WordArray.clear();
   }
 }
 
 void CSection::ClearWord(const CPVT_WordPlace& place) {
-  delete m_WordArray.GetAt(place.nWordIndex);
-  m_WordArray.RemoveAt(place.nWordIndex);
+  if (pdfium::IndexInBounds(m_WordArray, place.nWordIndex))
+    m_WordArray.erase(m_WordArray.begin() + place.nWordIndex);
 }
diff --git a/core/fpdfdoc/csection.h b/core/fpdfdoc/csection.h
index 6907b3d..b465d1d 100644
--- a/core/fpdfdoc/csection.h
+++ b/core/fpdfdoc/csection.h
@@ -27,8 +27,6 @@
   ~CSection();
 
   void ResetAll();
-  void ResetLineArray();
-  void ResetWordArray();
   void ResetLinePlace();
   CPVT_WordPlace AddWord(const CPVT_WordPlace& place,
                          const CPVT_WordInfo& wordinfo);
@@ -50,7 +48,7 @@
   CPVT_WordPlace SecPlace;
   CPVT_SectionInfo m_SecInfo;
   std::vector<std::unique_ptr<CLine>> m_LineArray;
-  CPVT_ArrayTemplate<CPVT_WordInfo*> m_WordArray;
+  std::vector<std::unique_ptr<CPVT_WordInfo>> m_WordArray;
 
  private:
   friend class CTypeset;
diff --git a/core/fpdfdoc/ctypeset.cpp b/core/fpdfdoc/ctypeset.cpp
index 34deb21..2e2f6c5 100644
--- a/core/fpdfdoc/ctypeset.cpp
+++ b/core/fpdfdoc/ctypeset.cpp
@@ -199,52 +199,58 @@
       pLine->m_LineInfo.fLineX = fNodeWidth * VARIABLETEXT_HALF;
       break;
     case 1:
-      nStart = (m_pVT->m_nCharArray - m_pSection->m_WordArray.GetSize()) / 2;
+      nStart = (m_pVT->m_nCharArray -
+                pdfium::CollectionSize<int32_t>(m_pSection->m_WordArray)) /
+               2;
       pLine->m_LineInfo.fLineX =
           fNodeWidth * nStart - fNodeWidth * VARIABLETEXT_HALF;
       break;
     case 2:
-      nStart = m_pVT->m_nCharArray - m_pSection->m_WordArray.GetSize();
+      nStart = m_pVT->m_nCharArray -
+               pdfium::CollectionSize<int32_t>(m_pSection->m_WordArray);
       pLine->m_LineInfo.fLineX =
           fNodeWidth * nStart - fNodeWidth * VARIABLETEXT_HALF;
       break;
   }
-  for (int32_t w = 0, sz = m_pSection->m_WordArray.GetSize(); w < sz; w++) {
+  for (int32_t w = 0,
+               sz = pdfium::CollectionSize<int32_t>(m_pSection->m_WordArray);
+       w < sz; w++) {
     if (w >= m_pVT->m_nCharArray)
       break;
 
     float fNextWidth = 0;
-    if (CPVT_WordInfo* pNextWord = m_pSection->m_WordArray.GetAt(w + 1)) {
+    if (pdfium::IndexInBounds(m_pSection->m_WordArray, w + 1)) {
+      CPVT_WordInfo* pNextWord = m_pSection->m_WordArray[w + 1].get();
       pNextWord->fWordTail = 0;
       fNextWidth = m_pVT->GetWordWidth(*pNextWord);
     }
-    if (CPVT_WordInfo* pWord = m_pSection->m_WordArray.GetAt(w)) {
-      pWord->fWordTail = 0;
-      float fWordWidth = m_pVT->GetWordWidth(*pWord);
-      float fWordAscent = m_pVT->GetWordAscent(*pWord);
-      float fWordDescent = m_pVT->GetWordDescent(*pWord);
-      x = (float)(fNodeWidth * (w + nStart + 0.5) -
-                  fWordWidth * VARIABLETEXT_HALF);
-      pWord->fWordX = x;
-      pWord->fWordY = y;
-      if (w == 0) {
-        pLine->m_LineInfo.fLineX = x;
-      }
-      if (w != m_pSection->m_WordArray.GetSize() - 1) {
-        pWord->fWordTail =
-            (fNodeWidth - (fWordWidth + fNextWidth) * VARIABLETEXT_HALF > 0
-                 ? fNodeWidth - (fWordWidth + fNextWidth) * VARIABLETEXT_HALF
-                 : 0);
-      } else {
-        pWord->fWordTail = 0;
-      }
-      x += fWordWidth;
-      fLineAscent = std::max(fLineAscent, fWordAscent);
-      fLineDescent = std::min(fLineDescent, fWordDescent);
+    CPVT_WordInfo* pWord = m_pSection->m_WordArray[w].get();
+    pWord->fWordTail = 0;
+    float fWordWidth = m_pVT->GetWordWidth(*pWord);
+    float fWordAscent = m_pVT->GetWordAscent(*pWord);
+    float fWordDescent = m_pVT->GetWordDescent(*pWord);
+    x = (float)(fNodeWidth * (w + nStart + 0.5) -
+                fWordWidth * VARIABLETEXT_HALF);
+    pWord->fWordX = x;
+    pWord->fWordY = y;
+    if (w == 0) {
+      pLine->m_LineInfo.fLineX = x;
     }
+    if (w != pdfium::CollectionSize<int32_t>(m_pSection->m_WordArray) - 1) {
+      pWord->fWordTail =
+          (fNodeWidth - (fWordWidth + fNextWidth) * VARIABLETEXT_HALF > 0
+               ? fNodeWidth - (fWordWidth + fNextWidth) * VARIABLETEXT_HALF
+               : 0);
+    } else {
+      pWord->fWordTail = 0;
+    }
+    x += fWordWidth;
+    fLineAscent = std::max(fLineAscent, fWordAscent);
+    fLineDescent = std::min(fLineDescent, fWordDescent);
   }
   pLine->m_LineInfo.nBeginWordIndex = 0;
-  pLine->m_LineInfo.nEndWordIndex = m_pSection->m_WordArray.GetSize() - 1;
+  pLine->m_LineInfo.nEndWordIndex =
+      pdfium::CollectionSize<int32_t>(m_pSection->m_WordArray) - 1;
   pLine->m_LineInfo.fLineY = y;
   pLine->m_LineInfo.fLineWidth = x - pLine->m_LineInfo.fLineX;
   pLine->m_LineInfo.fLineAscent = fLineAscent;
@@ -286,15 +292,16 @@
   float fTypesetWidth = std::max(
       m_pVT->GetPlateWidth() - m_pVT->GetLineIndent(m_pSection->m_SecInfo),
       0.0f);
-  int32_t nTotalWords = m_pSection->m_WordArray.GetSize();
+  int32_t nTotalWords =
+      pdfium::CollectionSize<int32_t>(m_pSection->m_WordArray);
   bool bOpened = false;
   if (nTotalWords > 0) {
     int32_t i = 0;
     while (i < nTotalWords) {
-      CPVT_WordInfo* pWord = m_pSection->m_WordArray.GetAt(i);
+      CPVT_WordInfo* pWord = m_pSection->m_WordArray[i].get();
       CPVT_WordInfo* pOldWord = pWord;
       if (i > 0) {
-        pOldWord = m_pSection->m_WordArray.GetAt(i - 1);
+        pOldWord = m_pSection->m_WordArray[i - 1].get();
       }
       if (pWord) {
         if (bTypeset) {
@@ -462,7 +469,8 @@
       pLine->m_LineInfo.fLineY = fPosY - fMinY;
       for (int32_t w = pLine->m_LineInfo.nBeginWordIndex;
            w <= pLine->m_LineInfo.nEndWordIndex; w++) {
-        if (CPVT_WordInfo* pWord = m_pSection->m_WordArray.GetAt(w)) {
+        if (pdfium::IndexInBounds(m_pSection->m_WordArray, w)) {
+          CPVT_WordInfo* pWord = m_pSection->m_WordArray[w].get();
           pWord->fWordX = fPosX - fMinX;
           if (pWord->pWordProps) {
             switch (pWord->pWordProps->nScriptType) {