Replace CountedFaceCache with RetainPtr<CFX_FaceCache>

Removes some add-hoc refcounting in favor of smart pointers. The
combination of Retainable and Observable creates a cache entry that
remains valid so long as there is at least one retain ptr outstanding.

Change-Id: I14f3c0b3ec42d9b845b6fb3965b0d7e6f9fc1a28
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/54272
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fxge/cfx_facecache.h b/core/fxge/cfx_facecache.h
index 224dd37..a99ddb3 100644
--- a/core/fxge/cfx_facecache.h
+++ b/core/fxge/cfx_facecache.h
@@ -12,6 +12,8 @@
 #include <tuple>
 
 #include "core/fxcrt/fx_string.h"
+#include "core/fxcrt/observable.h"
+#include "core/fxcrt/retain_ptr.h"
 #include "core/fxge/fx_freetype.h"
 
 #if defined _SKIA_SUPPORT_ || _SKIA_SUPPORT_PATHS_
@@ -24,10 +26,13 @@
 class CFX_Matrix;
 class CFX_PathData;
 
-class CFX_FaceCache {
+class CFX_FaceCache : public Retainable, public Observable<CFX_FaceCache> {
  public:
-  explicit CFX_FaceCache(FXFT_Face face);
-  ~CFX_FaceCache();
+  template <typename T, typename... Args>
+  friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);
+
+  ~CFX_FaceCache() override;
+
   const CFX_GlyphBitmap* LoadGlyphBitmap(const CFX_Font* pFont,
                                          uint32_t glyph_index,
                                          bool bFontStyle,
@@ -44,6 +49,8 @@
 #endif
 
  private:
+  explicit CFX_FaceCache(FXFT_Face face);
+
   using SizeGlyphCache = std::map<uint32_t, std::unique_ptr<CFX_GlyphBitmap>>;
   // <glyph_index, width, weight, angle, vertical>
   using PathMapKey = std::tuple<uint32_t, uint32_t, int, int, bool>;
diff --git a/core/fxge/cfx_font.cpp b/core/fxge/cfx_font.cpp
index 79b57f0..2f39a0b 100644
--- a/core/fxge/cfx_font.cpp
+++ b/core/fxge/cfx_font.cpp
@@ -581,18 +581,14 @@
   return true;
 }
 
-CFX_FaceCache* CFX_Font::GetFaceCache() const {
+RetainPtr<CFX_FaceCache> CFX_Font::GetOrCreateFaceCache() const {
   if (!m_FaceCache)
     m_FaceCache = CFX_GEModule::Get()->GetFontCache()->GetCachedFace(this);
-  return m_FaceCache.Get();
+  return m_FaceCache;
 }
 
 void CFX_Font::ClearFaceCache() {
-  if (!m_FaceCache)
-    return;
-
   m_FaceCache = nullptr;
-  CFX_GEModule::Get()->GetFontCache()->ReleaseCachedFace(this);
 }
 
 void CFX_Font::AdjustMMParams(int glyph_index,
@@ -713,17 +709,18 @@
                                                  uint32_t dest_width,
                                                  int anti_alias,
                                                  int* pTextFlags) const {
-  return GetFaceCache()->LoadGlyphBitmap(this, glyph_index, bFontStyle, matrix,
-                                         dest_width, anti_alias, pTextFlags);
+  return GetOrCreateFaceCache()->LoadGlyphBitmap(this, glyph_index, bFontStyle,
+                                                 matrix, dest_width, anti_alias,
+                                                 pTextFlags);
 }
 
 const CFX_PathData* CFX_Font::LoadGlyphPath(uint32_t glyph_index,
                                             uint32_t dest_width) const {
-  return GetFaceCache()->LoadGlyphPath(this, glyph_index, dest_width);
+  return GetOrCreateFaceCache()->LoadGlyphPath(this, glyph_index, dest_width);
 }
 
 #if defined _SKIA_SUPPORT_ || _SKIA_SUPPORT_PATHS_
 CFX_TypeFace* CFX_Font::GetDeviceCache() const {
-  return GetFaceCache()->GetDeviceCache(this);
+  return GetOrCreateFaceCache()->GetDeviceCache(this);
 }
 #endif
diff --git a/core/fxge/cfx_font.h b/core/fxge/cfx_font.h
index 8fe39ea..ab3fe6d 100644
--- a/core/fxge/cfx_font.h
+++ b/core/fxge/cfx_font.h
@@ -126,7 +126,7 @@
 #endif  // PDF_ENABLE_XFA
 
  private:
-  CFX_FaceCache* GetFaceCache() const;
+  RetainPtr<CFX_FaceCache> GetOrCreateFaceCache() const;
   void DeleteFace();
   void ClearFaceCache();
 #if defined(OS_MACOSX)
@@ -136,7 +136,7 @@
   ByteString GetFamilyNameOrUntitled() const;
 
   mutable UnownedPtr<FXFT_FaceRec> m_Face;
-  mutable UnownedPtr<CFX_FaceCache> m_FaceCache;
+  mutable RetainPtr<CFX_FaceCache> m_FaceCache;
   std::unique_ptr<CFX_SubstFont> m_pSubstFont;
   std::unique_ptr<uint8_t, FxFreeDeleter> m_pGsubData;
   std::vector<uint8_t> m_pFontDataAllocation;
diff --git a/core/fxge/cfx_fontcache.cpp b/core/fxge/cfx_fontcache.cpp
index 5ccac8c..b9300bc 100644
--- a/core/fxge/cfx_fontcache.cpp
+++ b/core/fxge/cfx_fontcache.cpp
@@ -10,40 +10,26 @@
 #include <utility>
 
 #include "core/fxge/cfx_facecache.h"
+#include "core/fxge/cfx_font.h"
 #include "core/fxge/fx_font.h"
 #include "core/fxge/fx_freetype.h"
 #include "third_party/base/ptr_util.h"
 
-CFX_FontCache::CountedFaceCache::CountedFaceCache() {}
+CFX_FontCache::CFX_FontCache() = default;
 
-CFX_FontCache::CountedFaceCache::~CountedFaceCache() {}
+CFX_FontCache::~CFX_FontCache() = default;
 
-CFX_FontCache::CFX_FontCache() {}
-
-CFX_FontCache::~CFX_FontCache() {
-  ASSERT(m_ExtFaceMap.empty());
-  ASSERT(m_FTFaceMap.empty());
-}
-
-CFX_FaceCache* CFX_FontCache::GetCachedFace(const CFX_Font* pFont) {
+RetainPtr<CFX_FaceCache> CFX_FontCache::GetCachedFace(const CFX_Font* pFont) {
   FXFT_Face face = pFont->GetFace();
   const bool bExternal = !face;
-  CFX_FTCacheMap& map = bExternal ? m_ExtFaceMap : m_FTFaceMap;
+  auto& map = bExternal ? m_ExtFaceMap : m_FTFaceMap;
   auto it = map.find(face);
-  if (it != map.end()) {
-    CountedFaceCache* counted_face_cache = it->second.get();
-    counted_face_cache->m_nCount++;
-    return counted_face_cache->m_Obj.get();
-  }
+  if (it != map.end() && it->second)
+    return pdfium::WrapRetain(it->second.Get());
 
-  auto counted_face_cache = pdfium::MakeUnique<CountedFaceCache>();
-  counted_face_cache->m_nCount = 2;
-  auto new_cache =
-      pdfium::MakeUnique<CFX_FaceCache>(bExternal ? nullptr : face);
-  CFX_FaceCache* face_cache = new_cache.get();
-  counted_face_cache->m_Obj = std::move(new_cache);
-  map[face] = std::move(counted_face_cache);
-  return face_cache;
+  auto new_cache = pdfium::MakeRetain<CFX_FaceCache>(face);
+  map[face].Reset(new_cache.Get());
+  return new_cache;
 }
 
 #ifdef _SKIA_SUPPORT_
@@ -51,20 +37,3 @@
   return GetCachedFace(pFont)->GetDeviceCache(pFont);
 }
 #endif
-
-void CFX_FontCache::ReleaseCachedFace(const CFX_Font* pFont) {
-  FXFT_Face face = pFont->GetFace();
-  const bool bExternal = !face;
-  CFX_FTCacheMap& map = bExternal ? m_ExtFaceMap : m_FTFaceMap;
-
-  auto it = map.find(face);
-  if (it == map.end())
-    return;
-
-  CountedFaceCache* counted_face_cache = it->second.get();
-  if (counted_face_cache->m_nCount > 2) {
-    counted_face_cache->m_nCount--;
-  } else {
-    map.erase(it);
-  }
-}
diff --git a/core/fxge/cfx_fontcache.h b/core/fxge/cfx_fontcache.h
index 44a4576..516e779 100644
--- a/core/fxge/cfx_fontcache.h
+++ b/core/fxge/cfx_fontcache.h
@@ -11,32 +11,24 @@
 #include <memory>
 
 #include "core/fxcrt/fx_system.h"
-#include "core/fxge/cfx_font.h"
+#include "core/fxge/cfx_facecache.h"
 #include "core/fxge/fx_freetype.h"
 
-class CFX_FaceCache;
+class CFX_Font;
 
 class CFX_FontCache {
  public:
   CFX_FontCache();
   ~CFX_FontCache();
-  CFX_FaceCache* GetCachedFace(const CFX_Font* pFont);
-  void ReleaseCachedFace(const CFX_Font* pFont);
+
+  RetainPtr<CFX_FaceCache> GetCachedFace(const CFX_Font* pFont);
 #ifdef _SKIA_SUPPORT_
   CFX_TypeFace* GetDeviceCache(const CFX_Font* pFont);
 #endif
 
  private:
-  struct CountedFaceCache {
-    CountedFaceCache();
-    ~CountedFaceCache();
-    std::unique_ptr<CFX_FaceCache> m_Obj;
-    uint32_t m_nCount;
-  };
-
-  using CFX_FTCacheMap = std::map<FXFT_Face, std::unique_ptr<CountedFaceCache>>;
-  CFX_FTCacheMap m_FTFaceMap;
-  CFX_FTCacheMap m_ExtFaceMap;
+  std::map<FXFT_Face, CFX_FaceCache::ObservedPtr> m_FTFaceMap;
+  std::map<FXFT_Face, CFX_FaceCache::ObservedPtr> m_ExtFaceMap;
 };
 
 #endif  // CORE_FXGE_CFX_FONTCACHE_H_
diff --git a/core/fxge/win32/cfx_psrenderer.cpp b/core/fxge/win32/cfx_psrenderer.cpp
index f2050c3..d684600 100644
--- a/core/fxge/win32/cfx_psrenderer.cpp
+++ b/core/fxge/win32/cfx_psrenderer.cpp
@@ -664,11 +664,11 @@
       << pObject2Device->e << " " << pObject2Device->f << "]cm\n";
 
   CFX_FontCache* pCache = CFX_GEModule::Get()->GetFontCache();
-  CFX_FaceCache* pFaceCache = pCache->GetCachedFace(pFont);
+  RetainPtr<CFX_FaceCache> pFaceCache = pCache->GetCachedFace(pFont);
   int last_fontnum = -1;
   for (int i = 0; i < nChars; i++) {
     int ps_fontnum, ps_glyphindex;
-    FindPSFontGlyph(pFaceCache, pFont, pCharPos[i], &ps_fontnum,
+    FindPSFontGlyph(pFaceCache.Get(), pFont, pCharPos[i], &ps_fontnum,
                     &ps_glyphindex);
     if (last_fontnum != ps_fontnum) {
       buf << "/X" << ps_fontnum << " Ff " << font_size << " Fs Sf ";
@@ -680,7 +680,6 @@
   }
   buf << "Q\n";
   WriteToStream(&buf);
-  pCache->ReleaseCachedFace(pFont);
   return true;
 }