Cache font widths in CFX_GlyphCache

Rendering text with Skia results in many font widths lookups, which can
cause performance slow downs. Since many lookups are redundant, mitigate
this issue by making CFX_GlyphCache cache the font width data.

The same cache may help with performance in general, as other code paths
do font widths lookups as well.

Change-Id: I847e1fa0d3a5e7a3993a8cbdae6caf56be0ea827
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/106370
Reviewed-by: Nigi <nigi@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fxge/cfx_font.cpp b/core/fxge/cfx_font.cpp
index d5a674c..e9ca56b 100644
--- a/core/fxge/cfx_font.cpp
+++ b/core/fxge/cfx_font.cpp
@@ -418,6 +418,13 @@
 int CFX_Font::GetGlyphWidth(uint32_t glyph_index,
                             int dest_width,
                             int weight) const {
+  return GetOrCreateGlyphCache()->GetGlyphWidth(this, glyph_index, dest_width,
+                                                weight);
+}
+
+int CFX_Font::GetGlyphWidthImpl(uint32_t glyph_index,
+                                int dest_width,
+                                int weight) const {
   if (!m_Face)
     return 0;
   if (m_pSubstFont && m_pSubstFont->IsBuiltInGenericFont())
diff --git a/core/fxge/cfx_font.h b/core/fxge/cfx_font.h
index 944cf79..bf94874 100644
--- a/core/fxge/cfx_font.h
+++ b/core/fxge/cfx_font.h
@@ -137,6 +137,7 @@
   void AdjustMMParams(int glyph_index, int dest_width, int weight) const;
   std::unique_ptr<CFX_Path> LoadGlyphPathImpl(uint32_t glyph_index,
                                               int dest_width) const;
+  int GetGlyphWidthImpl(uint32_t glyph_index, int dest_width, int weight) const;
 
 #if defined(_SKIA_SUPPORT_)
   CFX_TypeFace* GetDeviceCache() const;
diff --git a/core/fxge/cfx_glyphcache.cpp b/core/fxge/cfx_glyphcache.cpp
index 55cf873..e923f3c 100644
--- a/core/fxge/cfx_glyphcache.cpp
+++ b/core/fxge/cfx_glyphcache.cpp
@@ -312,6 +312,20 @@
 #endif  // BUILDFLAG(IS_APPLE)
 }
 
+int CFX_GlyphCache::GetGlyphWidth(const CFX_Font* font,
+                                  uint32_t glyph_index,
+                                  int dest_width,
+                                  int weight) {
+  const WidthMapKey key = std::make_tuple(glyph_index, dest_width, weight);
+  auto it = m_WidthMap.find(key);
+  if (it != m_WidthMap.end()) {
+    return it->second;
+  }
+
+  m_WidthMap[key] = font->GetGlyphWidthImpl(glyph_index, dest_width, weight);
+  return m_WidthMap[key];
+}
+
 #if defined(_SKIA_SUPPORT_)
 CFX_TypeFace* CFX_GlyphCache::GetDeviceCache(const CFX_Font* pFont) {
   if (!m_pTypeface) {
diff --git a/core/fxge/cfx_glyphcache.h b/core/fxge/cfx_glyphcache.h
index a57b770..99a0604 100644
--- a/core/fxge/cfx_glyphcache.h
+++ b/core/fxge/cfx_glyphcache.h
@@ -42,6 +42,10 @@
   const CFX_Path* LoadGlyphPath(const CFX_Font* pFont,
                                 uint32_t glyph_index,
                                 int dest_width);
+  int GetGlyphWidth(const CFX_Font* font,
+                    uint32_t glyph_index,
+                    int dest_width,
+                    int weight);
 
   RetainPtr<CFX_Face> GetFace() { return m_Face; }
   FXFT_FaceRec* GetFaceRec() { return m_Face ? m_Face->GetRec() : nullptr; }
@@ -56,6 +60,8 @@
   using SizeGlyphCache = std::map<uint32_t, std::unique_ptr<CFX_GlyphBitmap>>;
   // <glyph_index, width, weight, angle, vertical>
   using PathMapKey = std::tuple<uint32_t, int, int, int, bool>;
+  // <glyph_index, dest_width, weight>
+  using WidthMapKey = std::tuple<uint32_t, int, int>;
 
   std::unique_ptr<CFX_GlyphBitmap> RenderGlyph(const CFX_Font* pFont,
                                                uint32_t glyph_index,
@@ -82,6 +88,7 @@
   RetainPtr<CFX_Face> const m_Face;
   std::map<ByteString, SizeGlyphCache> m_SizeMap;
   std::map<PathMapKey, std::unique_ptr<CFX_Path>> m_PathMap;
+  std::map<WidthMapKey, int> m_WidthMap;
 #if defined(_SKIA_SUPPORT_)
   sk_sp<SkTypeface> m_pTypeface;
 #endif