Weakly cache CPDF_Type3Cache in CPDF_DocRenderData.

Typical Retainable/Observable pattern.

In order to keep fonts alive, let CPDF_Type3Cache directly manage
CPDF_CountedFont refcounts. Currently, this is being performed by
CPDF_RenderStatus outside the class with the use of something called
CPDF_RefType3Cache, which provides still yet another refcount.
This works because CPDF_RenderStatus::GetCachedType3() is the only
place a CPDF_Type3Cache might get created (and as a side-effect
introduces another unowned pointer into a font managed elsewhere
by a counted font object).

Ideally, CPDF_Font would be a Retainable, but there are circular
references to be resolved first. In the mean time, this makes things
a little cleaner.

Change-Id: I710815fe44bb0506fd8e35ae6dbe44517c171ba1
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/58110
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/render/cpdf_docrenderdata.cpp b/core/fpdfapi/render/cpdf_docrenderdata.cpp
index 7e95724..cb37c69 100644
--- a/core/fpdfapi/render/cpdf_docrenderdata.cpp
+++ b/core/fpdfapi/render/cpdf_docrenderdata.cpp
@@ -38,20 +38,14 @@
 RetainPtr<CPDF_Type3Cache> CPDF_DocRenderData::GetCachedType3(
     CPDF_Type3Font* pFont) {
   auto it = m_Type3FaceMap.find(pFont);
-  if (it != m_Type3FaceMap.end())
-    return it->second;
+  if (it != m_Type3FaceMap.end() && it->second)
+    return pdfium::WrapRetain(it->second.Get());
 
   auto pCache = pdfium::MakeRetain<CPDF_Type3Cache>(pFont);
-  m_Type3FaceMap[pFont] = pCache;
+  m_Type3FaceMap[pFont].Reset(pCache.Get());
   return pCache;
 }
 
-void CPDF_DocRenderData::MaybePurgeCachedType3(CPDF_Type3Font* pFont) {
-  auto it = m_Type3FaceMap.find(pFont);
-  if (it != m_Type3FaceMap.end() && it->second->HasOneRef())
-    m_Type3FaceMap.erase(it);
-}
-
 RetainPtr<CPDF_TransferFunc> CPDF_DocRenderData::GetTransferFunc(
     const CPDF_Object* pObj) {
   if (!pObj)
diff --git a/core/fpdfapi/render/cpdf_docrenderdata.h b/core/fpdfapi/render/cpdf_docrenderdata.h
index 1300dfe..32b90a3 100644
--- a/core/fpdfapi/render/cpdf_docrenderdata.h
+++ b/core/fpdfapi/render/cpdf_docrenderdata.h
@@ -9,9 +9,7 @@
 
 #include <map>
 
-#include "core/fpdfapi/page/cpdf_countedobject.h"
 #include "core/fpdfapi/parser/cpdf_document.h"
-#include "core/fxcrt/fx_system.h"
 #include "core/fxcrt/observed_ptr.h"
 #include "core/fxcrt/retain_ptr.h"
 
@@ -32,8 +30,6 @@
   CPDF_DocRenderData& operator=(const CPDF_DocRenderData&) = delete;
 
   RetainPtr<CPDF_Type3Cache> GetCachedType3(CPDF_Type3Font* pFont);
-  void MaybePurgeCachedType3(CPDF_Type3Font* pFont);
-
   RetainPtr<CPDF_TransferFunc> GetTransferFunc(const CPDF_Object* pObj);
 
  protected:
@@ -42,7 +38,7 @@
       const CPDF_Object* pObj) const;
 
  private:
-  std::map<CPDF_Font*, RetainPtr<CPDF_Type3Cache>> m_Type3FaceMap;
+  std::map<CPDF_Font*, ObservedPtr<CPDF_Type3Cache>> m_Type3FaceMap;
   std::map<const CPDF_Object*, ObservedPtr<CPDF_TransferFunc>>
       m_TransferFuncMap;
 };
