Introduce ref-counted CFX_Face class.

The class wraps the FXFT_FaceRec usage, and removes the ad-hoc
refcounting from CTTFontDesc.

This imposes some requirements upon the time at which the underling
FT library is created. These have been resolved as of 78f6819.

Change-Id: I6f0dac16aa0d8e629555af66acc9a34e20eba264
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/54790
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/core/fxge/BUILD.gn b/core/fxge/BUILD.gn
index b149732..1dcf751 100644
--- a/core/fxge/BUILD.gn
+++ b/core/fxge/BUILD.gn
@@ -24,9 +24,12 @@
     "cfx_color.cpp",
     "cfx_color.h",
     "cfx_defaultrenderdevice.h",
+    "cfx_face.cpp",
+    "cfx_face.h",
     "cfx_folderfontinfo.cpp",
     "cfx_folderfontinfo.h",
     "cfx_font.cpp",
+    "cfx_font.h",
     "cfx_fontcache.cpp",
     "cfx_fontcache.h",
     "cfx_fontmapper.cpp",
diff --git a/core/fxge/android/cfpf_skiafont.cpp b/core/fxge/android/cfpf_skiafont.cpp
index 926cf3e..eb299fb 100644
--- a/core/fxge/android/cfpf_skiafont.cpp
+++ b/core/fxge/android/cfpf_skiafont.cpp
@@ -26,76 +26,73 @@
       m_dwStyle(dwStyle),
       m_uCharset(uCharset) {}
 
-CFPF_SkiaFont::~CFPF_SkiaFont() {
-  if (m_Face)
-    FT_Done_Face(m_Face);
-}
+CFPF_SkiaFont::~CFPF_SkiaFont() = default;
 
 ByteString CFPF_SkiaFont::GetFamilyName() {
   if (!m_Face)
     return ByteString();
-  return ByteString(FXFT_Get_Face_Family_Name(m_Face));
+  return ByteString(FXFT_Get_Face_Family_Name(GetFaceRec()));
 }
 
 ByteString CFPF_SkiaFont::GetPsName() {
   if (!m_Face)
     return ByteString();
-  return FT_Get_Postscript_Name(m_Face);
+  return FT_Get_Postscript_Name(GetFaceRec());
 }
 
 int32_t CFPF_SkiaFont::GetGlyphIndex(wchar_t wUnicode) {
   if (!m_Face)
     return wUnicode;
-  if (FXFT_Select_Charmap(m_Face, FT_ENCODING_UNICODE))
+  if (FXFT_Select_Charmap(GetFaceRec(), FT_ENCODING_UNICODE))
     return 0;
-  return FT_Get_Char_Index(m_Face, wUnicode);
+  return FT_Get_Char_Index(GetFaceRec(), wUnicode);
 }
 
 int32_t CFPF_SkiaFont::GetGlyphWidth(int32_t iGlyphIndex) {
   if (!m_Face)
     return 0;
-  if (FT_Load_Glyph(m_Face, iGlyphIndex,
+  if (FT_Load_Glyph(GetFaceRec(), iGlyphIndex,
                     FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH)) {
     return 0;
   }
-  return FPF_EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face),
-                       FXFT_Get_Glyph_HoriAdvance(m_Face));
+  return FPF_EM_ADJUST(FXFT_Get_Face_UnitsPerEM(GetFaceRec()),
+                       FXFT_Get_Glyph_HoriAdvance(GetFaceRec()));
 }
 
 int32_t CFPF_SkiaFont::GetAscent() const {
   if (!m_Face)
     return 0;
-  return FPF_EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face),
-                       FXFT_Get_Face_Ascender(m_Face));
+  return FPF_EM_ADJUST(FXFT_Get_Face_UnitsPerEM(GetFaceRec()),
+                       FXFT_Get_Face_Ascender(GetFaceRec()));
 }
 
 int32_t CFPF_SkiaFont::GetDescent() const {
   if (!m_Face)
     return 0;
-  return FPF_EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face),
-                       FXFT_Get_Face_Descender(m_Face));
+  return FPF_EM_ADJUST(FXFT_Get_Face_UnitsPerEM(GetFaceRec()),
+                       FXFT_Get_Face_Descender(GetFaceRec()));
 }
 
 bool CFPF_SkiaFont::GetGlyphBBox(int32_t iGlyphIndex, FX_RECT& rtBBox) {
   if (!m_Face)
     return false;
-  if (FXFT_Is_Face_Tricky(m_Face)) {
-    if (FT_Set_Char_Size(m_Face, 0, 1000 * 64, 72, 72))
+  if (FXFT_Is_Face_Tricky(GetFaceRec())) {
+    if (FT_Set_Char_Size(GetFaceRec(), 0, 1000 * 64, 72, 72))
       return false;
-    if (FT_Load_Glyph(m_Face, iGlyphIndex,
+    if (FT_Load_Glyph(GetFaceRec(), iGlyphIndex,
                       FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH)) {
-      FT_Set_Pixel_Sizes(m_Face, 0, 64);
+      FT_Set_Pixel_Sizes(GetFaceRec(), 0, 64);
       return false;
     }
     FT_Glyph glyph;
-    if (FT_Get_Glyph(m_Face->glyph, &glyph)) {
-      FT_Set_Pixel_Sizes(m_Face, 0, 64);
+    if (FT_Get_Glyph(GetFaceRec()->glyph, &glyph)) {
+      FT_Set_Pixel_Sizes(GetFaceRec(), 0, 64);
       return false;
     }
     FT_BBox cbox;
     FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_PIXELS, &cbox);
-    int32_t x_ppem = m_Face->size->metrics.x_ppem;
-    int32_t y_ppem = m_Face->size->metrics.y_ppem;
+    int32_t x_ppem = GetFaceRec()->size->metrics.x_ppem;
+    int32_t y_ppem = GetFaceRec()->size->metrics.y_ppem;
     rtBBox.left = FPF_EM_ADJUST(x_ppem, cbox.xMin);
     rtBBox.right = FPF_EM_ADJUST(x_ppem, cbox.xMax);
     rtBBox.top = FPF_EM_ADJUST(y_ppem, cbox.yMax);
@@ -103,22 +100,22 @@
     rtBBox.top = std::min(rtBBox.top, GetAscent());
     rtBBox.bottom = std::max(rtBBox.bottom, GetDescent());
     FT_Done_Glyph(glyph);
-    return FT_Set_Pixel_Sizes(m_Face, 0, 64) == 0;
+    return FT_Set_Pixel_Sizes(GetFaceRec(), 0, 64) == 0;
   }
-  if (FT_Load_Glyph(m_Face, iGlyphIndex,
+  if (FT_Load_Glyph(GetFaceRec(), iGlyphIndex,
                     FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH)) {
     return false;
   }
-  rtBBox.left = FPF_EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face),
-                              FXFT_Get_Glyph_HoriBearingX(m_Face));
-  rtBBox.bottom = FPF_EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face),
-                                FXFT_Get_Glyph_HoriBearingY(m_Face));
-  rtBBox.right = FPF_EM_ADJUST(
-      FXFT_Get_Face_UnitsPerEM(m_Face),
-      FXFT_Get_Glyph_HoriBearingX(m_Face) + FXFT_Get_Glyph_Width(m_Face));
-  rtBBox.top = FPF_EM_ADJUST(
-      FXFT_Get_Face_UnitsPerEM(m_Face),
-      FXFT_Get_Glyph_HoriBearingY(m_Face) - FXFT_Get_Glyph_Height(m_Face));
+  rtBBox.left = FPF_EM_ADJUST(FXFT_Get_Face_UnitsPerEM(GetFaceRec()),
+                              FXFT_Get_Glyph_HoriBearingX(GetFaceRec()));
+  rtBBox.bottom = FPF_EM_ADJUST(FXFT_Get_Face_UnitsPerEM(GetFaceRec()),
+                                FXFT_Get_Glyph_HoriBearingY(GetFaceRec()));
+  rtBBox.right = FPF_EM_ADJUST(FXFT_Get_Face_UnitsPerEM(GetFaceRec()),
+                               FXFT_Get_Glyph_HoriBearingX(GetFaceRec()) +
+                                   FXFT_Get_Glyph_Width(GetFaceRec()));
+  rtBBox.top = FPF_EM_ADJUST(FXFT_Get_Face_UnitsPerEM(GetFaceRec()),
+                             FXFT_Get_Glyph_HoriBearingY(GetFaceRec()) -
+                                 FXFT_Get_Glyph_Height(GetFaceRec()));
   return true;
 }
 
@@ -126,30 +123,30 @@
   if (!m_Face) {
     return false;
   }
-  rtBBox.left = FPF_EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face),
-                              FXFT_Get_Face_xMin(m_Face));
-  rtBBox.top = FPF_EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face),
-                             FXFT_Get_Face_yMin(m_Face));
-  rtBBox.right = FPF_EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face),
-                               FXFT_Get_Face_xMax(m_Face));
-  rtBBox.bottom = FPF_EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face),
-                                FXFT_Get_Face_yMax(m_Face));
+  rtBBox.left = FPF_EM_ADJUST(FXFT_Get_Face_UnitsPerEM(GetFaceRec()),
+                              FXFT_Get_Face_xMin(GetFaceRec()));
+  rtBBox.top = FPF_EM_ADJUST(FXFT_Get_Face_UnitsPerEM(GetFaceRec()),
+                             FXFT_Get_Face_yMin(GetFaceRec()));
+  rtBBox.right = FPF_EM_ADJUST(FXFT_Get_Face_UnitsPerEM(GetFaceRec()),
+                               FXFT_Get_Face_xMax(GetFaceRec()));
+  rtBBox.bottom = FPF_EM_ADJUST(FXFT_Get_Face_UnitsPerEM(GetFaceRec()),
+                                FXFT_Get_Face_yMax(GetFaceRec()));
   return true;
 }
 
 int32_t CFPF_SkiaFont::GetHeight() const {
   if (!m_Face)
     return 0;
-  return FPF_EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face),
-                       FXFT_Get_Face_Height(m_Face));
+  return FPF_EM_ADJUST(FXFT_Get_Face_UnitsPerEM(GetFaceRec()),
+                       FXFT_Get_Face_Height(GetFaceRec()));
 }
 
 int32_t CFPF_SkiaFont::GetItalicAngle() const {
   if (!m_Face)
     return 0;
 
-  auto* info =
-      static_cast<TT_Postscript*>(FT_Get_Sfnt_Table(m_Face, ft_sfnt_post));
+  auto* info = static_cast<TT_Postscript*>(
+      FT_Get_Sfnt_Table(GetFaceRec(), ft_sfnt_post));
   return info ? info->italicAngle : 0;
 }
 
