Make CPDF_Font a retainable type.

In turn, this makes CPDF_CountedObject<> unused, so remove it.

We have to explicitly break some cycles between fonts and forms,
so introduce a WillBeDestroyed() method.

This also introduces the requirement that callers of
FPDFText_LoadStandardFont() release the resource via a call
to FPDFFont_Close().


Change-Id: I27451a24e55424e7f784a1af962036269295aed2
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/57470
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp
index 16676fe..984569e 100644
--- a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp
+++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp
@@ -494,7 +494,7 @@
                                             CPDF_TextObject* pTextObj) {
   ProcessGraphics(buf, pTextObj);
   *buf << "BT " << pTextObj->GetTextMatrix() << " Tm ";
-  CPDF_Font* pFont = pTextObj->GetFont();
+  RetainPtr<CPDF_Font> pFont(pTextObj->GetFont());
   if (!pFont)
     pFont = CPDF_Font::GetStockFont(m_pDocument.Get(), "Helvetica");
 
diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp
index d997420..a2ee17a 100644
--- a/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp
+++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp
@@ -247,9 +247,11 @@
   auto pTestPage = pdfium::MakeRetain<CPDF_Page>(pDoc.get(), pPageDict);
   CPDF_PageContentGenerator generator(pTestPage.Get());
   auto pTextObj = pdfium::MakeUnique<CPDF_TextObject>();
-  CPDF_Font* pFont = CPDF_Font::GetStockFont(pDoc.get(), "Times-Roman");
+  RetainPtr<CPDF_Font> pFont =
+      CPDF_Font::GetStockFont(pDoc.get(), "Times-Roman");
   pTextObj->m_TextState.SetFont(pFont);
   pTextObj->m_TextState.SetFontSize(10.0f);
+
   static const std::vector<float> rgb = {0.5f, 0.7f, 0.35f};
   RetainPtr<CPDF_ColorSpace> pCS = CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB);
   pTextObj->m_ColorState.SetFillColor(pCS, rgb);
@@ -320,7 +322,8 @@
     CPDF_Dictionary* pDict = pDoc->NewIndirect<CPDF_Dictionary>();
     pDict->SetNewFor<CPDF_Name>("Type", "Font");
     pDict->SetNewFor<CPDF_Name>("Subtype", "TrueType");
-    CPDF_Font* pFont = CPDF_Font::GetStockFont(pDoc.get(), "Arial");
+
+    RetainPtr<CPDF_Font> pFont = CPDF_Font::GetStockFont(pDoc.get(), "Arial");
     pDict->SetNewFor<CPDF_Name>("BaseFont", pFont->GetBaseFont());
 
     CPDF_Dictionary* pDesc = pDoc->NewIndirect<CPDF_Dictionary>();
@@ -329,9 +332,9 @@
     pDict->SetNewFor<CPDF_Reference>("FontDescriptor", pDoc.get(),
                                      pDesc->GetObjNum());
 
-    CPDF_Font* loadedFont =
+    RetainPtr<CPDF_Font> pLoadedFont =
         CPDF_DocPageData::FromDocument(pDoc.get())->GetFont(pDict);
-    pTextObj->m_TextState.SetFont(loadedFont);
+    pTextObj->m_TextState.SetFont(pLoadedFont);
     pTextObj->m_TextState.SetFontSize(15.5f);
     pTextObj->SetText("I am indirect");
     TestProcessText(&generator, &buf, pTextObj.get());
diff --git a/core/fpdfapi/font/cfx_stockfontarray.cpp b/core/fpdfapi/font/cfx_stockfontarray.cpp
index 235f38c..2c3bca4 100644
--- a/core/fpdfapi/font/cfx_stockfontarray.cpp
+++ b/core/fpdfapi/font/cfx_stockfontarray.cpp
@@ -24,17 +24,15 @@
   }
 }
 
-CPDF_Font* CFX_StockFontArray::GetFont(
+RetainPtr<CPDF_Font> CFX_StockFontArray::GetFont(
     CFX_FontMapper::StandardFont index) const {
   if (index >= FX_ArraySize(m_StockFonts))
     return nullptr;
-  return m_StockFonts[index].get();
+  return m_StockFonts[index];
 }
 
-CPDF_Font* CFX_StockFontArray::SetFont(CFX_FontMapper::StandardFont index,
-                                       std::unique_ptr<CPDF_Font> pFont) {
-  CPDF_Font* result = pFont.get();
+void CFX_StockFontArray::SetFont(CFX_FontMapper::StandardFont index,
+                                 const RetainPtr<CPDF_Font>& pFont) {
   if (index < FX_ArraySize(m_StockFonts))
-    m_StockFonts[index] = std::move(pFont);
-  return result;
+    m_StockFonts[index] = pFont;
 }
diff --git a/core/fpdfapi/font/cfx_stockfontarray.h b/core/fpdfapi/font/cfx_stockfontarray.h
index d5a8739..5e54704 100644
--- a/core/fpdfapi/font/cfx_stockfontarray.h
+++ b/core/fpdfapi/font/cfx_stockfontarray.h
@@ -9,6 +9,7 @@
 
 #include <memory>
 
+#include "core/fxcrt/retain_ptr.h"
 #include "core/fxge/cfx_fontmapper.h"
 
 class CPDF_Font;
@@ -18,13 +19,12 @@
   CFX_StockFontArray();
   ~CFX_StockFontArray();
 
-  // Takes ownership of |pFont|, returns unowned pointer to it.
-  CPDF_Font* SetFont(CFX_FontMapper::StandardFont index,
-                     std::unique_ptr<CPDF_Font> pFont);
-  CPDF_Font* GetFont(CFX_FontMapper::StandardFont index) const;
+  RetainPtr<CPDF_Font> GetFont(CFX_FontMapper::StandardFont index) const;
+  void SetFont(CFX_FontMapper::StandardFont index,
+               const RetainPtr<CPDF_Font>& pFont);
 
  private:
-  std::unique_ptr<CPDF_Font> m_StockFonts[14];
+  RetainPtr<CPDF_Font> m_StockFonts[14];
 };
 
 #endif  // CORE_FPDFAPI_FONT_CFX_STOCKFONTARRAY_H_
diff --git a/core/fpdfapi/font/cpdf_cidfont.h b/core/fpdfapi/font/cpdf_cidfont.h
index e400859..ea97f26 100644
--- a/core/fpdfapi/font/cpdf_cidfont.h
+++ b/core/fpdfapi/font/cpdf_cidfont.h
@@ -34,7 +34,9 @@
 
 class CPDF_CIDFont final : public CPDF_Font {
  public:
-  CPDF_CIDFont(CPDF_Document* pDocument, CPDF_Dictionary* pFontDict);
+  template <typename T, typename... Args>
+  friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);
+
   ~CPDF_CIDFont() override;
 
   static float CIDTransformToFloat(uint8_t ch);
@@ -62,6 +64,8 @@
   int GetCharSize(uint32_t charcode) const;
 
  private:
+  CPDF_CIDFont(CPDF_Document* pDocument, CPDF_Dictionary* pFontDict);
+
   void LoadGB2312();
   int GetGlyphIndex(uint32_t unicodeb, bool* pVertGlyph);
   int GetVerticalGlyph(int index, bool* pVertGlyph);
diff --git a/core/fpdfapi/font/cpdf_cidfont_unittest.cpp b/core/fpdfapi/font/cpdf_cidfont_unittest.cpp
index 563ee30..f8d3680 100644
--- a/core/fpdfapi/font/cpdf_cidfont_unittest.cpp
+++ b/core/fpdfapi/font/cpdf_cidfont_unittest.cpp
@@ -37,8 +37,8 @@
     font_dict->SetFor("DescendantFonts", std::move(descendant_fonts));
   }
 
-  CPDF_CIDFont font(&doc, font_dict.Get());
-  ASSERT_TRUE(font.Load());
+  auto font = pdfium::MakeRetain<CPDF_CIDFont>(&doc, font_dict.Get());
+  ASSERT_TRUE(font->Load());
 
   // It would be nice if we can test more values here. However, the glyph
   // indices are sometimes machine dependent.
@@ -53,6 +53,6 @@
 
   for (const auto& test_case : kTestCases) {
     EXPECT_EQ(test_case.glyph,
-              font.GlyphFromCharCode(test_case.charcode, nullptr));
+              font->GlyphFromCharCode(test_case.charcode, nullptr));
   }
 }
diff --git a/core/fpdfapi/font/cpdf_font.cpp b/core/fpdfapi/font/cpdf_font.cpp
index baac1d3..4a22d73 100644
--- a/core/fpdfapi/font/cpdf_font.cpp
+++ b/core/fpdfapi/font/cpdf_font.cpp
@@ -122,6 +122,8 @@
 }
 #endif
 
+void CPDF_Font::WillBeDestroyed() {}
+
 bool CPDF_Font::IsVertWriting() const {
   const CPDF_CIDFont* pCIDFont = AsCIDFont();
   return pCIDFont ? pCIDFont->IsVertWriting() : m_Font.IsVertical();
@@ -284,7 +286,8 @@
 }
 
 // static
