Remove some knowledge of fpdfapi/page types from CPDF_Document

Instead, implement the methods in CPDF_DocPageData, which is at a
higher level and has knowledge of page types (many of these are
just callbacks into the doc page data anyways). This gets us part
way to removing the circular include between fpdfapi/parser and
fpdfapi/page.

Change-Id: I4d6cd13bce12778799a21c0e3d7eef1d4bb5c99d
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/55630
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp
index 1ce21f4..789656c 100644
--- a/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp
+++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp
@@ -10,6 +10,7 @@
 #include "core/fpdfapi/cpdf_modulemgr.h"
 #include "core/fpdfapi/font/cpdf_font.h"
 #include "core/fpdfapi/page/cpdf_colorspace.h"
+#include "core/fpdfapi/page/cpdf_docpagedata.h"
 #include "core/fpdfapi/page/cpdf_form.h"
 #include "core/fpdfapi/page/cpdf_page.h"
 #include "core/fpdfapi/page/cpdf_pathobject.h"
@@ -317,7 +318,7 @@
     pDict->SetNewFor<CPDF_Reference>("FontDescriptor", pDoc.get(),
                                      pDesc->GetObjNum());
 
-    CPDF_Font* loadedFont = pDoc->LoadFont(pDict);
+    CPDF_Font* loadedFont = pDoc->GetPageData()->GetFont(pDict);
     pTextObj->m_TextState.SetFont(loadedFont);
     pTextObj->m_TextState.SetFontSize(15.5f);
     pTextObj->SetText("I am indirect");
diff --git a/core/fpdfapi/page/cpdf_docpagedata.cpp b/core/fpdfapi/page/cpdf_docpagedata.cpp
index 452f1a0..eb67fe1 100644
--- a/core/fpdfapi/page/cpdf_docpagedata.cpp
+++ b/core/fpdfapi/page/cpdf_docpagedata.cpp
@@ -10,7 +10,9 @@
 #include <memory>
 #include <set>
 #include <utility>
+#include <vector>
 
+#include "build/build_config.h"
 #include "core/fdrm/fx_crypt.h"
 #include "core/fpdfapi/font/cpdf_type1font.h"
 #include "core/fpdfapi/page/cpdf_iccprofile.h"
@@ -23,12 +25,138 @@
 #include "core/fpdfapi/parser/cpdf_dictionary.h"
 #include "core/fpdfapi/parser/cpdf_document.h"
 #include "core/fpdfapi/parser/cpdf_name.h"
+#include "core/fpdfapi/parser/cpdf_number.h"
+#include "core/fpdfapi/parser/cpdf_reference.h"
 #include "core/fpdfapi/parser/cpdf_stream.h"
 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
+#include "core/fpdfapi/parser/cpdf_string.h"
+#include "core/fxcrt/fx_codepage.h"
 #include "core/fxcrt/fx_safe_types.h"
+#include "core/fxge/cfx_font.h"
+#include "core/fxge/cfx_fontmapper.h"
+#include "core/fxge/cfx_substfont.h"
+#include "core/fxge/cfx_unicodeencoding.h"
+#include "core/fxge/fx_font.h"
 #include "third_party/base/ptr_util.h"
 #include "third_party/base/stl_util.h"
 
+namespace {
+
+void InsertWidthArrayImpl(std::vector<int> widths, CPDF_Array* pWidthArray) {
+  size_t i;
+  for (i = 1; i < widths.size(); i++) {
+    if (widths[i] != widths[0])
+      break;
+  }
+  if (i == widths.size()) {
+    int first = pWidthArray->GetIntegerAt(pWidthArray->size() - 1);
+    pWidthArray->AddNew<CPDF_Number>(first + static_cast<int>(widths.size()) -
+                                     1);
+    pWidthArray->AddNew<CPDF_Number>(widths[0]);
+    return;
+  }
+  CPDF_Array* pWidthArray1 = pWidthArray->AddNew<CPDF_Array>();
+  for (int w : widths)
+    pWidthArray1->AddNew<CPDF_Number>(w);
+}
+
+#if defined(OS_WIN)
+void InsertWidthArray(HDC hDC, int start, int end, CPDF_Array* pWidthArray) {
+  std::vector<int> widths(end - start + 1);
+  GetCharWidth(hDC, start, end, widths.data());
+  InsertWidthArrayImpl(std::move(widths), pWidthArray);
+}
+
+ByteString FPDF_GetPSNameFromTT(HDC hDC) {
+  ByteString result;
+  DWORD size = ::GetFontData(hDC, 'eman', 0, nullptr, 0);
+  if (size != GDI_ERROR) {
+    LPBYTE buffer = FX_Alloc(BYTE, size);
+    ::GetFontData(hDC, 'eman', 0, buffer, size);
+    result = GetNameFromTT(buffer, size, 6);
+    FX_Free(buffer);
+  }
+  return result;
+}
+#endif  // defined(OS_WIN)
+
+void InsertWidthArray1(CFX_Font* pFont,
+                       CFX_UnicodeEncoding* pEncoding,
+                       wchar_t start,
+                       wchar_t end,
+                       CPDF_Array* pWidthArray) {
+  std::vector<int> widths(end - start + 1);
+  for (size_t i = 0; i < widths.size(); ++i) {
+    int glyph_index = pEncoding->GlyphFromCharCode(start + i);
+    widths[i] = pFont->GetGlyphWidth(glyph_index);
+  }
+  InsertWidthArrayImpl(std::move(widths), pWidthArray);
+}
+
+int CalculateFlags(bool bold,
+                   bool italic,
+                   bool fixedPitch,
+                   bool serif,
+                   bool script,
+                   bool symbolic) {
+  int flags = 0;
+  if (bold)
+    flags |= FXFONT_BOLD;
+  if (italic)
+    flags |= FXFONT_ITALIC;
+  if (fixedPitch)
+    flags |= FXFONT_FIXED_PITCH;
+  if (serif)
+    flags |= FXFONT_SERIF;
+  if (script)
+    flags |= FXFONT_SCRIPT;
+  if (symbolic)
+    flags |= FXFONT_SYMBOLIC;
+  else
+    flags |= FXFONT_NONSYMBOLIC;
+  return flags;
+}
+
+void ProcessNonbCJK(CPDF_Dictionary* pBaseDict,
+                    bool bold,
+                    bool italic,
+                    ByteString basefont,
+                    RetainPtr<CPDF_Array> pWidths) {
+  if (bold && italic)
+    basefont += ",BoldItalic";
+  else if (bold)
+    basefont += ",Bold";
+  else if (italic)
+    basefont += ",Italic";
+  pBaseDict->SetNewFor<CPDF_Name>("Subtype", "TrueType");
+  pBaseDict->SetNewFor<CPDF_Name>("BaseFont", basefont);
+  pBaseDict->SetNewFor<CPDF_Number>("FirstChar", 32);
+  pBaseDict->SetNewFor<CPDF_Number>("LastChar", 255);
+  pBaseDict->SetFor("Widths", std::move(pWidths));
+}
+
+RetainPtr<CPDF_Dictionary> CalculateFontDesc(CPDF_Document* pDoc,
+                                             ByteString basefont,
+                                             int flags,
+                                             int italicangle,
+                                             int ascend,
+                                             int descend,
+                                             RetainPtr<CPDF_Array> bbox,
+                                             int32_t stemV) {
+  auto pFontDesc = pDoc->New<CPDF_Dictionary>();
+  pFontDesc->SetNewFor<CPDF_Name>("Type", "FontDescriptor");
+  pFontDesc->SetNewFor<CPDF_Name>("FontName", basefont);
+  pFontDesc->SetNewFor<CPDF_Number>("Flags", flags);
+  pFontDesc->SetFor("FontBBox", std::move(bbox));
+  pFontDesc->SetNewFor<CPDF_Number>("ItalicAngle", italicangle);
+  pFontDesc->SetNewFor<CPDF_Number>("Ascent", ascend);
+  pFontDesc->SetNewFor<CPDF_Number>("Descent", descend);
+  pFontDesc->SetNewFor<CPDF_Number>("StemV", stemV);
+  return pFontDesc;
+}
+
+}  // namespace
+
 CPDF_DocPageData::CPDF_DocPageData(CPDF_Document* pPDFDoc)
     : m_bForceClear(false), m_pPDFDoc(pPDFDoc) {
   ASSERT(m_pPDFDoc);
@@ -471,3 +599,269 @@
   auto it = m_PatternMap.find(pPatternObj);
   return it != m_PatternMap.end() ? it->second : nullptr;
 }
