Encapsulate FT_Get_First_Char() and FT_Get_Next_Char()

Implement a method in CFX_Face to return all the char codes and glyph
indices, and change callers to use it.

Bug: pdfium:2037
Change-Id: Ib3d0ff0a17737f320467b8fab20eb590aa8ebd19
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/114795
Reviewed-by: Dominik Röttsches <drott@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fxge/cfx_face.cpp b/core/fxge/cfx_face.cpp
index a5b5994..9bca779 100644
--- a/core/fxge/cfx_face.cpp
+++ b/core/fxge/cfx_face.cpp
@@ -8,6 +8,7 @@
 #include <limits>
 #include <memory>
 #include <utility>
+#include <vector>
 
 #include "core/fxge/cfx_font.h"
 #include "core/fxge/cfx_fontmgr.h"
@@ -579,6 +580,26 @@
   return FT_Get_Name_Index(GetRec(), name);
 }
 
+std::vector<CFX_Face::CharCodeAndIndex> CFX_Face::GetCharCodesAndIndices(
+    char32_t max_char) {
+  CharCodeAndIndex char_code_and_index;
+  char_code_and_index.char_code = static_cast<uint32_t>(
+      FT_Get_First_Char(GetRec(), &char_code_and_index.glyph_index));
+  if (char_code_and_index.char_code > max_char) {
+    return {};
+  }
+  std::vector<CharCodeAndIndex> results = {char_code_and_index};
+  while (true) {
+    char_code_and_index.char_code = static_cast<uint32_t>(FT_Get_Next_Char(
+        GetRec(), results.back().char_code, &char_code_and_index.glyph_index));
+    if (char_code_and_index.char_code > max_char ||
+        char_code_and_index.glyph_index == 0) {
+      return results;
+    }
+    results.push_back(char_code_and_index);
+  }
+}
+
 CFX_Face::CharMap CFX_Face::GetCurrentCharMap() const {
   return GetRec()->charmap;
 }
diff --git a/core/fxge/cfx_face.h b/core/fxge/cfx_face.h
index 6c57504..551f358 100644
--- a/core/fxge/cfx_face.h
+++ b/core/fxge/cfx_face.h
@@ -9,6 +9,7 @@
 
 #include <array>
 #include <memory>
+#include <vector>
 
 #include "build/build_config.h"
 #include "core/fxcrt/bytestring.h"
@@ -32,6 +33,11 @@
  public:
   using CharMap = void*;
 
+  struct CharCodeAndIndex {
+    uint32_t char_code;
+    uint32_t glyph_index;
+  };
+
   static RetainPtr<CFX_Face> New(FT_Library library,
                                  RetainPtr<Retainable> pDesc,
                                  pdfium::span<const FT_Byte> data,
@@ -95,6 +101,8 @@
   int GetCharIndex(uint32_t code);
   int GetNameIndex(const char* name);
 
+  std::vector<CharCodeAndIndex> GetCharCodesAndIndices(char32_t max_char);
+
   CharMap GetCurrentCharMap() const;
   absl::optional<fxge::FontEncoding> GetCurrentCharMapEncoding() const;
   int GetCharMapPlatformIdByIndex(size_t index) const;
diff --git a/fpdfsdk/fpdf_edittext.cpp b/fpdfsdk/fpdf_edittext.cpp
index 73e9916..608a4db 100644
--- a/fpdfsdk/fpdf_edittext.cpp
+++ b/fpdfsdk/fpdf_edittext.cpp
@@ -310,31 +310,31 @@
     return nullptr;
   }
 
-  uint32_t dwGlyphIndex;
-  uint32_t dwCurrentChar = static_cast<uint32_t>(
-      FT_Get_First_Char(pFont->GetFaceRec(), &dwGlyphIndex));
+  // Simple fonts have 1-byte charcodes only.
   static constexpr uint32_t kMaxSimpleFontChar = 0xFF;