@@ -160,7 +157,7 @@
     return 0;
 
   FT_ULong ulSize = pdfium::base::checked_cast<FT_ULong>(dwSize);
-  if (FT_Load_Sfnt_Table(m_Face, dwTable, 0, pBuffer, &ulSize))
+  if (FT_Load_Sfnt_Table(GetFaceRec(), dwTable, 0, pBuffer, &ulSize))
     return 0;
   return pdfium::base::checked_cast<uint32_t>(ulSize);
 }
diff --git a/core/fxge/android/cfpf_skiafont.h b/core/fxge/android/cfpf_skiafont.h
index a00a93e..67204d3 100644
--- a/core/fxge/android/cfpf_skiafont.h
+++ b/core/fxge/android/cfpf_skiafont.h
@@ -10,6 +10,7 @@
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/fx_system.h"
 #include "core/fxcrt/unowned_ptr.h"
+#include "core/fxge/cfx_face.h"
 #include "core/fxge/fx_freetype.h"
 
 class CFPF_SkiaFontMgr;
@@ -39,11 +40,12 @@
   int32_t GetHeight() const;
   int32_t GetItalicAngle() const;
   uint32_t GetFontData(uint32_t dwTable, uint8_t* pBuffer, uint32_t dwSize);
+  FXFT_FaceRec* GetFaceRec() const { return m_Face->GetRec(); }
 
  private:
   UnownedPtr<CFPF_SkiaFontMgr> const m_pFontMgr;
   UnownedPtr<const CFPF_SkiaPathFont> const m_pFont;
-  FXFT_FaceRec* const m_Face;
+  RetainPtr<CFX_Face> const m_Face;
   const uint32_t m_dwStyle;
   const uint8_t m_uCharset;
 };
diff --git a/core/fxge/android/cfpf_skiafontmgr.cpp b/core/fxge/android/cfpf_skiafontmgr.cpp
index 7d853ff..dc84f26 100644
--- a/core/fxge/android/cfpf_skiafontmgr.cpp
+++ b/core/fxge/android/cfpf_skiafontmgr.cpp
@@ -337,19 +337,23 @@
   return pRet;
 }
 
-FXFT_FaceRec* CFPF_SkiaFontMgr::GetFontFace(ByteStringView bsFile,
-                                            int32_t iFaceIndex) {
+RetainPtr<CFX_Face> CFPF_SkiaFontMgr::GetFontFace(ByteStringView bsFile,
+                                                  int32_t iFaceIndex) {
   if (bsFile.IsEmpty())
     return nullptr;
+
   if (iFaceIndex < 0)
     return nullptr;
+
   FT_Open_Args args;
   args.flags = FT_OPEN_PATHNAME;
   args.pathname = const_cast<FT_String*>(bsFile.unterminated_c_str());
-  FXFT_FaceRec* face;
-  if (FT_Open_Face(m_FTLibrary.get(), &args, iFaceIndex, &face))
+  RetainPtr<CFX_Face> face =
+      CFX_Face::Open(m_FTLibrary.get(), &args, iFaceIndex);
+  if (!face)
     return nullptr;
-  FT_Set_Pixel_Sizes(face, 0, 64);
+
+  FT_Set_Pixel_Sizes(face->GetRec(), 0, 64);
   return face;
 }
 
@@ -382,25 +386,25 @@
 }
 
 void CFPF_SkiaFontMgr::ScanFile(const ByteString& file) {
-  FXFT_FaceRec* face = GetFontFace(file.AsStringView(), 0);
+  RetainPtr<CFX_Face> face = GetFontFace(file.AsStringView(), 0);
   if (!face)
     return;
 
   m_FontFaces.push_back(ReportFace(face, file));
-  FT_Done_Face(face);
 }
 
 std::unique_ptr<CFPF_SkiaPathFont> CFPF_SkiaFontMgr::ReportFace(
-    FXFT_FaceRec* face,
+    RetainPtr<CFX_Face> face,
     const ByteString& file) {
   uint32_t dwStyle = 0;
-  if (FXFT_Is_Face_Bold(face))
+  if (FXFT_Is_Face_Bold(face->GetRec()))
     dwStyle |= FXFONT_BOLD;
-  if (FXFT_Is_Face_Italic(face))
+  if (FXFT_Is_Face_Italic(face->GetRec()))
     dwStyle |= FXFONT_ITALIC;
-  if (FT_IS_FIXED_WIDTH(face))
+  if (FT_IS_FIXED_WIDTH(face->GetRec()))
     dwStyle |= FXFONT_FIXED_PITCH;
-  TT_OS2* pOS2 = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(face, ft_sfnt_os2));
+  TT_OS2* pOS2 =
+      static_cast<TT_OS2*>(FT_Get_Sfnt_Table(face->GetRec(), ft_sfnt_os2));
   if (pOS2) {
     if (pOS2->ulCodePageRange1 & (1 << 31))
       dwStyle |= FXFONT_SYMBOLIC;
@@ -414,6 +418,7 @@
     dwStyle |= FXFONT_SYMBOLIC;
 
   return pdfium::MakeUnique<CFPF_SkiaPathFont>(
-      file, FXFT_Get_Face_Family_Name(face), dwStyle, face->face_index,
-      FPF_SkiaGetFaceCharset(pOS2), face->num_glyphs);
+      file, FXFT_Get_Face_Family_Name(face->GetRec()), dwStyle,
+      face->GetRec()->face_index, FPF_SkiaGetFaceCharset(pOS2),
+      face->GetRec()->num_glyphs);
 }
diff --git a/core/fxge/android/cfpf_skiafontmgr.h b/core/fxge/android/cfpf_skiafontmgr.h
index 3b660f5..4d5c788 100644
--- a/core/fxge/android/cfpf_skiafontmgr.h
+++ b/core/fxge/android/cfpf_skiafontmgr.h
@@ -12,6 +12,8 @@
 #include <vector>
 
 #include "core/fxcrt/fx_string.h"
+#include "core/fxcrt/retain_ptr.h"
+#include "core/fxge/cfx_face.h"
 #include "core/fxge/fx_freetype.h"
 
 class CFPF_SkiaFont;
@@ -28,12 +30,12 @@
                             uint32_t dwStyle);
 
   bool InitFTLibrary();
-  FXFT_FaceRec* GetFontFace(ByteStringView bsFile, int32_t iFaceIndex);
+  RetainPtr<CFX_Face> GetFontFace(ByteStringView bsFile, int32_t iFaceIndex);
 
  private:
   void ScanPath(const ByteString& path);
   void ScanFile(const ByteString& file);