+
+CPDF_Font* CPDF_DocPageData::AddStandardFont(
+    const char* font,
+    const CPDF_FontEncoding* pEncoding) {
+  ByteString name(font);
+  if (CFX_FontMapper::GetStandardFontName(&name) < 0)
+    return nullptr;
+  return GetStandardFont(name, pEncoding);
+}
+
+CPDF_Font* CPDF_DocPageData::AddFont(CFX_Font* pFont, int charset) {
+  if (!pFont)
+    return nullptr;
+
+  const bool bCJK = FX_CharSetIsCJK(charset);
+  ByteString basefont = pFont->GetFamilyName();
+  basefont.Replace(" ", "");
+  int flags =
+      CalculateFlags(pFont->IsBold(), pFont->IsItalic(), pFont->IsFixedWidth(),
+                     false, false, charset == FX_CHARSET_Symbol);
+
+  CPDF_Dictionary* pBaseDict = m_pPDFDoc->NewIndirect<CPDF_Dictionary>();
+  pBaseDict->SetNewFor<CPDF_Name>("Type", "Font");
+  auto pEncoding = pdfium::MakeUnique<CFX_UnicodeEncoding>(pFont);
+  CPDF_Dictionary* pFontDict = pBaseDict;
+  if (!bCJK) {
+    auto pWidths = pdfium::MakeRetain<CPDF_Array>();
+    for (int charcode = 32; charcode < 128; charcode++) {
+      int glyph_index = pEncoding->GlyphFromCharCode(charcode);
+      int char_width = pFont->GetGlyphWidth(glyph_index);
+      pWidths->AddNew<CPDF_Number>(char_width);
+    }
+    if (charset == FX_CHARSET_ANSI || charset == FX_CHARSET_Default ||
+        charset == FX_CHARSET_Symbol) {
+      pBaseDict->SetNewFor<CPDF_Name>("Encoding", "WinAnsiEncoding");
+      for (int charcode = 128; charcode <= 255; charcode++) {
+        int glyph_index = pEncoding->GlyphFromCharCode(charcode);
+        int char_width = pFont->GetGlyphWidth(glyph_index);
+        pWidths->AddNew<CPDF_Number>(char_width);
+      }
+    } else {
+      size_t i = CalculateEncodingDict(charset, pBaseDict);
+      if (i < FX_ArraySize(g_FX_CharsetUnicodes)) {
+        const uint16_t* pUnicodes = g_FX_CharsetUnicodes[i].m_pUnicodes;
+        for (int j = 0; j < 128; j++) {
+          int glyph_index = pEncoding->GlyphFromCharCode(pUnicodes[j]);
+          int char_width = pFont->GetGlyphWidth(glyph_index);
+          pWidths->AddNew<CPDF_Number>(char_width);
+        }
+      }
+    }
+    ProcessNonbCJK(pBaseDict, pFont->IsBold(), pFont->IsItalic(), basefont,
+                   std::move(pWidths));
+  } else {
+    pFontDict = ProcessbCJK(
+        pBaseDict, charset, basefont,
+        [pFont, &pEncoding](wchar_t start, wchar_t end, CPDF_Array* widthArr) {
+          InsertWidthArray1(pFont, pEncoding.get(), start, end, widthArr);
+        });
+  }
+  int italicangle =
+      pFont->GetSubstFont() ? pFont->GetSubstFont()->m_ItalicAngle : 0;
+  FX_RECT bbox;
+  pFont->GetBBox(&bbox);
+  auto pBBox = pdfium::MakeRetain<CPDF_Array>();
+  pBBox->AddNew<CPDF_Number>(bbox.left);
+  pBBox->AddNew<CPDF_Number>(bbox.bottom);
+  pBBox->AddNew<CPDF_Number>(bbox.right);
+  pBBox->AddNew<CPDF_Number>(bbox.top);
+  int32_t nStemV = 0;
+  if (pFont->GetSubstFont()) {
+    nStemV = pFont->GetSubstFont()->m_Weight / 5;
+  } else {
+    static const char stem_chars[] = {'i', 'I', '!', '1'};
+    const size_t count = FX_ArraySize(stem_chars);
+    uint32_t glyph = pEncoding->GlyphFromCharCode(stem_chars[0]);
+    nStemV = pFont->GetGlyphWidth(glyph);
+    for (size_t i = 1; i < count; i++) {
+      glyph = pEncoding->GlyphFromCharCode(stem_chars[i]);
+      int width = pFont->GetGlyphWidth(glyph);
+      if (width > 0 && width < nStemV)
+        nStemV = width;
+    }
+  }
+  CPDF_Dictionary* pFontDesc =
+      ToDictionary(m_pPDFDoc->AddIndirectObject(CalculateFontDesc(
+          m_pPDFDoc.Get(), basefont, flags, italicangle, pFont->GetAscent(),
+          pFont->GetDescent(), std::move(pBBox), nStemV)));
+  pFontDict->SetNewFor<CPDF_Reference>("FontDescriptor", m_pPDFDoc.Get(),
+                                       pFontDesc->GetObjNum());
+  return GetFont(pBaseDict);
+}
+
+#if defined(OS_WIN)
+CPDF_Font* CPDF_DocPageData::AddWindowsFont(LOGFONTA* pLogFont) {
+  pLogFont->lfHeight = -1000;
+  pLogFont->lfWidth = 0;
+  HGDIOBJ hFont = CreateFontIndirectA(pLogFont);
+  HDC hDC = CreateCompatibleDC(nullptr);
+  hFont = SelectObject(hDC, hFont);
+  int tm_size = GetOutlineTextMetrics(hDC, 0, nullptr);
+  if (tm_size == 0) {
+    hFont = SelectObject(hDC, hFont);
+    DeleteObject(hFont);
+    DeleteDC(hDC);
+    return nullptr;
+  }
+
+  LPBYTE tm_buf = FX_Alloc(BYTE, tm_size);
+  OUTLINETEXTMETRIC* ptm = reinterpret_cast<OUTLINETEXTMETRIC*>(tm_buf);
+  GetOutlineTextMetrics(hDC, tm_size, ptm);
+  int flags = CalculateFlags(false, pLogFont->lfItalic != 0,
+                             (pLogFont->lfPitchAndFamily & 3) == FIXED_PITCH,
+                             (pLogFont->lfPitchAndFamily & 0xf8) == FF_ROMAN,
+                             (pLogFont->lfPitchAndFamily & 0xf8) == FF_SCRIPT,
+                             pLogFont->lfCharSet == FX_CHARSET_Symbol);
+
+  const bool bCJK = FX_CharSetIsCJK(pLogFont->lfCharSet);
+  ByteString basefont;
+  if (bCJK)
+    basefont = FPDF_GetPSNameFromTT(hDC);
+
+  if (basefont.IsEmpty())
+    basefont = pLogFont->lfFaceName;
+
+  int italicangle = ptm->otmItalicAngle / 10;
+  int ascend = ptm->otmrcFontBox.top;
+  int descend = ptm->otmrcFontBox.bottom;
+  int capheight = ptm->otmsCapEmHeight;
+  int bbox[4] = {ptm->otmrcFontBox.left, ptm->otmrcFontBox.bottom,
+                 ptm->otmrcFontBox.right, ptm->otmrcFontBox.top};
+  FX_Free(tm_buf);
+  basefont.Replace(" ", "");
+  CPDF_Dictionary* pBaseDict = m_pPDFDoc->NewIndirect<CPDF_Dictionary>();
+  pBaseDict->SetNewFor<CPDF_Name>("Type", "Font");
+  CPDF_Dictionary* pFontDict = pBaseDict;
+  if (!bCJK) {
+    if (pLogFont->lfCharSet == FX_CHARSET_ANSI ||
+        pLogFont->lfCharSet == FX_CHARSET_Default ||
+        pLogFont->lfCharSet == FX_CHARSET_Symbol) {
+      pBaseDict->SetNewFor<CPDF_Name>("Encoding", "WinAnsiEncoding");
+    } else {
+      CalculateEncodingDict(pLogFont->lfCharSet, pBaseDict);
+    }
+    int char_widths[224];
+    GetCharWidth(hDC, 32, 255, char_widths);
+    auto pWidths = pdfium::MakeRetain<CPDF_Array>();
+    for (size_t i = 0; i < 224; i++)
+      pWidths->AddNew<CPDF_Number>(char_widths[i]);
+    ProcessNonbCJK(pBaseDict, pLogFont->lfWeight > FW_MEDIUM,
+                   pLogFont->lfItalic != 0, basefont, std::move(pWidths));
+  } else {
+    pFontDict =
+        ProcessbCJK(pBaseDict, pLogFont->lfCharSet, basefont,
+                    [&hDC](wchar_t start, wchar_t end, CPDF_Array* widthArr) {
+                      InsertWidthArray(hDC, start, end, widthArr);
+                    });
+  }
+  auto pBBox = pdfium::MakeRetain<CPDF_Array>();
+  for (int i = 0; i < 4; i++)
+    pBBox->AddNew<CPDF_Number>(bbox[i]);
+  RetainPtr<CPDF_Dictionary> pFontDesc =
+      CalculateFontDesc(m_pPDFDoc.Get(), basefont, flags, italicangle, ascend,
+                        descend, std::move(pBBox), pLogFont->lfWeight / 5);
+  pFontDesc->SetNewFor<CPDF_Number>("CapHeight", capheight);
+  pFontDict->SetFor("FontDescriptor",
+                    m_pPDFDoc->AddIndirectObject(std::move(pFontDesc))
+                        ->MakeReference(m_pPDFDoc.Get()));
+  hFont = SelectObject(hDC, hFont);
+  DeleteObject(hFont);
+  DeleteDC(hDC);
+  return GetFont(pBaseDict);
+}
+#endif  //  defined(OS_WIN)
+
+size_t CPDF_DocPageData::CalculateEncodingDict(int charset,
+                                               CPDF_Dictionary* pBaseDict) {
+  size_t i;
+  for (i = 0; i < FX_ArraySize(g_FX_CharsetUnicodes); ++i) {
+    if (g_FX_CharsetUnicodes[i].m_Charset == charset)
+      break;
+  }
+  if (i == FX_ArraySize(g_FX_CharsetUnicodes))
+    return i;
+
+  CPDF_Dictionary* pEncodingDict = m_pPDFDoc->NewIndirect<CPDF_Dictionary>();
+  pEncodingDict->SetNewFor<CPDF_Name>("BaseEncoding", "WinAnsiEncoding");
+
+  CPDF_Array* pArray = pEncodingDict->SetNewFor<CPDF_Array>("Differences");
+  pArray->AddNew<CPDF_Number>(128);
+
+  const uint16_t* pUnicodes = g_FX_CharsetUnicodes[i].m_pUnicodes;
+  for (int j = 0; j < 128; j++) {
+    ByteString name = PDF_AdobeNameFromUnicode(pUnicodes[j]);
+    pArray->AddNew<CPDF_Name>(name.IsEmpty() ? ".notdef" : name);
+  }
+  pBaseDict->SetNewFor<CPDF_Reference>("Encoding", m_pPDFDoc.Get(),
+                                       pEncodingDict->GetObjNum());
+  return i;
+}
+
+CPDF_Dictionary* CPDF_DocPageData::ProcessbCJK(
+    CPDF_Dictionary* pBaseDict,
+    int charset,
+    ByteString basefont,
+    std::function<void(wchar_t, wchar_t, CPDF_Array*)> Insert) {
+  CPDF_Dictionary* pFontDict = m_pPDFDoc->NewIndirect<CPDF_Dictionary>();
+  ByteString cmap;
+  ByteString ordering;
+  int supplement = 0;
+  CPDF_Array* pWidthArray = pFontDict->SetNewFor<CPDF_Array>("W");
+  switch (charset) {
+    case FX_CHARSET_ChineseTraditional:
+      cmap = "ETenms-B5-H";
+      ordering = "CNS1";
+      supplement = 4;
+      pWidthArray->AddNew<CPDF_Number>(1);
+      Insert(0x20, 0x7e, pWidthArray);
+      break;
+    case FX_CHARSET_ChineseSimplified:
+      cmap = "GBK-EUC-H";
+      ordering = "GB1";
+      supplement = 2;
+      pWidthArray->AddNew<CPDF_Number>(7716);
+      Insert(0x20, 0x20, pWidthArray);
+      pWidthArray->AddNew<CPDF_Number>(814);
+      Insert(0x21, 0x7e, pWidthArray);
+      break;
+    case FX_CHARSET_Hangul:
+      cmap = "KSCms-UHC-H";
+      ordering = "Korea1";
+      supplement = 2;
+      pWidthArray->AddNew<CPDF_Number>(1);
+      Insert(0x20, 0x7e, pWidthArray);
+      break;
+    case FX_CHARSET_ShiftJIS:
+      cmap = "90ms-RKSJ-H";
+      ordering = "Japan1";
+      supplement = 5;
+      pWidthArray->AddNew<CPDF_Number>(231);
+      Insert(0x20, 0x7d, pWidthArray);
+      pWidthArray->AddNew<CPDF_Number>(326);
+      Insert(0xa0, 0xa0, pWidthArray);
+      pWidthArray->AddNew<CPDF_Number>(327);
+      Insert(0xa1, 0xdf, pWidthArray);
+      pWidthArray->AddNew<CPDF_Number>(631);
+      Insert(0x7e, 0x7e, pWidthArray);
+      break;
+  }
+  pBaseDict->SetNewFor<CPDF_Name>("Subtype", "Type0");
+  pBaseDict->SetNewFor<CPDF_Name>("BaseFont", basefont);
+  pBaseDict->SetNewFor<CPDF_Name>("Encoding", cmap);
+  pFontDict->SetNewFor<CPDF_Name>("Type", "Font");
+  pFontDict->SetNewFor<CPDF_Name>("Subtype", "CIDFontType2");
+  pFontDict->SetNewFor<CPDF_Name>("BaseFont", basefont);
+
+  CPDF_Dictionary* pCIDSysInfo =
+      pFontDict->SetNewFor<CPDF_Dictionary>("CIDSystemInfo");
+  pCIDSysInfo->SetNewFor<CPDF_String>("Registry", "Adobe", false);
+  pCIDSysInfo->SetNewFor<CPDF_String>("Ordering", ordering, false);
+  pCIDSysInfo->SetNewFor<CPDF_Number>("Supplement", supplement);
+
+  CPDF_Array* pArray = pBaseDict->SetNewFor<CPDF_Array>("DescendantFonts");
+  pArray->AddNew<CPDF_Reference>(m_pPDFDoc.Get(), pFontDict->GetObjNum());
+  return pFontDict;
+}
diff --git a/core/fpdfapi/page/cpdf_docpagedata.h b/core/fpdfapi/page/cpdf_docpagedata.h
index ae3e8db..ff4b88b 100644
--- a/core/fpdfapi/page/cpdf_docpagedata.h
+++ b/core/fpdfapi/page/cpdf_docpagedata.h
@@ -16,6 +16,7 @@
 #include "core/fxcrt/retain_ptr.h"
 #include "core/fxcrt/unowned_ptr.h"
 