-  if (dwCurrentChar > kMaxSimpleFontChar) {
+  auto char_codes_and_indices =
+      pFont->GetFace()->GetCharCodesAndIndices(kMaxSimpleFontChar);
+  if (char_codes_and_indices.empty()) {
     return nullptr;
   }
-  pFontDict->SetNewFor<CPDF_Number>("FirstChar",
-                                    static_cast<int>(dwCurrentChar));
-  auto widthsArray = pDoc->NewIndirect<CPDF_Array>();
-  while (true) {
-    widthsArray->AppendNew<CPDF_Number>(pFont->GetGlyphWidth(dwGlyphIndex));
-    uint32_t nextChar = static_cast<uint32_t>(
-        FT_Get_Next_Char(pFont->GetFaceRec(), dwCurrentChar, &dwGlyphIndex));
-    // Simple fonts have 1-byte charcodes only.
-    if (nextChar > kMaxSimpleFontChar || dwGlyphIndex == 0)
-      break;
-    for (uint32_t i = dwCurrentChar + 1; i < nextChar; i++)
-      widthsArray->AppendNew<CPDF_Number>(0);
-    dwCurrentChar = nextChar;
+
+  pFontDict->SetNewFor<CPDF_Number>(
+      "FirstChar", static_cast<int>(char_codes_and_indices[0].char_code));
+  auto widths_array = pDoc->NewIndirect<CPDF_Array>();
+  for (size_t i = 0; i < char_codes_and_indices.size(); ++i) {
+    widths_array->AppendNew<CPDF_Number>(
+        pFont->GetGlyphWidth(char_codes_and_indices[i].glyph_index));
+    if (i > 0 && i < char_codes_and_indices.size() - 1) {
+      for (uint32_t j = char_codes_and_indices[i - 1].char_code + 1;
+           j < char_codes_and_indices[i].char_code; ++j) {
+        widths_array->AppendNew<CPDF_Number>(0);
+      }
+    }
   }
-  pFontDict->SetNewFor<CPDF_Number>("LastChar",
-                                    static_cast<int>(dwCurrentChar));
+  pFontDict->SetNewFor<CPDF_Number>(
+      "LastChar", static_cast<int>(char_codes_and_indices.back().char_code));
   pFontDict->SetNewFor<CPDF_Reference>("Widths", pDoc,
-                                       widthsArray->GetObjNum());
+                                       widths_array->GetObjNum());
   RetainPtr<CPDF_Dictionary> pFontDesc =
       LoadFontDesc(pDoc, name, pFont.get(), span, font_type);
 
@@ -383,27 +383,19 @@
     return nullptr;
   }
 
-  uint32_t dwGlyphIndex;
-  uint32_t dwCurrentChar = static_cast<uint32_t>(
-      FT_Get_First_Char(pFont->GetFaceRec(), &dwGlyphIndex));
-  if (dwCurrentChar > pdfium::kMaximumSupplementaryCodePoint) {
+  auto char_codes_and_indices = pFont->GetFace()->GetCharCodesAndIndices(
+      pdfium::kMaximumSupplementaryCodePoint);
+  if (char_codes_and_indices.empty()) {
     return nullptr;
   }
 
   std::multimap<uint32_t, uint32_t> to_unicode;
   std::map<uint32_t, uint32_t> widths;
-  while (true) {
-    if (dwCurrentChar > pdfium::kMaximumSupplementaryCodePoint) {
-      break;
+  for (const auto& item : char_codes_and_indices) {
+    if (!pdfium::Contains(widths, item.glyph_index)) {
+      widths[item.glyph_index] = pFont->GetGlyphWidth(item.glyph_index);
     }
-
-    if (!pdfium::Contains(widths, dwGlyphIndex))
-      widths[dwGlyphIndex] = pFont->GetGlyphWidth(dwGlyphIndex);
-    to_unicode.emplace(dwGlyphIndex, dwCurrentChar);
-    dwCurrentChar = static_cast<uint32_t>(
-        FT_Get_Next_Char(pFont->GetFaceRec(), dwCurrentChar, &dwGlyphIndex));
-    if (dwGlyphIndex == 0)
-      break;
+    to_unicode.emplace(item.glyph_index, item.char_code);
   }
   auto widthsArray = pDoc->NewIndirect<CPDF_Array>();
   for (auto it = widths.begin(); it != widths.end(); ++it) {