Refactor CFGAS_FontMgr's Windows implementation

This CL unifies a bit the public methods of CFGAS_FontMgr. It does so by
replacing the multiple maps on the Windows implementation to a single
map from hash to font. Also, cloning CFX_Fonts is avoided with the use
of SetLogicalFontStyle. These Windows changes are just mimicking other
OS's. As a side-effect, some members of CFX_Fonts are now owned so the
raw pointers are replaced with unique_ptrs.

Change-Id: I576d438572ccbe6c48f8f5cc434d66fc6adba372
Reviewed-on: https://pdfium-review.googlesource.com/18131
Reviewed-by: dsinclair <dsinclair@chromium.org>
Commit-Queue: Nicolás Peña Moreno <npm@chromium.org>
diff --git a/core/fxge/cfx_font.cpp b/core/fxge/cfx_font.cpp
index 3f4f135..bca711f 100644
--- a/core/fxge/cfx_font.cpp
+++ b/core/fxge/cfx_font.cpp
@@ -211,10 +211,6 @@
 
 CFX_Font::CFX_Font()
     :
-#ifdef PDF_ENABLE_XFA
-      m_bShallowCopy(false),
-      m_pOwnedStream(nullptr),
-#endif  // PDF_ENABLE_XFA
       m_Face(nullptr),
       m_FaceCache(nullptr),
       m_pFontData(nullptr),
@@ -228,48 +224,13 @@
 }
 
 #ifdef PDF_ENABLE_XFA
-bool CFX_Font::LoadClone(const CFX_Font* pFont) {
-  if (!pFont)
-    return false;
-
-  m_bShallowCopy = true;
-  if (pFont->m_pSubstFont) {
-    m_pSubstFont = pdfium::MakeUnique<CFX_SubstFont>();
-    m_pSubstFont->m_Charset = pFont->m_pSubstFont->m_Charset;
-    m_pSubstFont->m_bFlagMM = pFont->m_pSubstFont->m_bFlagMM;
-#ifdef PDF_ENABLE_XFA
-    m_pSubstFont->m_bFlagItalic = pFont->m_pSubstFont->m_bFlagItalic;
-#endif  // PDF_ENABLE_XFA
-    m_pSubstFont->m_Weight = pFont->m_pSubstFont->m_Weight;
-    m_pSubstFont->m_Family = pFont->m_pSubstFont->m_Family;
-    m_pSubstFont->m_ItalicAngle = pFont->m_pSubstFont->m_ItalicAngle;
-  }
-  m_Face = pFont->m_Face;
-  m_bEmbedded = pFont->m_bEmbedded;
-  m_bVertical = pFont->m_bVertical;
-  m_dwSize = pFont->m_dwSize;
-  m_pFontData = pFont->m_pFontData;
-  m_pGsubData = pFont->m_pGsubData;
-#if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
-  m_pPlatformFont = pFont->m_pPlatformFont;
-#endif
-  m_pOwnedStream = pFont->m_pOwnedStream;
-  m_FaceCache = pFont->GetFaceCache();
-  return true;
-}
-
 void CFX_Font::SetFace(FXFT_Face face) {
   ClearFaceCache();
   m_Face = face;
 }
-
 #endif  // PDF_ENABLE_XFA
 
 CFX_Font::~CFX_Font() {
-#ifdef PDF_ENABLE_XFA
-  if (m_bShallowCopy)
-    return;
-#endif  // PDF_ENABLE_XFA
   if (m_Face) {
 #ifndef PDF_ENABLE_XFA
     if (FXFT_Get_Face_External_Stream(m_Face)) {
@@ -278,11 +239,7 @@
 #endif  // PDF_ENABLE_XFA
     DeleteFace();
   }
-#ifdef PDF_ENABLE_XFA
-  delete m_pOwnedStream;
-#endif  // PDF_ENABLE_XFA
-  FX_Free(m_pGsubData);
-#if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_ && !defined _SKIA_SUPPORT_
+#if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
   ReleasePlatformResource();
 #endif
 }
@@ -328,7 +285,7 @@
   if (!LoadFileImp(library, &m_Face, pFile, nFaceIndex, &stream))
     return false;
 
-  m_pOwnedStream = stream.release();
+  m_pOwnedStream = std::move(stream);
   FXFT_Set_Pixel_Sizes(m_Face, 0, 64);
   return true;
 }
diff --git a/core/fxge/cfx_font.h b/core/fxge/cfx_font.h
index ecb64e5..13cb892 100644
--- a/core/fxge/cfx_font.h
+++ b/core/fxge/cfx_font.h
@@ -46,7 +46,6 @@
 #ifdef PDF_ENABLE_XFA
   bool LoadFile(const RetainPtr<IFX_SeekableReadStream>& pFile, int nFaceIndex);
 