+class CFX_Font;
 class CPDF_Dictionary;
 class CPDF_Document;
 class CPDF_Font;
@@ -35,11 +36,18 @@
   void Clear(bool bRelease);
   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);
 
+#if defined(OS_WIN)
+  CPDF_Font* AddWindowsFont(LOGFONTA* pLogFont);
+#endif
+
   // Loads a colorspace.
   RetainPtr<CPDF_ColorSpace> GetColorSpace(const CPDF_Object* pCSObj,
                                            const CPDF_Dictionary* pResources);
@@ -86,6 +94,13 @@
       std::set<const CPDF_Object*>* pVisited,
       std::set<const CPDF_Object*>* pVisitedInternal);
 
+  size_t CalculateEncodingDict(int charset, CPDF_Dictionary* pBaseDict);
+  CPDF_Dictionary* ProcessbCJK(
+      CPDF_Dictionary* pBaseDict,
+      int charset,
+      ByteString basefont,
+      std::function<void(wchar_t, wchar_t, CPDF_Array*)> Insert);
+
   bool m_bForceClear;
   UnownedPtr<CPDF_Document> const m_pPDFDoc;
   std::map<ByteString, const CPDF_Stream*> m_HashProfileMap;
diff --git a/core/fpdfapi/page/cpdf_streamcontentparser.cpp b/core/fpdfapi/page/cpdf_streamcontentparser.cpp
index 96dc904..9d6f5c4 100644
--- a/core/fpdfapi/page/cpdf_streamcontentparser.cpp
+++ b/core/fpdfapi/page/cpdf_streamcontentparser.cpp
@@ -1160,7 +1160,7 @@
                                    CFX_Font::kDefaultAnsiFontName);
   }
 