-  std::unique_ptr<CFPF_SkiaPathFont> ReportFace(FXFT_FaceRec* face,
+  std::unique_ptr<CFPF_SkiaPathFont> ReportFace(RetainPtr<CFX_Face> face,
                                                 const ByteString& file);
 
   bool m_bLoaded = false;
diff --git a/core/fxge/cfx_face.cpp b/core/fxge/cfx_face.cpp
new file mode 100644
index 0000000..c99210c
--- /dev/null
+++ b/core/fxge/cfx_face.cpp
@@ -0,0 +1,36 @@
+// Copyright 2019 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.
+
+#include "core/fxge/cfx_face.h"
+
+#include "third_party/base/ptr_util.h"
+
+// static
+RetainPtr<CFX_Face> CFX_Face::New(FT_Library library,
+                                  pdfium::span<const FT_Byte> data,
+                                  FT_Long face_index) {
+  FXFT_FaceRec* pRec = nullptr;
+  if (FT_New_Memory_Face(library, data.data(), data.size(), face_index,
+                         &pRec) != 0) {
+    return nullptr;
+  }
+  return pdfium::WrapRetain(new CFX_Face(pRec));
+}
+
+// static
+RetainPtr<CFX_Face> CFX_Face::Open(FT_Library library,
+                                   const FT_Open_Args* args,
+                                   FT_Long face_index) {
+  FXFT_FaceRec* pRec = nullptr;
+  if (FT_Open_Face(library, args, face_index, &pRec) != 0)
+    return nullptr;
+
+  return pdfium::WrapRetain(new CFX_Face(pRec));
+}
+
+CFX_Face::CFX_Face(FXFT_FaceRec* rec) : m_pRec(rec) {
+  ASSERT(m_pRec);
+}
+
+CFX_Face::~CFX_Face() = default;
diff --git a/core/fxge/cfx_face.h b/core/fxge/cfx_face.h
new file mode 100644
index 0000000..11925f3
--- /dev/null
+++ b/core/fxge/cfx_face.h
@@ -0,0 +1,33 @@
+// Copyright 2019 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.
+
+#ifndef CORE_FXGE_CFX_FACE_H_
+#define CORE_FXGE_CFX_FACE_H_
+
+#include "core/fxcrt/observed_ptr.h"
+#include "core/fxcrt/retain_ptr.h"
+#include "core/fxge/fx_freetype.h"
+#include "third_party/base/span.h"
+
+class CFX_Face : public Retainable, public Observable<CFX_Face> {
+ public:
+  static RetainPtr<CFX_Face> New(FT_Library library,
+                                 pdfium::span<const FT_Byte> file_span,
+                                 FT_Long face_index);
+
+  static RetainPtr<CFX_Face> Open(FT_Library library,
+                                  const FT_Open_Args* args,
+                                  FT_Long face_index);
+
+  ~CFX_Face() override;
+
+  FXFT_FaceRec* GetRec() { return m_pRec.get(); }
+
+ private:
+  explicit CFX_Face(FXFT_FaceRec* pRec);
+
+  ScopedFXFTFaceRec const m_pRec;
+};
+
+#endif  // CORE_FXGE_CFX_FACE_H_
diff --git a/core/fxge/cfx_font.cpp b/core/fxge/cfx_font.cpp
index aea8f16..2b2e1c4 100644
--- a/core/fxge/cfx_font.cpp
+++ b/core/fxge/cfx_font.cpp
@@ -55,10 +55,10 @@
 
 void FTStreamClose(FXFT_StreamRec* stream) {}
 
-FXFT_FaceRec* LoadFileImp(FXFT_LibraryRec* library,
-                          const RetainPtr<IFX_SeekableReadStream>& pFile,
-                          int32_t faceIndex,
-                          std::unique_ptr<FXFT_StreamRec>* stream) {
+RetainPtr<CFX_Face> LoadFileImp(FXFT_LibraryRec* library,
+                                const RetainPtr<IFX_SeekableReadStream>& pFile,
+                                int32_t faceIndex,
+                                std::unique_ptr<FXFT_StreamRec>* stream) {
   auto stream1 = pdfium::MakeUnique<FXFT_StreamRec>();
   stream1->base = nullptr;
   stream1->size = static_cast<unsigned long>(pFile->GetSize());
@@ -71,8 +71,8 @@
   args.flags = FT_OPEN_STREAM;
   args.stream = stream1.get();
 
-  FXFT_FaceRec* face;
-  if (FT_Open_Face(library, &args, faceIndex, &face))
+  RetainPtr<CFX_Face> face = CFX_Face::Open(library, &args, faceIndex);
+  if (!face)
     return nullptr;
 
   if (stream)
@@ -314,12 +314,12 @@
     return false;
 
   m_pOwnedStream = std::move(stream);
-  FT_Set_Pixel_Sizes(m_Face.Get(), 0, 64);
+  FT_Set_Pixel_Sizes(m_Face->GetRec(), 0, 64);
   return true;
 }
 
 #if !defined(OS_WIN)
-void CFX_Font::SetFace(FXFT_FaceRec* face) {
+void CFX_Font::SetFace(RetainPtr<CFX_Face> face) {
   ClearGlyphCache();
   m_Face = face;
 }
@@ -332,22 +332,13 @@
 
 CFX_Font::~CFX_Font() {
   m_FontData = {};  // m_FontData can't outive m_Face.
-  if (m_Face)
-    DeleteFace();
+  m_Face.Reset();
 
 #if defined(OS_MACOSX)
   ReleasePlatformResource();
 #endif
 }
 
-void CFX_Font::DeleteFace() {
-  ClearGlyphCache();
-  if (m_bEmbedded)
-    FT_Done_Face(m_Face.Release());
-  else
-    CFX_GEModule::Get()->GetFontMgr()->ReleaseFace(m_Face.Release());
-}
-
 void CFX_Font::LoadSubst(const ByteString& face_name,
                          bool bTrueType,
                          uint32_t flags,
@@ -362,8 +353,8 @@
       face_name, bTrueType, flags, weight, italic_angle, CharsetCP,
       m_pSubstFont.get());
   if (m_Face) {
-    m_FontData = {FXFT_Get_Face_Stream_Base(m_Face.Get()),
-                  FXFT_Get_Face_Stream_Size(m_Face.Get())};
+    m_FontData = {FXFT_Get_Face_Stream_Base(m_Face->GetRec()),
+                  FXFT_Get_Face_Stream_Size(m_Face->GetRec())};
   }
 }
 
@@ -373,16 +364,16 @@
   if (m_pSubstFont && m_pSubstFont->m_bFlagMM)
     AdjustMMParams(glyph_index, 0, 0);
   int err =
-      FT_Load_Glyph(m_Face.Get(), glyph_index,
+      FT_Load_Glyph(m_Face->GetRec(), glyph_index,
                     FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
   if (err)
     return 0;
 
-  int horiAdvance = FXFT_Get_Glyph_HoriAdvance(m_Face.Get());
+  int horiAdvance = FXFT_Get_Glyph_HoriAdvance(m_Face->GetRec());
   if (horiAdvance < 0 || horiAdvance > kThousandthMaxInt)
     return 0;
 
-  return EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face.Get()), horiAdvance);
+  return EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face->GetRec()), horiAdvance);
 }
 
 bool CFX_Font::LoadEmbedded(pdfium::span<const uint8_t> src_span) {
@@ -396,54 +387,54 @@
 }
 
 bool CFX_Font::IsTTFont() const {
-  return m_Face && FXFT_Is_Face_TT_OT(m_Face.Get()) == FT_FACE_FLAG_SFNT;
+  return m_Face && FXFT_Is_Face_TT_OT(m_Face->GetRec()) == FT_FACE_FLAG_SFNT;
 }
 
 int CFX_Font::GetAscent() const {
   if (!m_Face)
     return 0;
 
-  int ascender = FXFT_Get_Face_Ascender(m_Face.Get());
+  int ascender = FXFT_Get_Face_Ascender(m_Face->GetRec());
   if (ascender < kThousandthMinInt || ascender > kThousandthMaxInt)
     return 0;
 
-  return EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face.Get()), ascender);
+  return EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face->GetRec()), ascender);
 }
 
 int CFX_Font::GetDescent() const {
   if (!m_Face)
     return 0;
 
-  int descender = FXFT_Get_Face_Descender(m_Face.Get());
+  int descender = FXFT_Get_Face_Descender(m_Face->GetRec());
   if (descender < kThousandthMinInt || descender > kThousandthMaxInt)
     return 0;
 
-  return EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face.Get()), descender);
+  return EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face->GetRec()), descender);
 }
 
 bool CFX_Font::GetGlyphBBox(uint32_t glyph_index, FX_RECT* pBBox) {
   if (!m_Face)
     return false;
 
-  if (FXFT_Is_Face_Tricky(m_Face.Get())) {
-    int error = FT_Set_Char_Size(m_Face.Get(), 0, 1000 * 64, 72, 72);
+  if (FXFT_Is_Face_Tricky(m_Face->GetRec())) {
+    int error = FT_Set_Char_Size(m_Face->GetRec(), 0, 1000 * 64, 72, 72);
     if (error)
       return false;
 
-    error = FT_Load_Glyph(m_Face.Get(), glyph_index,
+    error = FT_Load_Glyph(m_Face->GetRec(), glyph_index,
                           FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
     if (error)
       return false;
 
     FT_BBox cbox;
     FT_Glyph glyph;
-    error = FT_Get_Glyph(m_Face->glyph, &glyph);
+    error = FT_Get_Glyph(m_Face->GetRec()->glyph, &glyph);
     if (error)
       return false;
 
     FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_PIXELS, &cbox);
-    int pixel_size_x = m_Face->size->metrics.x_ppem,
-        pixel_size_y = m_Face->size->metrics.y_ppem;
+    int pixel_size_x = m_Face->GetRec()->size->metrics.x_ppem;
+    int pixel_size_y = m_Face->GetRec()->size->metrics.y_ppem;
     if (pixel_size_x == 0 || pixel_size_y == 0) {
       pBBox->left = cbox.xMin;
       pBBox->right = cbox.xMax;
@@ -456,32 +447,33 @@
       pBBox->bottom = cbox.yMin * 1000 / pixel_size_y;
     }
     pBBox->top = std::min(
-        pBBox->top, static_cast<int32_t>(FXFT_Get_Face_Ascender(m_Face.Get())));
-    pBBox->bottom =
-        std::max(pBBox->bottom,
-                 static_cast<int32_t>(FXFT_Get_Face_Descender(m_Face.Get())));
+        pBBox->top,
+        static_cast<int32_t>(FXFT_Get_Face_Ascender(m_Face->GetRec())));
+    pBBox->bottom = std::max(
+        pBBox->bottom,
+        static_cast<int32_t>(FXFT_Get_Face_Descender(m_Face->GetRec())));
     FT_Done_Glyph(glyph);
-    return FT_Set_Pixel_Sizes(m_Face.Get(), 0, 64) == 0;
+    return FT_Set_Pixel_Sizes(m_Face->GetRec(), 0, 64) == 0;
   }
-  if (FT_Load_Glyph(m_Face.Get(), glyph_index,
+  if (FT_Load_Glyph(m_Face->GetRec(), glyph_index,
                     FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH)) {
     return false;
   }
-  int em = FXFT_Get_Face_UnitsPerEM(m_Face.Get());
+  int em = FXFT_Get_Face_UnitsPerEM(m_Face->GetRec());
   if (em == 0) {
-    pBBox->left = FXFT_Get_Glyph_HoriBearingX(m_Face.Get());
-    pBBox->bottom = FXFT_Get_Glyph_HoriBearingY(m_Face.Get());
-    pBBox->top = pBBox->bottom - FXFT_Get_Glyph_Height(m_Face.Get());
-    pBBox->right = pBBox->left + FXFT_Get_Glyph_Width(m_Face.Get());
+    pBBox->left = FXFT_Get_Glyph_HoriBearingX(m_Face->GetRec());
+    pBBox->bottom = FXFT_Get_Glyph_HoriBearingY(m_Face->GetRec());
+    pBBox->top = pBBox->bottom - FXFT_Get_Glyph_Height(m_Face->GetRec());
+    pBBox->right = pBBox->left + FXFT_Get_Glyph_Width(m_Face->GetRec());
   } else {
-    pBBox->left = FXFT_Get_Glyph_HoriBearingX(m_Face.Get()) * 1000 / em;
-    pBBox->top = (FXFT_Get_Glyph_HoriBearingY(m_Face.Get()) -
-                  FXFT_Get_Glyph_Height(m_Face.Get())) *
+    pBBox->left = FXFT_Get_Glyph_HoriBearingX(m_Face->GetRec()) * 1000 / em;
+    pBBox->top = (FXFT_Get_Glyph_HoriBearingY(m_Face->GetRec()) -
+                  FXFT_Get_Glyph_Height(m_Face->GetRec())) *
                  1000 / em;
-    pBBox->right = (FXFT_Get_Glyph_HoriBearingX(m_Face.Get()) +
-                    FXFT_Get_Glyph_Width(m_Face.Get())) *
+    pBBox->right = (FXFT_Get_Glyph_HoriBearingX(m_Face->GetRec()) +
+                    FXFT_Get_Glyph_Width(m_Face->GetRec())) *
                    1000 / em;
-    pBBox->bottom = (FXFT_Get_Glyph_HoriBearingY(m_Face.Get())) * 1000 / em;
+    pBBox->bottom = (FXFT_Get_Glyph_HoriBearingY(m_Face->GetRec())) * 1000 / em;
   }
   return true;
 }
@@ -489,27 +481,27 @@
 bool CFX_Font::IsItalic() const {
   if (!m_Face)
     return false;
-  if (FXFT_Is_Face_Italic(m_Face.Get()) == FT_STYLE_FLAG_ITALIC)
+  if (FXFT_Is_Face_Italic(m_Face->GetRec()) == FT_STYLE_FLAG_ITALIC)
     return true;
 
-  ByteString str(FXFT_Get_Face_Style_Name(m_Face.Get()));
+  ByteString str(FXFT_Get_Face_Style_Name(m_Face->GetRec()));
   str.MakeLower();
   return str.Contains("italic");
 }
 
 bool CFX_Font::IsBold() const {
-  return m_Face && FXFT_Is_Face_Bold(m_Face.Get()) == FT_STYLE_FLAG_BOLD;
+  return m_Face && FXFT_Is_Face_Bold(m_Face->GetRec()) == FT_STYLE_FLAG_BOLD;
 }
 
 bool CFX_Font::IsFixedWidth() const {
-  return m_Face && FXFT_Is_Face_fixedwidth(m_Face.Get()) != 0;
+  return m_Face && FXFT_Is_Face_fixedwidth(m_Face->GetRec()) != 0;
 }
 
 ByteString CFX_Font::GetPsName() const {
   if (!m_Face)
     return ByteString();
 
-  ByteString psName = FT_Get_Postscript_Name(m_Face.Get());
+  ByteString psName = FT_Get_Postscript_Name(m_Face->GetRec());
   if (psName.IsEmpty())
     psName = kUntitledFontName;
   return psName;
@@ -519,7 +511,7 @@
   if (!m_Face && !m_pSubstFont)
     return ByteString();
   if (m_Face)
-    return ByteString(FXFT_Get_Face_Family_Name(m_Face.Get()));
+    return ByteString(FXFT_Get_Face_Family_Name(m_Face->GetRec()));
   return m_pSubstFont->m_Family;
 }
 
@@ -532,7 +524,7 @@
   if (!m_Face && !m_pSubstFont)
     return ByteString();
   if (m_Face) {
-    ByteString style = ByteString(FXFT_Get_Face_Style_Name(m_Face.Get()));
+    ByteString style = ByteString(FXFT_Get_Face_Style_Name(m_Face->GetRec()));
     ByteString facename = GetFamilyNameOrUntitled();
     if (ShouldAppendStyle(style))
       facename += " " + style;
@@ -548,7 +540,7 @@
   if (!m_Face && !m_pSubstFont)
     return ByteString();
   if (m_Face) {
-    ByteString style = ByteString(FXFT_Get_Face_Style_Name(m_Face.Get()));
+    ByteString style = ByteString(FXFT_Get_Face_Style_Name(m_Face->GetRec()));
     ByteString facename = GetFamilyNameOrUntitled();
     if (IsTTFont())
       facename.Remove(' ');
@@ -563,17 +555,17 @@
   if (!m_Face)
     return false;
 
-  int em = FXFT_Get_Face_UnitsPerEM(m_Face.Get());
+  int em = FXFT_Get_Face_UnitsPerEM(m_Face->GetRec());
   if (em == 0) {
-    pBBox->left = FXFT_Get_Face_xMin(m_Face.Get());
-    pBBox->bottom = FXFT_Get_Face_yMax(m_Face.Get());
-    pBBox->top = FXFT_Get_Face_yMin(m_Face.Get());
-    pBBox->right = FXFT_Get_Face_xMax(m_Face.Get());
+    pBBox->left = FXFT_Get_Face_xMin(m_Face->GetRec());
+    pBBox->bottom = FXFT_Get_Face_yMax(m_Face->GetRec());
+    pBBox->top = FXFT_Get_Face_yMin(m_Face->GetRec());
+    pBBox->right = FXFT_Get_Face_xMax(m_Face->GetRec());
   } else {
-    pBBox->left = FXFT_Get_Face_xMin(m_Face.Get()) * 1000 / em;
-    pBBox->top = FXFT_Get_Face_yMin(m_Face.Get()) * 1000 / em;
-    pBBox->right = FXFT_Get_Face_xMax(m_Face.Get()) * 1000 / em;
-    pBBox->bottom = FXFT_Get_Face_yMax(m_Face.Get()) * 1000 / em;
+    pBBox->left = FXFT_Get_Face_xMin(m_Face->GetRec()) * 1000 / em;
+    pBBox->top = FXFT_Get_Face_yMin(m_Face->GetRec()) * 1000 / em;
+    pBBox->right = FXFT_Get_Face_xMax(m_Face->GetRec()) * 1000 / em;
+    pBBox->bottom = FXFT_Get_Face_yMax(m_Face->GetRec()) * 1000 / em;
   }
   return true;
 }
@@ -593,7 +585,7 @@
                               int weight) const {
   ASSERT(dest_width >= 0);
   FXFT_MM_VarPtr pMasters = nullptr;
-  FT_Get_MM_Var(m_Face.Get(), &pMasters);
+  FT_Get_MM_Var(m_Face->GetRec(), &pMasters);
   if (!pMasters)
     return;
 
@@ -609,27 +601,27 @@
     int min_param = FXFT_Get_MM_Axis_Min(FXFT_Get_MM_Axis(pMasters, 1)) / 65536;
     int max_param = FXFT_Get_MM_Axis_Max(FXFT_Get_MM_Axis(pMasters, 1)) / 65536;
     coords[1] = min_param;
-    FT_Set_MM_Design_Coordinates(m_Face.Get(), 2, coords);
-    FT_Load_Glyph(m_Face.Get(), glyph_index,
+    FT_Set_MM_Design_Coordinates(m_Face->GetRec(), 2, coords);
+    FT_Load_Glyph(m_Face->GetRec(), glyph_index,
                   FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
-    int min_width = FXFT_Get_Glyph_HoriAdvance(m_Face.Get()) * 1000 /
-                    FXFT_Get_Face_UnitsPerEM(m_Face.Get());
+    int min_width = FXFT_Get_Glyph_HoriAdvance(m_Face->GetRec()) * 1000 /
+                    FXFT_Get_Face_UnitsPerEM(m_Face->GetRec());
     coords[1] = max_param;
-    FT_Set_MM_Design_Coordinates(m_Face.Get(), 2, coords);
-    FT_Load_Glyph(m_Face.Get(), glyph_index,
+    FT_Set_MM_Design_Coordinates(m_Face->GetRec(), 2, coords);
+    FT_Load_Glyph(m_Face->GetRec(), glyph_index,
                   FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
-    int max_width = FXFT_Get_Glyph_HoriAdvance(m_Face.Get()) * 1000 /
-                    FXFT_Get_Face_UnitsPerEM(m_Face.Get());
+    int max_width = FXFT_Get_Glyph_HoriAdvance(m_Face->GetRec()) * 1000 /
+                    FXFT_Get_Face_UnitsPerEM(m_Face->GetRec());
     if (max_width == min_width) {
-      FXFT_Free(m_Face.Get(), pMasters);
+      FXFT_Free(m_Face->GetRec(), pMasters);
       return;
     }
     int param = min_param + (max_param - min_param) * (dest_width - min_width) /
                                 (max_width - min_width);
     coords[1] = param;
   }
-  FXFT_Free(m_Face.Get(), pMasters);
-  FT_Set_MM_Design_Coordinates(m_Face.Get(), 2, coords);
+  FXFT_Free(m_Face->GetRec(), pMasters);
+  FT_Set_MM_Design_Coordinates(m_Face->GetRec(), 2, coords);
 }
 
 CFX_PathData* CFX_Font::LoadGlyphPathImpl(uint32_t glyph_index,
@@ -637,7 +629,7 @@
   if (!m_Face)
     return nullptr;
 
-  FT_Set_Pixel_Sizes(m_Face.Get(), 0, 64);
+  FT_Set_Pixel_Sizes(m_Face->GetRec(), 0, 64);
   FT_Matrix ft_matrix = {65536, 0, 0, 65536};
   if (m_pSubstFont) {
     if (m_pSubstFont->m_ItalicAngle) {
@@ -658,11 +650,12 @@
     if (m_pSubstFont->m_bFlagMM)
       AdjustMMParams(glyph_index, dest_width, m_pSubstFont->m_Weight);
   }
-  ScopedFontTransform scoped_transform(m_Face.Get(), &ft_matrix);
+  ScopedFontTransform scoped_transform(m_Face, &ft_matrix);
   int load_flags = FT_LOAD_NO_BITMAP;
-  if (!(m_Face->face_flags & FT_FACE_FLAG_SFNT) || !FT_IS_TRICKY(m_Face.Get()))
+  if (!(m_Face->GetRec()->face_flags & FT_FACE_FLAG_SFNT) ||
+      !FT_IS_TRICKY(m_Face->GetRec()))
     load_flags |= FT_LOAD_NO_HINTING;
-  if (FT_Load_Glyph(m_Face.Get(), glyph_index, load_flags))
+  if (FT_Load_Glyph(m_Face->GetRec(), glyph_index, load_flags))
     return nullptr;
   if (m_pSubstFont && !m_pSubstFont->m_bFlagMM &&
       m_pSubstFont->m_Weight > 400) {
@@ -673,7 +666,7 @@
       level = s_WeightPow_SHIFTJIS[index] * 2 * 65536 / 36655;
     else
       level = s_WeightPow[index] * 2;
-    FT_Outline_Embolden(FXFT_Get_Glyph_Outline(m_Face.Get()), level);
+    FT_Outline_Embolden(FXFT_Get_Glyph_Outline(m_Face->GetRec()), level);
   }
 
   FT_Outline_Funcs funcs;
@@ -690,7 +683,8 @@
   params.m_CurX = params.m_CurY = 0;
   params.m_CoordUnit = 64 * 64.0;
 
-  FT_Outline_Decompose(FXFT_Get_Glyph_Outline(m_Face.Get()), &funcs, &params);
+  FT_Outline_Decompose(FXFT_Get_Glyph_Outline(m_Face->GetRec()), &funcs,
+                       &params);
   if (pPath->GetPoints().empty())
     return nullptr;
 
diff --git a/core/fxge/cfx_font.h b/core/fxge/cfx_font.h
index 8b3fdaf..83b8057 100644
--- a/core/fxge/cfx_font.h
+++ b/core/fxge/cfx_font.h
@@ -13,7 +13,7 @@
 #include "build/build_config.h"
 #include "core/fxcrt/bytestring.h"
 #include "core/fxcrt/fx_coordinates.h"
-#include "core/fxcrt/unowned_ptr.h"
+#include "core/fxge/cfx_face.h"
 #include "core/fxge/fx_freetype.h"
 #include "third_party/base/span.h"
 
@@ -49,17 +49,20 @@
                  bool bVertical);
 
   bool LoadEmbedded(pdfium::span<const uint8_t> src_span);
-  FXFT_FaceRec* GetFaceRec() const { return m_Face.Get(); }
+  RetainPtr<CFX_Face> GetFace() const { return m_Face; }
+  FXFT_FaceRec* GetFaceRec() const {
+    return m_Face ? m_Face->GetRec() : nullptr;
+  }
   CFX_SubstFont* GetSubstFont() const { return m_pSubstFont.get(); }
 
-#ifdef PDF_ENABLE_XFA
+#if defined(PDF_ENABLE_XFA)
   bool LoadFile(const RetainPtr<IFX_SeekableReadStream>& pFile, int nFaceIndex);
 
 #if !defined(OS_WIN)
-  void SetFace(FXFT_FaceRec* face);
+  void SetFace(RetainPtr<CFX_Face> face);
   void SetSubstFont(std::unique_ptr<CFX_SubstFont> subst);
 #endif  // !defined(OS_WIN)
-#endif  // PDF_ENABLE_XFA
+#endif  // defined(PDF_ENABLE_XFA)
 
   const CFX_GlyphBitmap* LoadGlyphBitmap(uint32_t glyph_index,
                                          bool bFontStyle,
@@ -120,24 +123,20 @@
    **/
   static const CharsetFontMap defaultTTFMap[];
 
-#ifdef PDF_ENABLE_XFA
- protected:
-  std::unique_ptr<FXFT_StreamRec> m_pOwnedStream;
-#endif  // PDF_ENABLE_XFA
-
  private:
   RetainPtr<CFX_GlyphCache> GetOrCreateGlyphCache() const;
-  void DeleteFace();
   void ClearGlyphCache();
 #if defined(OS_MACOSX)
   void ReleasePlatformResource();
 #endif
-
   ByteString GetFamilyNameOrUntitled() const;
 
-  mutable UnownedPtr<FXFT_FaceRec> m_Face;
+  mutable RetainPtr<CFX_Face> m_Face;
   mutable RetainPtr<CFX_GlyphCache> m_GlyphCache;
   std::unique_ptr<CFX_SubstFont> m_pSubstFont;
+#if defined(PDF_ENABLE_XFA)
+  std::unique_ptr<FXFT_StreamRec> m_pOwnedStream;
+#endif  // defined(PDF_ENABLE_XFA)
   std::unique_ptr<uint8_t, FxFreeDeleter> m_pGsubData;
   std::vector<uint8_t> m_pFontDataAllocation;
   pdfium::span<uint8_t> m_FontData;
diff --git a/core/fxge/cfx_fontcache.cpp b/core/fxge/cfx_fontcache.cpp
index 571517d..7289026 100644
--- a/core/fxge/cfx_fontcache.cpp
+++ b/core/fxge/cfx_fontcache.cpp
@@ -20,15 +20,15 @@
 CFX_FontCache::~CFX_FontCache() = default;
 
 RetainPtr<CFX_GlyphCache> CFX_FontCache::GetGlyphCache(const CFX_Font* pFont) {
-  FXFT_FaceRec* face = pFont->GetFaceRec();
+  RetainPtr<CFX_Face> face = pFont->GetFace();
   const bool bExternal = !face;
   auto& map = bExternal ? m_ExtGlyphCacheMap : m_GlyphCacheMap;
-  auto it = map.find(face);
+  auto it = map.find(face.Get());
   if (it != map.end() && it->second)
     return pdfium::WrapRetain(it->second.Get());
 
   auto new_cache = pdfium::MakeRetain<CFX_GlyphCache>(face);
-  map[face].Reset(new_cache.Get());
+  map[face.Get()].Reset(new_cache.Get());
   return new_cache;
 }
 
diff --git a/core/fxge/cfx_fontcache.h b/core/fxge/cfx_fontcache.h
index 55a74c6..7036852 100644
--- a/core/fxge/cfx_fontcache.h
+++ b/core/fxge/cfx_fontcache.h
@@ -27,8 +27,8 @@
 #endif
 
  private:
-  std::map<FXFT_FaceRec*, CFX_GlyphCache::ObservedPtr> m_GlyphCacheMap;
-  std::map<FXFT_FaceRec*, CFX_GlyphCache::ObservedPtr> m_ExtGlyphCacheMap;
+  std::map<CFX_Face*, CFX_GlyphCache::ObservedPtr> m_GlyphCacheMap;
+  std::map<CFX_Face*, CFX_GlyphCache::ObservedPtr> m_ExtGlyphCacheMap;
 };
 
 #endif  // CORE_FXGE_CFX_FONTCACHE_H_
diff --git a/core/fxge/cfx_fontmapper.cpp b/core/fxge/cfx_fontmapper.cpp
index c3df1cb..1e17ae6 100644
--- a/core/fxge/cfx_fontmapper.cpp
+++ b/core/fxge/cfx_fontmapper.cpp
@@ -336,20 +336,19 @@
   return ByteString();
 }
 
-FXFT_FaceRec* CFX_FontMapper::UseInternalSubst(CFX_SubstFont* pSubstFont,
-                                               int iBaseFont,
-                                               int italic_angle,
-                                               int weight,
-                                               int pitch_family) {
+RetainPtr<CFX_Face> CFX_FontMapper::UseInternalSubst(CFX_SubstFont* pSubstFont,
+                                                     int iBaseFont,
+                                                     int italic_angle,
+                                                     int weight,
+                                                     int pitch_family) {
   if (iBaseFont < kNumStandardFonts) {
     if (m_FoxitFaces[iBaseFont])
-      return m_FoxitFaces[iBaseFont].get();
+      return m_FoxitFaces[iBaseFont];
     Optional<pdfium::span<const uint8_t>> font_data =
         m_pFontMgr->GetBuiltinFont(iBaseFont);
     if (font_data.has_value()) {
-      m_FoxitFaces[iBaseFont].reset(
-          m_pFontMgr->GetFixedFace(font_data.value(), 0));
-      return m_FoxitFaces[iBaseFont].get();
+      m_FoxitFaces[iBaseFont] = m_pFontMgr->GetFixedFace(font_data.value(), 0);
+      return m_FoxitFaces[iBaseFont];
     }
   }
   pSubstFont->m_bFlagMM = true;
@@ -360,26 +359,26 @@
     pSubstFont->m_Weight = pSubstFont->m_Weight * 4 / 5;
     pSubstFont->m_Family = "Chrome Serif";
     if (!m_MMFaces[1]) {
-      m_MMFaces[1].reset(
-          m_pFontMgr->GetFixedFace(m_pFontMgr->GetBuiltinFont(14).value(), 0));
+      m_MMFaces[1] =
+          m_pFontMgr->GetFixedFace(m_pFontMgr->GetBuiltinFont(14).value(), 0);
     }
-    return m_MMFaces[1].get();
+    return m_MMFaces[1];
   }
   pSubstFont->m_Family = "Chrome Sans";
   if (!m_MMFaces[0]) {
-    m_MMFaces[0].reset(
-        m_pFontMgr->GetFixedFace(m_pFontMgr->GetBuiltinFont(15).value(), 0));
+    m_MMFaces[0] =
+        m_pFontMgr->GetFixedFace(m_pFontMgr->GetBuiltinFont(15).value(), 0);
   }
-  return m_MMFaces[0].get();
+  return m_MMFaces[0];
 }
 
-FXFT_FaceRec* CFX_FontMapper::FindSubstFont(const ByteString& name,
-                                            bool bTrueType,
-                                            uint32_t flags,
-                                            int weight,
-                                            int italic_angle,
-                                            int WindowCP,
-                                            CFX_SubstFont* pSubstFont) {
+RetainPtr<CFX_Face> CFX_FontMapper::FindSubstFont(const ByteString& name,
+                                                  bool bTrueType,
+                                                  uint32_t flags,
+                                                  int weight,
+                                                  int italic_angle,
+                                                  int WindowCP,
+                                                  CFX_SubstFont* pSubstFont) {
   if (weight == 0)
     weight = FXFONT_FW_NORMAL;
 
@@ -625,7 +624,7 @@
     m_pFontInfo->DeleteFont(hFont);
     return nullptr;
   }
-  FXFT_FaceRec* face = nullptr;
+  RetainPtr<CFX_Face> face;
   if (ttc_size)
     face = GetCachedTTCFace(hFont, kTableTTCF, ttc_size, font_size);
   else
@@ -637,13 +636,13 @@
   pSubstFont->m_Family = SubstName;
   pSubstFont->m_Charset = Charset;
   bool bNeedUpdateWeight = false;
-  if (FXFT_Is_Face_Bold(face))
+  if (FXFT_Is_Face_Bold(face->GetRec()))
     bNeedUpdateWeight = weight != FXFONT_FW_BOLD;
   else
     bNeedUpdateWeight = weight != FXFONT_FW_NORMAL;
   if (bNeedUpdateWeight)
     pSubstFont->m_Weight = weight;
-  if (bItalic && !FXFT_Is_Face_Italic(face)) {
+  if (bItalic && !FXFT_Is_Face_Italic(face->GetRec())) {
     if (italic_angle == 0)
       italic_angle = -12;
     else if (abs(italic_angle) < 5)
@@ -658,22 +657,22 @@
   return pdfium::CollectionSize<int>(m_FaceArray);
 }
 
-bool CFX_FontMapper::IsBuiltinFace(const FXFT_FaceRec* face) const {
+bool CFX_FontMapper::IsBuiltinFace(const RetainPtr<CFX_Face>& face) const {
   for (size_t i = 0; i < MM_FACE_COUNT; ++i) {
-    if (m_MMFaces[i].get() == face)
+    if (m_MMFaces[i] == face)
       return true;
   }
   for (size_t i = 0; i < FOXIT_FACE_COUNT; ++i) {
-    if (m_FoxitFaces[i].get() == face)
+    if (m_FoxitFaces[i] == face)
       return true;
   }
   return false;
 }
 
-FXFT_FaceRec* CFX_FontMapper::GetCachedTTCFace(void* hFont,
-                                               const uint32_t tableTTCF,
-                                               uint32_t ttc_size,
-                                               uint32_t font_size) {
+RetainPtr<CFX_Face> CFX_FontMapper::GetCachedTTCFace(void* hFont,
+                                                     const uint32_t tableTTCF,
+                                                     uint32_t ttc_size,
+                                                     uint32_t font_size) {
   uint32_t checksum = 0;
   {
     uint8_t buffer[1024];
@@ -683,7 +682,7 @@
       checksum += pBuffer[i];
   }
   uint8_t* pIgnore = nullptr;
-  FXFT_FaceRec* face = m_pFontMgr->GetCachedTTCFace(
+  RetainPtr<CFX_Face> face = m_pFontMgr->GetCachedTTCFace(
       ttc_size, checksum, ttc_size - font_size, &pIgnore);
   if (face)
     return face;
@@ -695,13 +694,13 @@
                                       ttc_size, ttc_size - font_size);
 }
 
-FXFT_FaceRec* CFX_FontMapper::GetCachedFace(void* hFont,
-                                            ByteString SubstName,
-                                            int weight,
-                                            bool bItalic,
-                                            uint32_t font_size) {
+RetainPtr<CFX_Face> CFX_FontMapper::GetCachedFace(void* hFont,
+                                                  ByteString SubstName,
+                                                  int weight,
+                                                  bool bItalic,
+                                                  uint32_t font_size) {
   uint8_t* pIgnore = nullptr;
-  FXFT_FaceRec* face =
+  RetainPtr<CFX_Face> face =
       m_pFontMgr->GetCachedFace(SubstName, weight, bItalic, &pIgnore);
   if (face)
     return face;
diff --git a/core/fxge/cfx_fontmapper.h b/core/fxge/cfx_fontmapper.h
index 7b9b00b..532448a 100644
--- a/core/fxge/cfx_fontmapper.h
+++ b/core/fxge/cfx_fontmapper.h
@@ -12,7 +12,7 @@
 #include <vector>
 
 #include "core/fxcrt/fx_string.h"
-#include "core/fxge/fx_freetype.h"
+#include "core/fxge/cfx_face.h"
 
 class CFX_FontMgr;
 class CFX_SubstFont;
@@ -30,15 +30,15 @@
   void AddInstalledFont(const ByteString& name, int charset);
   void LoadInstalledFonts();
 
-  FXFT_FaceRec* FindSubstFont(const ByteString& face_name,
-                              bool bTrueType,
-                              uint32_t flags,
-                              int weight,
-                              int italic_angle,
-                              int CharsetCP,
-                              CFX_SubstFont* pSubstFont);
+  RetainPtr<CFX_Face> FindSubstFont(const ByteString& face_name,
+                                    bool bTrueType,
+                                    uint32_t flags,
+                                    int weight,
+                                    int italic_angle,
+                                    int CharsetCP,
+                                    CFX_SubstFont* pSubstFont);
 
-  bool IsBuiltinFace(const FXFT_FaceRec* face) const;
+  bool IsBuiltinFace(const RetainPtr<CFX_Face>& face) const;
   int GetFaceSize() const;
   ByteString GetFaceName(int index) const { return m_FaceArray[index].name; }
 
@@ -51,20 +51,20 @@
 
   ByteString GetPSNameFromTT(void* hFont);
   ByteString MatchInstalledFonts(const ByteString& norm_name);
-  FXFT_FaceRec* UseInternalSubst(CFX_SubstFont* pSubstFont,
-                                 int iBaseFont,
-                                 int italic_angle,
-                                 int weight,
-                                 int picthfamily);
-  FXFT_FaceRec* GetCachedTTCFace(void* hFont,
-                                 const uint32_t tableTTCF,
-                                 uint32_t ttc_size,
-                                 uint32_t font_size);
-  FXFT_FaceRec* GetCachedFace(void* hFont,
-                              ByteString SubstName,
-                              int weight,
-                              bool bItalic,
-                              uint32_t font_size);
+  RetainPtr<CFX_Face> UseInternalSubst(CFX_SubstFont* pSubstFont,
+                                       int iBaseFont,
+                                       int italic_angle,
+                                       int weight,
+                                       int picthfamily);
+  RetainPtr<CFX_Face> GetCachedTTCFace(void* hFont,
+                                       const uint32_t tableTTCF,
+                                       uint32_t ttc_size,
+                                       uint32_t font_size);
+  RetainPtr<CFX_Face> GetCachedFace(void* hFont,
+                                    ByteString SubstName,
+                                    int weight,
+                                    bool bItalic,
+                                    uint32_t font_size);
 
   struct FaceData {
     ByteString name;
@@ -76,8 +76,8 @@
   std::vector<FaceData> m_FaceArray;
   std::unique_ptr<SystemFontInfoIface> m_pFontInfo;
   UnownedPtr<CFX_FontMgr> const m_pFontMgr;
-  ScopedFXFTFaceRec m_MMFaces[MM_FACE_COUNT];
-  ScopedFXFTFaceRec m_FoxitFaces[FOXIT_FACE_COUNT];
+  RetainPtr<CFX_Face> m_MMFaces[MM_FACE_COUNT];
+  RetainPtr<CFX_Face> m_FoxitFaces[FOXIT_FACE_COUNT];
 };
 
 #endif  // CORE_FXGE_CFX_FONTMAPPER_H_
diff --git a/core/fxge/cfx_fontmgr.cpp b/core/fxge/cfx_fontmgr.cpp
index 28a7e1e..2961e18 100644
--- a/core/fxge/cfx_fontmgr.cpp
+++ b/core/fxge/cfx_fontmgr.cpp
@@ -97,33 +97,32 @@
   m_pBuiltinMapper->SetSystemFontInfo(std::move(pFontInfo));
 }
 
-FXFT_FaceRec* CFX_FontMgr::FindSubstFont(const ByteString& face_name,
-                                         bool bTrueType,
-                                         uint32_t flags,
-                                         int weight,
-                                         int italic_angle,
-                                         int CharsetCP,
-                                         CFX_SubstFont* pSubstFont) {
+RetainPtr<CFX_Face> CFX_FontMgr::FindSubstFont(const ByteString& face_name,
+                                               bool bTrueType,
+                                               uint32_t flags,
+                                               int weight,
+                                               int italic_angle,
+                                               int CharsetCP,
+                                               CFX_SubstFont* pSubstFont) {
   InitFTLibrary();
   return m_pBuiltinMapper->FindSubstFont(face_name, bTrueType, flags, weight,
                                          italic_angle, CharsetCP, pSubstFont);
 }
 
-FXFT_FaceRec* CFX_FontMgr::GetCachedFace(const ByteString& face_name,
-                                         int weight,
-                                         bool bItalic,
-                                         uint8_t** pFontData) {
+RetainPtr<CFX_Face> CFX_FontMgr::GetCachedFace(const ByteString& face_name,
+                                               int weight,
+                                               bool bItalic,
+                                               uint8_t** pFontData) {
   auto it = m_FaceMap.find(KeyNameFromFace(face_name, weight, bItalic));
   if (it == m_FaceMap.end())
     return nullptr;
 
   CTTFontDesc* pFontDesc = it->second.get();
   *pFontData = pFontDesc->FontData();
-  pFontDesc->AddRef();
   return pFontDesc->GetFace(0);
 }
 
-FXFT_FaceRec* CFX_FontMgr::AddCachedFace(
+RetainPtr<CFX_Face> CFX_FontMgr::AddCachedFace(
     const ByteString& face_name,
     int weight,
     bool bItalic,
@@ -132,27 +131,26 @@
     int face_index) {
   InitFTLibrary();
 
-  FXFT_FaceRec* face = nullptr;
-  int ret = FT_New_Memory_Face(m_FTLibrary.get(), pData.get(), size, face_index,
-                               &face);
-  if (ret)
+  RetainPtr<CFX_Face> face =
+      CFX_Face::New(m_FTLibrary.get(), {pData.get(), size}, face_index);
+  if (!face)
     return nullptr;
 
-  ret = FT_Set_Pixel_Sizes(face, 64, 64);
-  if (ret)
+  if (FT_Set_Pixel_Sizes(face->GetRec(), 64, 64) != 0)
     return nullptr;
 
   auto pFontDesc = pdfium::MakeUnique<CTTFontDesc>(std::move(pData));
-  pFontDesc->SetFace(0, face);
+  pFontDesc->SetFace(0, std::move(face));
+
   CTTFontDesc* pResult = pFontDesc.get();
   m_FaceMap[KeyNameFromFace(face_name, weight, bItalic)] = std::move(pFontDesc);
   return pResult->GetFace(0);
 }
 
-FXFT_FaceRec* CFX_FontMgr::GetCachedTTCFace(int ttc_size,
-                                            uint32_t checksum,
-                                            int font_offset,
-                                            uint8_t** pFontData) {
+RetainPtr<CFX_Face> CFX_FontMgr::GetCachedTTCFace(int ttc_size,
+                                                  uint32_t checksum,
+                                                  int font_offset,
+                                                  uint8_t** pFontData) {
   auto it = m_FaceMap.find(KeyNameFromSize(ttc_size, checksum));
   if (it == m_FaceMap.end())
     return nullptr;
@@ -165,18 +163,17 @@
                                                  static_cast<size_t>(ttc_size)},
                                                 face_index));
   }
-  pFontDesc->AddRef();
   return pFontDesc->GetFace(face_index);
 }
 
-FXFT_FaceRec* CFX_FontMgr::AddCachedTTCFace(
+RetainPtr<CFX_Face> CFX_FontMgr::AddCachedTTCFace(
     int ttc_size,
     uint32_t checksum,
     std::unique_ptr<uint8_t, FxFreeDeleter> pData,
     uint32_t size,
     int font_offset) {
   int face_index = GetTTCIndex(pData.get(), ttc_size, font_offset);
-  FXFT_FaceRec* face =
+  RetainPtr<CFX_Face> face =
       GetFixedFace({pData.get(), static_cast<size_t>(ttc_size)}, face_index);
   auto pFontDesc = pdfium::MakeUnique<CTTFontDesc>(std::move(pData));
   pFontDesc->SetFace(face_index, face);
@@ -184,32 +181,17 @@
   return face;
 }
 
-FXFT_FaceRec* CFX_FontMgr::GetFixedFace(pdfium::span<const uint8_t> span,
-                                        int face_index) {
+RetainPtr<CFX_Face> CFX_FontMgr::GetFixedFace(pdfium::span<const uint8_t> span,
+                                              int face_index) {
   InitFTLibrary();
-  FXFT_FaceRec* face = nullptr;
-  if (FT_New_Memory_Face(m_FTLibrary.get(), span.data(), span.size(),
-                         face_index, &face)) {
-    return nullptr;
-  }
-  return FT_Set_Pixel_Sizes(face, 64, 64) ? nullptr : face;
-}
-
-void CFX_FontMgr::ReleaseFace(FXFT_FaceRec* face) {
+  RetainPtr<CFX_Face> face = CFX_Face::New(m_FTLibrary.get(), span, face_index);
   if (!face)
-    return;
-  bool bNeedFaceDone = true;
-  for (auto it = m_FaceMap.begin(); it != m_FaceMap.end(); ++it) {
-    CTTFontDesc::ReleaseStatus nRet = it->second->ReleaseFace(face);
-    if (nRet == CTTFontDesc::kNotAppropriate)
-      continue;
-    bNeedFaceDone = false;
-    if (nRet == CTTFontDesc::kReleased)
-      m_FaceMap.erase(it);
-    break;
-  }
-  if (bNeedFaceDone && !m_pBuiltinMapper->IsBuiltinFace(face))
-    FT_Done_Face(face);
+    return nullptr;
+
+  if (FT_Set_Pixel_Sizes(face->GetRec(), 64, 64) != 0)
+    return nullptr;
+
+  return face;
 }
 
 // static
diff --git a/core/fxge/cfx_fontmgr.h b/core/fxge/cfx_fontmgr.h
index bb388db..18fe9ad 100644
--- a/core/fxge/cfx_fontmgr.h
+++ b/core/fxge/cfx_fontmgr.h
@@ -12,6 +12,7 @@
 
 #include "core/fxcrt/fx_memory.h"
 #include "core/fxcrt/fx_string.h"
+#include "core/fxge/cfx_face.h"
 #include "core/fxge/fx_freetype.h"
 #include "third_party/base/optional.h"
 #include "third_party/base/span.h"
@@ -30,35 +31,38 @@
 
   void InitFTLibrary();
 
-  FXFT_FaceRec* GetCachedFace(const ByteString& face_name,
-                              int weight,
-                              bool bItalic,
-                              uint8_t** pFontData);
-  FXFT_FaceRec* AddCachedFace(const ByteString& face_name,
-                              int weight,
-                              bool bItalic,
-                              std::unique_ptr<uint8_t, FxFreeDeleter> pData,
-                              uint32_t size,
-                              int face_index);
-  FXFT_FaceRec* GetCachedTTCFace(int ttc_size,
-                                 uint32_t checksum,
-                                 int font_offset,
-                                 uint8_t** pFontData);
-  FXFT_FaceRec* AddCachedTTCFace(int ttc_size,
-                                 uint32_t checksum,
-                                 std::unique_ptr<uint8_t, FxFreeDeleter> pData,
-                                 uint32_t size,
-                                 int font_offset);
-  FXFT_FaceRec* GetFixedFace(pdfium::span<const uint8_t> span, int face_index);
-  void ReleaseFace(FXFT_FaceRec* face);
+  RetainPtr<CFX_Face> GetCachedFace(const ByteString& face_name,
+                                    int weight,
+                                    bool bItalic,
+                                    uint8_t** pFontData);
+  RetainPtr<CFX_Face> AddCachedFace(
+      const ByteString& face_name,
+      int weight,
+      bool bItalic,
+      std::unique_ptr<uint8_t, FxFreeDeleter> pData,
+      uint32_t size,
+      int face_index);
+  RetainPtr<CFX_Face> GetCachedTTCFace(int ttc_size,
+                                       uint32_t checksum,
+                                       int font_offset,
+                                       uint8_t** pFontData);
+  RetainPtr<CFX_Face> AddCachedTTCFace(
+      int ttc_size,
+      uint32_t checksum,
+      std::unique_ptr<uint8_t, FxFreeDeleter> pData,
+      uint32_t size,
+      int font_offset);
+  RetainPtr<CFX_Face> GetFixedFace(pdfium::span<const uint8_t> span,
+                                   int face_index);
+  void ReleaseFace(RetainPtr<CFX_Face> face);
   void SetSystemFontInfo(std::unique_ptr<SystemFontInfoIface> pFontInfo);
-  FXFT_FaceRec* FindSubstFont(const ByteString& face_name,
-                              bool bTrueType,
-                              uint32_t flags,
-                              int weight,
-                              int italic_angle,
-                              int CharsetCP,
-                              CFX_SubstFont* pSubstFont);
+  RetainPtr<CFX_Face> FindSubstFont(const ByteString& face_name,
+                                    bool bTrueType,
+                                    uint32_t flags,
+                                    int weight,
+                                    int italic_angle,
+                                    int CharsetCP,
+                                    CFX_SubstFont* pSubstFont);
 
   // Always present.
   CFX_FontMapper* GetBuiltinMapper() const { return m_pBuiltinMapper.get(); }
diff --git a/core/fxge/cfx_glyphcache.cpp b/core/fxge/cfx_glyphcache.cpp
index 8d7a302..80e33d4 100644
--- a/core/fxge/cfx_glyphcache.cpp
+++ b/core/fxge/cfx_glyphcache.cpp
@@ -95,7 +95,7 @@
 
 }  // namespace
 
-CFX_GlyphCache::CFX_GlyphCache(FXFT_FaceRec* face) : m_Face(face) {}
+CFX_GlyphCache::CFX_GlyphCache(RetainPtr<CFX_Face> face) : m_Face(face) {}
 
 CFX_GlyphCache::~CFX_GlyphCache() = default;
 
@@ -142,7 +142,7 @@
                             pFont->GetSubstFont()->m_Weight);
     }
   }
-  ScopedFontTransform scoped_transform(GetFaceRec(), &ft_matrix);
+  ScopedFontTransform scoped_transform(GetFace(), &ft_matrix);
   int load_flags = (GetFaceRec()->face_flags & FT_FACE_FLAG_SFNT)
                        ? FT_LOAD_NO_BITMAP
                        : (FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING);
diff --git a/core/fxge/cfx_glyphcache.h b/core/fxge/cfx_glyphcache.h
index 7cdc5a4..165359c 100644
--- a/core/fxge/cfx_glyphcache.h
+++ b/core/fxge/cfx_glyphcache.h
@@ -14,7 +14,7 @@
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/observed_ptr.h"
 #include "core/fxcrt/retain_ptr.h"
-#include "core/fxge/fx_freetype.h"
+#include "core/fxge/cfx_face.h"
 
 #if defined _SKIA_SUPPORT_ || _SKIA_SUPPORT_PATHS_
 #include "core/fxge/fx_font.h"
@@ -44,14 +44,15 @@
                                     uint32_t glyph_index,
                                     uint32_t dest_width);
 
-  FXFT_FaceRec* GetFaceRec() { return m_Face; }
+  RetainPtr<CFX_Face> GetFace() { return m_Face; }
+  FXFT_FaceRec* GetFaceRec() { return m_Face ? m_Face->GetRec() : nullptr; }
 
 #if defined _SKIA_SUPPORT_ || _SKIA_SUPPORT_PATHS_
   CFX_TypeFace* GetDeviceCache(const CFX_Font* pFont);
 #endif
 
  private:
-  explicit CFX_GlyphCache(FXFT_FaceRec* face);
+  explicit CFX_GlyphCache(RetainPtr<CFX_Face> face);
 
   using SizeGlyphCache = std::map<uint32_t, std::unique_ptr<CFX_GlyphBitmap>>;
   // <glyph_index, width, weight, angle, vertical>
@@ -79,7 +80,7 @@
   void InitPlatform();
   void DestroyPlatform();
 
-  FXFT_FaceRec* const m_Face;
+  RetainPtr<CFX_Face> const m_Face;
   std::map<ByteString, SizeGlyphCache> m_SizeMap;
   std::map<PathMapKey, std::unique_ptr<CFX_PathData>> m_PathMap;
 #if defined _SKIA_SUPPORT_ || _SKIA_SUPPORT_PATHS_
diff --git a/core/fxge/cttfontdesc.cpp b/core/fxge/cttfontdesc.cpp
index ff01e4f..9d504bb 100644
--- a/core/fxge/cttfontdesc.cpp
+++ b/core/fxge/cttfontdesc.cpp
@@ -8,42 +8,18 @@
 
 #include <utility>
 
-#include "core/fxge/fx_freetype.h"
-#include "third_party/base/stl_util.h"
-
 CTTFontDesc::CTTFontDesc(std::unique_ptr<uint8_t, FxFreeDeleter> pData)
     : m_pFontData(std::move(pData)) {
-  for (size_t i = 0; i < FX_ArraySize(m_TTCFaces); i++)
-    m_TTCFaces[i] = nullptr;
 }
 
-CTTFontDesc::~CTTFontDesc() {
-  ASSERT(m_RefCount == 0);
-  for (size_t i = 0; i < FX_ArraySize(m_TTCFaces); i++) {
-    if (m_TTCFaces[i])
-      FT_Done_Face(m_TTCFaces[i]);
-  }
-}
+CTTFontDesc::~CTTFontDesc() = default;
 
-void CTTFontDesc::SetFace(size_t index, FXFT_FaceRec* face) {
+void CTTFontDesc::SetFace(size_t index, const RetainPtr<CFX_Face>& face) {
   ASSERT(index < FX_ArraySize(m_TTCFaces));
-  m_TTCFaces[index] = face;
+  m_TTCFaces[index].Reset(face.Get());
 }
 
-void CTTFontDesc::AddRef() {
-  ASSERT(m_RefCount > 0);
-  ++m_RefCount;
-}
-
-CTTFontDesc::ReleaseStatus CTTFontDesc::ReleaseFace(FXFT_FaceRec* face) {
-  if (!pdfium::ContainsValue(m_TTCFaces, face))
-    return kNotAppropriate;
-
-  ASSERT(m_RefCount > 0);
-  return --m_RefCount == 0 ? kReleased : kNotReleased;
-}
-
-FXFT_FaceRec* CTTFontDesc::GetFace(size_t index) const {
+RetainPtr<CFX_Face> CTTFontDesc::GetFace(size_t index) const {
   ASSERT(index < FX_ArraySize(m_TTCFaces));
-  return m_TTCFaces[index];
+  return pdfium::WrapRetain(m_TTCFaces[index].Get());
 }
diff --git a/core/fxge/cttfontdesc.h b/core/fxge/cttfontdesc.h
index 624b576..e79d89a 100644
--- a/core/fxge/cttfontdesc.h
+++ b/core/fxge/cttfontdesc.h
@@ -11,33 +11,20 @@
 
 #include "core/fxcrt/fx_memory.h"
 #include "core/fxcrt/fx_system.h"
-#include "core/fxge/fx_freetype.h"
+#include "core/fxge/cfx_face.h"
 
 class CTTFontDesc {
  public:
-  enum ReleaseStatus {
-    kNotAppropriate,  // ReleaseFace() not appropriate for given object.
-    kReleased,
-    kNotReleased  // Object still alive.
-  };
-
   explicit CTTFontDesc(std::unique_ptr<uint8_t, FxFreeDeleter> pData);
   ~CTTFontDesc();
 
-  void SetFace(size_t index, FXFT_FaceRec* face);
-
-  void AddRef();
-
-  // May not decrement refcount, depending on the value of |face|.
-  ReleaseStatus ReleaseFace(FXFT_FaceRec* face);
-
   uint8_t* FontData() const { return m_pFontData.get(); }
-  FXFT_FaceRec* GetFace(size_t index) const;
+  void SetFace(size_t index, const RetainPtr<CFX_Face>& face);
+  RetainPtr<CFX_Face> GetFace(size_t index) const;
 
  private:
-  int m_RefCount = 1;
   std::unique_ptr<uint8_t, FxFreeDeleter> const m_pFontData;
-  FXFT_FaceRec* m_TTCFaces[16];
+  CFX_Face::ObservedPtr m_TTCFaces[16];
 };
 
 #endif  // CORE_FXGE_CTTFONTDESC_H_
diff --git a/core/fxge/scoped_font_transform.cpp b/core/fxge/scoped_font_transform.cpp
index ef3b5cf..2bd5396 100644
--- a/core/fxge/scoped_font_transform.cpp
+++ b/core/fxge/scoped_font_transform.cpp
@@ -6,6 +6,8 @@
 
 #include "core/fxge/scoped_font_transform.h"
 
+#include <utility>
+
 namespace {
 
 void ResetTransform(FT_Face face) {
@@ -19,11 +21,12 @@
 
 }  // namespace
 
-ScopedFontTransform::ScopedFontTransform(FT_Face face, FT_Matrix* matrix)
-    : m_Face(face) {
-  FT_Set_Transform(m_Face, matrix, 0);
+ScopedFontTransform::ScopedFontTransform(RetainPtr<CFX_Face> face,
+                                         FT_Matrix* matrix)
+    : m_Face(std::move(face)) {
+  FT_Set_Transform(m_Face->GetRec(), matrix, 0);
 }
 
 ScopedFontTransform::~ScopedFontTransform() {
-  ResetTransform(m_Face);
+  ResetTransform(m_Face->GetRec());
 }
diff --git a/core/fxge/scoped_font_transform.h b/core/fxge/scoped_font_transform.h
index 3f33f40..bcbbb50 100644
--- a/core/fxge/scoped_font_transform.h
+++ b/core/fxge/scoped_font_transform.h
@@ -7,17 +7,18 @@
 #ifndef CORE_FXGE_SCOPED_FONT_TRANSFORM_H_
 #define CORE_FXGE_SCOPED_FONT_TRANSFORM_H_
 
+#include "core/fxge/cfx_face.h"
 #include "core/fxge/fx_freetype.h"
 
 // Sets the given transform on the font, and resets it to the identity when it
 // goes out of scope.
 class ScopedFontTransform {
  public:
-  ScopedFontTransform(FT_Face face, FT_Matrix* matrix);
+  ScopedFontTransform(RetainPtr<CFX_Face> face, FT_Matrix* matrix);
   ~ScopedFontTransform();
 
  private:
-  FT_Face m_Face;
+  RetainPtr<CFX_Face> m_Face;
 };
 
 #endif  // CORE_FXGE_SCOPED_FONT_TRANSFORM_H_
diff --git a/xfa/fde/cfde_textout.cpp b/xfa/fde/cfde_textout.cpp
index 4ae263a..eb21c93 100644
--- a/xfa/fde/cfde_textout.cpp
+++ b/xfa/fde/cfde_textout.cpp
@@ -79,7 +79,7 @@
 
         CFX_Font* font;
 #if !defined(OS_WIN)
-        FxFont.SetFace(pFxFont->GetFaceRec());
+        FxFont.SetFace(pFxFont->GetFace());
         font = &FxFont;
 #else
         font = pFxFont;
@@ -101,7 +101,7 @@
     pFxFont = pCurFont->GetDevFont();
     CFX_Font* font;
 #if !defined(OS_WIN)
-    FxFont.SetFace(pFxFont->GetFaceRec());
+    FxFont.SetFace(pFxFont->GetFace());
     font = &FxFont;
 #else
     font = pFxFont;
diff --git a/xfa/fgas/font/cfgas_fontmgr.cpp b/xfa/fgas/font/cfgas_fontmgr.cpp
index 51f46a4..e956845 100644
--- a/xfa/fgas/font/cfgas_fontmgr.cpp
+++ b/xfa/fgas/font/cfgas_fontmgr.cpp
@@ -31,13 +31,17 @@
 namespace {
 
 bool VerifyUnicode(const RetainPtr<CFGAS_GEFont>& pFont, wchar_t wcUnicode) {
-  FXFT_FaceRec* pFace = pFont->GetDevFont()->GetFaceRec();
-  FT_CharMap charmap = FXFT_Get_Face_Charmap(pFace);
-  if (FXFT_Select_Charmap(pFace, FT_ENCODING_UNICODE) != 0)
+  RetainPtr<CFX_Face> pFace = pFont->GetDevFont()->GetFace();
+  if (!pFace)
     return false;
 
-  if (FT_Get_Char_Index(pFace, wcUnicode) == 0) {
-    FT_Set_Charmap(pFace, charmap);
+  FXFT_FaceRec* pFaceRec = pFace->GetRec();
+  FT_CharMap charmap = FXFT_Get_Face_Charmap(pFaceRec);
+  if (FXFT_Select_Charmap(pFaceRec, FT_ENCODING_UNICODE) != 0)
+    return false;
+
+  if (FT_Get_Char_Index(pFaceRec, wcUnicode) == 0) {
+    FT_Set_Charmap(pFaceRec, charmap);
     return false;
   }
   return true;
@@ -476,8 +480,9 @@
   return nullptr;
 }
 
-FXFT_FaceRec* LoadFace(const RetainPtr<IFX_SeekableReadStream>& pFontStream,
-                       int32_t iFaceIndex) {
+RetainPtr<CFX_Face> LoadFace(
+    const RetainPtr<IFX_SeekableReadStream>& pFontStream,
+    int32_t iFaceIndex) {
   if (!pFontStream)
     return nullptr;
 
@@ -507,13 +512,12 @@
   ftArgs.flags |= FT_OPEN_STREAM;
   ftArgs.stream = ftStream;
 
-  FXFT_FaceRec* pFace = nullptr;
-  if (FT_Open_Face(library, &ftArgs, iFaceIndex, &pFace)) {
+  RetainPtr<CFX_Face> pFace = CFX_Face::Open(library, &ftArgs, iFaceIndex);
+  if (!pFace) {
     ft_sfree(ftStream);
     return nullptr;
   }
-
-  FT_Set_Pixel_Sizes(pFace, 0, 64);
+  FT_Set_Pixel_Sizes(pFace->GetRec(), 0, 64);
   return pFace;
 }
 
@@ -524,17 +528,17 @@
   if (!pFileRead)
     return false;
 
-  FXFT_FaceRec* pFace = LoadFace(pFileRead, pDesc->m_nFaceIndex);
+  RetainPtr<CFX_Face> pFace = LoadFace(pFileRead, pDesc->m_nFaceIndex);
   if (!pFace)
     return false;
 
-  FT_Error retCharmap = FXFT_Select_Charmap(pFace, FT_ENCODING_UNICODE);
-  FT_Error retIndex = FT_Get_Char_Index(pFace, wcUnicode);
+  FT_Error retCharmap =
+      FXFT_Select_Charmap(pFace->GetRec(), FT_ENCODING_UNICODE);
+  FT_Error retIndex = FT_Get_Char_Index(pFace->GetRec(), wcUnicode);
 
-  if (FXFT_Get_Face_External_Stream(pFace))
-    FXFT_Clear_Face_External_Stream(pFace);
+  if (FXFT_Get_Face_External_Stream(pFace->GetRec()))
+    FXFT_Clear_Face_External_Stream(pFace->GetRec());
 
-  FT_Done_Face(pFace);
   return !retCharmap && retIndex;
 }
 
@@ -743,33 +747,36 @@
   std::sort(pMatchedFonts->begin(), pMatchedFonts->end());
 }
 
-void CFGAS_FontMgr::RegisterFace(FXFT_FaceRec* pFace,
+void CFGAS_FontMgr::RegisterFace(RetainPtr<CFX_Face> pFace,
                                  const WideString* pFaceName) {
-  if ((pFace->face_flags & FT_FACE_FLAG_SCALABLE) == 0)
+  if ((pFace->GetRec()->face_flags & FT_FACE_FLAG_SCALABLE) == 0)
     return;
 
   auto pFont = pdfium::MakeUnique<CFX_FontDescriptor>();
-  pFont->m_dwFontStyles |= GetFlags(pFace);
+  pFont->m_dwFontStyles |= GetFlags(pFace->GetRec());
 
-  GetUSBCSB(pFace, pFont->m_dwUsb, pFont->m_dwCsb);
+  GetUSBCSB(pFace->GetRec(), pFont->m_dwUsb, pFont->m_dwCsb);
 
   FT_ULong dwTag;
   FT_ENC_TAG(dwTag, 'n', 'a', 'm', 'e');
 
   std::vector<uint8_t> table;
   unsigned long nLength = 0;
-  unsigned int error = FT_Load_Sfnt_Table(pFace, dwTag, 0, nullptr, &nLength);
+  unsigned int error =
+      FT_Load_Sfnt_Table(pFace->GetRec(), dwTag, 0, nullptr, &nLength);
   if (error == 0 && nLength != 0) {
     table.resize(nLength);
-    if (FT_Load_Sfnt_Table(pFace, dwTag, 0, table.data(), nullptr))
+    if (FT_Load_Sfnt_Table(pFace->GetRec(), dwTag, 0, table.data(), nullptr))
       table.clear();
   }
   pFont->m_wsFamilyNames = GetNames(table.empty() ? nullptr : table.data());
-  pFont->m_wsFamilyNames.push_back(WideString::FromUTF8(pFace->family_name));
+  pFont->m_wsFamilyNames.push_back(
+      WideString::FromUTF8(pFace->GetRec()->family_name));
   pFont->m_wsFaceName =
-      pFaceName ? *pFaceName
-                : WideString::FromDefANSI(FT_Get_Postscript_Name(pFace));
-  pFont->m_nFaceIndex = pFace->face_index;
+      pFaceName
+          ? *pFaceName
+          : WideString::FromDefANSI(FT_Get_Postscript_Name(pFace->GetRec()));
+  pFont->m_nFaceIndex = pFace->GetRec()->face_index;
   m_InstalledFonts.push_back(std::move(pFont));
 }
 
@@ -779,16 +786,15 @@
   int32_t index = 0;
   int32_t num_faces = 0;
   do {
-    FXFT_FaceRec* pFace = LoadFace(pFontStream, index++);
+    RetainPtr<CFX_Face> pFace = LoadFace(pFontStream, index++);
     if (!pFace)
       continue;
     // All faces keep number of faces. It can be retrieved from any one face.
     if (num_faces == 0)
-      num_faces = pFace->num_faces;
+      num_faces = pFace->GetRec()->num_faces;
     RegisterFace(pFace, pFaceName);
-    if (FXFT_Get_Face_External_Stream(pFace))
-      FXFT_Clear_Face_External_Stream(pFace);
-    FT_Done_Face(pFace);
+    if (FXFT_Get_Face_External_Stream(pFace->GetRec()))
+      FXFT_Clear_Face_External_Stream(pFace->GetRec());
   } while (index < num_faces);
 }
 
diff --git a/xfa/fgas/font/cfgas_fontmgr.h b/xfa/fgas/font/cfgas_fontmgr.h
index 9dff7e4..b8eca58 100644
--- a/xfa/fgas/font/cfgas_fontmgr.h
+++ b/xfa/fgas/font/cfgas_fontmgr.h
@@ -133,7 +133,7 @@
 #else   // defined(OS_WIN)
   bool EnumFontsFromFontMapper();
   bool EnumFontsFromFiles();
-  void RegisterFace(FXFT_FaceRec* pFace, const WideString* pFaceName);
+  void RegisterFace(RetainPtr<CFX_Face> pFace, const WideString* pFaceName);
   void RegisterFaces(const RetainPtr<IFX_SeekableReadStream>& pFontStream,
                      const WideString* pFaceName);
   void MatchFonts(std::vector<CFX_FontDescriptorInfo>* MatchedFonts,