-  bool LoadClone(const CFX_Font* pFont);
   void SetFace(FXFT_Face face);
   void SetSubstFont(std::unique_ptr<CFX_SubstFont> subst) {
     m_pSubstFont = std::move(subst);
@@ -79,8 +78,8 @@
   bool IsTTFont() const;
   bool GetBBox(FX_RECT& bbox);
   bool IsEmbedded() const { return m_bEmbedded; }
-  uint8_t* GetSubData() const { return m_pGsubData; }
-  void SetSubData(uint8_t* data) { m_pGsubData = data; }
+  uint8_t* GetSubData() const { return m_pGsubData.get(); }
+  void SetSubData(uint8_t* data) { m_pGsubData.reset(data); }
 #if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
   void* GetPlatformFont() const { return m_pPlatformFont; }
   void SetPlatformFont(void* font) { m_pPlatformFont = font; }
@@ -100,13 +99,14 @@
 
 #ifdef PDF_ENABLE_XFA
  protected:
-  bool m_bShallowCopy;
-  FXFT_StreamRec* m_pOwnedStream;
+  std::unique_ptr<FXFT_StreamRec> m_pOwnedStream;
 #endif  // PDF_ENABLE_XFA
 
  private:
   CFX_FaceCache* GetFaceCache() const;
+#if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
   void ReleasePlatformResource();
+#endif  // _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
   void DeleteFace();
   void ClearFaceCache();
 
@@ -115,7 +115,7 @@
   std::unique_ptr<CFX_SubstFont> m_pSubstFont;
   std::vector<uint8_t> m_pFontDataAllocation;
   uint8_t* m_pFontData;
-  uint8_t* m_pGsubData;
+  std::unique_ptr<uint8_t, FxFreeDeleter> m_pGsubData;
   uint32_t m_dwSize;
 #if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
   void* m_pPlatformFont;
diff --git a/xfa/fgas/font/cfgas_fontmgr.cpp b/xfa/fgas/font/cfgas_fontmgr.cpp
index 3838434..1e829e5 100644
--- a/xfa/fgas/font/cfgas_fontmgr.cpp
+++ b/xfa/fgas/font/cfgas_fontmgr.cpp
@@ -150,36 +150,6 @@
   return iBestSimilar < 1 ? nullptr : pBestFont;
 }
 
-uint32_t GetFontHashCode(uint16_t wCodePage, uint32_t dwFontStyles) {
-  uint32_t dwHash = wCodePage;
-  if (FontStyleIsFixedPitch(dwFontStyles))
-    dwHash |= 0x00010000;
-  if (FontStyleIsSerif(dwFontStyles))
-    dwHash |= 0x00020000;
-  if (FontStyleIsSymbolic(dwFontStyles))
-    dwHash |= 0x00040000;
-  if (FontStyleIsScript(dwFontStyles))
-    dwHash |= 0x00080000;
-  if (FontStyleIsItalic(dwFontStyles))
-    dwHash |= 0x00100000;
-  if (FontStyleIsBold(dwFontStyles))
-    dwHash |= 0x00200000;
-  return dwHash;
-}
-
-uint32_t GetFontFamilyHash(const wchar_t* pszFontFamily,
-                           uint32_t dwFontStyles,
-                           uint16_t wCodePage) {
-  WideString wsFont(pszFontFamily);
-  if (FontStyleIsBold(dwFontStyles))
-    wsFont += L"Bold";
-  if (FontStyleIsItalic(dwFontStyles))
-    wsFont += L"Italic";
-
-  wsFont += wCodePage;
-  return FX_HashCode_GetW(wsFont.AsStringView(), false);
-}
-
 uint32_t GetGdiFontStyles(const LOGFONTW& lf) {
   uint32_t dwStyles = 0;
   if ((lf.lfPitchAndFamily & 0x03) == FIXED_PITCH)
@@ -245,155 +215,6 @@
   return true;
 }
 
-RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::GetFontByCodePage(
-    uint16_t wCodePage,
-    uint32_t dwFontStyles,
-    const wchar_t* pszFontFamily) {
-  uint32_t dwHash = GetFontHashCode(wCodePage, dwFontStyles);
-  auto it = m_CPFonts.find(dwHash);
-  if (it != m_CPFonts.end()) {
-    return it->second ? LoadFont(it->second, dwFontStyles, wCodePage) : nullptr;
-  }
-  const FX_FONTDESCRIPTOR* pFD =
-      FindFont(pszFontFamily, dwFontStyles, true, wCodePage, 999, 0);
-  if (!pFD)
-    pFD = FindFont(nullptr, dwFontStyles, true, wCodePage, 999, 0);
-  if (!pFD)
-    pFD = FindFont(nullptr, dwFontStyles, false, wCodePage, 999, 0);
-  if (!pFD)
-    return nullptr;
-
-  RetainPtr<CFGAS_GEFont> pFont =
-      CFGAS_GEFont::LoadFont(pFD->wsFontFace, dwFontStyles, wCodePage, this);
-  if (!pFont)
-    return nullptr;
-
-  m_Fonts.push_back(pFont);
-  m_CPFonts[dwHash] = pFont;
-  dwHash = GetFontFamilyHash(pFD->wsFontFace, dwFontStyles, wCodePage);
-  m_FamilyFonts[dwHash] = pFont;
-  return LoadFont(pFont, dwFontStyles, wCodePage);
-}
-
-RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::GetFontByUnicode(
-    wchar_t wUnicode,
-    uint32_t dwFontStyles,
-    const wchar_t* pszFontFamily) {
-  const FGAS_FONTUSB* pRet = FGAS_GetUnicodeBitField(wUnicode);
-  if (pRet->wBitField == 999)
-    return nullptr;
-
-  uint32_t dwHash =
-      GetFontFamilyHash(pszFontFamily, dwFontStyles, pRet->wBitField);
-  auto it = m_UnicodeFonts.find(dwHash);
-  if (it != m_UnicodeFonts.end()) {
-    return it->second ? LoadFont(it->second, dwFontStyles, pRet->wCodePage)
-                      : nullptr;
-  }
-  const FX_FONTDESCRIPTOR* pFD =
-      FindFont(pszFontFamily, dwFontStyles, false, pRet->wCodePage,
-               pRet->wBitField, wUnicode);
-  if (!pFD && pszFontFamily) {
-    pFD = FindFont(nullptr, dwFontStyles, false, pRet->wCodePage,
-                   pRet->wBitField, wUnicode);
-  }
-  if (!pFD)
-    return nullptr;
-
-  uint16_t wCodePage = GetCodePageFromCharset(pFD->uCharSet);
-  const wchar_t* pFontFace = pFD->wsFontFace;
-  RetainPtr<CFGAS_GEFont> pFont =
-      CFGAS_GEFont::LoadFont(pFontFace, dwFontStyles, wCodePage, this);
-  if (!pFont)
-    return nullptr;
-
-  m_Fonts.push_back(pFont);
-  m_UnicodeFonts[dwHash] = pFont;
-  m_CPFonts[GetFontHashCode(wCodePage, dwFontStyles)] = pFont;
-  m_FamilyFonts[GetFontFamilyHash(pFontFace, dwFontStyles, wCodePage)] = pFont;
-  return LoadFont(pFont, dwFontStyles, wCodePage);
-}
-
-RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::LoadFont(const wchar_t* pszFontFamily,
-                                                uint32_t dwFontStyles,
-                                                uint16_t wCodePage) {
-  RetainPtr<CFGAS_GEFont> pFont;
-  uint32_t dwHash = GetFontFamilyHash(pszFontFamily, dwFontStyles, wCodePage);
-  auto it = m_FamilyFonts.find(dwHash);
-  if (it != m_FamilyFonts.end())
-    return it->second ? LoadFont(it->second, dwFontStyles, wCodePage) : nullptr;
-
-  const FX_FONTDESCRIPTOR* pFD =
-      FindFont(pszFontFamily, dwFontStyles, true, wCodePage, 999, 0);
-  if (!pFD)
-    pFD = FindFont(pszFontFamily, dwFontStyles, false, wCodePage, 999, 0);
-  if (!pFD)
-    return nullptr;
-
-  if (wCodePage == 0xFFFF)
-    wCodePage = GetCodePageFromCharset(pFD->uCharSet);
-
-  pFont =
-      CFGAS_GEFont::LoadFont(pFD->wsFontFace, dwFontStyles, wCodePage, this);
-  if (!pFont)
-    return nullptr;
-
-  m_Fonts.push_back(pFont);
-  m_FamilyFonts[dwHash] = pFont;
-  dwHash = GetFontHashCode(wCodePage, dwFontStyles);
-  m_CPFonts[dwHash] = pFont;
-  return LoadFont(pFont, dwFontStyles, wCodePage);
-}
-
-RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::LoadFont(
-    const RetainPtr<CFGAS_GEFont>& pSrcFont,
-    uint32_t dwFontStyles,
-    uint16_t wCodePage) {
-  if (pSrcFont->GetFontStyles() == dwFontStyles)
-    return pSrcFont;
-
-  void* buffer[3] = {pSrcFont.Get(), (void*)(uintptr_t)dwFontStyles,
-                     (void*)(uintptr_t)wCodePage};
-  uint32_t dwHash =
-      FX_HashCode_GetA(ByteStringView((uint8_t*)buffer, sizeof(buffer)), false);
-  auto it = m_DeriveFonts.find(dwHash);
-  if (it != m_DeriveFonts.end() && it->second)
-    return it->second;
-
-  RetainPtr<CFGAS_GEFont> pFont = pSrcFont->Derive(dwFontStyles, wCodePage);
-  if (!pFont)
-    return nullptr;
-
-  m_DeriveFonts[dwHash] = pFont;
-  auto iter = std::find(m_Fonts.begin(), m_Fonts.end(), pFont);
-  if (iter == m_Fonts.end())
-    m_Fonts.push_back(pFont);
-  return pFont;
-}
-
-void CFGAS_FontMgr::RemoveFont(
-    std::map<uint32_t, RetainPtr<CFGAS_GEFont>>* pFontMap,
-    const RetainPtr<CFGAS_GEFont>& pFont) {
-  auto iter = pFontMap->begin();
-  while (iter != pFontMap->end()) {
-    auto old_iter = iter++;
-    if (old_iter->second == pFont)
-      pFontMap->erase(old_iter);
-  }
-}
-
-void CFGAS_FontMgr::RemoveFont(const RetainPtr<CFGAS_GEFont>& pFont) {
-  RemoveFont(&m_CPFonts, pFont);
-  RemoveFont(&m_FamilyFonts, pFont);
-  RemoveFont(&m_UnicodeFonts, pFont);
-  RemoveFont(&m_BufferFonts, pFont);
-  RemoveFont(&m_StreamFonts, pFont);
-  RemoveFont(&m_DeriveFonts, pFont);
-  auto it = std::find(m_Fonts.begin(), m_Fonts.end(), pFont);
-  if (it != m_Fonts.end())
-    m_Fonts.erase(it);
-}
-
 const FX_FONTDESCRIPTOR* CFGAS_FontMgr::FindFont(const wchar_t* pszFontFamily,
                                                  uint32_t dwFontStyles,
                                                  bool matchParagraphStyle,
@@ -753,95 +574,6 @@
   return EnumFontsFromFontMapper() || EnumFontsFromFiles();
 }
 
-RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::LoadFont(const wchar_t* pszFontFamily,
-                                                uint32_t dwFontStyles,
-                                                uint16_t wCodePage) {
-  return GetFontByCodePage(wCodePage, dwFontStyles, pszFontFamily);
-}
-
-RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::GetFontByCodePage(
-    uint16_t wCodePage,
-    uint32_t dwFontStyles,
-    const wchar_t* pszFontFamily) {
-  ByteString bsHash;
-  bsHash.Format("%d, %d", wCodePage, dwFontStyles);
-  bsHash += FX_UTF8Encode(WideStringView(pszFontFamily));
-  uint32_t dwHash = FX_HashCode_GetA(bsHash.AsStringView(), false);
-  std::vector<RetainPtr<CFGAS_GEFont>>* pFontArray = &m_Hash2Fonts[dwHash];
-  if (!pFontArray->empty())
-    return (*pFontArray)[0];
-
-  std::vector<CFX_FontDescriptorInfo>* sortedFontInfos =
-      m_Hash2CandidateList[dwHash].get();
-  if (!sortedFontInfos) {
-    auto pNewFonts = pdfium::MakeUnique<std::vector<CFX_FontDescriptorInfo>>();
-    sortedFontInfos = pNewFonts.get();
-    MatchFonts(sortedFontInfos, wCodePage, dwFontStyles,
-               WideString(pszFontFamily), 0);
-    m_Hash2CandidateList[dwHash] = std::move(pNewFonts);
-  }
-  if (sortedFontInfos->empty())
-    return nullptr;
-
-  CFX_FontDescriptor* pDesc = (*sortedFontInfos)[0].pFont;
-  RetainPtr<CFGAS_GEFont> pFont =
-      LoadFont(pDesc->m_wsFaceName, pDesc->m_nFaceIndex, nullptr);
-  if (!pFont)
-    return nullptr;
-
-  pFont->SetLogicalFontStyle(dwFontStyles);
-  pFontArray->push_back(pFont);
-  return pFont;
-}
-
-RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::GetFontByUnicode(
-    wchar_t wUnicode,
-    uint32_t dwFontStyles,
-    const wchar_t* pszFontFamily) {
-  if (pdfium::ContainsKey(m_FailedUnicodesSet, wUnicode))
-    return nullptr;
-
-  const FGAS_FONTUSB* x = FGAS_GetUnicodeBitField(wUnicode);
-  uint16_t wCodePage = x ? x->wCodePage : 0xFFFF;
-  uint16_t wBitField = x ? x->wBitField : 0x03E7;
-  ByteString bsHash;
-  if (wCodePage == 0xFFFF)
-    bsHash.Format("%d, %d, %d", wCodePage, wBitField, dwFontStyles);
-  else
-    bsHash.Format("%d, %d", wCodePage, dwFontStyles);
-  bsHash += FX_UTF8Encode(WideStringView(pszFontFamily));
-  uint32_t dwHash = FX_HashCode_GetA(bsHash.AsStringView(), false);
-  std::vector<RetainPtr<CFGAS_GEFont>>* pFonts = &m_Hash2Fonts[dwHash];
-  for (size_t i = 0; i < pFonts->size(); ++i) {
-    if (VerifyUnicode((*pFonts)[i], wUnicode))
-      return (*pFonts)[i];
-  }
-  std::vector<CFX_FontDescriptorInfo>* sortedFontInfos =
-      m_Hash2CandidateList[dwHash].get();
-  if (!sortedFontInfos) {
-    auto pNewFonts = pdfium::MakeUnique<std::vector<CFX_FontDescriptorInfo>>();
-    sortedFontInfos = pNewFonts.get();
-    MatchFonts(sortedFontInfos, wCodePage, dwFontStyles,
-               WideString(pszFontFamily), wUnicode);
-    m_Hash2CandidateList[dwHash] = std::move(pNewFonts);
-  }
-  for (const auto& info : *sortedFontInfos) {
-    CFX_FontDescriptor* pDesc = info.pFont;
-    if (!VerifyUnicode(pDesc, wUnicode))
-      continue;
-    RetainPtr<CFGAS_GEFont> pFont =
-        LoadFont(pDesc->m_wsFaceName, pDesc->m_nFaceIndex, nullptr);
-    if (!pFont)
-      continue;
-    pFont->SetLogicalFontStyle(dwFontStyles);
-    pFonts->push_back(pFont);
-    return pFont;
-  }
-  if (!pszFontFamily)
-    m_FailedUnicodesSet.insert(wUnicode);
-  return nullptr;
-}
-
 bool CFGAS_FontMgr::VerifyUnicode(CFX_FontDescriptor* pDesc,
                                   wchar_t wcUnicode) {
   RetainPtr<IFX_SeekableReadStream> pFileRead =
@@ -862,23 +594,6 @@
   return !retCharmap && retIndex;
 }
 