diff --git a/core/fpdfapi/render/cpdf_renderstatus.cpp b/core/fpdfapi/render/cpdf_renderstatus.cpp
index 3eac9fa..f18b552 100644
--- a/core/fpdfapi/render/cpdf_renderstatus.cpp
+++ b/core/fpdfapi/render/cpdf_renderstatus.cpp
@@ -11,6 +11,7 @@
 #include <cmath>
 #include <limits>
 #include <memory>
+#include <set>
 #include <utility>
 #include <vector>
 
@@ -81,26 +82,6 @@
 constexpr int kRenderMaxRecursionDepth = 64;
 int g_CurrentRecursionDepth = 0;
 
-void ReleaseCachedType3(CPDF_Type3Font* pFont) {
-  CPDF_Document* pDoc = pFont->GetDocument();
-  CPDF_DocRenderData::FromDocument(pDoc)->MaybePurgeCachedType3(pFont);
-  CPDF_DocPageData::FromDocument(pDoc)->ReleaseFont(pFont->GetFontDict());
-}
-
-class CPDF_RefType3Cache {
- public:
-  explicit CPDF_RefType3Cache(CPDF_Type3Font* pType3Font)
-      : m_pType3Font(pType3Font) {}
-
-  ~CPDF_RefType3Cache() {
-    while (m_dwCount--)
-      ReleaseCachedType3(m_pType3Font.Get());
-  }
-
-  uint32_t m_dwCount = 0;
-  UnownedPtr<CPDF_Type3Font> const m_pType3Font;
-};
-
 uint32_t CountOutputsFromFunctions(
     const std::vector<std::unique_ptr<CPDF_Function>>& funcs) {
   FX_SAFE_UINT32 total = 0;
@@ -1781,13 +1762,6 @@
       font_size, text_matrix, fill_argb, m_Options);
 }
 
-RetainPtr<CPDF_Type3Cache> CPDF_RenderStatus::GetCachedType3(
-    CPDF_Type3Font* pFont) {
-  CPDF_Document* pDoc = pFont->GetDocument();
-  CPDF_DocPageData::FromDocument(pDoc)->GetFont(pFont->GetFontDict());
-  return CPDF_DocRenderData::FromDocument(pDoc)->GetCachedType3(pFont);
-}
-
 // TODO(npm): Font fallback for type 3 fonts? (Completely separate code!!)
 bool CPDF_RenderStatus::ProcessType3Text(CPDF_TextObject* textobj,
                                          const CFX_Matrix& mtObj2Device) {
@@ -1807,7 +1781,7 @@
   char_matrix.Scale(font_size, font_size);
 
   // Must come before |glyphs|, because |glyphs| points into |refTypeCache|.
-  CPDF_RefType3Cache refTypeCache(pType3Font);
+  std::set<RetainPtr<CPDF_Type3Cache>> refTypeCache;
   std::vector<TextGlyphPos> glyphs;
   if (device_type == DeviceType::kDisplay)
     glyphs.resize(textobj->GetCharCodes().size());
@@ -1896,8 +1870,11 @@
       }
     } else if (pType3Char->GetBitmap()) {
       if (device_type == DeviceType::kDisplay) {
-        RetainPtr<CPDF_Type3Cache> pCache = GetCachedType3(pType3Font);
-        refTypeCache.m_dwCount++;
+        CPDF_Document* pDoc = pType3Font->GetDocument();
+        RetainPtr<CPDF_Type3Cache> pCache =
+            CPDF_DocRenderData::FromDocument(pDoc)->GetCachedType3(pType3Font);
+        refTypeCache.insert(pCache);
+
         const CFX_GlyphBitmap* pBitmap = pCache->LoadGlyph(charcode, &matrix);
         if (!pBitmap)
           continue;
diff --git a/core/fpdfapi/render/cpdf_renderstatus.h b/core/fpdfapi/render/cpdf_renderstatus.h
index 4e9476e..cb07221 100644
--- a/core/fpdfapi/render/cpdf_renderstatus.h
+++ b/core/fpdfapi/render/cpdf_renderstatus.h
@@ -118,6 +118,10 @@
                          const CPDF_Transparency& transparency);
 
  private:
+  static std::unique_ptr<CPDF_GraphicStates> CloneObjStates(
+      const CPDF_GraphicStates* pSrcStates,
+      bool bStroke);
+
   FX_ARGB GetFillArgbInternal(CPDF_PageObject* pObj, bool bType3) const;
   bool ProcessTransparency(CPDF_PageObject* PageObj,
                            const CFX_Matrix& mtObj2Device);
@@ -176,10 +180,6 @@
   FX_ARGB GetBackColor(const CPDF_Dictionary* pSMaskDict,
                        const CPDF_Dictionary* pGroupDict,
                        int* pCSFamily);
-  static RetainPtr<CPDF_Type3Cache> GetCachedType3(CPDF_Type3Font* pFont);
-  static std::unique_ptr<CPDF_GraphicStates> CloneObjStates(
-      const CPDF_GraphicStates* pSrcStates,
-      bool bStroke);
   FX_ARGB GetStrokeArgb(CPDF_PageObject* pObj) const;
   FX_RECT GetObjectClippedRect(const CPDF_PageObject* pObj,
                                const CFX_Matrix& mtObj2Device) const;
diff --git a/core/fpdfapi/render/cpdf_type3cache.cpp b/core/fpdfapi/render/cpdf_type3cache.cpp
index d2d6cd6..3411416 100644
--- a/core/fpdfapi/render/cpdf_type3cache.cpp
+++ b/core/fpdfapi/render/cpdf_type3cache.cpp
@@ -12,6 +12,8 @@
 
 #include "core/fpdfapi/font/cpdf_type3char.h"
 #include "core/fpdfapi/font/cpdf_type3font.h"
+#include "core/fpdfapi/page/cpdf_docpagedata.h"
+#include "core/fpdfapi/render/cpdf_docrenderdata.h"
 #include "core/fpdfapi/render/cpdf_type3glyphmap.h"
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_safe_types.h"
@@ -83,9 +85,17 @@
 
 }  // namespace
 