-  CPDF_Font* pFont = m_pDocument->LoadFont(pFontDict);
+  CPDF_Font* pFont = m_pDocument->GetPageData()->GetFont(pFontDict);
   if (pFont && pFont->IsType3Font()) {
     pFont->AsType3Font()->SetPageResources(m_pResources.Get());
     pFont->AsType3Font()->CheckType3FontMetrics();
@@ -1170,30 +1170,30 @@
 
 RetainPtr<CPDF_ColorSpace> CPDF_StreamContentParser::FindColorSpace(
     const ByteString& name) {
-  if (name == "Pattern") {
+  if (name == "Pattern")
     return CPDF_ColorSpace::GetStockCS(PDFCS_PATTERN);
-  }
+
   if (name == "DeviceGray" || name == "DeviceCMYK" || name == "DeviceRGB") {
     ByteString defname = "Default";
     defname += name.Right(name.GetLength() - 7);
     const CPDF_Object* pDefObj = FindResourceObj("ColorSpace", defname);
     if (!pDefObj) {
-      if (name == "DeviceGray") {
+      if (name == "DeviceGray")
         return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY);
-      }
-      if (name == "DeviceRGB") {
+
+      if (name == "DeviceRGB")
         return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB);
-      }
+
       return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICECMYK);
     }
-    return m_pDocument->LoadColorSpace(pDefObj, nullptr);
+    return m_pDocument->GetPageData()->GetColorSpace(pDefObj, nullptr);
   }
   const CPDF_Object* pCSObj = FindResourceObj("ColorSpace", name);
   if (!pCSObj) {
     m_bResourceMissing = true;
     return nullptr;
   }
-  return m_pDocument->LoadColorSpace(pCSObj, nullptr);
+  return m_pDocument->GetPageData()->GetColorSpace(pCSObj, nullptr);
 }
 
 CPDF_Pattern* CPDF_StreamContentParser::FindPattern(const ByteString& name,
@@ -1204,8 +1204,8 @@
     m_bResourceMissing = true;
     return nullptr;
   }
-  return m_pDocument->LoadPattern(pPattern, bShading,
-                                  m_pCurStates->m_ParentMatrix);
+  return m_pDocument->GetPageData()->GetPattern(pPattern, bShading,
+                                                m_pCurStates->m_ParentMatrix);
 }
 
 void CPDF_StreamContentParser::AddTextObject(const ByteString* pStrs,
diff --git a/core/fpdfapi/page/cpdf_streamparser.cpp b/core/fpdfapi/page/cpdf_streamparser.cpp
index 3b34131..a949a44 100644
--- a/core/fpdfapi/page/cpdf_streamparser.cpp
+++ b/core/fpdfapi/page/cpdf_streamparser.cpp
@@ -155,7 +155,8 @@
   uint32_t bpc = 1;
   uint32_t nComponents = 1;
   if (pCSObj) {
-    RetainPtr<CPDF_ColorSpace> pCS = pDoc->LoadColorSpace(pCSObj, nullptr);
+    RetainPtr<CPDF_ColorSpace> pCS =
+        pDoc->GetPageData()->GetColorSpace(pCSObj, nullptr);
     nComponents = pCS ? pCS->CountComponents() : 3;
     bpc = pDict->GetIntegerFor("BitsPerComponent");
   }
diff --git a/core/fpdfapi/parser/cpdf_document.cpp b/core/fpdfapi/parser/cpdf_document.cpp
index 629a73b..5b0314d 100644
--- a/core/fpdfapi/parser/cpdf_document.cpp
+++ b/core/fpdfapi/parser/cpdf_document.cpp
@@ -28,10 +28,6 @@
 #include "core/fpdfapi/render/cpdf_docrenderdata.h"
 #include "core/fxcodec/JBig2_DocumentContext.h"
 #include "core/fxcrt/fx_codepage.h"
-#include "core/fxge/cfx_font.h"
-#include "core/fxge/cfx_fontmapper.h"
-#include "core/fxge/cfx_substfont.h"
-#include "core/fxge/cfx_unicodeencoding.h"
 #include "core/fxge/fx_font.h"
 #include "third_party/base/ptr_util.h"
 #include "third_party/base/stl_util.h"
@@ -40,57 +36,6 @@
 
 const int kMaxPageLevel = 1024;
 
-void InsertWidthArrayImpl(std::vector<int> widths, CPDF_Array* pWidthArray) {
-  size_t i;
-  for (i = 1; i < widths.size(); i++) {
-    if (widths[i] != widths[0])
-      break;
-  }
-  if (i == widths.size()) {
-    int first = pWidthArray->GetIntegerAt(pWidthArray->size() - 1);
-    pWidthArray->AddNew<CPDF_Number>(first + static_cast<int>(widths.size()) -
-                                     1);
-    pWidthArray->AddNew<CPDF_Number>(widths[0]);
-    return;
-  }
-  CPDF_Array* pWidthArray1 = pWidthArray->AddNew<CPDF_Array>();
-  for (int w : widths)
-    pWidthArray1->AddNew<CPDF_Number>(w);
-}
-
-#if defined(OS_WIN)
-void InsertWidthArray(HDC hDC, int start, int end, CPDF_Array* pWidthArray) {
-  std::vector<int> widths(end - start + 1);
-  GetCharWidth(hDC, start, end, widths.data());
-  InsertWidthArrayImpl(std::move(widths), pWidthArray);
-}
-
-ByteString FPDF_GetPSNameFromTT(HDC hDC) {
-  ByteString result;
-  DWORD size = ::GetFontData(hDC, 'eman', 0, nullptr, 0);
-  if (size != GDI_ERROR) {
-    LPBYTE buffer = FX_Alloc(BYTE, size);
-    ::GetFontData(hDC, 'eman', 0, buffer, size);
-    result = GetNameFromTT(buffer, size, 6);
-    FX_Free(buffer);
-  }
-  return result;
-}
-#endif  // defined(OS_WIN)
-
-void InsertWidthArray1(CFX_Font* pFont,
-                       CFX_UnicodeEncoding* pEncoding,
-                       wchar_t start,
-                       wchar_t end,
-                       CPDF_Array* pWidthArray) {
-  std::vector<int> widths(end - start + 1);
-  for (size_t i = 0; i < widths.size(); ++i) {
-    int glyph_index = pEncoding->GlyphFromCharCode(start + i);
-    widths[i] = pFont->GetGlyphWidth(glyph_index);
-  }
-  InsertWidthArrayImpl(std::move(widths), pWidthArray);
-}
-
 int CountPages(CPDF_Dictionary* pPages,
                std::set<CPDF_Dictionary*>* visited_pages) {
   int count = pPages->GetIntegerFor("Count");
@@ -118,68 +63,6 @@
   return count;
 }
 
-int CalculateFlags(bool bold,
-                   bool italic,
-                   bool fixedPitch,
-                   bool serif,
-                   bool script,
-                   bool symbolic) {
-  int flags = 0;
-  if (bold)
-    flags |= FXFONT_BOLD;
-  if (italic)
-    flags |= FXFONT_ITALIC;
-  if (fixedPitch)
-    flags |= FXFONT_FIXED_PITCH;
-  if (serif)
-    flags |= FXFONT_SERIF;
-  if (script)
-    flags |= FXFONT_SCRIPT;
-  if (symbolic)
-    flags |= FXFONT_SYMBOLIC;
-  else
-    flags |= FXFONT_NONSYMBOLIC;
-  return flags;
-}
-
-void ProcessNonbCJK(CPDF_Dictionary* pBaseDict,
-                    bool bold,
-                    bool italic,
-                    ByteString basefont,
-                    RetainPtr<CPDF_Array> pWidths) {
-  if (bold && italic)
-    basefont += ",BoldItalic";
-  else if (bold)
-    basefont += ",Bold";
-  else if (italic)
-    basefont += ",Italic";
-  pBaseDict->SetNewFor<CPDF_Name>("Subtype", "TrueType");
-  pBaseDict->SetNewFor<CPDF_Name>("BaseFont", basefont);
-  pBaseDict->SetNewFor<CPDF_Number>("FirstChar", 32);
-  pBaseDict->SetNewFor<CPDF_Number>("LastChar", 255);
-  pBaseDict->SetFor("Widths", std::move(pWidths));
-}
-
-RetainPtr<CPDF_Dictionary> CalculateFontDesc(CPDF_Document* pDoc,
-                                             ByteString basefont,
-                                             int flags,
-                                             int italicangle,
-                                             int ascend,
-                                             int descend,
-                                             RetainPtr<CPDF_Array> bbox,
-                                             int32_t stemV) {
-  auto pFontDesc = pDoc->New<CPDF_Dictionary>();
-  pFontDesc->SetNewFor<CPDF_Name>("Type", "FontDescriptor");
-  pFontDesc->SetNewFor<CPDF_Name>("FontName", basefont);
-  pFontDesc->SetNewFor<CPDF_Number>("Flags", flags);
-  pFontDesc->SetFor("FontBBox", std::move(bbox));
-  pFontDesc->SetNewFor<CPDF_Number>("ItalicAngle", italicangle);
-  pFontDesc->SetNewFor<CPDF_Number>("Ascent", ascend);
-  pFontDesc->SetNewFor<CPDF_Number>("Descent", descend);
-  pFontDesc->SetNewFor<CPDF_Number>("StemV", stemV);
-  return pFontDesc;
-}
-
 }  // namespace
 
 CPDF_Document::CPDF_Document()