-bool CFGAS_FontMgr::VerifyUnicode(const RetainPtr<CFGAS_GEFont>& pFont,
-                                  wchar_t wcUnicode) {
-  if (!pFont)
-    return false;
-
-  FXFT_Face pFace = pFont->GetDevFont()->GetFace();
-  FXFT_CharMap charmap = FXFT_Get_Face_Charmap(pFace);
-  if (FXFT_Select_Charmap(pFace, FXFT_ENCODING_UNICODE) != 0)
-    return false;
-
-  if (FXFT_Get_Char_Index(pFace, wcUnicode) == 0) {
-    FXFT_Set_Charmap(pFace, charmap);
-    return false;
-  }
-  return true;
-}
-
 RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::LoadFont(const WideString& wsFaceName,
                                                 int32_t iFaceIndex,
                                                 int32_t* pFaceCount) {
@@ -1081,27 +796,6 @@
   return nPenalty;
 }
 
-void CFGAS_FontMgr::RemoveFont(const RetainPtr<CFGAS_GEFont>& pEFont) {
-  if (!pEFont)
-    return;
-
-  m_IFXFont2FileRead.erase(pEFont);
-
-  auto iter = m_Hash2Fonts.begin();
-  while (iter != m_Hash2Fonts.end()) {
-    auto old_iter = iter++;
-    bool all_empty = true;
-    for (size_t i = 0; i < old_iter->second.size(); i++) {
-      if (old_iter->second[i] == pEFont)
-        old_iter->second[i].Reset();
-      else if (old_iter->second[i])
-        all_empty = false;
-    }
-    if (all_empty)
-      m_Hash2Fonts.erase(old_iter);
-  }
-}
-
 void CFGAS_FontMgr::RegisterFace(FXFT_Face pFace, const WideString* pFaceName) {
   if ((pFace->face_flags & FT_FACE_FLAG_SCALABLE) == 0)
     return;
@@ -1253,3 +947,197 @@
 }
 
 #endif  // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+
+RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::GetFontByCodePage(
+    uint16_t wCodePage,
+    uint32_t dwFontStyles,
+    const wchar_t* pszFontFamily) {
+  ByteString bsHash;
+  bsHash.Format("%d, %d", wCodePage, dwFontStyles);
+  bsHash += FX_UTF8Encode(WideStringView(pszFontFamily));
+  uint32_t dwHash = FX_HashCode_GetA(bsHash.AsStringView(), false);
+  std::vector<RetainPtr<CFGAS_GEFont>>* pFontArray = &m_Hash2Fonts[dwHash];
+  if (!pFontArray->empty())
+    return (*pFontArray)[0];
+
+#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+  const FX_FONTDESCRIPTOR* pFD =
+      FindFont(pszFontFamily, dwFontStyles, true, wCodePage, 999, 0);
+  if (!pFD)
+    pFD = FindFont(nullptr, dwFontStyles, true, wCodePage, 999, 0);
+  if (!pFD)
+    pFD = FindFont(nullptr, dwFontStyles, false, wCodePage, 999, 0);
+  if (!pFD)
+    return nullptr;
+
+  RetainPtr<CFGAS_GEFont> pFont =
+      CFGAS_GEFont::LoadFont(pFD->wsFontFace, dwFontStyles, wCodePage, this);
+#else   // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+  std::vector<CFX_FontDescriptorInfo>* sortedFontInfos =
+      m_Hash2CandidateList[dwHash].get();
+  if (!sortedFontInfos) {
+    auto pNewFonts = pdfium::MakeUnique<std::vector<CFX_FontDescriptorInfo>>();
+    sortedFontInfos = pNewFonts.get();
+    MatchFonts(sortedFontInfos, wCodePage, dwFontStyles,
+               WideString(pszFontFamily), 0);
+    m_Hash2CandidateList[dwHash] = std::move(pNewFonts);
+  }
+  if (sortedFontInfos->empty())
+    return nullptr;
+
+  CFX_FontDescriptor* pDesc = (*sortedFontInfos)[0].pFont;
+  RetainPtr<CFGAS_GEFont> pFont =
+      LoadFont(pDesc->m_wsFaceName, pDesc->m_nFaceIndex, nullptr);
+#endif  // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+
+  if (!pFont)
+    return nullptr;
+
+  pFont->SetLogicalFontStyle(dwFontStyles);
+  pFontArray->push_back(pFont);
+  return pFont;
+}
+
+RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::GetFontByUnicode(
+    wchar_t wUnicode,
+    uint32_t dwFontStyles,
+    const wchar_t* pszFontFamily) {
+#if _FX_PLATFORM_ != _FX_PLATFORM_WINDOWS_
+  if (pdfium::ContainsKey(m_FailedUnicodesSet, wUnicode))
+    return nullptr;
+#endif  // _FX_PLATFORM_ != _FX_PLATFORM_WINDOWS_
+
+  const FGAS_FONTUSB* x = FGAS_GetUnicodeBitField(wUnicode);
+  uint16_t wCodePage = x ? x->wCodePage : 0xFFFF;
+  uint16_t wBitField = x ? x->wBitField : 0x03E7;
+  ByteString bsHash;
+  if (wCodePage == 0xFFFF)
+    bsHash.Format("%d, %d, %d", wCodePage, wBitField, dwFontStyles);
+  else
+    bsHash.Format("%d, %d", wCodePage, dwFontStyles);
+  bsHash += FX_UTF8Encode(WideStringView(pszFontFamily));
+  uint32_t dwHash = FX_HashCode_GetA(bsHash.AsStringView(), false);
+  std::vector<RetainPtr<CFGAS_GEFont>>* pFonts = &m_Hash2Fonts[dwHash];
+  for (size_t i = 0; i < pFonts->size(); ++i) {
+    if (VerifyUnicode((*pFonts)[i], wUnicode))
+      return (*pFonts)[i];
+  }
+#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+  const FX_FONTDESCRIPTOR* pFD = FindFont(pszFontFamily, dwFontStyles, false,
+                                          wCodePage, wBitField, wUnicode);
+  if (!pFD && pszFontFamily) {
+    pFD =
+        FindFont(nullptr, dwFontStyles, false, wCodePage, wBitField, wUnicode);
+  }
+  if (!pFD)
+    return nullptr;
+
+  uint16_t newCodePage = GetCodePageFromCharset(pFD->uCharSet);
+  const wchar_t* pFontFace = pFD->wsFontFace;
+  RetainPtr<CFGAS_GEFont> pFont =
+      CFGAS_GEFont::LoadFont(pFontFace, dwFontStyles, newCodePage, this);
+  if (!pFont)
+    return nullptr;
+
+  pFont->SetLogicalFontStyle(dwFontStyles);
+  pFonts->push_back(pFont);
+  return pFont;
+#else   // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+  std::vector<CFX_FontDescriptorInfo>* sortedFontInfos =
+      m_Hash2CandidateList[dwHash].get();
+  if (!sortedFontInfos) {
+    auto pNewFonts = pdfium::MakeUnique<std::vector<CFX_FontDescriptorInfo>>();
+    sortedFontInfos = pNewFonts.get();
+    MatchFonts(sortedFontInfos, wCodePage, dwFontStyles,
+               WideString(pszFontFamily), wUnicode);
+    m_Hash2CandidateList[dwHash] = std::move(pNewFonts);
+  }
+  for (const auto& info : *sortedFontInfos) {
+    CFX_FontDescriptor* pDesc = info.pFont;
+    if (!VerifyUnicode(pDesc, wUnicode))
+      continue;
+    RetainPtr<CFGAS_GEFont> pFont =
+        LoadFont(pDesc->m_wsFaceName, pDesc->m_nFaceIndex, nullptr);
+    if (!pFont)
+      continue;
+    pFont->SetLogicalFontStyle(dwFontStyles);
+    pFonts->push_back(pFont);
+    return pFont;
+  }
+  if (!pszFontFamily)
+    m_FailedUnicodesSet.insert(wUnicode);
+  return nullptr;
+#endif  // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+}
+
+bool CFGAS_FontMgr::VerifyUnicode(const RetainPtr<CFGAS_GEFont>& pFont,
+                                  wchar_t wcUnicode) {
+  if (!pFont)
+    return false;
+
+  FXFT_Face pFace = pFont->GetDevFont()->GetFace();
+  FXFT_CharMap charmap = FXFT_Get_Face_Charmap(pFace);
+  if (FXFT_Select_Charmap(pFace, FXFT_ENCODING_UNICODE) != 0)
+    return false;
+
+  if (FXFT_Get_Char_Index(pFace, wcUnicode) == 0) {
+    FXFT_Set_Charmap(pFace, charmap);
+    return false;
+  }
+  return true;
+}
+
+RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::LoadFont(const wchar_t* pszFontFamily,
+                                                uint32_t dwFontStyles,
+                                                uint16_t wCodePage) {
+#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+  ByteString bsHash;
+  bsHash.Format("%d, %d", wCodePage, dwFontStyles);
+  bsHash += FX_UTF8Encode(WideStringView(pszFontFamily));
+  uint32_t dwHash = FX_HashCode_GetA(bsHash.AsStringView(), false);
+  std::vector<RetainPtr<CFGAS_GEFont>>* pFontArray = &m_Hash2Fonts[dwHash];
+  if (!pFontArray->empty())
+    return (*pFontArray)[0];
+
+  const FX_FONTDESCRIPTOR* pFD =
+      FindFont(pszFontFamily, dwFontStyles, true, wCodePage, 999, 0);
+  if (!pFD)
+    pFD = FindFont(pszFontFamily, dwFontStyles, false, wCodePage, 999, 0);
+  if (!pFD)
+    return nullptr;
+
+  RetainPtr<CFGAS_GEFont> pFont =
+      CFGAS_GEFont::LoadFont(pFD->wsFontFace, dwFontStyles, wCodePage, this);
+  if (!pFont)
+    return nullptr;
+
+  pFont->SetLogicalFontStyle(dwFontStyles);
+  pFontArray->push_back(pFont);
+  return pFont;
+#else   // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+  return GetFontByCodePage(wCodePage, dwFontStyles, pszFontFamily);
+#endif  // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+}
+
+void CFGAS_FontMgr::RemoveFont(const RetainPtr<CFGAS_GEFont>& pEFont) {
+  if (!pEFont)
+    return;
+
+#if _FX_PLATFORM_ != _FX_PLATFORM_WINDOWS_
+  m_IFXFont2FileRead.erase(pEFont);
+#endif  // _FX_PLATFORM_ != _FX_PLATFORM_WINDOWS_
+
+  auto iter = m_Hash2Fonts.begin();
+  while (iter != m_Hash2Fonts.end()) {
+    auto old_iter = iter++;
+    bool all_empty = true;
+    for (size_t i = 0; i < old_iter->second.size(); i++) {
+      if (old_iter->second[i] == pEFont)
+        old_iter->second[i].Reset();
+      else if (old_iter->second[i])
+        all_empty = false;
+    }
+    if (all_empty)
+      m_Hash2Fonts.erase(old_iter);
+  }
+}
diff --git a/xfa/fgas/font/cfgas_fontmgr.h b/xfa/fgas/font/cfgas_fontmgr.h
index 351b5d6..42171de 100644
--- a/xfa/fgas/font/cfgas_fontmgr.h
+++ b/xfa/fgas/font/cfgas_fontmgr.h
@@ -146,11 +146,6 @@
 
  private:
 #if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
-  RetainPtr<CFGAS_GEFont> LoadFont(const RetainPtr<CFGAS_GEFont>& pSrcFont,
-                                   uint32_t dwFontStyles,
-                                   uint16_t wCodePage);
-  void RemoveFont(std::map<uint32_t, RetainPtr<CFGAS_GEFont>>* pFontMap,
-                  const RetainPtr<CFGAS_GEFont>& pFont);
   const FX_FONTDESCRIPTOR* FindFont(const wchar_t* pszFontFamily,
                                     uint32_t dwFontStyles,
                                     bool matchParagraphStyle,
@@ -160,13 +155,6 @@
 
   FX_LPEnumAllFonts m_pEnumerator;
   std::deque<FX_FONTDESCRIPTOR> m_FontFaces;
-  std::vector<RetainPtr<CFGAS_GEFont>> m_Fonts;
-  std::map<uint32_t, RetainPtr<CFGAS_GEFont>> m_CPFonts;
-  std::map<uint32_t, RetainPtr<CFGAS_GEFont>> m_FamilyFonts;
-  std::map<uint32_t, RetainPtr<CFGAS_GEFont>> m_UnicodeFonts;
-  std::map<uint32_t, RetainPtr<CFGAS_GEFont>> m_BufferFonts;
-  std::map<uint32_t, RetainPtr<CFGAS_GEFont>> m_StreamFonts;
-  std::map<uint32_t, RetainPtr<CFGAS_GEFont>> m_DeriveFonts;
 #else   // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
   bool EnumFontsFromFontMapper();
   bool EnumFontsFromFiles();
@@ -178,7 +166,6 @@
   void GetUSBCSB(FXFT_Face pFace, uint32_t* USB, uint32_t* CSB);
   uint32_t GetFlags(FXFT_Face pFace);
   bool VerifyUnicode(CFX_FontDescriptor* pDesc, wchar_t wcUnicode);
-  bool VerifyUnicode(const RetainPtr<CFGAS_GEFont>& pFont, wchar_t wcUnicode);
   int32_t IsPartName(const WideString& Name1, const WideString& Name2);
   void MatchFonts(std::vector<CFX_FontDescriptorInfo>* MatchedFonts,
                   uint16_t wCodePage,
@@ -206,11 +193,14 @@
   std::vector<std::unique_ptr<CFX_FontDescriptor>> m_InstalledFonts;
   std::map<uint32_t, std::unique_ptr<std::vector<CFX_FontDescriptorInfo>>>
       m_Hash2CandidateList;
-  std::map<uint32_t, std::vector<RetainPtr<CFGAS_GEFont>>> m_Hash2Fonts;
   std::map<RetainPtr<CFGAS_GEFont>, RetainPtr<IFX_SeekableReadStream>>
       m_IFXFont2FileRead;
   std::set<wchar_t> m_FailedUnicodesSet;
 #endif  // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+
+  bool VerifyUnicode(const RetainPtr<CFGAS_GEFont>& pFont, wchar_t wcUnicode);
+
+  std::map<uint32_t, std::vector<RetainPtr<CFGAS_GEFont>>> m_Hash2Fonts;
 };
 
 #endif  // XFA_FGAS_FONT_CFGAS_FONTMGR_H_
diff --git a/xfa/fgas/font/cfgas_gefont.cpp b/xfa/fgas/font/cfgas_gefont.cpp
index 43d019f..83b7ad6 100644
--- a/xfa/fgas/font/cfgas_gefont.cpp
+++ b/xfa/fgas/font/cfgas_gefont.cpp
@@ -56,43 +56,13 @@
 
 CFGAS_GEFont::CFGAS_GEFont(CFGAS_FontMgr* pFontMgr)
     :
-#if _FX_PLATFORM_ != _FX_PLATFORM_WINDOWS_
       m_bUseLogFontStyle(false),
       m_dwLogFontStyle(0),
-#endif
       m_pFont(nullptr),
       m_bExternalFont(false),
       m_pFontMgr(pFontMgr) {
 }
 
-CFGAS_GEFont::CFGAS_GEFont(const RetainPtr<CFGAS_GEFont>& src,
-                           uint32_t dwFontStyles)
-    :
-#if _FX_PLATFORM_ != _FX_PLATFORM_WINDOWS_
-      m_bUseLogFontStyle(false),
-      m_dwLogFontStyle(0),
-#endif
-      m_pFont(nullptr),
-      m_bExternalFont(false),
-      m_pSrcFont(src),
-      m_pFontMgr(src->m_pFontMgr) {
-  ASSERT(m_pSrcFont->m_pFont);
-  m_pFont = new CFX_Font;
-  m_pFont->LoadClone(m_pSrcFont->m_pFont);
-
-  CFX_SubstFont* pSubst = m_pFont->GetSubstFont();
-  if (!pSubst) {
-    pSubst = new CFX_SubstFont;
-    m_pFont->SetSubstFont(std::unique_ptr<CFX_SubstFont>(pSubst));
-  }
-  pSubst->m_Weight =
-      FontStyleIsBold(dwFontStyles) ? FXFONT_FW_BOLD : FXFONT_FW_NORMAL;
-  if (FontStyleIsItalic(dwFontStyles))
-    pSubst->m_bFlagItalic = true;
-
-  InitFont();
-}
-
 CFGAS_GEFont::~CFGAS_GEFont() {
   if (!m_bExternalFont)
     delete m_pFont;
@@ -155,16 +125,6 @@
   return !!m_pFontEncoding;
 }
 
-#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
-RetainPtr<CFGAS_GEFont> CFGAS_GEFont::Derive(uint32_t dwFontStyles,
-                                             uint16_t wCodePage) {
-  RetainPtr<CFGAS_GEFont> pFont(this);
-  if (GetFontStyles() == dwFontStyles)
-    return pFont;
-  return pdfium::MakeRetain<CFGAS_GEFont>(pFont, dwFontStyles);
-}
-#endif  // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
-
 WideString CFGAS_GEFont::GetFamilyName() const {
   if (!m_pFont->GetSubstFont() ||
       m_pFont->GetSubstFont()->m_Family.GetLength() == 0) {
@@ -176,10 +136,8 @@
 
 uint32_t CFGAS_GEFont::GetFontStyles() const {
   ASSERT(m_pFont);
-#if _FX_PLATFORM_ != _FX_PLATFORM_WINDOWS_
   if (m_bUseLogFontStyle)
     return m_dwLogFontStyle;
-#endif
 
   uint32_t dwStyles = 0;
   auto* pSubstFont = m_pFont->GetSubstFont();
diff --git a/xfa/fgas/font/cfgas_gefont.h b/xfa/fgas/font/cfgas_gefont.h
index 2e63ee5..d145547 100644
--- a/xfa/fgas/font/cfgas_gefont.h
+++ b/xfa/fgas/font/cfgas_gefont.h
@@ -54,18 +54,13 @@
     m_pProvider.Reset(pProvider);
   }
 
-#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
-  RetainPtr<CFGAS_GEFont> Derive(uint32_t dwFontStyles, uint16_t wCodePage);
-#else   // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
   void SetLogicalFontStyle(uint32_t dwLogFontStyle) {
     m_bUseLogFontStyle = true;
     m_dwLogFontStyle = dwLogFontStyle;
   }
-#endif  // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
 
  private:
   explicit CFGAS_GEFont(CFGAS_FontMgr* pFontMgr);
-  CFGAS_GEFont(const RetainPtr<CFGAS_GEFont>& src, uint32_t dwFontStyles);
   ~CFGAS_GEFont() override;
 
 #if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
@@ -84,10 +79,8 @@
       bool bRecursive);
   WideString GetFamilyName() const;
 
-#if _FX_PLATFORM_ != _FX_PLATFORM_WINDOWS_
   bool m_bUseLogFontStyle;
   uint32_t m_dwLogFontStyle;
-#endif
   CFX_Font* m_pFont;
   bool m_bExternalFont;
   RetainPtr<CFGAS_GEFont> m_pSrcFont;  // Only set by ctor, so no cycles.