-CPDF_Type3Cache::CPDF_Type3Cache(CPDF_Type3Font* pFont) : m_pFont(pFont) {}
+CPDF_Type3Cache::CPDF_Type3Cache(CPDF_Type3Font* pFont) : m_pFont(pFont) {
+  // Increments refcount in CPDF_DocPageData.
+  CPDF_Document* pDoc = m_pFont->GetDocument();
+  CPDF_DocPageData::FromDocument(pDoc)->GetFont(m_pFont->GetFontDict());
+}
 
-CPDF_Type3Cache::~CPDF_Type3Cache() {}
+CPDF_Type3Cache::~CPDF_Type3Cache() {
+  // Decrements refcount in CPDF_DocPageData.
+  CPDF_Document* pDoc = m_pFont->GetDocument();
+  CPDF_DocPageData::FromDocument(pDoc)->ReleaseFont(m_pFont->GetFontDict());
+}
 
 const CFX_GlyphBitmap* CPDF_Type3Cache::LoadGlyph(uint32_t charcode,
                                                   const CFX_Matrix* pMatrix) {
diff --git a/core/fpdfapi/render/cpdf_type3cache.h b/core/fpdfapi/render/cpdf_type3cache.h
index 2f5c9ca..1717e8a 100644
--- a/core/fpdfapi/render/cpdf_type3cache.h
+++ b/core/fpdfapi/render/cpdf_type3cache.h
@@ -12,6 +12,7 @@
 
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/fx_system.h"
+#include "core/fxcrt/observed_ptr.h"
 #include "core/fxcrt/retain_ptr.h"
 
 class CFX_GlyphBitmap;
@@ -19,7 +20,7 @@
 class CPDF_Type3Font;
 class CPDF_Type3GlyphMap;
 
-class CPDF_Type3Cache final : public Retainable {
+class CPDF_Type3Cache final : public Retainable, public Observable {
  public:
   template <typename T, typename... Args>
   friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);