@@ -463,27 +346,11 @@
   return m_pExtension ? m_pExtension->GetUserPermissions() : 0;
 }
 
-CPDF_Font* CPDF_Document::LoadFont(CPDF_Dictionary* pFontDict) {
-  ASSERT(pFontDict);
-  return m_pDocPage->GetFont(pFontDict);
-}
-
 RetainPtr<CPDF_StreamAcc> CPDF_Document::LoadFontFile(
     const CPDF_Stream* pStream) {
   return m_pDocPage->GetFontFileStreamAcc(pStream);
 }
 
-RetainPtr<CPDF_ColorSpace> CPDF_Document::LoadColorSpace(
-    const CPDF_Object* pCSObj,
-    const CPDF_Dictionary* pResources) {
-  return m_pDocPage->GetColorSpace(pCSObj, pResources);
-}
-
-CPDF_Pattern* CPDF_Document::LoadPattern(CPDF_Object* pPatternObj,
-                                         bool bShading,
-                                         const CFX_Matrix& matrix) {
-  return m_pDocPage->GetPattern(pPatternObj, bShading, matrix);
-}
 
 void CPDF_Document::CreateNewDoc() {
   ASSERT(!m_pRootDict);
@@ -613,270 +480,6 @@
   m_PageList.erase(m_PageList.begin() + iPage);
 }
 