-CPDF_Font* CPDF_Font::GetStockFont(CPDF_Document* pDoc, ByteStringView name) {
+RetainPtr<CPDF_Font> CPDF_Font::GetStockFont(CPDF_Document* pDoc,
+                                             ByteStringView name) {
   ByteString fontname(name);
   Optional<CFX_FontMapper::StandardFont> font_id =
       CFX_FontMapper::GetStandardFontName(&fontname);
@@ -292,7 +295,7 @@
     return nullptr;
 
   auto* pFontGlobals = CPDF_FontGlobals::GetInstance();
-  CPDF_Font* pFont = pFontGlobals->Find(pDoc, font_id.value());
+  RetainPtr<CPDF_Font> pFont = pFontGlobals->Find(pDoc, font_id.value());
   if (pFont)
     return pFont;
 
@@ -301,16 +304,17 @@
   pDict->SetNewFor<CPDF_Name>("Subtype", "Type1");
   pDict->SetNewFor<CPDF_Name>("BaseFont", fontname);
   pDict->SetNewFor<CPDF_Name>("Encoding", "WinAnsiEncoding");
-  return pFontGlobals->Set(pDoc, font_id.value(),
-                           CPDF_Font::Create(nullptr, pDict.Get(), nullptr));
+  pFont = CPDF_Font::Create(nullptr, pDict.Get(), nullptr);
+  pFontGlobals->Set(pDoc, font_id.value(), pFont);
+  return pFont;
 }
 
 // static
-std::unique_ptr<CPDF_Font> CPDF_Font::Create(CPDF_Document* pDoc,
-                                             CPDF_Dictionary* pFontDict,
-                                             FormFactoryIface* pFactory) {
+RetainPtr<CPDF_Font> CPDF_Font::Create(CPDF_Document* pDoc,
+                                       CPDF_Dictionary* pFontDict,
+                                       FormFactoryIface* pFactory) {
   ByteString type = pFontDict->GetStringFor("Subtype");
-  std::unique_ptr<CPDF_Font> pFont;
+  RetainPtr<CPDF_Font> pFont;
   if (type == "TrueType") {
     ByteString tag = pFontDict->GetStringFor("BaseFont").Left(4);
     for (size_t i = 0; i < FX_ArraySize(kChineseFontNames); ++i) {
@@ -318,20 +322,23 @@
         const CPDF_Dictionary* pFontDesc =
             pFontDict->GetDictFor("FontDescriptor");
         if (!pFontDesc || !pFontDesc->KeyExist("FontFile2"))
-          pFont = pdfium::MakeUnique<CPDF_CIDFont>(pDoc, pFontDict);
+          pFont = pdfium::MakeRetain<CPDF_CIDFont>(pDoc, pFontDict);
         break;
       }
     }
     if (!pFont)
-      pFont = pdfium::MakeUnique<CPDF_TrueTypeFont>(pDoc, pFontDict);
+      pFont = pdfium::MakeRetain<CPDF_TrueTypeFont>(pDoc, pFontDict);
   } else if (type == "Type3") {
-    pFont = pdfium::MakeUnique<CPDF_Type3Font>(pDoc, pFontDict, pFactory);
+    pFont = pdfium::MakeRetain<CPDF_Type3Font>(pDoc, pFontDict, pFactory);
   } else if (type == "Type0") {
-    pFont = pdfium::MakeUnique<CPDF_CIDFont>(pDoc, pFontDict);
+    pFont = pdfium::MakeRetain<CPDF_CIDFont>(pDoc, pFontDict);
   } else {
-    pFont = pdfium::MakeUnique<CPDF_Type1Font>(pDoc, pFontDict);
+    pFont = pdfium::MakeRetain<CPDF_Type1Font>(pDoc, pFontDict);
   }
-  return pFont->Load() ? std::move(pFont) : nullptr;
+  if (!pFont->Load())
+    return nullptr;
+
+  return pFont;
 }
 
 uint32_t CPDF_Font::GetNextChar(ByteStringView pString, size_t* pOffset) const {
diff --git a/core/fpdfapi/font/cpdf_font.h b/core/fpdfapi/font/cpdf_font.h
index 1a1d361..028fb3e 100644
--- a/core/fpdfapi/font/cpdf_font.h
+++ b/core/fpdfapi/font/cpdf_font.h
@@ -16,6 +16,8 @@
 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/fx_system.h"
+#include "core/fxcrt/observed_ptr.h"
+#include "core/fxcrt/retain_ptr.h"
 #include "core/fxcrt/unowned_ptr.h"
 #include "core/fxge/cfx_font.h"
 
@@ -30,7 +32,7 @@
 class CPDF_Type3Font;
 class CPDF_ToUnicodeMap;
 
-class CPDF_Font {
+class CPDF_Font : public Retainable, public Observable {
  public:
   // Callback mechanism for Type3 fonts to get pixels from forms.
   class FormIface {
@@ -55,15 +57,16 @@
         CPDF_Stream* pFormStream) = 0;
   };
 
-  // |pFactory| only required for Type3 fonts.
-  static std::unique_ptr<CPDF_Font> Create(CPDF_Document* pDoc,
-                                           CPDF_Dictionary* pFontDict,
-                                           FormFactoryIface* pFactory);
-
-  static CPDF_Font* GetStockFont(CPDF_Document* pDoc, ByteStringView fontname);
   static const uint32_t kInvalidCharCode = static_cast<uint32_t>(-1);
 
-  virtual ~CPDF_Font();
+  // |pFactory| only required for Type3 fonts.
+  static RetainPtr<CPDF_Font> Create(CPDF_Document* pDoc,
+                                     CPDF_Dictionary* pFontDict,
+                                     FormFactoryIface* pFactory);
+  static RetainPtr<CPDF_Font> GetStockFont(CPDF_Document* pDoc,
+                                           ByteStringView fontname);
+
+  ~CPDF_Font() override;
 
   virtual bool IsType1Font() const;
   virtual bool IsTrueTypeFont() const;
@@ -78,6 +81,7 @@
   virtual const CPDF_CIDFont* AsCIDFont() const;
   virtual CPDF_CIDFont* AsCIDFont();
 
+  virtual void WillBeDestroyed();
   virtual bool IsVertWriting() const;
   virtual bool IsUnicodeCompatible() const;
   virtual uint32_t GetNextChar(ByteStringView pString, size_t* pOffset) const;
diff --git a/core/fpdfapi/font/cpdf_fontglobals.cpp b/core/fpdfapi/font/cpdf_fontglobals.cpp
index f4350eb..e3b19e2 100644
--- a/core/fpdfapi/font/cpdf_fontglobals.cpp
+++ b/core/fpdfapi/font/cpdf_fontglobals.cpp
@@ -6,8 +6,6 @@
 
 #include "core/fpdfapi/font/cpdf_fontglobals.h"
 
-#include <utility>
-
 #include "core/fpdfapi/font/cfx_stockfontarray.h"
 #include "core/fpdfapi/parser/cpdf_document.h"
 #include "third_party/base/ptr_util.h"
@@ -45,20 +43,22 @@
 
 CPDF_FontGlobals::~CPDF_FontGlobals() = default;
 
-CPDF_Font* CPDF_FontGlobals::Find(CPDF_Document* pDoc,
-                                  CFX_FontMapper::StandardFont index) {
+RetainPtr<CPDF_Font> CPDF_FontGlobals::Find(
+    CPDF_Document* pDoc,
+    CFX_FontMapper::StandardFont index) {
   auto it = m_StockMap.find(pDoc);
-  if (it == m_StockMap.end())
+  if (it == m_StockMap.end() || !it->second)
     return nullptr;
-  return it->second ? it->second->GetFont(index) : nullptr;
+
+  return it->second->GetFont(index);
 }
 
-CPDF_Font* CPDF_FontGlobals::Set(CPDF_Document* pDoc,
-                                 CFX_FontMapper::StandardFont index,
-                                 std::unique_ptr<CPDF_Font> pFont) {
+void CPDF_FontGlobals::Set(CPDF_Document* pDoc,
+                           CFX_FontMapper::StandardFont index,
+                           const RetainPtr<CPDF_Font>& pFont) {
   if (!pdfium::ContainsKey(m_StockMap, pDoc))
     m_StockMap[pDoc] = pdfium::MakeUnique<CFX_StockFontArray>();
-  return m_StockMap[pDoc]->SetFont(index, std::move(pFont));
+  m_StockMap[pDoc]->SetFont(index, pFont);
 }
 
 void CPDF_FontGlobals::Clear(CPDF_Document* pDoc) {
diff --git a/core/fpdfapi/font/cpdf_fontglobals.h b/core/fpdfapi/font/cpdf_fontglobals.h
index 6ae9064..ff3449e 100644
--- a/core/fpdfapi/font/cpdf_fontglobals.h
+++ b/core/fpdfapi/font/cpdf_fontglobals.h
@@ -12,6 +12,7 @@
 
 #include "core/fpdfapi/cmaps/cmap_int.h"
 #include "core/fpdfapi/font/cpdf_cmapmanager.h"
+#include "core/fxcrt/retain_ptr.h"
 #include "core/fxge/cfx_fontmapper.h"
 #include "third_party/base/span.h"
 
@@ -25,12 +26,11 @@
   static CPDF_FontGlobals* GetInstance();
 
   void Clear(CPDF_Document* pDoc);
-  CPDF_Font* Find(CPDF_Document* pDoc, CFX_FontMapper::StandardFont index);
-
-  // Takes ownership of |pFont|, returns unowned pointer to it.
-  CPDF_Font* Set(CPDF_Document* pDoc,
-                 CFX_FontMapper::StandardFont index,
-                 std::unique_ptr<CPDF_Font> pFont);
+  RetainPtr<CPDF_Font> Find(CPDF_Document* pDoc,
+                            CFX_FontMapper::StandardFont index);
+  void Set(CPDF_Document* pDoc,
+           CFX_FontMapper::StandardFont index,
+           const RetainPtr<CPDF_Font>& pFont);
 
   void SetEmbeddedCharset(size_t idx, pdfium::span<const FXCMAP_CMap> map) {
     m_EmbeddedCharsets[idx] = map;
diff --git a/core/fpdfapi/font/cpdf_simplefont.h b/core/fpdfapi/font/cpdf_simplefont.h
index 290016b..8c909ab 100644
--- a/core/fpdfapi/font/cpdf_simplefont.h
+++ b/core/fpdfapi/font/cpdf_simplefont.h
@@ -16,7 +16,6 @@
 
 class CPDF_SimpleFont : public CPDF_Font {
  public:
-  CPDF_SimpleFont(CPDF_Document* pDocument, CPDF_Dictionary* pFontDict);
   ~CPDF_SimpleFont() override;
 
   // CPDF_Font
@@ -32,6 +31,8 @@
   bool HasFontWidths() const override;
 
  protected:
+  CPDF_SimpleFont(CPDF_Document* pDocument, CPDF_Dictionary* pFontDict);
+
   virtual void LoadGlyphMap() = 0;
 
   bool LoadCommon();
diff --git a/core/fpdfapi/font/cpdf_truetypefont.h b/core/fpdfapi/font/cpdf_truetypefont.h
index 158a5df..caa1625 100644
--- a/core/fpdfapi/font/cpdf_truetypefont.h
+++ b/core/fpdfapi/font/cpdf_truetypefont.h
@@ -12,7 +12,9 @@
 
 class CPDF_TrueTypeFont final : public CPDF_SimpleFont {
  public:
-  CPDF_TrueTypeFont(CPDF_Document* pDocument, CPDF_Dictionary* pFontDict);
+  template <typename T, typename... Args>
+  friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);
+
   ~CPDF_TrueTypeFont() override;
 
   // CPDF_Font:
@@ -21,6 +23,8 @@
   CPDF_TrueTypeFont* AsTrueTypeFont() override;
 
  private:
+  CPDF_TrueTypeFont(CPDF_Document* pDocument, CPDF_Dictionary* pFontDict);
+
   // CPDF_Font:
   bool Load() override;
 
diff --git a/core/fpdfapi/font/cpdf_type1font.h b/core/fpdfapi/font/cpdf_type1font.h
index eb01ec7..79dfe31 100644
--- a/core/fpdfapi/font/cpdf_type1font.h
+++ b/core/fpdfapi/font/cpdf_type1font.h
@@ -14,7 +14,9 @@
 
 class CPDF_Type1Font final : public CPDF_SimpleFont {
  public:
-  CPDF_Type1Font(CPDF_Document* pDocument, CPDF_Dictionary* pFontDict);
+  template <typename T, typename... Args>
+  friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);
+
   ~CPDF_Type1Font() override;
 
   // CPDF_Font:
@@ -28,6 +30,8 @@
   bool IsBase14Font() const { return m_Base14Font.has_value(); }
 
  private:
+  CPDF_Type1Font(CPDF_Document* pDocument, CPDF_Dictionary* pFontDict);
+
   // CPDF_Font:
   bool Load() override;
 
diff --git a/core/fpdfapi/font/cpdf_type3char.cpp b/core/fpdfapi/font/cpdf_type3char.cpp
index 1bf5ebb..7d71e8c 100644
--- a/core/fpdfapi/font/cpdf_type3char.cpp
+++ b/core/fpdfapi/font/cpdf_type3char.cpp
@@ -58,6 +58,11 @@
   m_BBox.top = FXSYS_round(TextUnitToGlyphUnit(pData[5]));
 }
 
+void CPDF_Type3Char::WillBeDestroyed() {
+  // Break cycles.
+  m_pForm.reset();
+}
+
 void CPDF_Type3Char::Transform(CPDF_Font::FormIface* pForm,
                                const CFX_Matrix& matrix) {
   m_Width = m_Width * matrix.GetXUnit() + 0.5f;
diff --git a/core/fpdfapi/font/cpdf_type3char.h b/core/fpdfapi/font/cpdf_type3char.h
index 05ade5f..ca83452 100644
--- a/core/fpdfapi/font/cpdf_type3char.h
+++ b/core/fpdfapi/font/cpdf_type3char.h
@@ -29,6 +29,7 @@
   bool LoadBitmapFromSoleImageOfForm();
   void InitializeFromStreamData(bool bColored, const float* pData);
   void Transform(CPDF_Font::FormIface* pForm, const CFX_Matrix& matrix);
+  void WillBeDestroyed();
 
   RetainPtr<CFX_DIBitmap> GetBitmap();
   const RetainPtr<CFX_DIBitmap>& GetBitmap() const;
diff --git a/core/fpdfapi/font/cpdf_type3font.cpp b/core/fpdfapi/font/cpdf_type3font.cpp
index 9983f8a..7e2e59d 100644
--- a/core/fpdfapi/font/cpdf_type3font.cpp
+++ b/core/fpdfapi/font/cpdf_type3font.cpp
@@ -45,6 +45,15 @@
   return this;
 }
 
+void CPDF_Type3Font::WillBeDestroyed() {
+  // Last reference to |this| may be through one of its CPDF_Type3Chars.
+  RetainPtr<CPDF_Font> protector(this);
+  for (const auto& item : m_CacheMap) {
+    if (item.second)
+      item.second->WillBeDestroyed();
+  }
+}
+
 bool CPDF_Type3Font::Load() {
   m_pFontResources.Reset(m_pFontDict->GetDictFor("Resources"));
   const CPDF_Array* pMatrix = m_pFontDict->GetArrayFor("FontMatrix");
diff --git a/core/fpdfapi/font/cpdf_type3font.h b/core/fpdfapi/font/cpdf_type3font.h
index 68e0e92..1ef469b 100644
--- a/core/fpdfapi/font/cpdf_type3font.h
+++ b/core/fpdfapi/font/cpdf_type3font.h
@@ -22,15 +22,16 @@
 
 class CPDF_Type3Font final : public CPDF_SimpleFont {
  public:
-  CPDF_Type3Font(CPDF_Document* pDocument,
-                 CPDF_Dictionary* pFontDict,
-                 FormFactoryIface* pFormFactory);
+  template <typename T, typename... Args>
+  friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);
+
   ~CPDF_Type3Font() override;
 
   // CPDF_Font:
   bool IsType3Font() const override;
   const CPDF_Type3Font* AsType3Font() const override;
   CPDF_Type3Font* AsType3Font() override;
+  void WillBeDestroyed() override;
   uint32_t GetCharWidthF(uint32_t charcode) override;
   FX_RECT GetCharBBox(uint32_t charcode) override;
 
@@ -43,6 +44,10 @@
   CFX_Matrix& GetFontMatrix() { return m_FontMatrix; }
 
  private:
+  CPDF_Type3Font(CPDF_Document* pDocument,
+                 CPDF_Dictionary* pFontDict,
+                 FormFactoryIface* pFormFactory);
+
   // CPDF_Font:
   bool Load() override;
 
diff --git a/core/fpdfapi/page/BUILD.gn b/core/fpdfapi/page/BUILD.gn
index edb73b8..5bb8115 100644
--- a/core/fpdfapi/page/BUILD.gn
+++ b/core/fpdfapi/page/BUILD.gn
@@ -24,7 +24,6 @@
     "cpdf_contentmarks.h",
     "cpdf_contentparser.cpp",
     "cpdf_contentparser.h",
-    "cpdf_countedobject.h",
     "cpdf_devicecs.cpp",
     "cpdf_devicecs.h",
     "cpdf_dibbase.cpp",
diff --git a/core/fpdfapi/page/cpdf_allstates.cpp b/core/fpdfapi/page/cpdf_allstates.cpp
index 2485a06..a12ce33 100644
--- a/core/fpdfapi/page/cpdf_allstates.cpp
+++ b/core/fpdfapi/page/cpdf_allstates.cpp
@@ -10,6 +10,7 @@
 #include <utility>
 #include <vector>
 
+#include "core/fpdfapi/font/cpdf_font.h"
 #include "core/fpdfapi/page/cpdf_pageobjectholder.h"
 #include "core/fpdfapi/page/cpdf_streamcontentparser.h"
 #include "core/fpdfapi/parser/cpdf_array.h"
diff --git a/core/fpdfapi/page/cpdf_countedobject.h b/core/fpdfapi/page/cpdf_countedobject.h
deleted file mode 100644
index cb39616..0000000
--- a/core/fpdfapi/page/cpdf_countedobject.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2016 PDFium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
-
-#ifndef CORE_FPDFAPI_PAGE_CPDF_COUNTEDOBJECT_H_
-#define CORE_FPDFAPI_PAGE_CPDF_COUNTEDOBJECT_H_
-
-#include <memory>
-
-#include "core/fxcrt/fx_system.h"
-
-template <class T>
-class CPDF_CountedObject {
- public:
-  explicit CPDF_CountedObject(std::unique_ptr<T> ptr)
-      : m_nCount(1), m_pObj(ptr.release()) {}
-  void reset(std::unique_ptr<T> ptr) {  // CAUTION: tosses prior ref counts.
-    m_nCount = 1;
-    m_pObj = ptr.release();
-  }
-  void clear() {  // Now you're all weak ptrs ...
-    // Guard against accidental re-entry.
-    T* pObj = m_pObj;
-    m_pObj = nullptr;
-    delete pObj;
-  }
-  T* get() const { return m_pObj; }
-  T* AddRef() {
-    ASSERT(m_pObj);
-    ++m_nCount;
-    return m_pObj;
-  }
-  void RemoveRef() {
-    if (m_nCount)
-      --m_nCount;
-  }
-  size_t use_count() const { return m_nCount; }
-
- protected:
-  size_t m_nCount;
-  T* m_pObj;
-};
-
-#endif  // CORE_FPDFAPI_PAGE_CPDF_COUNTEDOBJECT_H_
diff --git a/core/fpdfapi/page/cpdf_dibbase.h b/core/fpdfapi/page/cpdf_dibbase.h
index c4309a9..0e1da42 100644
--- a/core/fpdfapi/page/cpdf_dibbase.h
+++ b/core/fpdfapi/page/cpdf_dibbase.h
@@ -12,7 +12,6 @@
 
 #include "core/fpdfapi/page/cpdf_clippath.h"
 #include "core/fpdfapi/page/cpdf_colorspace.h"
-#include "core/fpdfapi/page/cpdf_countedobject.h"
 #include "core/fpdfapi/page/cpdf_graphicstates.h"
 #include "core/fxcrt/retain_ptr.h"
 #include "core/fxcrt/unowned_ptr.h"
diff --git a/core/fpdfapi/page/cpdf_docpagedata.cpp b/core/fpdfapi/page/cpdf_docpagedata.cpp
index b727a79..908f081 100644
--- a/core/fpdfapi/page/cpdf_docpagedata.cpp
+++ b/core/fpdfapi/page/cpdf_docpagedata.cpp
@@ -166,62 +166,40 @@
 
 CPDF_DocPageData::~CPDF_DocPageData() {
   for (auto& it : m_FontMap) {
-    CPDF_CountedFont* fontData = it.second;
-    if (fontData->get() && fontData->use_count() < 2)
-      fontData->clear();
+    if (it.second)
+      it.second->WillBeDestroyed();
   }
-
-  m_FontFileMap.clear();
-  m_bForceClear = true;
-  for (auto& it : m_FontMap) {
-    CPDF_CountedFont* fontData = it.second;
-    if (fontData->get())
-      fontData->clear();
-  }
-
-  for (auto& it : m_FontMap)
-    delete it.second;
 }
 
 void CPDF_DocPageData::ClearStockFont() {
   CPDF_PageModule::GetInstance()->ClearStockFont(GetDocument());
 }
 
-CPDF_Font* CPDF_DocPageData::GetFont(CPDF_Dictionary* pFontDict) {
+RetainPtr<CPDF_Font> CPDF_DocPageData::GetFont(CPDF_Dictionary* pFontDict) {
   if (!pFontDict)
     return nullptr;
 
-  CPDF_CountedFont* pFontData = nullptr;
   auto it = m_FontMap.find(pFontDict);
-  if (it != m_FontMap.end()) {
-    pFontData = it->second;
-    if (pFontData->get()) {
-      return pFontData->AddRef();
-    }
-  }
-  std::unique_ptr<CPDF_Font> pFont =
+  if (it != m_FontMap.end() && it->second)
+    return pdfium::WrapRetain(it->second.Get());
+
+  RetainPtr<CPDF_Font> pFont =
       CPDF_Font::Create(GetDocument(), pFontDict, this);
   if (!pFont)
     return nullptr;
 
-  if (pFontData) {
-    pFontData->reset(std::move(pFont));
-  } else {
-    pFontData = new CPDF_CountedFont(std::move(pFont));
-    m_FontMap[pFontDict] = pFontData;
-  }
-  return pFontData->AddRef();
+  m_FontMap[pFontDict].Reset(pFont.Get());
+  return pFont;
 }
 
-CPDF_Font* CPDF_DocPageData::GetStandardFont(
+RetainPtr<CPDF_Font> CPDF_DocPageData::GetStandardFont(
     const ByteString& fontName,
     const CPDF_FontEncoding* pEncoding) {
   if (fontName.IsEmpty())
     return nullptr;
 
   for (auto& it : m_FontMap) {
-    CPDF_CountedFont* fontData = it.second;
-    CPDF_Font* pFont = fontData->get();
+    CPDF_Font* pFont = it.second.Get();
     if (!pFont)
       continue;
     if (pFont->GetBaseFont() != fontName)
@@ -237,7 +215,7 @@
     if (pEncoding && !pT1Font->GetEncoding()->IsIdentical(pEncoding))
       continue;
 
-    return fontData->AddRef();
+    return pdfium::WrapRetain(pFont);
   }
 
   CPDF_Dictionary* pDict = GetDocument()->NewIndirect<CPDF_Dictionary>();
@@ -250,34 +228,12 @@
   }
 
   // Note: NULL FormFactoryIface OK since known Type1 font from above.
-  std::unique_ptr<CPDF_Font> pFont =
-      CPDF_Font::Create(GetDocument(), pDict, nullptr);
+  RetainPtr<CPDF_Font> pFont = CPDF_Font::Create(GetDocument(), pDict, nullptr);
   if (!pFont)
     return nullptr;
 
-  CPDF_CountedFont* fontData = new CPDF_CountedFont(std::move(pFont));
-  m_FontMap[pDict] = fontData;
-  return fontData->AddRef();
-}
-
-void CPDF_DocPageData::ReleaseFont(const CPDF_Dictionary* pFontDict) {
-  if (!pFontDict)
-    return;
-
-  auto it = m_FontMap.find(pFontDict);
-  if (it == m_FontMap.end())
-    return;
-
-  CPDF_CountedFont* pFontData = it->second;
-  if (!pFontData->get())
-    return;
-
-  pFontData->RemoveRef();
-  if (pFontData->use_count() > 1)
-    return;
-
-  // We have font data only in m_FontMap cache. Clean it.
-  pFontData->clear();
+  m_FontMap[pDict].Reset(pFont.Get());
+  return pFont;
 }
 
 RetainPtr<CPDF_ColorSpace> CPDF_DocPageData::GetColorSpace(
@@ -491,7 +447,7 @@
   return pdfium::MakeUnique<CPDF_Form>(pDocument, pPageResources, pFormStream);
 }
 
-CPDF_Font* CPDF_DocPageData::AddStandardFont(
+RetainPtr<CPDF_Font> CPDF_DocPageData::AddStandardFont(
     const char* font,
     const CPDF_FontEncoding* pEncoding) {
   ByteString name(font);
@@ -500,7 +456,8 @@
   return GetStandardFont(name, pEncoding);
 }
 
-CPDF_Font* CPDF_DocPageData::AddFont(CFX_Font* pFont, int charset) {
+RetainPtr<CPDF_Font> CPDF_DocPageData::AddFont(std::unique_ptr<CFX_Font> pFont,
+                                               int charset) {
   if (!pFont)
     return nullptr;
 
@@ -513,7 +470,7 @@
 
   CPDF_Dictionary* pBaseDict = GetDocument()->NewIndirect<CPDF_Dictionary>();
   pBaseDict->SetNewFor<CPDF_Name>("Type", "Font");
-  auto pEncoding = pdfium::MakeUnique<CFX_UnicodeEncoding>(pFont);
+  auto pEncoding = pdfium::MakeUnique<CFX_UnicodeEncoding>(pFont.get());
   CPDF_Dictionary* pFontDict = pBaseDict;
   if (!bCJK) {
     auto pWidths = pdfium::MakeRetain<CPDF_Array>();
@@ -546,8 +503,8 @@
   } else {
     pFontDict = ProcessbCJK(
         pBaseDict, charset, basefont,
-        [pFont, &pEncoding](wchar_t start, wchar_t end, CPDF_Array* widthArr) {
-          InsertWidthArray1(pFont, pEncoding.get(), start, end, widthArr);
+        [&pFont, &pEncoding](wchar_t start, wchar_t end, CPDF_Array* widthArr) {
+          InsertWidthArray1(pFont.get(), pEncoding.get(), start, end, widthArr);
         });
   }
   int italicangle =
@@ -584,7 +541,7 @@
 }
 
 #if defined(OS_WIN)
-CPDF_Font* CPDF_DocPageData::AddWindowsFont(LOGFONTA* pLogFont) {
+RetainPtr<CPDF_Font> CPDF_DocPageData::AddWindowsFont(LOGFONTA* pLogFont) {
   pLogFont->lfHeight = -1000;
   pLogFont->lfWidth = 0;
   HGDIOBJ hFont = CreateFontIndirectA(pLogFont);
diff --git a/core/fpdfapi/page/cpdf_docpagedata.h b/core/fpdfapi/page/cpdf_docpagedata.h
index 10eed18..bb9059c 100644
--- a/core/fpdfapi/page/cpdf_docpagedata.h
+++ b/core/fpdfapi/page/cpdf_docpagedata.h
@@ -13,10 +13,10 @@
 
 #include "core/fpdfapi/font/cpdf_font.h"
 #include "core/fpdfapi/page/cpdf_colorspace.h"
-#include "core/fpdfapi/page/cpdf_countedobject.h"
 #include "core/fpdfapi/parser/cpdf_document.h"
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_string.h"
+#include "core/fxcrt/observed_ptr.h"
 #include "core/fxcrt/retain_ptr.h"
 #include "core/fxcrt/unowned_ptr.h"
 
@@ -52,16 +52,14 @@
 
   bool IsForceClear() const { return m_bForceClear; }
 
-  CPDF_Font* AddFont(CFX_Font* pFont, int charset);
-  CPDF_Font* GetFont(CPDF_Dictionary* pFontDict);
-  CPDF_Font* AddStandardFont(const char* font,
-                             const CPDF_FontEncoding* pEncoding);
-  CPDF_Font* GetStandardFont(const ByteString& fontName,
-                             const CPDF_FontEncoding* pEncoding);
-  void ReleaseFont(const CPDF_Dictionary* pFontDict);
-
+  RetainPtr<CPDF_Font> AddFont(std::unique_ptr<CFX_Font> pFont, int charset);
+  RetainPtr<CPDF_Font> GetFont(CPDF_Dictionary* pFontDict);
+  RetainPtr<CPDF_Font> AddStandardFont(const char* font,
+                                       const CPDF_FontEncoding* pEncoding);
+  RetainPtr<CPDF_Font> GetStandardFont(const ByteString& fontName,
+                                       const CPDF_FontEncoding* pEncoding);
 #if defined(OS_WIN)
-  CPDF_Font* AddWindowsFont(LOGFONTA* pLogFont);
+  RetainPtr<CPDF_Font> AddWindowsFont(LOGFONTA* pLogFont);
 #endif
 
   // Loads a colorspace.
@@ -86,8 +84,6 @@
   RetainPtr<CPDF_IccProfile> GetIccProfile(const CPDF_Stream* pProfileStream);
 
  private:
-  using CPDF_CountedFont = CPDF_CountedObject<CPDF_Font>;
-
   // Loads a colorspace in a context that might be while loading another
   // colorspace, or even in a recursive call from this method itself. |pVisited|
   // is passed recursively to avoid circular calls involving
@@ -116,7 +112,7 @@
   std::map<const CPDF_Stream*, ObservedPtr<CPDF_IccProfile>> m_IccProfileMap;
   std::map<const CPDF_Object*, ObservedPtr<CPDF_Pattern>> m_PatternMap;
   std::map<uint32_t, RetainPtr<CPDF_Image>> m_ImageMap;
-  std::map<const CPDF_Dictionary*, CPDF_CountedFont*> m_FontMap;
+  std::map<const CPDF_Dictionary*, ObservedPtr<CPDF_Font>> m_FontMap;
 };
 
 #endif  // CORE_FPDFAPI_PAGE_CPDF_DOCPAGEDATA_H_
diff --git a/core/fpdfapi/page/cpdf_streamcontentparser.cpp b/core/fpdfapi/page/cpdf_streamcontentparser.cpp
index c4021d8..8885760 100644
--- a/core/fpdfapi/page/cpdf_streamcontentparser.cpp
+++ b/core/fpdfapi/page/cpdf_streamcontentparser.cpp
@@ -1125,14 +1125,13 @@
 
 void CPDF_StreamContentParser::Handle_SetFont() {
   float fs = GetNumber(0);
-  if (fs == 0) {
+  if (fs == 0)
     fs = m_DefFontSize;
-  }
+
   m_pCurStates->m_TextState.SetFontSize(fs);
-  CPDF_Font* pFont = FindFont(GetString(1));
-  if (pFont) {
+  RetainPtr<CPDF_Font> pFont = FindFont(GetString(1));
+  if (pFont)
     m_pCurStates->m_TextState.SetFont(pFont);
-  }
 }
 
 CPDF_Dictionary* CPDF_StreamContentParser::FindResourceHolder(
@@ -1156,14 +1155,15 @@
   return pHolder ? pHolder->GetDirectObjectFor(name) : nullptr;
 }
 
-CPDF_Font* CPDF_StreamContentParser::FindFont(const ByteString& name) {
+RetainPtr<CPDF_Font> CPDF_StreamContentParser::FindFont(
+    const ByteString& name) {
   CPDF_Dictionary* pFontDict = ToDictionary(FindResourceObj("Font", name));
   if (!pFontDict) {
     m_bResourceMissing = true;
     return CPDF_Font::GetStockFont(m_pDocument.Get(),
                                    CFX_Font::kDefaultAnsiFontName);
   }
-  CPDF_Font* pFont =
+  RetainPtr<CPDF_Font> pFont =
       CPDF_DocPageData::FromDocument(m_pDocument.Get())->GetFont(pFontDict);
   if (pFont && pFont->IsType3Font()) {
     pFont->AsType3Font()->SetPageResources(m_pResources.Get());
@@ -1219,7 +1219,7 @@
                                              float fInitKerning,
                                              const std::vector<float>& kernings,
                                              size_t nSegs) {
-  CPDF_Font* pFont = m_pCurStates->m_TextState.GetFont();
+  RetainPtr<CPDF_Font> pFont = m_pCurStates->m_TextState.GetFont();
   if (!pFont)
     return;
 
diff --git a/core/fpdfapi/page/cpdf_streamcontentparser.h b/core/fpdfapi/page/cpdf_streamcontentparser.h
index a20dbe1..cd47938 100644
--- a/core/fpdfapi/page/cpdf_streamcontentparser.h
+++ b/core/fpdfapi/page/cpdf_streamcontentparser.h
@@ -58,7 +58,7 @@
   CPDF_AllStates* GetCurStates() const { return m_pCurStates.get(); }
   bool IsColored() const { return m_bColored; }
   const float* GetType3Data() const { return m_Type3Data; }
-  CPDF_Font* FindFont(const ByteString& name);
+  RetainPtr<CPDF_Font> FindFont(const ByteString& name);
 
   static ByteStringView FindKeyAbbreviationForTesting(ByteStringView abbr);
   static ByteStringView FindValueAbbreviationForTesting(ByteStringView abbr);
diff --git a/core/fpdfapi/page/cpdf_textobject.cpp b/core/fpdfapi/page/cpdf_textobject.cpp
index c554113..49d6a69 100644
--- a/core/fpdfapi/page/cpdf_textobject.cpp
+++ b/core/fpdfapi/page/cpdf_textobject.cpp
@@ -40,10 +40,8 @@
   if (pInfo->m_CharCode == CPDF_Font::kInvalidCharCode)
     return;
 
-  CPDF_Font* pFont = m_TextState.GetFont();
-  if (!pFont->IsCIDFont())
-    return;
-  if (!pFont->AsCIDFont()->IsVertWriting())
+  RetainPtr<CPDF_Font> pFont = m_TextState.GetFont();
+  if (!pFont->IsCIDFont() || !pFont->AsCIDFont()->IsVertWriting())
     return;
 
   uint16_t CID = pFont->AsCIDFont()->CIDFromCharCode(pInfo->m_CharCode);
@@ -150,7 +148,7 @@
                                   size_t nSegs) {
   m_CharCodes.clear();
   m_CharPos.clear();
-  CPDF_Font* pFont = m_TextState.GetFont();
+  RetainPtr<CPDF_Font> pFont = m_TextState.GetFont();
   int nChars = 0;
   for (size_t i = 0; i < nSegs; ++i)
     nChars += pFont->CountChar(pStrs[i].AsStringView());
@@ -180,7 +178,7 @@
 
 float CPDF_TextObject::GetCharWidth(uint32_t charcode) const {
   float fontsize = m_TextState.GetFontSize() / 1000;
-  CPDF_Font* pFont = m_TextState.GetFont();
+  RetainPtr<CPDF_Font> pFont = m_TextState.GetFont();
   bool bVertWriting = false;
   CPDF_CIDFont* pCIDFont = pFont->AsCIDFont();
   if (pCIDFont)
@@ -192,7 +190,7 @@
   return pCIDFont->GetVertWidth(CID) * fontsize;
 }
 
-CPDF_Font* CPDF_TextObject::GetFont() const {
+RetainPtr<CPDF_Font> CPDF_TextObject::GetFont() const {
   return m_TextState.GetFont();
 }
 
@@ -206,7 +204,7 @@
   float max_x = -10000 * 1.0f;
   float min_y = 10000 * 1.0f;
   float max_y = -10000 * 1.0f;
-  CPDF_Font* pFont = m_TextState.GetFont();
+  RetainPtr<CPDF_Font> pFont = m_TextState.GetFont();
   bool bVertWriting = false;
   CPDF_CIDFont* pCIDFont = pFont->AsCIDFont();
   if (pCIDFont)
diff --git a/core/fpdfapi/page/cpdf_textobject.h b/core/fpdfapi/page/cpdf_textobject.h
index 076dcbb..129a0fe 100644
--- a/core/fpdfapi/page/cpdf_textobject.h
+++ b/core/fpdfapi/page/cpdf_textobject.h
@@ -13,6 +13,7 @@
 #include "core/fpdfapi/page/cpdf_pageobject.h"
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/fx_system.h"
+#include "core/fxcrt/retain_ptr.h"
 
 class CPDF_TextObjectItem {
  public:
@@ -48,7 +49,7 @@
 
   CFX_PointF GetPos() const { return m_Pos; }
   CFX_Matrix GetTextMatrix() const;
-  CPDF_Font* GetFont() const;
+  RetainPtr<CPDF_Font> GetFont() const;
   float GetFontSize() const;
 
   void SetText(const ByteString& str);
diff --git a/core/fpdfapi/page/cpdf_textstate.cpp b/core/fpdfapi/page/cpdf_textstate.cpp
index a72594c..8b65332 100644
--- a/core/fpdfapi/page/cpdf_textstate.cpp
+++ b/core/fpdfapi/page/cpdf_textstate.cpp
@@ -18,11 +18,11 @@
   m_Ref.Emplace();
 }
 
-CPDF_Font* CPDF_TextState::GetFont() const {
+RetainPtr<CPDF_Font> CPDF_TextState::GetFont() const {
   return m_Ref.GetObject()->m_pFont;
 }
 
-void CPDF_TextState::SetFont(CPDF_Font* pFont) {
+void CPDF_TextState::SetFont(const RetainPtr<CPDF_Font>& pFont) {
   m_Ref.GetPrivateCopy()->SetFont(pFont);
 }
 
@@ -122,16 +122,13 @@
   }
 }
 
-CPDF_TextState::TextData::~TextData() {
-  ReleaseFont();
-}
+CPDF_TextState::TextData::~TextData() = default;
 
 RetainPtr<CPDF_TextState::TextData> CPDF_TextState::TextData::Clone() const {
   return pdfium::MakeRetain<CPDF_TextState::TextData>(*this);
 }
 
-void CPDF_TextState::TextData::SetFont(CPDF_Font* pFont) {
-  ReleaseFont();
+void CPDF_TextState::TextData::SetFont(const RetainPtr<CPDF_Font>& pFont) {
   m_pDocument = pFont ? pFont->GetDocument() : nullptr;
   m_pFont = pFont;
 }
@@ -152,15 +149,6 @@
   return GetBaselineAngle() + atan2(m_Matrix[1], m_Matrix[3]);
 }
 
-void CPDF_TextState::TextData::ReleaseFont() {
-  if (!m_pDocument || !m_pFont)
-    return;
-
-  auto* pPageData = CPDF_DocPageData::FromDocument(m_pDocument.Get());
-  if (pPageData && !pPageData->IsForceClear())
-    pPageData->ReleaseFont(m_pFont->GetFontDict());
-}
-
 bool SetTextRenderingModeFromInt(int iMode, TextRenderingMode* mode) {
   if (iMode < 0 || iMode > 7)
     return false;
diff --git a/core/fpdfapi/page/cpdf_textstate.h b/core/fpdfapi/page/cpdf_textstate.h
index a466db6..53934ec 100644
--- a/core/fpdfapi/page/cpdf_textstate.h
+++ b/core/fpdfapi/page/cpdf_textstate.h
@@ -7,6 +7,7 @@
 #ifndef CORE_FPDFAPI_PAGE_CPDF_TEXTSTATE_H_
 #define CORE_FPDFAPI_PAGE_CPDF_TEXTSTATE_H_
 
+#include "core/fxcrt/retain_ptr.h"
 #include "core/fxcrt/shared_copy_on_write.h"
 #include "core/fxcrt/unowned_ptr.h"
 
@@ -32,8 +33,8 @@
 
   void Emplace();
 
-  CPDF_Font* GetFont() const;
-  void SetFont(CPDF_Font* pFont);
+  RetainPtr<CPDF_Font> GetFont() const;
+  void SetFont(const RetainPtr<CPDF_Font>& pFont);
 
   float GetFontSize() const;
   void SetFontSize(float size);
@@ -66,13 +67,13 @@
 
     RetainPtr<TextData> Clone() const;
 
-    void SetFont(CPDF_Font* pFont);
+    void SetFont(const RetainPtr<CPDF_Font>& pFont);
     float GetFontSizeV() const;
     float GetFontSizeH() const;
     float GetBaselineAngle() const;
     float GetShearAngle() const;
 
-    CPDF_Font* m_pFont;
+    RetainPtr<CPDF_Font> m_pFont;
     UnownedPtr<CPDF_Document> m_pDocument;
     float m_FontSize;
     float m_CharSpace;
@@ -85,8 +86,6 @@
     TextData();
     TextData(const TextData& that);
     ~TextData() override;
-
-    void ReleaseFont();
   };
 
   SharedCopyOnWrite<TextData> m_Ref;
diff --git a/core/fpdfapi/render/cpdf_renderstatus.cpp b/core/fpdfapi/render/cpdf_renderstatus.cpp
index bbea4e3..00e3008 100644
--- a/core/fpdfapi/render/cpdf_renderstatus.cpp
+++ b/core/fpdfapi/render/cpdf_renderstatus.cpp
@@ -1536,9 +1536,10 @@
       // TODO(thestig): Should we check the return value here?
       CPDF_TextRenderer::DrawTextPath(
           &text_device, textobj->GetCharCodes(), textobj->GetCharPositions(),
-          textobj->m_TextState.GetFont(), textobj->m_TextState.GetFontSize(),
-          textobj->GetTextMatrix(), &new_matrix,
-          textobj->m_GraphState.GetObject(), 0xffffffff, 0, nullptr, 0);
+          textobj->m_TextState.GetFont().Get(),
+          textobj->m_TextState.GetFontSize(), textobj->GetTextMatrix(),
+          &new_matrix, textobj->m_GraphState.GetObject(), 0xffffffff, 0,
+          nullptr, 0);
     }
   }
   CPDF_RenderStatus bitmap_render(m_pContext.Get(), &bitmap_device);
@@ -1664,7 +1665,7 @@
   if (text_render_mode == TextRenderingMode::MODE_INVISIBLE)
     return true;
 
-  CPDF_Font* pFont = textobj->m_TextState.GetFont();
+  RetainPtr<CPDF_Font> pFont = textobj->m_TextState.GetFont();
   if (pFont->IsType3Font())
     return ProcessType3Text(textobj, mtObj2Device);
 
@@ -1724,7 +1725,7 @@
 
   float font_size = textobj->m_TextState.GetFontSize();
   if (bPattern) {
-    DrawTextPathWithPattern(textobj, mtObj2Device, pFont, font_size,
+    DrawTextPathWithPattern(textobj, mtObj2Device, pFont.Get(), font_size,
                             &text_matrix, bFill, bStroke);
     return true;
   }
@@ -1750,15 +1751,15 @@
     if (m_Options.GetOptions().bNoTextSmooth)
       flag |= FXFILL_NOPATHSMOOTH;
     return CPDF_TextRenderer::DrawTextPath(
-        m_pDevice, textobj->GetCharCodes(), textobj->GetCharPositions(), pFont,
-        font_size, text_matrix, pDeviceMatrix,
+        m_pDevice, textobj->GetCharCodes(), textobj->GetCharPositions(),
+        pFont.Get(), font_size, text_matrix, pDeviceMatrix,
         textobj->m_GraphState.GetObject(), fill_argb, stroke_argb,
         pClippingPath, flag);
   }
   text_matrix.Concat(mtObj2Device);
   return CPDF_TextRenderer::DrawNormalText(
-      m_pDevice, textobj->GetCharCodes(), textobj->GetCharPositions(), pFont,
-      font_size, text_matrix, fill_argb, m_Options);
+      m_pDevice, textobj->GetCharCodes(), textobj->GetCharPositions(),
+      pFont.Get(), font_size, text_matrix, fill_argb, m_Options);
 }
 
 // TODO(npm): Font fallback for type 3 fonts? (Completely separate code!!)
@@ -1872,12 +1873,13 @@
         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;
 
+        refTypeCache.insert(std::move(pCache));
+
         CFX_Point origin(FXSYS_round(matrix.e), FXSYS_round(matrix.f));
         if (glyphs.empty()) {
           FX_SAFE_INT32 left = origin.x;
diff --git a/core/fpdfapi/render/cpdf_type3cache.cpp b/core/fpdfapi/render/cpdf_type3cache.cpp
index 3411416..078bec7 100644
--- a/core/fpdfapi/render/cpdf_type3cache.cpp
+++ b/core/fpdfapi/render/cpdf_type3cache.cpp
@@ -85,17 +85,9 @@
 
 }  // namespace
 
-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_Type3Font* pFont) : m_pFont(pFont) {}
 
-CPDF_Type3Cache::~CPDF_Type3Cache() {
-  // Decrements refcount in CPDF_DocPageData.
-  CPDF_Document* pDoc = m_pFont->GetDocument();
-  CPDF_DocPageData::FromDocument(pDoc)->ReleaseFont(m_pFont->GetFontDict());
-}
+CPDF_Type3Cache::~CPDF_Type3Cache() = default;
 
 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 1717e8a..4371a01 100644
--- a/core/fpdfapi/render/cpdf_type3cache.h
+++ b/core/fpdfapi/render/cpdf_type3cache.h
@@ -36,7 +36,7 @@
                                                uint32_t charcode,
                                                const CFX_Matrix* pMatrix);
 
-  UnownedPtr<CPDF_Type3Font> const m_pFont;
+  RetainPtr<CPDF_Type3Font> const m_pFont;
   std::map<ByteString, std::unique_ptr<CPDF_Type3GlyphMap>> m_SizeMap;
 };
 
diff --git a/core/fpdfdoc/cba_fontmap.cpp b/core/fpdfdoc/cba_fontmap.cpp
index b4f737e..974d765 100644
--- a/core/fpdfdoc/cba_fontmap.cpp
+++ b/core/fpdfdoc/cba_fontmap.cpp
@@ -53,20 +53,26 @@
   return false;
 }
 
-CPDF_Font* AddNativeTrueTypeFontToPDF(CPDF_Document* pDoc,
-                                      ByteString sFontFaceName,
-                                      uint8_t nCharset) {
+RetainPtr<CPDF_Font> AddNativeTrueTypeFontToPDF(CPDF_Document* pDoc,
+                                                ByteString sFontFaceName,
+                                                uint8_t nCharset) {
   if (!pDoc)
     return nullptr;
 
   auto pFXFont = pdfium::MakeUnique<CFX_Font>();
   pFXFont->LoadSubst(sFontFaceName, true, 0, 0, 0,
                      FX_GetCodePageFromCharset(nCharset), false);
-  return CPDF_DocPageData::FromDocument(pDoc)->AddFont(pFXFont.get(), nCharset);
+
+  auto* pDocPageData = CPDF_DocPageData::FromDocument(pDoc);
+  return pDocPageData->AddFont(std::move(pFXFont), nCharset);
 }
 
 }  // namespace
 
+CBA_FontMap::Data::Data() = default;
+
+CBA_FontMap::Data::~Data() = default;
+
 CBA_FontMap::CBA_FontMap(CPDF_Document* pDocument, CPDF_Dictionary* pAnnotDict)
     : m_pDocument(pDocument), m_pAnnotDict(pAnnotDict) {
   Initialize();
@@ -76,7 +82,7 @@
   Empty();
 }
 
-CPDF_Font* CBA_FontMap::GetPDFFont(int32_t nFontIndex) {
+RetainPtr<CPDF_Font> CBA_FontMap::GetPDFFont(int32_t nFontIndex) {
   if (pdfium::IndexInBounds(m_Data, nFontIndex))
     return m_Data[nFontIndex]->pFont;
   return nullptr;
@@ -156,7 +162,7 @@
   m_sDefaultFontName.clear();
 }
 
-void CBA_FontMap::SetDefaultFont(CPDF_Font* pFont,
+void CBA_FontMap::SetDefaultFont(const RetainPtr<CPDF_Font>& pFont,
                                  const ByteString& sFontName) {
   ASSERT(pFont);
 
@@ -166,10 +172,9 @@
   m_pDefaultFont = pFont;
   m_sDefaultFontName = sFontName;
 
-  int32_t nCharset = FX_CHARSET_Default;
-  if (const CFX_SubstFont* pSubstFont = m_pDefaultFont->GetSubstFont())
-    nCharset = pSubstFont->m_Charset;
-  AddFontData(m_pDefaultFont.Get(), m_sDefaultFontName, nCharset);
+  const CFX_SubstFont* pSubstFont = m_pDefaultFont->GetSubstFont();
+  int32_t nCharset = pSubstFont ? pSubstFont->m_Charset : FX_CHARSET_Default;
+  AddFontData(m_pDefaultFont, m_sDefaultFontName, nCharset);
 }
 
 void CBA_FontMap::SetAPType(const ByteString& sAPType) {
@@ -196,8 +201,8 @@
         else
           nCharset = FX_CHARSET_ANSI;
       }
-      AddFontData(m_pDefaultFont.Get(), m_sDefaultFontName, nCharset);
-      AddFontToAnnotDict(m_pDefaultFont.Get(), m_sDefaultFontName);
+      AddFontData(m_pDefaultFont, m_sDefaultFontName, nCharset);
+      AddFontToAnnotDict(m_pDefaultFont, m_sDefaultFontName);
     }
   }
 
@@ -205,8 +210,8 @@
     GetFontIndex(CFX_Font::kDefaultAnsiFontName, FX_CHARSET_ANSI, false);
 }
 
-CPDF_Font* CBA_FontMap::FindFontSameCharset(ByteString* sFontAlias,
-                                            int32_t nCharset) {
+RetainPtr<CPDF_Font> CBA_FontMap::FindFontSameCharset(ByteString* sFontAlias,
+                                                      int32_t nCharset) {
   if (m_pAnnotDict->GetStringFor(pdfium::annotation::kSubtype) != "Widget")
     return nullptr;
 
@@ -225,9 +230,10 @@
   return FindResFontSameCharset(pDRDict, sFontAlias, nCharset);
 }
 
-CPDF_Font* CBA_FontMap::FindResFontSameCharset(const CPDF_Dictionary* pResDict,
-                                               ByteString* sFontAlias,
-                                               int32_t nCharset) {
+RetainPtr<CPDF_Font> CBA_FontMap::FindResFontSameCharset(
+    const CPDF_Dictionary* pResDict,
+    ByteString* sFontAlias,
+    int32_t nCharset) {
   if (!pResDict)
     return nullptr;
 
@@ -235,7 +241,7 @@
   if (!pFonts)
     return nullptr;
 
-  CPDF_Font* pFind = nullptr;
+  RetainPtr<CPDF_Font> pFind;
   CPDF_DictionaryLocker locker(pFonts);
   for (const auto& it : locker) {
     const ByteString& csKey = it.first;
@@ -247,7 +253,7 @@
       continue;
 
     auto* pData = CPDF_DocPageData::FromDocument(m_pDocument.Get());
-    CPDF_Font* pFont = pData->GetFont(pElement);
+    RetainPtr<CPDF_Font> pFont = pData->GetFont(pElement);
     if (!pFont)
       continue;
 
@@ -257,13 +263,13 @@
 
     if (pSubst->m_Charset == nCharset) {
       *sFontAlias = csKey;
-      pFind = pFont;
+      pFind = std::move(pFont);
     }
   }
   return pFind;
 }
 
-CPDF_Font* CBA_FontMap::GetAnnotDefaultFont(ByteString* sAlias) {
+RetainPtr<CPDF_Font> CBA_FontMap::GetAnnotDefaultFont(ByteString* sAlias) {
   CPDF_Dictionary* pAcroFormDict = nullptr;
   const bool bWidget =
       (m_pAnnotDict->GetStringFor(pdfium::annotation::kSubtype) == "Widget");
@@ -315,7 +321,7 @@
   return CPDF_DocPageData::FromDocument(m_pDocument.Get())->GetFont(pFontDict);
 }
 
-void CBA_FontMap::AddFontToAnnotDict(CPDF_Font* pFont,
+void CBA_FontMap::AddFontToAnnotDict(const RetainPtr<CPDF_Font>& pFont,
                                      const ByteString& sAlias) {
   if (!pFont)
     return;
@@ -378,7 +384,8 @@
     return nFontIndex;
 
   ByteString sAlias;
-  CPDF_Font* pFont = bFind ? FindFontSameCharset(&sAlias, nCharset) : nullptr;
+  RetainPtr<CPDF_Font> pFont =
+      bFind ? FindFontSameCharset(&sAlias, nCharset) : nullptr;
   if (!pFont) {
     ByteString sTemp = sFontName;
     pFont = AddFontToDocument(m_pDocument.Get(), sTemp, nCharset);
@@ -388,7 +395,7 @@
   return AddFontData(pFont, sAlias, nCharset);
 }
 
-int32_t CBA_FontMap::AddFontData(CPDF_Font* pFont,
+int32_t CBA_FontMap::AddFontData(const RetainPtr<CPDF_Font>& pFont,
                                  const ByteString& sFontAlias,
                                  int32_t nCharset) {
   auto pNewData = pdfium::MakeUnique<Data>();
@@ -450,9 +457,9 @@
   return sNew;
 }
 
-CPDF_Font* CBA_FontMap::AddFontToDocument(CPDF_Document* pDoc,
-                                          ByteString& sFontName,
-                                          uint8_t nCharset) {
+RetainPtr<CPDF_Font> CBA_FontMap::AddFontToDocument(CPDF_Document* pDoc,
+                                                    ByteString& sFontName,
+                                                    uint8_t nCharset) {
   if (IsStandardFont(sFontName))
     return AddStandardFont(pDoc, sFontName);
 
@@ -478,29 +485,25 @@
     if (sFontName == name)
       return true;
   }
-
   return false;
 }
 
-CPDF_Font* CBA_FontMap::AddStandardFont(CPDF_Document* pDoc,
-                                        ByteString& sFontName) {
+RetainPtr<CPDF_Font> CBA_FontMap::AddStandardFont(CPDF_Document* pDoc,
+                                                  ByteString& sFontName) {
   if (!pDoc)
     return nullptr;
 
-  CPDF_Font* pFont = nullptr;
   auto* pPageData = CPDF_DocPageData::FromDocument(pDoc);
-  if (sFontName == "ZapfDingbats") {
-    pFont = pPageData->AddStandardFont(sFontName.c_str(), nullptr);
-  } else {
-    CPDF_FontEncoding fe(PDFFONT_ENCODING_WINANSI);
-    pFont = pPageData->AddStandardFont(sFontName.c_str(), &fe);
-  }
-  return pFont;
+  if (sFontName == "ZapfDingbats")
+    return pPageData->AddStandardFont(sFontName.c_str(), nullptr);
+
+  CPDF_FontEncoding fe(PDFFONT_ENCODING_WINANSI);
+  return pPageData->AddStandardFont(sFontName.c_str(), &fe);
 }
 
-CPDF_Font* CBA_FontMap::AddSystemFont(CPDF_Document* pDoc,
-                                      ByteString& sFontName,
-                                      uint8_t nCharset) {
+RetainPtr<CPDF_Font> CBA_FontMap::AddSystemFont(CPDF_Document* pDoc,
+                                                ByteString& sFontName,
+                                                uint8_t nCharset) {
   if (!pDoc)
     return nullptr;
 
diff --git a/core/fpdfdoc/cba_fontmap.h b/core/fpdfdoc/cba_fontmap.h
index f4abfba..ae14809 100644
--- a/core/fpdfdoc/cba_fontmap.h
+++ b/core/fpdfdoc/cba_fontmap.h
@@ -12,6 +12,7 @@
 
 #include "core/fpdfdoc/ipvt_fontmap.h"
 #include "core/fxcrt/fx_codepage.h"
+#include "core/fxcrt/retain_ptr.h"
 #include "core/fxcrt/unowned_ptr.h"
 
 class CPDF_Dictionary;
@@ -19,11 +20,13 @@
 
 class CBA_FontMap final : public IPVT_FontMap {
  public:
+  static int32_t GetNativeCharset();
+
   CBA_FontMap(CPDF_Document* pDocument, CPDF_Dictionary* pAnnotDict);
   ~CBA_FontMap() override;
 
   // IPVT_FontMap
-  CPDF_Font* GetPDFFont(int32_t nFontIndex) override;
+  RetainPtr<CPDF_Font> GetPDFFont(int32_t nFontIndex) override;
   ByteString GetPDFFontAlias(int32_t nFontIndex) override;
   int32_t GetWordFontIndex(uint16_t word,
                            int32_t nCharset,
@@ -31,15 +34,17 @@
   int32_t CharCodeFromUnicode(int32_t nFontIndex, uint16_t word) override;
   int32_t CharSetFromUnicode(uint16_t word, int32_t nOldCharset) override;
 
-  static int32_t GetNativeCharset();
-
   void Reset();
-  void SetDefaultFont(CPDF_Font* pFont, const ByteString& sFontName);
   void SetAPType(const ByteString& sAPType);
+  void SetDefaultFont(const RetainPtr<CPDF_Font>& pFont,
+                      const ByteString& sFontName);
 
  private:
   struct Data {
-    CPDF_Font* pFont;
+    Data();
+    ~Data();
+
+    RetainPtr<CPDF_Font> pFont;
     int32_t nCharset;
     ByteString sFontName;
   };
@@ -50,13 +55,14 @@
   };
 
   void Initialize();
-  CPDF_Font* FindFontSameCharset(ByteString* sFontAlias, int32_t nCharset);
-
-  CPDF_Font* FindResFontSameCharset(const CPDF_Dictionary* pResDict,
-                                    ByteString* sFontAlias,
-                                    int32_t nCharset);
-  CPDF_Font* GetAnnotDefaultFont(ByteString* sAlias);
-  void AddFontToAnnotDict(CPDF_Font* pFont, const ByteString& sAlias);
+  RetainPtr<CPDF_Font> FindFontSameCharset(ByteString* sFontAlias,
+                                           int32_t nCharset);
+  RetainPtr<CPDF_Font> FindResFontSameCharset(const CPDF_Dictionary* pResDict,
+                                              ByteString* sFontAlias,
+                                              int32_t nCharset);
+  RetainPtr<CPDF_Font> GetAnnotDefaultFont(ByteString* sAlias);
+  void AddFontToAnnotDict(const RetainPtr<CPDF_Font>& pFont,
+                          const ByteString& sAlias);
 
   bool KnowWord(int32_t nFontIndex, uint16_t word);
 
@@ -64,7 +70,7 @@
   int32_t GetFontIndex(const ByteString& sFontName,
                        int32_t nCharset,
                        bool bFind);
-  int32_t AddFontData(CPDF_Font* pFont,
+  int32_t AddFontData(const RetainPtr<CPDF_Font>& pFont,
                       const ByteString& sFontAlias,
                       int32_t nCharset);
 
@@ -74,20 +80,21 @@
   int32_t FindFont(const ByteString& sFontName, int32_t nCharset);
   ByteString GetNativeFontName(int32_t nCharset);
   ByteString GetCachedNativeFontName(int32_t nCharset);
-  CPDF_Font* AddFontToDocument(CPDF_Document* pDoc,
-                               ByteString& sFontName,
-                               uint8_t nCharset);
   bool IsStandardFont(const ByteString& sFontName);
-  CPDF_Font* AddStandardFont(CPDF_Document* pDoc, ByteString& sFontName);
-  CPDF_Font* AddSystemFont(CPDF_Document* pDoc,
-                           ByteString& sFontName,
-                           uint8_t nCharset);
+  RetainPtr<CPDF_Font> AddFontToDocument(CPDF_Document* pDoc,
+                                         ByteString& sFontName,
+                                         uint8_t nCharset);
+  RetainPtr<CPDF_Font> AddStandardFont(CPDF_Document* pDoc,
+                                       ByteString& sFontName);
+  RetainPtr<CPDF_Font> AddSystemFont(CPDF_Document* pDoc,
+                                     ByteString& sFontName,
+                                     uint8_t nCharset);
 
   std::vector<std::unique_ptr<Data>> m_Data;
   std::vector<std::unique_ptr<Native>> m_NativeFont;
   UnownedPtr<CPDF_Document> const m_pDocument;
   RetainPtr<CPDF_Dictionary> const m_pAnnotDict;
-  UnownedPtr<CPDF_Font> m_pDefaultFont;
+  RetainPtr<CPDF_Font> m_pDefaultFont;
   ByteString m_sDefaultFontName;
   ByteString m_sAPType = "N";
 };
diff --git a/core/fpdfdoc/cpdf_formcontrol.cpp b/core/fpdfdoc/cpdf_formcontrol.cpp
index d7491e5..5d1efb8 100644
--- a/core/fpdfdoc/cpdf_formcontrol.cpp
+++ b/core/fpdfdoc/cpdf_formcontrol.cpp
@@ -8,6 +8,7 @@
 
 #include <algorithm>
 
+#include "core/fpdfapi/font/cpdf_font.h"
 #include "core/fpdfapi/page/cpdf_docpagedata.h"
 #include "core/fpdfapi/parser/cpdf_array.h"
 #include "core/fpdfapi/parser/cpdf_dictionary.h"
@@ -201,7 +202,7 @@
   return CPDF_DefaultAppearance(pObj->GetString());
 }
 
-CPDF_Font* CPDF_FormControl::GetDefaultControlFont() {
+RetainPtr<CPDF_Font> CPDF_FormControl::GetDefaultControlFont() {
   float fFontSize;
   CPDF_DefaultAppearance cDA = GetDefaultAppearance();
   Optional<ByteString> csFontNameTag = cDA.GetFont(&fFontSize);
@@ -215,30 +216,32 @@
       CPDF_Dictionary* pElement = pFonts->GetDictFor(*csFontNameTag);
       if (pElement) {
         auto* pData = CPDF_DocPageData::FromDocument(m_pForm->GetDocument());
-        CPDF_Font* pFont = pData->GetFont(pElement);
+        RetainPtr<CPDF_Font> pFont = pData->GetFont(pElement);
         if (pFont)
           return pFont;
       }
     }
   }
-  if (CPDF_Font* pFormFont = m_pForm->GetFormFont(*csFontNameTag))
+  RetainPtr<CPDF_Font> pFormFont = m_pForm->GetFormFont(*csFontNameTag);
+  if (pFormFont)
     return pFormFont;
 
   CPDF_Dictionary* pPageDict = m_pWidgetDict->GetDictFor("P");
-  pObj = FPDF_GetFieldAttr(pPageDict, "Resources");
-  if (CPDF_Dictionary* pDict = ToDictionary(pObj)) {
-    CPDF_Dictionary* pFonts = pDict->GetDictFor("Font");
-    if (pFonts) {
-      CPDF_Dictionary* pElement = pFonts->GetDictFor(*csFontNameTag);
-      if (pElement) {
-        auto* pData = CPDF_DocPageData::FromDocument(m_pForm->GetDocument());
-        CPDF_Font* pFont = pData->GetFont(pElement);
-        if (pFont)
-          return pFont;
-      }
-    }
-  }
-  return nullptr;
+  CPDF_Dictionary* pDict =
+      ToDictionary(FPDF_GetFieldAttr(pPageDict, "Resources"));
+  if (!pDict)
+    return nullptr;
+
+  CPDF_Dictionary* pFonts = pDict->GetDictFor("Font");
+  if (!pFonts)
+    return nullptr;
+
+  CPDF_Dictionary* pElement = pFonts->GetDictFor(*csFontNameTag);
+  if (!pElement)
+    return nullptr;
+
+  auto* pDocPageData = CPDF_DocPageData::FromDocument(m_pForm->GetDocument());
+  return pDocPageData->GetFont(pElement);
 }
 
 int CPDF_FormControl::GetControlAlignment() const {
diff --git a/core/fpdfdoc/cpdf_formcontrol.h b/core/fpdfdoc/cpdf_formcontrol.h
index 778e079..18c1f23 100644
--- a/core/fpdfdoc/cpdf_formcontrol.h
+++ b/core/fpdfdoc/cpdf_formcontrol.h
@@ -18,6 +18,7 @@
 #include "core/fpdfdoc/ipdf_formnotify.h"
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_string.h"
+#include "core/fxcrt/retain_ptr.h"
 #include "core/fxge/fx_dib.h"
 
 #define TEXTPOS_CAPTION 0
@@ -98,7 +99,7 @@
   CPDF_AAction GetAdditionalAction() const;
   CPDF_DefaultAppearance GetDefaultAppearance() const;
 
-  CPDF_Font* GetDefaultControlFont();
+  RetainPtr<CPDF_Font> GetDefaultControlFont();
   int GetControlAlignment() const;
 
   ByteString GetOnStateName() const;
diff --git a/core/fpdfdoc/cpdf_formfield.cpp b/core/fpdfdoc/cpdf_formfield.cpp
index b8d01f8..7b1b6ff 100644
--- a/core/fpdfdoc/cpdf_formfield.cpp
+++ b/core/fpdfdoc/cpdf_formfield.cpp
@@ -12,6 +12,7 @@
 
 #include "constants/form_fields.h"
 #include "constants/form_flags.h"
+#include "core/fpdfapi/font/cpdf_font.h"
 #include "core/fpdfapi/page/cpdf_docpagedata.h"
 #include "core/fpdfapi/parser/cfdf_document.h"
 #include "core/fpdfapi/parser/cpdf_array.h"
diff --git a/core/fpdfdoc/cpdf_formfield.h b/core/fpdfdoc/cpdf_formfield.h
index ab81651..a07720f 100644
--- a/core/fpdfdoc/cpdf_formfield.h
+++ b/core/fpdfdoc/cpdf_formfield.h
@@ -14,6 +14,7 @@
 #include "core/fpdfdoc/cpdf_aaction.h"
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/fx_system.h"
+#include "core/fxcrt/retain_ptr.h"
 #include "core/fxcrt/unowned_ptr.h"
 
 class CPDF_Dictionary;
@@ -194,15 +195,14 @@
   const std::vector<UnownedPtr<CPDF_FormControl>>& GetControls() const;
 
   CPDF_FormField::Type m_Type = kUnknown;
-  uint32_t m_Flags = 0;
   bool m_bReadOnly = false;
   bool m_bRequired = false;
   bool m_bNoExport = false;
-
+  uint32_t m_Flags = 0;
+  float m_FontSize = 0;
   UnownedPtr<CPDF_InteractiveForm> const m_pForm;
   RetainPtr<CPDF_Dictionary> const m_pDict;
-  float m_FontSize = 0;
-  UnownedPtr<CPDF_Font> m_pFont;
+  RetainPtr<CPDF_Font> m_pFont;
 };
 
 #endif  // CORE_FPDFDOC_CPDF_FORMFIELD_H_
diff --git a/core/fpdfdoc/cpdf_interactiveform.cpp b/core/fpdfdoc/cpdf_interactiveform.cpp
index 2d9ff05..e810383 100644
--- a/core/fpdfdoc/cpdf_interactiveform.cpp
+++ b/core/fpdfdoc/cpdf_interactiveform.cpp
@@ -36,6 +36,11 @@
 
 const int nMaxRecursion = 32;
 
+void AddFont(CPDF_Dictionary*& pFormDict,
+             CPDF_Document* pDocument,
+             const RetainPtr<CPDF_Font>& pFont,
+             ByteString* csNameTag);
+
 ByteString GenerateNewFontResourceName(const CPDF_Dictionary* pResDict,
                                        const ByteString& csPrefix) {
   static const char kDummyFontName[] = "ZiTi";
@@ -72,11 +77,6 @@
   return csTmp;
 }
 
-void AddFont(CPDF_Dictionary*& pFormDict,
-             CPDF_Document* pDocument,
-             const CPDF_Font* pFont,
-             ByteString* csNameTag);
-
 void InitDict(CPDF_Dictionary*& pFormDict, CPDF_Document* pDocument) {
   if (!pDocument)
     return;
@@ -91,7 +91,7 @@
   if (!pFormDict->KeyExist("DR")) {
     ByteString csBaseName;
     uint8_t charSet = CPDF_InteractiveForm::GetNativeCharSet();
-    CPDF_Font* pFont = CPDF_InteractiveForm::AddStandardFont(
+    RetainPtr<CPDF_Font> pFont = CPDF_InteractiveForm::AddStandardFont(
         pDocument, CFX_Font::kDefaultAnsiFontName);
     if (pFont)
       AddFont(pFormDict, pDocument, pFont, &csBaseName);
@@ -118,9 +118,9 @@
     pFormDict->SetNewFor<CPDF_String>("DA", csDA, false);
 }
 
-CPDF_Font* GetFont(CPDF_Dictionary* pFormDict,
-                   CPDF_Document* pDocument,
-                   const ByteString& csNameTag) {
+RetainPtr<CPDF_Font> GetFont(CPDF_Dictionary* pFormDict,
+                             CPDF_Document* pDocument,
+                             const ByteString& csNameTag) {
   ByteString csAlias = PDF_NameDecode(csNameTag.AsStringView());
   if (!pFormDict || csAlias.IsEmpty())
     return nullptr;
@@ -140,10 +140,10 @@
   return CPDF_DocPageData::FromDocument(pDocument)->GetFont(pElement);
 }
 
-CPDF_Font* GetNativeFont(CPDF_Dictionary* pFormDict,
-                         CPDF_Document* pDocument,
-                         uint8_t charSet,
-                         ByteString* csNameTag) {
+RetainPtr<CPDF_Font> GetNativeFont(CPDF_Dictionary* pFormDict,
+                                   CPDF_Document* pDocument,
+                                   uint8_t charSet,
+                                   ByteString* csNameTag) {
   if (!pFormDict)
     return nullptr;
 
@@ -166,7 +166,7 @@
       continue;
 
     auto* pData = CPDF_DocPageData::FromDocument(pDocument);
-    CPDF_Font* pFind = pData->GetFont(pElement);
+    RetainPtr<CPDF_Font> pFind = pData->GetFont(pElement);
     if (!pFind)
       continue;
 
@@ -217,7 +217,7 @@
 bool FindFont(CPDF_Dictionary* pFormDict,
               CPDF_Document* pDocument,
               ByteString csFontName,
-              CPDF_Font*& pFont,
+              RetainPtr<CPDF_Font>& pFont,
               ByteString* csNameTag) {
   if (!pFormDict)
     return false;
@@ -259,7 +259,7 @@
 
 void AddFont(CPDF_Dictionary*& pFormDict,
              CPDF_Document* pDocument,
-             const CPDF_Font* pFont,
+             const RetainPtr<CPDF_Font>& pFont,
              ByteString* csNameTag) {
   if (!pFont)
     return;
@@ -267,7 +267,7 @@
     InitDict(pFormDict, pDocument);
 
   ByteString csTag;
-  if (FindFont(pFormDict, pFont, &csTag)) {
+  if (FindFont(pFormDict, pFont.Get(), &csTag)) {
     *csNameTag = std::move(csTag);
     return;
   }
@@ -291,15 +291,16 @@
                                     pFont->GetFontDict()->GetObjNum());
 }
 
-CPDF_Font* AddNativeFont(CPDF_Dictionary*& pFormDict,
-                         CPDF_Document* pDocument,
-                         uint8_t charSet,
-                         ByteString* csNameTag) {
+RetainPtr<CPDF_Font> AddNativeFont(CPDF_Dictionary*& pFormDict,
+                                   CPDF_Document* pDocument,
+                                   uint8_t charSet,
+                                   ByteString* csNameTag) {
   if (!pFormDict)
     InitDict(pFormDict, pDocument);
 
   ByteString csTemp;
-  CPDF_Font* pFont = GetNativeFont(pFormDict, pDocument, charSet, &csTemp);
+  RetainPtr<CPDF_Font> pFont =
+      GetNativeFont(pFormDict, pDocument, charSet, &csTemp);
   if (pFont) {
     *csNameTag = std::move(csTemp);
     return pFont;
@@ -311,9 +312,10 @@
     return pFont;
   }
   pFont = CPDF_InteractiveForm::AddNativeFont(charSet, pDocument);
-  if (pFont)
-    AddFont(pFormDict, pDocument, pFont, csNameTag);
+  if (!pFont)
+    return nullptr;
 
+  AddFont(pFormDict, pDocument, pFont, csNameTag);
   return pFont;
 }
 
@@ -570,9 +572,9 @@
   return pNode;
 }
 
-CPDF_Font* AddNativeInteractiveFormFont(CPDF_Dictionary*& pFormDict,
-                                        CPDF_Document* pDocument,
-                                        ByteString* csNameTag) {
+RetainPtr<CPDF_Font> AddNativeInteractiveFormFont(CPDF_Dictionary*& pFormDict,
+                                                  CPDF_Document* pDocument,
+                                                  ByteString* csNameTag) {
   uint8_t charSet = CPDF_InteractiveForm::GetNativeCharSet();
   return AddNativeFont(pFormDict, pDocument, charSet, csNameTag);
 }
@@ -612,8 +614,9 @@
   s_bUpdateAP = bUpdateAP;
 }
 
-CPDF_Font* CPDF_InteractiveForm::AddStandardFont(CPDF_Document* pDocument,
-                                                 ByteString csFontName) {
+RetainPtr<CPDF_Font> CPDF_InteractiveForm::AddStandardFont(
+    CPDF_Document* pDocument,
+    ByteString csFontName) {
   if (!pDocument || csFontName.IsEmpty())
     return nullptr;
 
@@ -664,8 +667,9 @@
   return csFontName;
 }
 
-CPDF_Font* CPDF_InteractiveForm::AddNativeFont(uint8_t charSet,
-                                               CPDF_Document* pDocument) {
+RetainPtr<CPDF_Font> CPDF_InteractiveForm::AddNativeFont(
+    uint8_t charSet,
+    CPDF_Document* pDocument) {
   if (!pDocument)
     return nullptr;
 
@@ -681,7 +685,8 @@
   return nullptr;
 }
 
-CPDF_Font* CPDF_InteractiveForm::AddNativeFont(CPDF_Document* pDocument) {
+RetainPtr<CPDF_Font> CPDF_InteractiveForm::AddNativeFont(
+    CPDF_Document* pDocument) {
   return pDocument ? AddNativeFont(GetNativeCharSet(), pDocument) : nullptr;
 }
 
@@ -789,7 +794,8 @@
   return -1;
 }
 
-CPDF_Font* CPDF_InteractiveForm::GetFormFont(ByteString csNameTag) const {
+RetainPtr<CPDF_Font> CPDF_InteractiveForm::GetFormFont(
+    ByteString csNameTag) const {
   return GetFont(m_pFormDict.Get(), m_pDocument.Get(), csNameTag);
 }
 
diff --git a/core/fpdfdoc/cpdf_interactiveform.h b/core/fpdfdoc/cpdf_interactiveform.h
index 91de032..6d66f83 100644
--- a/core/fpdfdoc/cpdf_interactiveform.h
+++ b/core/fpdfdoc/cpdf_interactiveform.h
@@ -16,6 +16,7 @@
 #include "core/fpdfdoc/cpdf_formfield.h"
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/fx_system.h"
+#include "core/fxcrt/retain_ptr.h"
 #include "core/fxcrt/unowned_ptr.h"
 
 class CFieldTree;
@@ -28,9 +29,9 @@
 class CPDF_Page;
 class IPDF_FormNotify;
 
-CPDF_Font* AddNativeInteractiveFormFont(CPDF_Dictionary*& pFormDict,
-                                        CPDF_Document* pDocument,
-                                        ByteString* csNameTag);
+RetainPtr<CPDF_Font> AddNativeInteractiveFormFont(CPDF_Dictionary*& pFormDict,
+                                                  CPDF_Document* pDocument,
+                                                  ByteString* csNameTag);
 
 class CPDF_InteractiveForm {
  public:
@@ -39,12 +40,13 @@
 
   static void SetUpdateAP(bool bUpdateAP);
   static bool IsUpdateAPEnabled();
-  static CPDF_Font* AddStandardFont(CPDF_Document* pDocument,
-                                    ByteString csFontName);
-  static ByteString GetNativeFontName(uint8_t iCharSet, void* pLogFont);
   static uint8_t GetNativeCharSet();
-  static CPDF_Font* AddNativeFont(uint8_t iCharSet, CPDF_Document* pDocument);
-  static CPDF_Font* AddNativeFont(CPDF_Document* pDocument);
+  static ByteString GetNativeFontName(uint8_t iCharSet, void* pLogFont);
+  static RetainPtr<CPDF_Font> AddStandardFont(CPDF_Document* pDocument,
+                                              ByteString csFontName);
+  static RetainPtr<CPDF_Font> AddNativeFont(uint8_t iCharSet,
+                                            CPDF_Document* pDocument);
+  static RetainPtr<CPDF_Font> AddNativeFont(CPDF_Document* pDocument);
 
   size_t CountFields(const WideString& csFieldName) const;
   CPDF_FormField* GetField(uint32_t index, const WideString& csFieldName) const;
@@ -60,7 +62,7 @@
   CPDF_FormField* GetFieldInCalculationOrder(int index);
   int FindFieldInCalculationOrder(const CPDF_FormField* pField);
 
-  CPDF_Font* GetFormFont(ByteString csNameTag) const;
+  RetainPtr<CPDF_Font> GetFormFont(ByteString csNameTag) const;
   CPDF_DefaultAppearance GetDefaultAppearance() const;
   int GetFormAlignment() const;
 
diff --git a/core/fpdfdoc/cpdf_variabletext.cpp b/core/fpdfdoc/cpdf_variabletext.cpp
index fea7444..4373dd6 100644
--- a/core/fpdfdoc/cpdf_variabletext.cpp
+++ b/core/fpdfdoc/cpdf_variabletext.cpp
@@ -40,34 +40,35 @@
 
 uint32_t CPDF_VariableText::Provider::GetCharWidth(int32_t nFontIndex,
                                                    uint16_t word) {
-  if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex)) {
-    uint32_t charcode = pPDFFont->CharCodeFromUnicode(word);
-    if (charcode != CPDF_Font::kInvalidCharCode)
-      return pPDFFont->GetCharWidthF(charcode);
-  }
-  return 0;
+  RetainPtr<CPDF_Font> pPDFFont = m_pFontMap->GetPDFFont(nFontIndex);
+  if (!pPDFFont)
+    return 0;
+
+  uint32_t charcode = pPDFFont->CharCodeFromUnicode(word);
+  if (charcode == CPDF_Font::kInvalidCharCode)
+    return 0;
+
+  return pPDFFont->GetCharWidthF(charcode);
 }
 
 int32_t CPDF_VariableText::Provider::GetTypeAscent(int32_t nFontIndex) {
-  if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex))
-    return pPDFFont->GetTypeAscent();
-  return 0;
+  RetainPtr<CPDF_Font> pPDFFont = m_pFontMap->GetPDFFont(nFontIndex);
+  return pPDFFont ? pPDFFont->GetTypeAscent() : 0;
 }
 
 int32_t CPDF_VariableText::Provider::GetTypeDescent(int32_t nFontIndex) {
-  if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex))
-    return pPDFFont->GetTypeDescent();
-  return 0;
+  RetainPtr<CPDF_Font> pPDFFont = m_pFontMap->GetPDFFont(nFontIndex);
+  return pPDFFont ? pPDFFont->GetTypeDescent() : 0;
 }
 
 int32_t CPDF_VariableText::Provider::GetWordFontIndex(uint16_t word,
                                                       int32_t charset,
                                                       int32_t nFontIndex) {
-  if (CPDF_Font* pDefFont = m_pFontMap->GetPDFFont(0)) {
+  if (RetainPtr<CPDF_Font> pDefFont = m_pFontMap->GetPDFFont(0)) {
     if (pDefFont->CharCodeFromUnicode(word) != CPDF_Font::kInvalidCharCode)
       return 0;
   }
-  if (CPDF_Font* pSysFont = m_pFontMap->GetPDFFont(1)) {
+  if (RetainPtr<CPDF_Font> pSysFont = m_pFontMap->GetPDFFont(1)) {
     if (pSysFont->CharCodeFromUnicode(word) != CPDF_Font::kInvalidCharCode)
       return 1;
   }
diff --git a/core/fpdfdoc/cpvt_fontmap.cpp b/core/fpdfdoc/cpvt_fontmap.cpp
index 635869a..038a6f4 100644
--- a/core/fpdfdoc/cpvt_fontmap.cpp
+++ b/core/fpdfdoc/cpvt_fontmap.cpp
@@ -16,7 +16,7 @@
 
 CPVT_FontMap::CPVT_FontMap(CPDF_Document* pDoc,
                            CPDF_Dictionary* pResDict,
-                           CPDF_Font* pDefFont,
+                           const RetainPtr<CPDF_Font>& pDefFont,
                            const ByteString& sDefFontAlias)
     : m_pDocument(pDoc),
       m_pResDict(pResDict),
@@ -26,14 +26,15 @@
 CPVT_FontMap::~CPVT_FontMap() {}
 
 // static
-CPDF_Font* CPVT_FontMap::GetAnnotSysPDFFont(CPDF_Document* pDoc,
-                                            CPDF_Dictionary* pResDict,
-                                            ByteString* sSysFontAlias) {
+RetainPtr<CPDF_Font> CPVT_FontMap::GetAnnotSysPDFFont(
+    CPDF_Document* pDoc,
+    CPDF_Dictionary* pResDict,
+    ByteString* sSysFontAlias) {
   if (!pDoc || !pResDict)
     return nullptr;
 
   CPDF_Dictionary* pFormDict = pDoc->GetRoot()->GetDictFor("AcroForm");
-  CPDF_Font* pPDFFont =
+  RetainPtr<CPDF_Font> pPDFFont =
       AddNativeInteractiveFormFont(pFormDict, pDoc, sSysFontAlias);
   if (!pPDFFont)
     return nullptr;
@@ -46,16 +47,16 @@
   return pPDFFont;
 }
 
-CPDF_Font* CPVT_FontMap::GetPDFFont(int32_t nFontIndex) {
+RetainPtr<CPDF_Font> CPVT_FontMap::GetPDFFont(int32_t nFontIndex) {
   switch (nFontIndex) {
     case 0:
-      return m_pDefFont.Get();
+      return m_pDefFont;
     case 1:
       if (!m_pSysFont) {
         m_pSysFont = GetAnnotSysPDFFont(m_pDocument.Get(), m_pResDict.Get(),
                                         &m_sSysFontAlias);
       }
-      return m_pSysFont.Get();
+      return m_pSysFont;
     default:
       return nullptr;
   }
diff --git a/core/fpdfdoc/cpvt_fontmap.h b/core/fpdfdoc/cpvt_fontmap.h
index cce03bf..a85afcf 100644
--- a/core/fpdfdoc/cpvt_fontmap.h
+++ b/core/fpdfdoc/cpvt_fontmap.h
@@ -11,6 +11,7 @@
 
 #include "core/fpdfdoc/ipvt_fontmap.h"
 #include "core/fxcrt/fx_string.h"
+#include "core/fxcrt/retain_ptr.h"
 #include "core/fxcrt/unowned_ptr.h"
 
 class CPDF_Document;
@@ -21,12 +22,12 @@
  public:
   CPVT_FontMap(CPDF_Document* pDoc,
                CPDF_Dictionary* pResDict,
-               CPDF_Font* pDefFont,
+               const RetainPtr<CPDF_Font>& pDefFont,
                const ByteString& sDefFontAlias);
   ~CPVT_FontMap() override;
 
   // IPVT_FontMap:
-  CPDF_Font* GetPDFFont(int32_t nFontIndex) override;
+  RetainPtr<CPDF_Font> GetPDFFont(int32_t nFontIndex) override;
   ByteString GetPDFFontAlias(int32_t nFontIndex) override;
   int32_t GetWordFontIndex(uint16_t word,
                            int32_t charset,
@@ -34,15 +35,15 @@
   int32_t CharCodeFromUnicode(int32_t nFontIndex, uint16_t word) override;
   int32_t CharSetFromUnicode(uint16_t word, int32_t nOldCharset) override;
 
-  static CPDF_Font* GetAnnotSysPDFFont(CPDF_Document* pDoc,
-                                       CPDF_Dictionary* pResDict,
-                                       ByteString* sSysFontAlias);
+  static RetainPtr<CPDF_Font> GetAnnotSysPDFFont(CPDF_Document* pDoc,
+                                                 CPDF_Dictionary* pResDict,
+                                                 ByteString* sSysFontAlias);
 
  private:
   UnownedPtr<CPDF_Document> const m_pDocument;
   RetainPtr<CPDF_Dictionary> const m_pResDict;
-  UnownedPtr<CPDF_Font> const m_pDefFont;
-  UnownedPtr<CPDF_Font> m_pSysFont;
+  RetainPtr<CPDF_Font> const m_pDefFont;
+  RetainPtr<CPDF_Font> m_pSysFont;
   const ByteString m_sDefFontAlias;
   ByteString m_sSysFontAlias;
 };
diff --git a/core/fpdfdoc/cpvt_generateap.cpp b/core/fpdfdoc/cpvt_generateap.cpp
index 3a9a16d..4bd50db 100644
--- a/core/fpdfdoc/cpvt_generateap.cpp
+++ b/core/fpdfdoc/cpvt_generateap.cpp
@@ -59,7 +59,7 @@
   if (!pFontMap)
     return ByteString();
 
-  CPDF_Font* pPDFFont = pFontMap->GetPDFFont(nFontIndex);
+  RetainPtr<CPDF_Font> pPDFFont = pFontMap->GetPDFFont(nFontIndex);
   if (!pPDFFont)
     return ByteString();
 
@@ -72,6 +72,7 @@
   uint32_t dwCharCode = pPDFFont->CharCodeFromUnicode(Word);
   if (dwCharCode != CPDF_Font::kInvalidCharCode)
     pPDFFont->AppendChar(&sWord, dwCharCode);
+
   return sWord;
 }
 
@@ -367,7 +368,7 @@
 
 ByteString GetPopupContentsString(CPDF_Document* pDoc,
                                   const CPDF_Dictionary& pAnnotDict,
-                                  CPDF_Font* pDefFont,
+                                  const RetainPtr<CPDF_Font>& pDefFont,
                                   const ByteString& sFontName) {
   WideString swValue(pAnnotDict.GetUnicodeTextFor(pdfium::form_fields::kT));
   swValue += L'\n';
@@ -761,16 +762,18 @@
              << rect.Height() << " re b\n";
 
   ByteString sFontName = "FONT";
-  auto pResourceFontDict = GenerateResourceFontDict(pDoc, sFontName);
+  RetainPtr<CPDF_Dictionary> pResourceFontDict =
+      GenerateResourceFontDict(pDoc, sFontName);
+
   auto* pData = CPDF_DocPageData::FromDocument(pDoc);
-  CPDF_Font* pDefFont = pData->GetFont(pResourceFontDict.Get());
+  RetainPtr<CPDF_Font> pDefFont = pData->GetFont(pResourceFontDict.Get());
   if (!pDefFont)
     return false;
 
-  auto pExtGStateDict =
+  RetainPtr<CPDF_Dictionary> pExtGStateDict =
       GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal");
-  auto pResourceDict = GenerateResourceDict(pDoc, std::move(pExtGStateDict),
-                                            std::move(pResourceFontDict));
+  RetainPtr<CPDF_Dictionary> pResourceDict = GenerateResourceDict(
+      pDoc, std::move(pExtGStateDict), std::move(pResourceFontDict));
 
   sAppStream << GetPopupContentsString(pDoc, *pAnnotDict, pDefFont, sFontName);
   GenerateAndSetAPDict(pDoc, pAnnotDict, &sAppStream, std::move(pResourceDict),
@@ -956,14 +959,13 @@
                                            pFontDict->GetObjNum());
   }
   auto* pData = CPDF_DocPageData::FromDocument(pDoc);
-  CPDF_Font* pDefFont = pData->GetFont(pFontDict);
+  RetainPtr<CPDF_Font> pDefFont = pData->GetFont(pFontDict);
   if (!pDefFont)
     return;
 
   CFX_FloatRect rcAnnot = pAnnotDict->GetRectFor(pdfium::annotation::kRect);
-  int32_t nRotate = 0;
-  if (CPDF_Dictionary* pMKDict = pAnnotDict->GetDictFor("MK"))
-    nRotate = pMKDict->GetIntegerFor("R");
+  CPDF_Dictionary* pMKDict = pAnnotDict->GetDictFor("MK");
+  int32_t nRotate = pMKDict ? pMKDict->GetIntegerFor("R") : 0;
 
   CFX_FloatRect rcBBox;
   CFX_Matrix matrix;
@@ -1031,7 +1033,7 @@
   }
   CFX_Color crBorder;
   CFX_Color crBG;
-  if (CPDF_Dictionary* pMKDict = pAnnotDict->GetDictFor("MK")) {
+  if (pMKDict) {
     if (CPDF_Array* pArray = pMKDict->GetArrayFor("BC"))
       crBorder = fpdfdoc::CFXColorFromArray(*pArray);
     if (CPDF_Array* pArray = pMKDict->GetArrayFor("BG"))
diff --git a/core/fpdfdoc/ipvt_fontmap.h b/core/fpdfdoc/ipvt_fontmap.h
index a27c0ac..e818356 100644
--- a/core/fpdfdoc/ipvt_fontmap.h
+++ b/core/fpdfdoc/ipvt_fontmap.h
@@ -10,6 +10,7 @@
 #include <stdint.h>
 
 #include "core/fxcrt/fx_string.h"
+#include "core/fxcrt/retain_ptr.h"
 
 class CPDF_Font;
 
@@ -17,7 +18,7 @@
  public:
   virtual ~IPVT_FontMap() = default;
 
-  virtual CPDF_Font* GetPDFFont(int32_t nFontIndex) = 0;
+  virtual RetainPtr<CPDF_Font> GetPDFFont(int32_t nFontIndex) = 0;
   virtual ByteString GetPDFFontAlias(int32_t nFontIndex) = 0;
   virtual int32_t GetWordFontIndex(uint16_t word,
                                    int32_t charset,
diff --git a/core/fpdftext/cpdf_textpage.cpp b/core/fpdftext/cpdf_textpage.cpp
index 1ba470f..4c99247 100644
--- a/core/fpdftext/cpdf_textpage.cpp
+++ b/core/fpdftext/cpdf_textpage.cpp
@@ -771,14 +771,14 @@
   CPDF_TextObjectItem item;
   prev_Obj.m_pTextObj->GetItemInfo(nItem - 1, &item);
   float prev_width =
-      GetCharWidth(item.m_CharCode, prev_Obj.m_pTextObj->GetFont()) *
+      GetCharWidth(item.m_CharCode, prev_Obj.m_pTextObj->GetFont().Get()) *
       prev_Obj.m_pTextObj->GetFontSize() / 1000;
 
   CFX_Matrix prev_matrix =
       prev_Obj.m_pTextObj->GetTextMatrix() * prev_Obj.m_formMatrix;
   prev_width = prev_matrix.TransformDistance(fabs(prev_width));
   pTextObj->GetItemInfo(0, &item);
-  float this_width = GetCharWidth(item.m_CharCode, pTextObj->GetFont()) *
+  float this_width = GetCharWidth(item.m_CharCode, pTextObj->GetFont().Get()) *
                      pTextObj->GetFontSize() / 1000;
   this_width = fabs(this_width);
 
@@ -845,7 +845,7 @@
   if (actText.IsEmpty())
     return FPDFText_MarkedContent::Pass;
 
-  CPDF_Font* pFont = pTextObj->GetFont();
+  RetainPtr<CPDF_Font> pFont = pTextObj->GetFont();
   bExist = false;
   for (size_t i = 0; i < actText.GetLength(); ++i) {
     if (pFont->CharCodeFromUnicode(actText[i]) != CPDF_Font::kInvalidCharCode) {
@@ -887,7 +887,7 @@
   if (actText.IsEmpty())
     return;
 
-  CPDF_Font* pFont = pTextObj->GetFont();
+  RetainPtr<CPDF_Font> pFont = pTextObj->GetFont();
   CFX_Matrix matrix = pTextObj->GetTextMatrix() * Obj.m_formMatrix;
 
   for (size_t k = 0; k < actText.GetLength(); ++k) {
@@ -939,10 +939,10 @@
   CPDF_TextObject* pTextObj = Obj.m_pTextObj.Get();
   if (fabs(pTextObj->GetRect().Width()) < kSizeEpsilon)
     return;
-  CFX_Matrix formMatrix = Obj.m_formMatrix;
-  CPDF_Font* pFont = pTextObj->GetFont();
-  CFX_Matrix matrix = pTextObj->GetTextMatrix() * formMatrix;
 
+  CFX_Matrix formMatrix = Obj.m_formMatrix;
+  RetainPtr<CPDF_Font> pFont = pTextObj->GetFont();
+  CFX_Matrix matrix = pTextObj->GetTextMatrix() * formMatrix;
   FPDFText_MarkedContent ePreMKC = PreMarkedContent(Obj);
   if (ePreMKC == FPDFText_MarkedContent::Done) {
     m_pPreTextObj = pTextObj;
@@ -1058,7 +1058,8 @@
       else
         threshold /= 2;
       if (threshold == 0) {
-        threshold = static_cast<float>(GetCharWidth(item.m_CharCode, pFont));
+        threshold =
+            static_cast<float>(GetCharWidth(item.m_CharCode, pFont.Get()));
         threshold = NormalizeThreshold(threshold, 300, 500, 700);
         threshold = fontsize_h * threshold / 1000;
       }
@@ -1259,10 +1260,10 @@
 
   float last_pos = PrevItem.m_Origin.x;
   uint32_t nLastWidth =
-      GetCharWidth(PrevItem.m_CharCode, m_pPreTextObj->GetFont());
+      GetCharWidth(PrevItem.m_CharCode, m_pPreTextObj->GetFont().Get());
   float last_width = nLastWidth * m_pPreTextObj->GetFontSize() / 1000;
   last_width = fabs(last_width);
-  uint32_t nThisWidth = GetCharWidth(item.m_CharCode, pObj->GetFont());
+  uint32_t nThisWidth = GetCharWidth(item.m_CharCode, pObj->GetFont().Get());
   float this_width = fabs(nThisWidth * pObj->GetFontSize() / 1000);
   float threshold = std::max(last_width, this_width) / 4;
 
@@ -1389,7 +1390,8 @@
 
   CFX_PointF diff = pTextObj1->GetPos() - pTextObj2->GetPos();
   float font_size = pTextObj2->GetFontSize();
-  float char_size = GetCharWidth(itemPer.m_CharCode, pTextObj2->GetFont());
+  float char_size =
+      GetCharWidth(itemPer.m_CharCode, pTextObj2->GetFont().Get());
   float max_pre_size =
       std::max(std::max(rcPreObj.Height(), rcPreObj.Width()), font_size);
   return fabs(diff.x) <= 0.9 * char_size * font_size / 1000 &&
@@ -1427,7 +1429,7 @@
   int preWidth = 0;
   if (pPrevCharInfo->m_pTextObj && pPrevCharInfo->m_CharCode != -1) {
     preWidth = GetCharWidth(pPrevCharInfo->m_CharCode,
-                            pPrevCharInfo->m_pTextObj->GetFont());
+                            pPrevCharInfo->m_pTextObj->GetFont().Get());
   }
 
   float fFontSize = pPrevCharInfo->m_pTextObj
diff --git a/fpdfsdk/fpdf_edit_embeddertest.cpp b/fpdfsdk/fpdf_edit_embeddertest.cpp
index f3af839..a8c33c7 100644
--- a/fpdfsdk/fpdf_edit_embeddertest.cpp
+++ b/fpdfsdk/fpdf_edit_embeddertest.cpp
@@ -2087,12 +2087,12 @@
   ScopedFPDFPage page(FPDFPage_New(CreateNewDocument(), 0, 612, 792));
 
   // Load a standard font.
-  FPDF_FONT font = FPDFText_LoadStandardFont(document(), "Helvetica");
+  ScopedFPDFFont font(FPDFText_LoadStandardFont(document(), "Helvetica"));
   ASSERT_TRUE(font);
 
   // Add some text to the page.
   FPDF_PAGEOBJECT text_object =
-      FPDFPageObj_CreateTextObj(document(), font, 12.0f);
+      FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
   EXPECT_TRUE(text_object);
   ScopedFPDFWideString text =
       GetFPDFWideString(L"I'm at the bottom of the page");
@@ -2136,7 +2136,7 @@
       "TimesNewRoman-Italic",
       "ZapfDingbats"};
   for (const char* font_name : kStandardFontNames) {
-    FPDF_FONT font = FPDFText_LoadStandardFont(document(), font_name);
+    ScopedFPDFFont font(FPDFText_LoadStandardFont(document(), font_name));
     EXPECT_TRUE(font) << font_name << " should be considered a standard font.";
   }
   static constexpr const char* kNotStandardFontNames[] = {
@@ -2145,7 +2145,7 @@
       "TestFontName", "Quack",     "Symbol-Italic",
       "Zapf"};
   for (const char* font_name : kNotStandardFontNames) {
-    FPDF_FONT font = FPDFText_LoadStandardFont(document(), font_name);
+    ScopedFPDFFont font(FPDFText_LoadStandardFont(document(), font_name));
     EXPECT_FALSE(font) << font_name
                        << " should not be considered a standard font.";
   }
@@ -2271,7 +2271,7 @@
 TEST_F(FPDFEditEmbedderTest, LoadSimpleType1Font) {
   CreateNewDocument();
   // TODO(npm): use other fonts after disallowing loading any font as any type
-  const CPDF_Font* stock_font =
+  RetainPtr<CPDF_Font> stock_font =
       CPDF_Font::GetStockFont(cpdf_doc(), "Times-Bold");
   pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
   ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
@@ -2300,7 +2300,8 @@
 
 TEST_F(FPDFEditEmbedderTest, LoadSimpleTrueTypeFont) {
   CreateNewDocument();
-  const CPDF_Font* stock_font = CPDF_Font::GetStockFont(cpdf_doc(), "Courier");
+  RetainPtr<CPDF_Font> stock_font =
+      CPDF_Font::GetStockFont(cpdf_doc(), "Courier");
   pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
   ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
                                         FPDF_FONT_TRUETYPE, false));
@@ -2328,7 +2329,7 @@
 
 TEST_F(FPDFEditEmbedderTest, LoadCIDType0Font) {
   CreateNewDocument();
-  const CPDF_Font* stock_font =
+  RetainPtr<CPDF_Font> stock_font =
       CPDF_Font::GetStockFont(cpdf_doc(), "Times-Roman");
   pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
   ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
@@ -2377,7 +2378,7 @@
 
 TEST_F(FPDFEditEmbedderTest, LoadCIDType2Font) {
   CreateNewDocument();
-  const CPDF_Font* stock_font =
+  RetainPtr<CPDF_Font> stock_font =
       CPDF_Font::GetStockFont(cpdf_doc(), "Helvetica-Oblique");
   pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
   ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
@@ -2430,7 +2431,8 @@
   // Start with a blank page
   FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
   {
-    const CPDF_Font* stock_font = CPDF_Font::GetStockFont(cpdf_doc(), "Arial");
+    RetainPtr<CPDF_Font> stock_font =
+        CPDF_Font::GetStockFont(cpdf_doc(), "Arial");
     pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
     ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
                                           FPDF_FONT_TRUETYPE, 0));
@@ -2740,7 +2742,8 @@
   // Start with a blank page.
   FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
 
-  const CPDF_Font* stock_font = CPDF_Font::GetStockFont(cpdf_doc(), "Arial");
+  RetainPtr<CPDF_Font> stock_font =
+      CPDF_Font::GetStockFont(cpdf_doc(), "Arial");
   pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
   ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
                                         FPDF_FONT_TRUETYPE, 0));
diff --git a/fpdfsdk/fpdf_edittext.cpp b/fpdfsdk/fpdf_edittext.cpp
index ce4c414..1cc703c 100644
--- a/fpdfsdk/fpdf_edittext.cpp
+++ b/fpdfsdk/fpdf_edittext.cpp
@@ -261,10 +261,10 @@
   return stream;
 }
 
-CPDF_Font* LoadSimpleFont(CPDF_Document* pDoc,
-                          std::unique_ptr<CFX_Font> pFont,
-                          pdfium::span<const uint8_t> span,
-                          int font_type) {
+RetainPtr<CPDF_Font> LoadSimpleFont(CPDF_Document* pDoc,
+                                    std::unique_ptr<CFX_Font> pFont,
+                                    pdfium::span<const uint8_t> span,
+                                    int font_type) {
   CPDF_Dictionary* pFontDict = pDoc->NewIndirect<CPDF_Dictionary>();
   pFontDict->SetNewFor<CPDF_Name>("Type", "Font");
   pFontDict->SetNewFor<CPDF_Name>(
@@ -309,10 +309,10 @@
   return CPDF_DocPageData::FromDocument(pDoc)->GetFont(pFontDict);
 }
 
-CPDF_Font* LoadCompositeFont(CPDF_Document* pDoc,
-                             std::unique_ptr<CFX_Font> pFont,
-                             pdfium::span<const uint8_t> span,
-                             int font_type) {
+RetainPtr<CPDF_Font> LoadCompositeFont(CPDF_Document* pDoc,
+                                       std::unique_ptr<CFX_Font> pFont,
+                                       pdfium::span<const uint8_t> span,
+                                       int font_type) {
   CPDF_Dictionary* pFontDict = pDoc->NewIndirect<CPDF_Dictionary>();
   pFontDict->SetNewFor<CPDF_Name>("Type", "Font");
   pFontDict->SetNewFor<CPDF_Name>("Subtype", "Type0");
@@ -444,7 +444,8 @@
   if (!pDoc)
     return nullptr;
 
-  CPDF_Font* pFont = CPDF_Font::GetStockFont(pDoc, ByteStringView(font));
+  RetainPtr<CPDF_Font> pFont =
+      CPDF_Font::GetStockFont(pDoc, ByteStringView(font));
   if (!pFont)
     return nullptr;
 
@@ -493,9 +494,10 @@
   if (!pFont->LoadEmbedded(span))
     return nullptr;
 
+  // Caller takes ownership.
   return FPDFFontFromCPDFFont(
-      cid ? LoadCompositeFont(pDoc, std::move(pFont), span, font_type)
-          : LoadSimpleFont(pDoc, std::move(pFont), span, font_type));
+      cid ? LoadCompositeFont(pDoc, std::move(pFont), span, font_type).Leak()
+          : LoadSimpleFont(pDoc, std::move(pFont), span, font_type).Leak());
 }
 
 FPDF_EXPORT FPDF_FONT FPDF_CALLCONV
@@ -504,8 +506,9 @@
   if (!pDoc)
     return nullptr;
 
+  // Caller takes ownership.
   return FPDFFontFromCPDFFont(
-      CPDF_Font::GetStockFont(pDoc, ByteStringView(font)));
+      CPDF_Font::GetStockFont(pDoc, ByteStringView(font)).Leak());
 }
 
 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetMatrix(FPDF_PAGEOBJECT text,
@@ -539,17 +542,16 @@
   if (!pTextObj)
     return 0;
 
-  CPDF_Font* pPdfFont = pTextObj->GetFont();
+  RetainPtr<CPDF_Font> pPdfFont = pTextObj->GetFont();
   if (!pPdfFont)
     return 0;
 
   CFX_Font* pFont = pPdfFont->GetFont();
-  ASSERT(pFont);
-
   ByteString name = pFont->GetFamilyName();
   unsigned long dwStringLen = name.GetLength() + 1;
   if (buffer && length >= dwStringLen)
     memcpy(buffer, name.c_str(), dwStringLen);
+
   return dwStringLen;
 }
 
@@ -571,17 +573,8 @@
 }
 
 FPDF_EXPORT void FPDF_CALLCONV FPDFFont_Close(FPDF_FONT font) {
-  CPDF_Font* pFont = CPDFFontFromFPDFFont(font);
-  if (!pFont)
-    return;
-
-  CPDF_Document* pDoc = pFont->GetDocument();
-  if (!pDoc)
-    return;
-
-  auto* pPageData = CPDF_DocPageData::FromDocument(pDoc);
-  if (!pPageData->IsForceClear())
-    pPageData->ReleaseFont(pFont->GetFontDict());
+  // Take back ownership from caller and release.
+  RetainPtr<CPDF_Font>().Unleak(CPDFFontFromFPDFFont(font));
 }
 
 FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV
diff --git a/fpdfsdk/fpdf_text.cpp b/fpdfsdk/fpdf_text.cpp
index 2421ea2..21aec91 100644
--- a/fpdfsdk/fpdf_text.cpp
+++ b/fpdfsdk/fpdf_text.cpp
@@ -108,16 +108,18 @@
   if (!charinfo.m_pTextObj)
     return 0;
 
-  CPDF_Font* font = charinfo.m_pTextObj->GetFont();
+  RetainPtr<CPDF_Font> font = charinfo.m_pTextObj->GetFont();
   if (!font)
     return 0;
 
   if (flags)
     *flags = font->GetFontFlags();
+
   ByteString basefont = font->GetBaseFont();
   unsigned long length = basefont.GetLength() + 1;
   if (buffer && buflen >= length)
     memcpy(buffer, basefont.c_str(), length);
+
   return length;
 }
 
diff --git a/fpdfsdk/pwl/cpwl_appstream.cpp b/fpdfsdk/pwl/cpwl_appstream.cpp
index 261b274..eeac642 100644
--- a/fpdfsdk/pwl/cpwl_appstream.cpp
+++ b/fpdfsdk/pwl/cpwl_appstream.cpp
@@ -9,6 +9,7 @@
 #include <utility>
 
 #include "constants/form_flags.h"
+#include "core/fpdfapi/font/cpdf_font.h"
 #include "core/fpdfapi/parser/cpdf_dictionary.h"
 #include "core/fpdfapi/parser/cpdf_document.h"
 #include "core/fpdfapi/parser/cpdf_name.h"
@@ -1776,10 +1777,9 @@
   if (nMaxLen > 0) {
     if (bCharArray) {
       pEdit->SetCharArray(nMaxLen);
-
       if (IsFloatZero(fFontSize)) {
-        fFontSize = CPWL_Edit::GetCharArrayAutoFontSize(font_map.GetPDFFont(0),
-                                                        rcClient, nMaxLen);
+        fFontSize = CPWL_Edit::GetCharArrayAutoFontSize(
+            font_map.GetPDFFont(0).Get(), rcClient, nMaxLen);
       }
     } else {
       if (sValue.has_value())
diff --git a/fpdfsdk/pwl/cpwl_edit.cpp b/fpdfsdk/pwl/cpwl_edit.cpp
index 6f52971..1aab8ef 100644
--- a/fpdfsdk/pwl/cpwl_edit.cpp
+++ b/fpdfsdk/pwl/cpwl_edit.cpp
@@ -392,7 +392,7 @@
   if (!pFontMap)
     return;
 
-  float fFontSize = GetCharArrayAutoFontSize(pFontMap->GetPDFFont(0),
+  float fFontSize = GetCharArrayAutoFontSize(pFontMap->GetPDFFont(0).Get(),
                                              GetClientRect(), nCharArray);
   if (fFontSize <= 0.0f)
     return;
diff --git a/fpdfsdk/pwl/cpwl_edit_impl.cpp b/fpdfsdk/pwl/cpwl_edit_impl.cpp
index 613cda9..80e1367 100644
--- a/fpdfsdk/pwl/cpwl_edit_impl.cpp
+++ b/fpdfsdk/pwl/cpwl_edit_impl.cpp
@@ -112,33 +112,28 @@
 
 uint32_t CPWL_EditImpl_Provider::GetCharWidth(int32_t nFontIndex,
                                               uint16_t word) {
-  if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex)) {
-    uint32_t charcode = word;
+  RetainPtr<CPDF_Font> pPDFFont = m_pFontMap->GetPDFFont(nFontIndex);
+  if (!pPDFFont)
+    return 0;
 
-    if (pPDFFont->IsUnicodeCompatible())
-      charcode = pPDFFont->CharCodeFromUnicode(word);
-    else
-      charcode = m_pFontMap->CharCodeFromUnicode(nFontIndex, word);
+  uint32_t charcode = pPDFFont->IsUnicodeCompatible()
+                          ? pPDFFont->CharCodeFromUnicode(word)
+                          : m_pFontMap->CharCodeFromUnicode(nFontIndex, word);
 
-    if (charcode != CPDF_Font::kInvalidCharCode)
-      return pPDFFont->GetCharWidthF(charcode);
-  }
+  if (charcode == CPDF_Font::kInvalidCharCode)
+    return 0;
 
-  return 0;
+  return pPDFFont->GetCharWidthF(charcode);
 }
 
 int32_t CPWL_EditImpl_Provider::GetTypeAscent(int32_t nFontIndex) {
-  if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex))
-    return pPDFFont->GetTypeAscent();
-
-  return 0;
+  RetainPtr<CPDF_Font> pPDFFont = m_pFontMap->GetPDFFont(nFontIndex);
+  return pPDFFont ? pPDFFont->GetTypeAscent() : 0;
 }
 
 int32_t CPWL_EditImpl_Provider::GetTypeDescent(int32_t nFontIndex) {
-  if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex))
-    return pPDFFont->GetTypeDescent();
-
-  return 0;
+  RetainPtr<CPDF_Font> pPDFFont = m_pFontMap->GetPDFFont(nFontIndex);
+  return pPDFFont ? pPDFFont->GetTypeDescent() : 0;
 }
 
 int32_t CPWL_EditImpl_Provider::GetWordFontIndex(uint16_t word,
@@ -536,7 +531,7 @@
           if (sTextBuf.tellp() > 0) {
             DrawTextString(pDevice,
                            CFX_PointF(ptBT.x + ptOffset.x, ptBT.y + ptOffset.y),
-                           pFontMap->GetPDFFont(nFontIndex), fFontSize,
+                           pFontMap->GetPDFFont(nFontIndex).Get(), fFontSize,
                            mtUser2Device, ByteString(sTextBuf), crOldFill);
 
             sTextBuf.str("");
@@ -552,7 +547,8 @@
         DrawTextString(
             pDevice,
             CFX_PointF(word.ptWord.x + ptOffset.x, word.ptWord.y + ptOffset.y),
-            pFontMap->GetPDFFont(word.nFontIndex), fFontSize, mtUser2Device,
+            pFontMap->GetPDFFont(word.nFontIndex).Get(), fFontSize,
+            mtUser2Device,
             pEdit->GetPDFWordString(word.nFontIndex, word.Word, SubWord),
             crCurFill);
       }
@@ -563,8 +559,8 @@
   if (sTextBuf.tellp() > 0) {
     DrawTextString(pDevice,
                    CFX_PointF(ptBT.x + ptOffset.x, ptBT.y + ptOffset.y),
-                   pFontMap->GetPDFFont(nFontIndex), fFontSize, mtUser2Device,
-                   ByteString(sTextBuf), crOldFill);
+                   pFontMap->GetPDFFont(nFontIndex).Get(), fFontSize,
+                   mtUser2Device, ByteString(sTextBuf), crOldFill);
   }
 }
 
@@ -1878,7 +1874,7 @@
                                            uint16_t Word,
                                            uint16_t SubWord) {
   IPVT_FontMap* pFontMap = GetFontMap();
-  CPDF_Font* pPDFFont = pFontMap->GetPDFFont(nFontIndex);
+  RetainPtr<CPDF_Font> pPDFFont = pFontMap->GetPDFFont(nFontIndex);
   if (!pPDFFont)
     return ByteString();
 
diff --git a/fxjs/cjs_document.cpp b/fxjs/cjs_document.cpp
index a9a9368..34b5e2a 100644
--- a/fxjs/cjs_document.cpp
+++ b/fxjs/cjs_document.cpp
@@ -34,7 +34,7 @@
 #define ISLATINWORD(u) (u != 0x20 && u <= 0x28FF)
 
 int CountWords(const CPDF_TextObject* pTextObj) {
-  CPDF_Font* pFont = pTextObj->GetFont();
+  RetainPtr<CPDF_Font> pFont = pTextObj->GetFont();
   if (!pFont)
     return 0;
 
@@ -64,7 +64,7 @@
 }
 
 WideString GetObjWordStr(const CPDF_TextObject* pTextObj, int nWordIndex) {
-  CPDF_Font* pFont = pTextObj->GetFont();
+  RetainPtr<CPDF_Font> pFont = pTextObj->GetFont();
   if (!pFont)
     return WideString();
 
diff --git a/fxjs/cjs_field.cpp b/fxjs/cjs_field.cpp
index dd3dd02..4399d30 100644
--- a/fxjs/cjs_field.cpp
+++ b/fxjs/cjs_field.cpp
@@ -1984,7 +1984,7 @@
     return CJS_Result::Failure(JSMessage::kObjectTypeError);
   }
 
-  CPDF_Font* pFont = pFormControl->GetDefaultControlFont();
+  RetainPtr<CPDF_Font> pFont = pFormControl->GetDefaultControlFont();
   if (!pFont)
     return CJS_Result::Failure(JSMessage::kBadObjectError);
 
diff --git a/public/fpdf_edit.h b/public/fpdf_edit.h
index b6df866..5596c55 100644
--- a/public/fpdf_edit.h
+++ b/public/fpdf_edit.h
@@ -1110,8 +1110,7 @@
 // document   - handle to the document.
 // font       - string containing the font name, without spaces.
 //
-// The loaded font should NOT be closed using FPDFFont_Close. It will be
-// unloaded during the document's destruction.
+// The loaded font can be closed using FPDFFont_Close.
 //
 // Returns NULL on failure.
 FPDF_EXPORT FPDF_FONT FPDF_CALLCONV
diff --git a/xfa/fgas/font/cfgas_gefont.cpp b/xfa/fgas/font/cfgas_gefont.cpp
index 23c0662..6ef72b9 100644
--- a/xfa/fgas/font/cfgas_gefont.cpp
+++ b/xfa/fgas/font/cfgas_gefont.cpp
@@ -37,11 +37,13 @@
 }
 
 // static
-RetainPtr<CFGAS_GEFont> CFGAS_GEFont::LoadFont(CPDF_Font* pPDFFont,
-                                               CFGAS_FontMgr* pFontMgr) {
+RetainPtr<CFGAS_GEFont> CFGAS_GEFont::LoadFont(
+    const RetainPtr<CPDF_Font>& pPDFFont,
+    CFGAS_FontMgr* pFontMgr) {
   auto pFont = pdfium::MakeRetain<CFGAS_GEFont>(pFontMgr);
-  if (!pFont->LoadFontInternal(pPDFFont->GetFont()))
+  if (!pFont->LoadFontInternal(pPDFFont))
     return nullptr;
+
   return pFont;
 }
 
@@ -85,12 +87,17 @@
 }
 #endif  // defined(OS_WIN)
 
-bool CFGAS_GEFont::LoadFontInternal(CFX_Font* pExternalFont) {
+bool CFGAS_GEFont::LoadFontInternal(const RetainPtr<CPDF_Font>& pPDFFont) {
+  CFX_Font* pExternalFont = pPDFFont->GetFont();
   if (m_pFont || !pExternalFont)
     return false;
 
   m_pFont = pExternalFont;
-  return InitFont();
+  if (!InitFont())
+    return false;
+
+  m_pPDFFont = pPDFFont;  // Keep pPDFFont alive for the duration.
+  return true;
 }
 
 bool CFGAS_GEFont::LoadFontInternal(std::unique_ptr<CFX_Font> pInternalFont) {
diff --git a/xfa/fgas/font/cfgas_gefont.h b/xfa/fgas/font/cfgas_gefont.h
index 30c4395..b7988db 100644
--- a/xfa/fgas/font/cfgas_gefont.h
+++ b/xfa/fgas/font/cfgas_gefont.h
@@ -33,7 +33,7 @@
                                           uint32_t dwFontStyles,
                                           uint16_t wCodePage,
                                           CFGAS_FontMgr* pFontMgr);
-  static RetainPtr<CFGAS_GEFont> LoadFont(CPDF_Font* pPDFFont,
+  static RetainPtr<CFGAS_GEFont> LoadFont(const RetainPtr<CPDF_Font>& pPDFFont,
                                           CFGAS_FontMgr* pFontMgr);
   static RetainPtr<CFGAS_GEFont> LoadFont(
       std::unique_ptr<CFX_Font> pInternalFont,
@@ -66,7 +66,7 @@
   bool LoadFontInternal(const uint8_t* pBuffer, int32_t length);
 #endif
   bool LoadFontInternal(std::unique_ptr<CFX_Font> pInternalFont);
-  bool LoadFontInternal(CFX_Font* pExternalFont);
+  bool LoadFontInternal(const RetainPtr<CPDF_Font>& pPDFFont);
   bool InitFont();
   std::pair<int32_t, RetainPtr<CFGAS_GEFont>> GetGlyphIndexAndFont(
       wchar_t wUnicode,
@@ -74,7 +74,8 @@
   WideString GetFamilyName() const;
 
   Optional<uint32_t> m_dwLogFontStyle;
-  MaybeOwned<CFX_Font> m_pFont;  // Must come before |m_pFontEncoding|.
+  RetainPtr<CPDF_Font> m_pPDFFont;  // Must come before |m_pFont|.
+  MaybeOwned<CFX_Font> m_pFont;     // Must come before |m_pFontEncoding|.
   ObservedPtr<CFGAS_FontMgr> const m_pFontMgr;
   std::unique_ptr<CFX_UnicodeEncodingEx> m_pFontEncoding;
   std::map<wchar_t, int32_t> m_CharWidthMap;
diff --git a/xfa/fgas/font/cfgas_pdffontmgr.cpp b/xfa/fgas/font/cfgas_pdffontmgr.cpp
index 4cdaffa..e020007 100644
--- a/xfa/fgas/font/cfgas_pdffontmgr.cpp
+++ b/xfa/fgas/font/cfgas_pdffontmgr.cpp
@@ -51,6 +51,7 @@
   ByteString name = strPsName;
   name.Remove(' ');
 
+  auto* pData = CPDF_DocPageData::FromDocument(m_pDoc.Get());
   CPDF_DictionaryLocker locker(pFontSetDict);
   for (const auto& it : locker) {
     const ByteString& key = it.first;
@@ -63,12 +64,8 @@
     if (!pFontDict || pFontDict->GetStringFor("Type") != "Font")
       return nullptr;
 
-    auto* pData = CPDF_DocPageData::FromDocument(m_pDoc.Get());
-    CPDF_Font* pPDFFont = pData->GetFont(pFontDict);
-    if (!pPDFFont)
-      return nullptr;
-
-    if (!pPDFFont->IsEmbedded())
+    RetainPtr<CPDF_Font> pPDFFont = pData->GetFont(pFontDict);
+    if (!pPDFFont || !pPDFFont->IsEmbedded())
       return nullptr;
 
     return CFGAS_GEFont::LoadFont(pPDFFont, m_pFontMgr.Get());
diff --git a/xfa/fxfa/cxfa_fontmgr.cpp b/xfa/fxfa/cxfa_fontmgr.cpp
index f78de66..c7ced0c 100644
--- a/xfa/fxfa/cxfa_fontmgr.cpp
+++ b/xfa/fxfa/cxfa_fontmgr.cpp
@@ -62,7 +62,7 @@
   if (!pFont) {
     ByteString font_family =
         ByteString::Format("%ls", WideString(wsFontFamily).c_str());
-    CPDF_Font* stock_font =
+    RetainPtr<CPDF_Font> stock_font =
         CPDF_Font::GetStockFont(hDoc->GetPDFDoc(), font_family.AsStringView());
     if (stock_font) {
       pFont =