-CPDF_Font* CPDF_Document::AddStandardFont(const char* font,
-                                          const CPDF_FontEncoding* pEncoding) {
-  ByteString name(font);
-  if (CFX_FontMapper::GetStandardFontName(&name) < 0)
-    return nullptr;
-  return GetPageData()->GetStandardFont(name, pEncoding);
-}
-
-size_t CPDF_Document::CalculateEncodingDict(int charset,
-                                            CPDF_Dictionary* pBaseDict) {
-  size_t i;
-  for (i = 0; i < FX_ArraySize(g_FX_CharsetUnicodes); ++i) {
-    if (g_FX_CharsetUnicodes[i].m_Charset == charset)
-      break;
-  }
-  if (i == FX_ArraySize(g_FX_CharsetUnicodes))
-    return i;
-
-  CPDF_Dictionary* pEncodingDict = NewIndirect<CPDF_Dictionary>();
-  pEncodingDict->SetNewFor<CPDF_Name>("BaseEncoding", "WinAnsiEncoding");
-
-  CPDF_Array* pArray = pEncodingDict->SetNewFor<CPDF_Array>("Differences");
-  pArray->AddNew<CPDF_Number>(128);
-
-  const uint16_t* pUnicodes = g_FX_CharsetUnicodes[i].m_pUnicodes;
-  for (int j = 0; j < 128; j++) {
-    ByteString name = PDF_AdobeNameFromUnicode(pUnicodes[j]);
-    pArray->AddNew<CPDF_Name>(name.IsEmpty() ? ".notdef" : name);
-  }
-  pBaseDict->SetNewFor<CPDF_Reference>("Encoding", this,
-                                       pEncodingDict->GetObjNum());
-  return i;
-}
-
-CPDF_Dictionary* CPDF_Document::ProcessbCJK(
-    CPDF_Dictionary* pBaseDict,
-    int charset,
-    ByteString basefont,
-    std::function<void(wchar_t, wchar_t, CPDF_Array*)> Insert) {
-  CPDF_Dictionary* pFontDict = NewIndirect<CPDF_Dictionary>();
-  ByteString cmap;
-  ByteString ordering;
-  int supplement = 0;
-  CPDF_Array* pWidthArray = pFontDict->SetNewFor<CPDF_Array>("W");
-  switch (charset) {
-    case FX_CHARSET_ChineseTraditional:
-      cmap = "ETenms-B5-H";
-      ordering = "CNS1";
-      supplement = 4;
-      pWidthArray->AddNew<CPDF_Number>(1);
-      Insert(0x20, 0x7e, pWidthArray);
-      break;
-    case FX_CHARSET_ChineseSimplified:
-      cmap = "GBK-EUC-H";
-      ordering = "GB1";
-      supplement = 2;
-      pWidthArray->AddNew<CPDF_Number>(7716);
-      Insert(0x20, 0x20, pWidthArray);
-      pWidthArray->AddNew<CPDF_Number>(814);
-      Insert(0x21, 0x7e, pWidthArray);
-      break;
-    case FX_CHARSET_Hangul:
-      cmap = "KSCms-UHC-H";
-      ordering = "Korea1";
-      supplement = 2;
-      pWidthArray->AddNew<CPDF_Number>(1);
-      Insert(0x20, 0x7e, pWidthArray);
-      break;
-    case FX_CHARSET_ShiftJIS:
-      cmap = "90ms-RKSJ-H";
-      ordering = "Japan1";
-      supplement = 5;
-      pWidthArray->AddNew<CPDF_Number>(231);
-      Insert(0x20, 0x7d, pWidthArray);
-      pWidthArray->AddNew<CPDF_Number>(326);
-      Insert(0xa0, 0xa0, pWidthArray);
-      pWidthArray->AddNew<CPDF_Number>(327);
-      Insert(0xa1, 0xdf, pWidthArray);
-      pWidthArray->AddNew<CPDF_Number>(631);
-      Insert(0x7e, 0x7e, pWidthArray);
-      break;
-  }
-  pBaseDict->SetNewFor<CPDF_Name>("Subtype", "Type0");
-  pBaseDict->SetNewFor<CPDF_Name>("BaseFont", basefont);
-  pBaseDict->SetNewFor<CPDF_Name>("Encoding", cmap);
-  pFontDict->SetNewFor<CPDF_Name>("Type", "Font");
-  pFontDict->SetNewFor<CPDF_Name>("Subtype", "CIDFontType2");
-  pFontDict->SetNewFor<CPDF_Name>("BaseFont", basefont);
-
-  CPDF_Dictionary* pCIDSysInfo =
-      pFontDict->SetNewFor<CPDF_Dictionary>("CIDSystemInfo");
-  pCIDSysInfo->SetNewFor<CPDF_String>("Registry", "Adobe", false);
-  pCIDSysInfo->SetNewFor<CPDF_String>("Ordering", ordering, false);
-  pCIDSysInfo->SetNewFor<CPDF_Number>("Supplement", supplement);
-
-  CPDF_Array* pArray = pBaseDict->SetNewFor<CPDF_Array>("DescendantFonts");
-  pArray->AddNew<CPDF_Reference>(this, pFontDict->GetObjNum());
-  return pFontDict;
-}
-
-CPDF_Font* CPDF_Document::AddFont(CFX_Font* pFont, int charset) {
-  if (!pFont)
-    return nullptr;
-
-  const bool bCJK = FX_CharSetIsCJK(charset);
-  ByteString basefont = pFont->GetFamilyName();
-  basefont.Replace(" ", "");
-  int flags =
-      CalculateFlags(pFont->IsBold(), pFont->IsItalic(), pFont->IsFixedWidth(),
-                     false, false, charset == FX_CHARSET_Symbol);
-
-  CPDF_Dictionary* pBaseDict = NewIndirect<CPDF_Dictionary>();
-  pBaseDict->SetNewFor<CPDF_Name>("Type", "Font");
-  auto pEncoding = pdfium::MakeUnique<CFX_UnicodeEncoding>(pFont);
-  CPDF_Dictionary* pFontDict = pBaseDict;
-  if (!bCJK) {
-    auto pWidths = pdfium::MakeRetain<CPDF_Array>();
-    for (int charcode = 32; charcode < 128; charcode++) {
-      int glyph_index = pEncoding->GlyphFromCharCode(charcode);
-      int char_width = pFont->GetGlyphWidth(glyph_index);
-      pWidths->AddNew<CPDF_Number>(char_width);
-    }
-    if (charset == FX_CHARSET_ANSI || charset == FX_CHARSET_Default ||
-        charset == FX_CHARSET_Symbol) {
-      pBaseDict->SetNewFor<CPDF_Name>("Encoding", "WinAnsiEncoding");
-      for (int charcode = 128; charcode <= 255; charcode++) {
-        int glyph_index = pEncoding->GlyphFromCharCode(charcode);
-        int char_width = pFont->GetGlyphWidth(glyph_index);
-        pWidths->AddNew<CPDF_Number>(char_width);
-      }
-    } else {
-      size_t i = CalculateEncodingDict(charset, pBaseDict);
-      if (i < FX_ArraySize(g_FX_CharsetUnicodes)) {
-        const uint16_t* pUnicodes = g_FX_CharsetUnicodes[i].m_pUnicodes;
-        for (int j = 0; j < 128; j++) {
-          int glyph_index = pEncoding->GlyphFromCharCode(pUnicodes[j]);
-          int char_width = pFont->GetGlyphWidth(glyph_index);
-          pWidths->AddNew<CPDF_Number>(char_width);
-        }
-      }
-    }
-    ProcessNonbCJK(pBaseDict, pFont->IsBold(), pFont->IsItalic(), basefont,
-                   std::move(pWidths));
-  } else {
-    pFontDict = ProcessbCJK(
-        pBaseDict, charset, basefont,
-        [pFont, &pEncoding](wchar_t start, wchar_t end, CPDF_Array* widthArr) {
-          InsertWidthArray1(pFont, pEncoding.get(), start, end, widthArr);
-        });
-  }
-  int italicangle =
-      pFont->GetSubstFont() ? pFont->GetSubstFont()->m_ItalicAngle : 0;
-  FX_RECT bbox;
-  pFont->GetBBox(&bbox);
-  auto pBBox = pdfium::MakeRetain<CPDF_Array>();
-  pBBox->AddNew<CPDF_Number>(bbox.left);
-  pBBox->AddNew<CPDF_Number>(bbox.bottom);
-  pBBox->AddNew<CPDF_Number>(bbox.right);
-  pBBox->AddNew<CPDF_Number>(bbox.top);
-  int32_t nStemV = 0;
-  if (pFont->GetSubstFont()) {
-    nStemV = pFont->GetSubstFont()->m_Weight / 5;
-  } else {
-    static const char stem_chars[] = {'i', 'I', '!', '1'};
-    const size_t count = FX_ArraySize(stem_chars);
-    uint32_t glyph = pEncoding->GlyphFromCharCode(stem_chars[0]);
-    nStemV = pFont->GetGlyphWidth(glyph);
-    for (size_t i = 1; i < count; i++) {
-      glyph = pEncoding->GlyphFromCharCode(stem_chars[i]);
-      int width = pFont->GetGlyphWidth(glyph);
-      if (width > 0 && width < nStemV)
-        nStemV = width;
-    }
-  }
-  CPDF_Dictionary* pFontDesc = ToDictionary(AddIndirectObject(
-      CalculateFontDesc(this, basefont, flags, italicangle, pFont->GetAscent(),
-                        pFont->GetDescent(), std::move(pBBox), nStemV)));
-  pFontDict->SetNewFor<CPDF_Reference>("FontDescriptor", this,
-                                       pFontDesc->GetObjNum());
-  return LoadFont(pBaseDict);
-}
-
-#if defined(OS_WIN)
-CPDF_Font* CPDF_Document::AddWindowsFont(LOGFONTA* pLogFont) {
-  pLogFont->lfHeight = -1000;
-  pLogFont->lfWidth = 0;
-  HGDIOBJ hFont = CreateFontIndirectA(pLogFont);
-  HDC hDC = CreateCompatibleDC(nullptr);
-  hFont = SelectObject(hDC, hFont);
-  int tm_size = GetOutlineTextMetrics(hDC, 0, nullptr);
-  if (tm_size == 0) {
-    hFont = SelectObject(hDC, hFont);
-    DeleteObject(hFont);
-    DeleteDC(hDC);
-    return nullptr;
-  }
-
-  LPBYTE tm_buf = FX_Alloc(BYTE, tm_size);
-  OUTLINETEXTMETRIC* ptm = reinterpret_cast<OUTLINETEXTMETRIC*>(tm_buf);
-  GetOutlineTextMetrics(hDC, tm_size, ptm);
-  int flags = CalculateFlags(false, pLogFont->lfItalic != 0,
-                             (pLogFont->lfPitchAndFamily & 3) == FIXED_PITCH,
-                             (pLogFont->lfPitchAndFamily & 0xf8) == FF_ROMAN,
-                             (pLogFont->lfPitchAndFamily & 0xf8) == FF_SCRIPT,
-                             pLogFont->lfCharSet == FX_CHARSET_Symbol);
-
-  const bool bCJK = FX_CharSetIsCJK(pLogFont->lfCharSet);
-  ByteString basefont;
-  if (bCJK)
-    basefont = FPDF_GetPSNameFromTT(hDC);
-
-  if (basefont.IsEmpty())
-    basefont = pLogFont->lfFaceName;
-
-  int italicangle = ptm->otmItalicAngle / 10;
-  int ascend = ptm->otmrcFontBox.top;
-  int descend = ptm->otmrcFontBox.bottom;
-  int capheight = ptm->otmsCapEmHeight;
-  int bbox[4] = {ptm->otmrcFontBox.left, ptm->otmrcFontBox.bottom,
-                 ptm->otmrcFontBox.right, ptm->otmrcFontBox.top};
-  FX_Free(tm_buf);
-  basefont.Replace(" ", "");
-  CPDF_Dictionary* pBaseDict = NewIndirect<CPDF_Dictionary>();
-  pBaseDict->SetNewFor<CPDF_Name>("Type", "Font");
-  CPDF_Dictionary* pFontDict = pBaseDict;
-  if (!bCJK) {
-    if (pLogFont->lfCharSet == FX_CHARSET_ANSI ||
-        pLogFont->lfCharSet == FX_CHARSET_Default ||
-        pLogFont->lfCharSet == FX_CHARSET_Symbol) {
-      pBaseDict->SetNewFor<CPDF_Name>("Encoding", "WinAnsiEncoding");
-    } else {
-      CalculateEncodingDict(pLogFont->lfCharSet, pBaseDict);
-    }
-    int char_widths[224];
-    GetCharWidth(hDC, 32, 255, char_widths);
-    auto pWidths = pdfium::MakeRetain<CPDF_Array>();
-    for (size_t i = 0; i < 224; i++)
-      pWidths->AddNew<CPDF_Number>(char_widths[i]);
-    ProcessNonbCJK(pBaseDict, pLogFont->lfWeight > FW_MEDIUM,
-                   pLogFont->lfItalic != 0, basefont, std::move(pWidths));
-  } else {
-    pFontDict =
-        ProcessbCJK(pBaseDict, pLogFont->lfCharSet, basefont,
-                    [&hDC](wchar_t start, wchar_t end, CPDF_Array* widthArr) {
-                      InsertWidthArray(hDC, start, end, widthArr);
-                    });
-  }
-  auto pBBox = pdfium::MakeRetain<CPDF_Array>();
-  for (int i = 0; i < 4; i++)
-    pBBox->AddNew<CPDF_Number>(bbox[i]);
-  RetainPtr<CPDF_Dictionary> pFontDesc =
-      CalculateFontDesc(this, basefont, flags, italicangle, ascend, descend,
-                        std::move(pBBox), pLogFont->lfWeight / 5);
-  pFontDesc->SetNewFor<CPDF_Number>("CapHeight", capheight);
-  pFontDict->SetFor(
-      "FontDescriptor",
-      AddIndirectObject(std::move(pFontDesc))->MakeReference(this));
-  hFont = SelectObject(hDC, hFont);
-  DeleteObject(hFont);
-  DeleteDC(hDC);
-  return LoadFont(pBaseDict);
-}
-#endif  //  defined(OS_WIN)
-
 CPDF_Document::StockFontClearer::StockFontClearer(CPDF_Document* pDoc)
     : m_pDoc(pDoc) {}
 
diff --git a/core/fpdfapi/parser/cpdf_document.h b/core/fpdfapi/parser/cpdf_document.h
index fa80747..97c75f6 100644
--- a/core/fpdfapi/parser/cpdf_document.h
+++ b/core/fpdfapi/parser/cpdf_document.h
@@ -21,14 +21,10 @@
 
 class CFX_Font;
 class CFX_Matrix;
-class CPDF_ColorSpace;
 class CPDF_DocPageData;
 class CPDF_DocRenderData;
-class CPDF_Font;
-class CPDF_FontEncoding;
 class CPDF_LinearizedHeader;
 class CPDF_Object;
-class CPDF_Pattern;
 class CPDF_ReadValidator;
 class CPDF_StreamAcc;
 class IFX_SeekableReadStream;
@@ -94,15 +90,6 @@
 
   CPDF_DocRenderData* GetRenderData() const { return m_pDocRender.get(); }
 
-  // |pFontDict| must not be null.
-  CPDF_Font* LoadFont(CPDF_Dictionary* pFontDict);
-  RetainPtr<CPDF_ColorSpace> LoadColorSpace(const CPDF_Object* pCSObj,
-                                            const CPDF_Dictionary* pResources);
-
-  CPDF_Pattern* LoadPattern(CPDF_Object* pObj,
-                            bool bShading,
-                            const CFX_Matrix& matrix);
-
   RetainPtr<CPDF_StreamAcc> LoadFontFile(const CPDF_Stream* pStream);
 
   //  CPDF_Parser::ParsedObjectsHolder overrides:
@@ -125,14 +112,6 @@
   void IncrementParsedPageCount() { ++m_ParsedPageCount; }
   uint32_t GetParsedPageCountForTesting() { return m_ParsedPageCount; }
 
-  CPDF_Font* AddStandardFont(const char* font,
-                             const CPDF_FontEncoding* pEncoding);
-  CPDF_Font* AddFont(CFX_Font* pFont, int charset);
-
-#if defined(OS_WIN)
-  CPDF_Font* AddWindowsFont(LOGFONTA* pLogFont);
-#endif
-
  protected:
   class StockFontClearer {
    public:
@@ -153,14 +132,8 @@
                     int* index,
                     int level) const;
   RetainPtr<CPDF_Object> ParseIndirectObject(uint32_t objnum) override;
-  size_t CalculateEncodingDict(int charset, CPDF_Dictionary* pBaseDict);
   const CPDF_Dictionary* GetPagesDict() const;
   CPDF_Dictionary* GetPagesDict();
-  CPDF_Dictionary* ProcessbCJK(
-      CPDF_Dictionary* pBaseDict,
-      int charset,
-      ByteString basefont,
-      std::function<void(wchar_t, wchar_t, CPDF_Array*)> Insert);
   bool InsertDeletePDFPage(CPDF_Dictionary* pPages,
                            int nPagesToGo,
                            CPDF_Dictionary* pPageDict,
diff --git a/core/fpdfapi/render/cpdf_imagerenderer.cpp b/core/fpdfapi/render/cpdf_imagerenderer.cpp
index 784c976..1f7e4d9 100644
--- a/core/fpdfapi/render/cpdf_imagerenderer.cpp
+++ b/core/fpdfapi/render/cpdf_imagerenderer.cpp
@@ -148,7 +148,7 @@
       m_pImageObject->GetImage()->GetStream()->GetDict()->GetDirectObjectFor(
           "ColorSpace");
   RetainPtr<CPDF_ColorSpace> pColorSpace =
-      pDocument->LoadColorSpace(pCSObj, pPageResources);
+      pDocument->GetPageData()->GetColorSpace(pCSObj, pPageResources);
   if (pColorSpace) {
     int format = pColorSpace->GetFamily();
     if (format == PDFCS_DEVICECMYK || format == PDFCS_SEPARATION ||
diff --git a/core/fpdfapi/render/cpdf_renderstatus.cpp b/core/fpdfapi/render/cpdf_renderstatus.cpp
index 38dc6c5..ee2a9d1 100644
--- a/core/fpdfapi/render/cpdf_renderstatus.cpp
+++ b/core/fpdfapi/render/cpdf_renderstatus.cpp
@@ -1483,7 +1483,7 @@
                                     ->GetDict()
                                     ->GetDirectObjectFor("ColorSpace");
     RetainPtr<CPDF_ColorSpace> pColorSpace =
-        pDocument->LoadColorSpace(pCSObj, pPageResources);
+        pDocument->GetPageData()->GetColorSpace(pCSObj, pPageResources);
     if (pColorSpace) {
       int format = pColorSpace->GetFamily();
       if (format == PDFCS_DEVICECMYK || format == PDFCS_SEPARATION ||
@@ -2622,7 +2622,7 @@
   if (pGroup)
     pCSObj = pGroup->GetDirectObjectFor(pdfium::transparency::kCS);
   RetainPtr<CPDF_ColorSpace> pCS =
-      m_pContext->GetDocument()->LoadColorSpace(pCSObj, nullptr);
+      m_pContext->GetDocument()->GetPageData()->GetColorSpace(pCSObj, nullptr);
   if (!pCS)
     return kDefaultColor;
 
diff --git a/core/fpdfdoc/cba_fontmap.cpp b/core/fpdfdoc/cba_fontmap.cpp
index fbeee07..994648f 100644
--- a/core/fpdfdoc/cba_fontmap.cpp
+++ b/core/fpdfdoc/cba_fontmap.cpp
@@ -13,6 +13,7 @@
 #include "core/fpdfapi/cpdf_modulemgr.h"
 #include "core/fpdfapi/font/cpdf_font.h"
 #include "core/fpdfapi/font/cpdf_fontencoding.h"
+#include "core/fpdfapi/page/cpdf_docpagedata.h"
 #include "core/fpdfapi/page/cpdf_page.h"
 #include "core/fpdfapi/parser/cpdf_dictionary.h"
 #include "core/fpdfapi/parser/cpdf_document.h"
@@ -61,7 +62,7 @@
   auto pFXFont = pdfium::MakeUnique<CFX_Font>();
   pFXFont->LoadSubst(sFontFaceName, true, 0, 0, 0,
                      FX_GetCodePageFromCharset(nCharset), false);
-  return pDoc->AddFont(pFXFont.get(), nCharset);
+  return pDoc->GetPageData()->AddFont(pFXFont.get(), nCharset);
 }
 
 }  // namespace
@@ -247,7 +248,7 @@
     if (pElement->GetStringFor("Type") != "Font")
       continue;
 
-    CPDF_Font* pFont = m_pDocument->LoadFont(pElement);
+    CPDF_Font* pFont = m_pDocument->GetPageData()->GetFont(pElement);
     if (!pFont)
       continue;
     const CFX_SubstFont* pSubst = pFont->GetSubstFont();
@@ -307,7 +308,7 @@
         pFontDict = pDRFontDict->GetDictFor(*sAlias);
     }
   }
-  return pFontDict ? m_pDocument->LoadFont(pFontDict) : nullptr;
+  return pFontDict ? m_pDocument->GetPageData()->GetFont(pFontDict) : nullptr;
 }
 
 void CBA_FontMap::AddFontToAnnotDict(CPDF_Font* pFont,
@@ -483,14 +484,13 @@
     return nullptr;
 
   CPDF_Font* pFont = nullptr;
-
+  CPDF_DocPageData* pPageData = pDoc->GetPageData();
   if (sFontName == "ZapfDingbats") {
-    pFont = pDoc->AddStandardFont(sFontName.c_str(), nullptr);
+    pFont = pPageData->AddStandardFont(sFontName.c_str(), nullptr);
   } else {
     CPDF_FontEncoding fe(PDFFONT_ENCODING_WINANSI);
-    pFont = pDoc->AddStandardFont(sFontName.c_str(), &fe);
+    pFont = pPageData->AddStandardFont(sFontName.c_str(), &fe);
   }
-
   return pFont;
 }
 
diff --git a/core/fpdfdoc/cpdf_formcontrol.cpp b/core/fpdfdoc/cpdf_formcontrol.cpp
index 7044606..be6b732 100644
--- a/core/fpdfdoc/cpdf_formcontrol.cpp
+++ b/core/fpdfdoc/cpdf_formcontrol.cpp
@@ -8,6 +8,7 @@
 
 #include <algorithm>
 
+#include "core/fpdfapi/page/cpdf_docpagedata.h"
 #include "core/fpdfapi/parser/cpdf_array.h"
 #include "core/fpdfapi/parser/cpdf_dictionary.h"
 #include "core/fpdfapi/parser/cpdf_document.h"
@@ -213,7 +214,8 @@
     if (pFonts) {
       CPDF_Dictionary* pElement = pFonts->GetDictFor(*csFontNameTag);
       if (pElement) {
-        CPDF_Font* pFont = m_pForm->GetDocument()->LoadFont(pElement);
+        CPDF_Font* pFont =
+            m_pForm->GetDocument()->GetPageData()->GetFont(pElement);
         if (pFont)
           return pFont;
       }
@@ -229,7 +231,8 @@
     if (pFonts) {
       CPDF_Dictionary* pElement = pFonts->GetDictFor(*csFontNameTag);
       if (pElement) {
-        CPDF_Font* pFont = m_pForm->GetDocument()->LoadFont(pElement);
+        CPDF_Font* pFont =
+            m_pForm->GetDocument()->GetPageData()->GetFont(pElement);
         if (pFont)
           return pFont;
       }
diff --git a/core/fpdfdoc/cpdf_formfield.cpp b/core/fpdfdoc/cpdf_formfield.cpp
index bd3b020..666d502 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/page/cpdf_docpagedata.h"
 #include "core/fpdfapi/parser/cfdf_document.h"
 #include "core/fpdfapi/parser/cpdf_array.h"
 #include "core/fpdfapi/parser/cpdf_dictionary.h"
@@ -911,7 +912,7 @@
   if (!pFontDict)
     return;
 
-  m_pFont = m_pForm->GetDocument()->LoadFont(pFontDict);
+  m_pFont = m_pForm->GetDocument()->GetPageData()->GetFont(pFontDict);
 }
 
 bool CPDF_FormField::NotifyBeforeSelectionChange(const WideString& value) {
diff --git a/core/fpdfdoc/cpdf_interactiveform.cpp b/core/fpdfdoc/cpdf_interactiveform.cpp
index 3649bc0..175bf00 100644
--- a/core/fpdfdoc/cpdf_interactiveform.cpp
+++ b/core/fpdfdoc/cpdf_interactiveform.cpp
@@ -14,6 +14,7 @@
 #include "constants/stream_dict_common.h"
 #include "core/fpdfapi/font/cpdf_font.h"
 #include "core/fpdfapi/font/cpdf_fontencoding.h"
+#include "core/fpdfapi/page/cpdf_docpagedata.h"
 #include "core/fpdfapi/page/cpdf_page.h"
 #include "core/fpdfapi/parser/cfdf_document.h"
 #include "core/fpdfapi/parser/cpdf_array.h"
@@ -136,9 +137,10 @@
   if (!pElement)
     return nullptr;
 
-  if (pElement->GetStringFor("Type") == "Font")
-    return pDocument->LoadFont(pElement);
-  return nullptr;
+  if (pElement->GetStringFor("Type") != "Font")
+    return nullptr;
+
+  return pDocument->GetPageData()->GetFont(pElement);
 }
 
 CPDF_Font* GetNativeFont(CPDF_Dictionary* pFormDict,
@@ -167,7 +169,7 @@
       continue;
     if (pElement->GetStringFor("Type") != "Font")
       continue;
-    CPDF_Font* pFind = pDocument->LoadFont(pElement);
+    CPDF_Font* pFind = pDocument->GetPageData()->GetFont(pElement);
     if (!pFind)
       continue;
 
@@ -245,7 +247,7 @@
       continue;
     if (pElement->GetStringFor("Type") != "Font")
       continue;
-    pFont = pDocument->LoadFont(pElement);
+    pFont = pDocument->GetPageData()->GetFont(pElement);
     if (!pFont)
       continue;
 
@@ -618,11 +620,12 @@
   if (!pDocument || csFontName.IsEmpty())
     return nullptr;
 
+  CPDF_DocPageData* pPageData = pDocument->GetPageData();
   if (csFontName == "ZapfDingbats")
-    return pDocument->AddStandardFont(csFontName.c_str(), nullptr);
+    return pPageData->AddStandardFont(csFontName.c_str(), nullptr);
 
   CPDF_FontEncoding encoding(PDFFONT_ENCODING_WINANSI);
-  return pDocument->AddStandardFont(csFontName.c_str(), &encoding);
+  return pPageData->AddStandardFont(csFontName.c_str(), &encoding);
 }
 
 ByteString CPDF_InteractiveForm::GetNativeFont(uint8_t charSet,
@@ -675,7 +678,7 @@
   if (!csFontName.IsEmpty()) {
     if (csFontName == CFX_Font::kDefaultAnsiFontName)
       return AddStandardFont(pDocument, csFontName);
-    return pDocument->AddWindowsFont(&lf);
+    return pDocument->GetPageData()->AddWindowsFont(&lf);
   }
 #endif
   return nullptr;
diff --git a/core/fpdfdoc/cpvt_generateap.cpp b/core/fpdfdoc/cpvt_generateap.cpp
index ade105f..af1685e 100644
--- a/core/fpdfdoc/cpvt_generateap.cpp
+++ b/core/fpdfdoc/cpvt_generateap.cpp
@@ -14,6 +14,7 @@
 #include "constants/annotation_common.h"
 #include "constants/form_fields.h"
 #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_boolean.h"
 #include "core/fpdfapi/parser/cpdf_dictionary.h"
@@ -763,7 +764,7 @@
 
   ByteString sFontName = "FONT";
   auto pResourceFontDict = GenerateResourceFontDict(pDoc, sFontName);
-  CPDF_Font* pDefFont = pDoc->LoadFont(pResourceFontDict.Get());
+  CPDF_Font* pDefFont = pDoc->GetPageData()->GetFont(pResourceFontDict.Get());
   if (!pDefFont)
     return false;
 
@@ -955,7 +956,7 @@
     pDRFontDict->SetNewFor<CPDF_Reference>(font_name, pDoc,
                                            pFontDict->GetObjNum());
   }
-  CPDF_Font* pDefFont = pDoc->LoadFont(pFontDict);
+  CPDF_Font* pDefFont = pDoc->GetPageData()->GetFont(pFontDict);
   if (!pDefFont)
     return;
 
diff --git a/fpdfsdk/fpdf_edittext.cpp b/fpdfsdk/fpdf_edittext.cpp
index f152b5e..f8fb78c 100644
--- a/fpdfsdk/fpdf_edittext.cpp
+++ b/fpdfsdk/fpdf_edittext.cpp
@@ -305,7 +305,7 @@
 
   pFontDict->SetNewFor<CPDF_Reference>("FontDescriptor", pDoc,
                                        pFontDesc->GetObjNum());
-  return pDoc->LoadFont(pFontDict);
+  return pDoc->GetPageData()->GetFont(pFontDict);
 }
 
 CPDF_Font* LoadCompositeFont(CPDF_Document* pDoc,
@@ -424,7 +424,7 @@
   CPDF_Stream* toUnicodeStream = LoadUnicode(pDoc, to_unicode);
   pFontDict->SetNewFor<CPDF_Reference>("ToUnicode", pDoc,
                                        toUnicodeStream->GetObjNum());
-  return pDoc->LoadFont(pFontDict);
+  return pDoc->GetPageData()->GetFont(pFontDict);
 }
 
 CPDF_TextObject* CPDFTextObjectFromFPDFPageObject(FPDF_PAGEOBJECT page_object) {
@@ -592,7 +592,8 @@
     return nullptr;
 
   auto pTextObj = pdfium::MakeUnique<CPDF_TextObject>();
-  pTextObj->m_TextState.SetFont(pDoc->LoadFont(pFont->GetFontDict()));
+  pTextObj->m_TextState.SetFont(
+      pDoc->GetPageData()->GetFont(pFont->GetFontDict()));
   pTextObj->m_TextState.SetFontSize(font_size);
   pTextObj->DefaultStates();
   return FPDFPageObjectFromCPDFPageObject(pTextObj.release());
diff --git a/xfa/fgas/BUILD.gn b/xfa/fgas/BUILD.gn
index 04b4a92..f11c990 100644
--- a/xfa/fgas/BUILD.gn
+++ b/xfa/fgas/BUILD.gn
@@ -29,6 +29,7 @@
   ]
   deps = [
     "../../core/fpdfapi/font",
+    "../../core/fpdfapi/page",
     "../../core/fpdfapi/parser",
     "../../core/fxcrt",
     "../../core/fxge",
diff --git a/xfa/fgas/font/cfgas_pdffontmgr.cpp b/xfa/fgas/font/cfgas_pdffontmgr.cpp
index 9c504d2..2704cb3 100644
--- a/xfa/fgas/font/cfgas_pdffontmgr.cpp
+++ b/xfa/fgas/font/cfgas_pdffontmgr.cpp
@@ -9,6 +9,7 @@
 #include <algorithm>
 
 #include "core/fpdfapi/font/cpdf_font.h"
+#include "core/fpdfapi/page/cpdf_docpagedata.h"
 #include "core/fpdfapi/parser/cpdf_dictionary.h"
 #include "core/fpdfapi/parser/cpdf_document.h"
 #include "core/fxge/fx_font.h"
@@ -62,7 +63,7 @@
     if (!pFontDict || pFontDict->GetStringFor("Type") != "Font")
       return nullptr;
 
-    CPDF_Font* pPDFFont = m_pDoc->LoadFont(pFontDict);
+    CPDF_Font* pPDFFont = m_pDoc->GetPageData()->GetFont(pFontDict);
     if (!pPDFFont)
       return nullptr;