Revert "Make CFX_FontMgr member variables private."
[pdfium.git] / core / src / fxge / ge / fx_ge_fontmap.cpp
index 6549e8e..e88791a 100644 (file)
-// Copyright 2014 PDFium Authors. All rights reserved.\r
-// Use of this source code is governed by a BSD-style license that can be\r
-// found in the LICENSE file.\r
\r
-// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
-\r
-#include "../../../include/fxge/fx_ge.h"\r
-#include "../../../include/fxge/fx_freetype.h"\r
-#include "text_int.h"\r
-#define GET_TT_SHORT(w)  (FX_WORD)(((w)[0] << 8) | (w)[1])\r
-#define GET_TT_LONG(w) (FX_DWORD)(((w)[0] << 24) | ((w)[1] << 16) | ((w)[2] << 8) | (w)[3])\r
-CFX_SubstFont::CFX_SubstFont()\r
-{\r
-    m_ExtHandle = NULL;\r
-    m_Charset = 0;\r
-    m_SubstFlags = 0;\r
-    m_Weight = 0;\r
-    m_ItalicAngle = 0;\r
-    m_bSubstOfCJK = FALSE;\r
-    m_WeightCJK = 0;\r
-    m_bItlicCJK = FALSE;\r
-}\r
-CTTFontDesc::~CTTFontDesc()\r
-{\r
-    if (m_Type == 1) {\r
-        if (m_SingleFace.m_pFace) {\r
-            FXFT_Done_Face(m_SingleFace.m_pFace);\r
-        }\r
-    } else if (m_Type == 2) {\r
-        for (int i = 0; i < 16; i ++)\r
-            if (m_TTCFace.m_pFaces[i]) {\r
-                FXFT_Done_Face(m_TTCFace.m_pFaces[i]);\r
-            }\r
-    }\r
-    if (m_pFontData) {\r
-        FX_Free(m_pFontData);\r
-    }\r
-}\r
-FX_BOOL CTTFontDesc::ReleaseFace(FXFT_Face face)\r
-{\r
-    if (m_Type == 1) {\r
-        if (m_SingleFace.m_pFace != face) {\r
-            return FALSE;\r
-        }\r
-    } else if (m_Type == 2) {\r
-        int i;\r
-        for (i = 0; i < 16; i ++)\r
-            if (m_TTCFace.m_pFaces[i] == face) {\r
-                break;\r
-            }\r
-        if (i == 16) {\r
-            return FALSE;\r
-        }\r
-    }\r
-    m_RefCount --;\r
-    if (m_RefCount) {\r
-        return FALSE;\r
-    }\r
-    delete this;\r
-    return TRUE;\r
-}\r
-CFX_FontMgr::CFX_FontMgr()\r
-{\r
-    m_pBuiltinMapper = FX_NEW CFX_FontMapper;\r
-    if (!m_pBuiltinMapper) {\r
-        return;\r
-    }\r
-    m_pBuiltinMapper->m_pFontMgr = this;\r
-    m_pExtMapper = NULL;\r
-    m_FTLibrary = NULL;\r
-    FXSYS_memset32(m_ExternalFonts, 0, sizeof m_ExternalFonts);\r
-}\r
-CFX_FontMgr::~CFX_FontMgr()\r
-{\r
-    if (m_pBuiltinMapper) {\r
-        delete m_pBuiltinMapper;\r
-    }\r
-    FreeCache();\r
-    if (m_FTLibrary) {\r
-        FXFT_Done_FreeType(m_FTLibrary);\r
-    }\r
-}\r
-void CFX_FontMgr::InitFTLibrary()\r
-{\r
-    if (m_FTLibrary == NULL) {\r
-        FXFT_Init_FreeType(&m_FTLibrary);\r
-    }\r
-}\r
-void CFX_FontMgr::FreeCache()\r
-{\r
-    FX_POSITION pos = m_FaceMap.GetStartPosition();\r
-    while(pos) {\r
-        CFX_ByteString Key;\r
-        CTTFontDesc* face;\r
-        m_FaceMap.GetNextAssoc(pos, Key, (void*&)face);\r
-        delete face;\r
-    }\r
-    m_FaceMap.RemoveAll();\r
-}\r
-void CFX_FontMgr::SetSystemFontInfo(IFX_SystemFontInfo* pFontInfo)\r
-{\r
-    m_pBuiltinMapper->SetSystemFontInfo(pFontInfo);\r
-}\r
-FXFT_Face CFX_FontMgr::FindSubstFont(const CFX_ByteString& face_name, FX_BOOL bTrueType,\r
-                                     FX_DWORD flags, int weight, int italic_angle, int CharsetCP, CFX_SubstFont* pSubstFont)\r
-{\r
-    if (m_FTLibrary == NULL) {\r
-        FXFT_Init_FreeType(&m_FTLibrary);\r
-    }\r
-    if (m_pExtMapper) {\r
-        FXFT_Face face = m_pExtMapper->FindSubstFont(face_name, bTrueType, flags, weight, italic_angle,\r
-                         CharsetCP, pSubstFont);\r
-        if (face) {\r
-            return face;\r
-        }\r
-    }\r
-    return m_pBuiltinMapper->FindSubstFont(face_name, bTrueType, flags, weight, italic_angle,\r
-                                           CharsetCP, pSubstFont);\r
-}\r
-FXFT_Face CFX_FontMgr::GetCachedFace(const CFX_ByteString& face_name,\r
-                                     int weight, FX_BOOL bItalic, FX_LPBYTE& pFontData)\r
-{\r
-    CFX_ByteString key(face_name);\r
-    key += ',';\r
-    key += CFX_ByteString::FormatInteger(weight);\r
-    key += bItalic ? 'I' : 'N';\r
-    CTTFontDesc* pFontDesc = NULL;\r
-    m_FaceMap.Lookup(key, (void*&)pFontDesc);\r
-    if(pFontDesc) {\r
-        pFontData = pFontDesc->m_pFontData;\r
-        pFontDesc->m_RefCount ++;\r
-        return pFontDesc->m_SingleFace.m_pFace;\r
-    }\r
-    return NULL;\r
-}\r
-FXFT_Face CFX_FontMgr::AddCachedFace(const CFX_ByteString& face_name,\r
-                                     int weight, FX_BOOL bItalic, FX_LPBYTE pData, FX_DWORD size, int face_index)\r
-{\r
-    CTTFontDesc* pFontDesc = FX_NEW CTTFontDesc;\r
-    if (!pFontDesc) {\r
-        return NULL;\r
-    }\r
-    pFontDesc->m_Type = 1;\r
-    pFontDesc->m_SingleFace.m_pFace = NULL;\r
-    pFontDesc->m_SingleFace.m_bBold = weight;\r
-    pFontDesc->m_SingleFace.m_bItalic = bItalic;\r
-    pFontDesc->m_pFontData = pData;\r
-    pFontDesc->m_RefCount = 1;\r
-    FXFT_Library library;\r
-    if (m_FTLibrary == NULL) {\r
-        FXFT_Init_FreeType(&m_FTLibrary);\r
-    }\r
-    library = m_FTLibrary;\r
-    int ret = FXFT_New_Memory_Face(library, pData, size, face_index, &pFontDesc->m_SingleFace.m_pFace);\r
-    if (ret) {\r
-        delete pFontDesc;\r
-        return NULL;\r
-    }\r
-    ret = FXFT_Set_Pixel_Sizes(pFontDesc->m_SingleFace.m_pFace, 64, 64);\r
-    if (ret) {\r
-        delete pFontDesc;\r
-        return NULL;\r
-    }\r
-    CFX_ByteString key(face_name);\r
-    key += ',';\r
-    key += CFX_ByteString::FormatInteger(weight);\r
-    key += bItalic ? 'I' : 'N';\r
-    m_FaceMap.SetAt(key, pFontDesc);\r
-    return pFontDesc->m_SingleFace.m_pFace;\r
-}\r
-const FX_LPCSTR g_Base14FontNames[14] = {\r
-    "Courier",\r
-    "Courier-Bold",\r
-    "Courier-BoldOblique",\r
-    "Courier-Oblique",\r
-    "Helvetica",\r
-    "Helvetica-Bold",\r
-    "Helvetica-BoldOblique",\r
-    "Helvetica-Oblique",\r
-    "Times-Roman",\r
-    "Times-Bold",\r
-    "Times-BoldItalic",\r
-    "Times-Italic",\r
-    "Symbol",\r
-    "ZapfDingbats",\r
-};\r
-const struct _AltFontName {\r
-    const FX_CHAR*     m_pName;\r
-    int                m_Index;\r
-}\r
-g_AltFontNames[] = {\r
-    {"Arial", 4},\r
-    {"Arial,Bold", 5},\r
-    {"Arial,BoldItalic", 6},\r
-    {"Arial,Italic", 7},\r
-    {"Arial-Bold", 5},\r
-    {"Arial-BoldItalic", 6},\r
-    {"Arial-BoldItalicMT", 6},\r
-    {"Arial-BoldMT", 5},\r
-    {"Arial-Italic", 7},\r
-    {"Arial-ItalicMT", 7},\r
-    {"ArialBold", 5},\r
-    {"ArialBoldItalic", 6},\r
-    {"ArialItalic", 7},\r
-    {"ArialMT", 4},\r
-    {"ArialMT,Bold", 5},\r
-    {"ArialMT,BoldItalic", 6},\r
-    {"ArialMT,Italic", 7},\r
-    {"ArialRoundedMTBold", 5},\r
-    {"Courier", 0},\r
-    {"Courier,Bold", 1},\r
-    {"Courier,BoldItalic", 2},\r
-    {"Courier,Italic", 3},\r
-    {"Courier-Bold", 1},\r
-    {"Courier-BoldOblique", 2},\r
-    {"Courier-Oblique", 3},\r
-    {"CourierBold", 1},\r
-    {"CourierBoldItalic", 2},\r
-    {"CourierItalic", 3},\r
-    {"CourierNew", 0},\r
-    {"CourierNew,Bold", 1},\r
-    {"CourierNew,BoldItalic", 2},\r
-    {"CourierNew,Italic", 3},\r
-    {"CourierNew-Bold", 1},\r
-    {"CourierNew-BoldItalic", 2},\r
-    {"CourierNew-Italic", 3},\r
-    {"CourierNewBold", 1},\r
-    {"CourierNewBoldItalic", 2},\r
-    {"CourierNewItalic", 3},\r
-    {"CourierNewPS-BoldItalicMT", 2},\r
-    {"CourierNewPS-BoldMT", 1},\r
-    {"CourierNewPS-ItalicMT", 3},\r
-    {"CourierNewPSMT", 0},\r
-    {"CourierStd", 0},\r
-    {"CourierStd-Bold", 1},\r
-    {"CourierStd-BoldOblique", 2},\r
-    {"CourierStd-Oblique", 3},\r
-    {"Helvetica", 4},\r
-    {"Helvetica,Bold", 5},\r
-    {"Helvetica,BoldItalic", 6},\r
-    {"Helvetica,Italic", 7},\r
-    {"Helvetica-Bold", 5},\r
-    {"Helvetica-BoldItalic", 6},\r
-    {"Helvetica-BoldOblique", 6},\r
-    {"Helvetica-Italic", 7},\r
-    {"Helvetica-Oblique", 7},\r
-    {"HelveticaBold", 5},\r
-    {"HelveticaBoldItalic", 6},\r
-    {"HelveticaItalic", 7},\r
-    {"Symbol", 12},\r
-    {"SymbolMT", 12},\r
-    {"Times-Bold", 9},\r
-    {"Times-BoldItalic", 10},\r
-    {"Times-Italic", 11},\r
-    {"Times-Roman", 8},\r
-    {"TimesBold", 9},\r
-    {"TimesBoldItalic", 10},\r
-    {"TimesItalic", 11},\r
-    {"TimesNewRoman", 8},\r
-    {"TimesNewRoman,Bold", 9},\r
-    {"TimesNewRoman,BoldItalic", 10},\r
-    {"TimesNewRoman,Italic", 11},\r
-    {"TimesNewRoman-Bold", 9},\r
-    {"TimesNewRoman-BoldItalic", 10},\r
-    {"TimesNewRoman-Italic", 11},\r
-    {"TimesNewRomanBold", 9},\r
-    {"TimesNewRomanBoldItalic", 10},\r
-    {"TimesNewRomanItalic", 11},\r
-    {"TimesNewRomanPS", 8},\r
-    {"TimesNewRomanPS-Bold", 9},\r
-    {"TimesNewRomanPS-BoldItalic", 10},\r
-    {"TimesNewRomanPS-BoldItalicMT", 10},\r
-    {"TimesNewRomanPS-BoldMT", 9},\r
-    {"TimesNewRomanPS-Italic", 11},\r
-    {"TimesNewRomanPS-ItalicMT", 11},\r
-    {"TimesNewRomanPSMT", 8},\r
-    {"TimesNewRomanPSMT,Bold", 9},\r
-    {"TimesNewRomanPSMT,BoldItalic", 10},\r
-    {"TimesNewRomanPSMT,Italic", 11},\r
-    {"ZapfDingbats", 13},\r
-};\r
-extern "C" {\r
-    static int compareString(const void* key, const void* element)\r
-    {\r
-        return FXSYS_stricmp((FX_LPCSTR)key, ((_AltFontName*)element)->m_pName);\r
-    }\r
-}\r
-int _PDF_GetStandardFontName(CFX_ByteString& name)\r
-{\r
-    _AltFontName* found = (_AltFontName*)FXSYS_bsearch((FX_LPCSTR)name, g_AltFontNames,\r
-                          sizeof g_AltFontNames / sizeof (_AltFontName), sizeof (_AltFontName), compareString);\r
-    if (found == NULL) {\r
-        return -1;\r
-    }\r
-    name = g_Base14FontNames[found->m_Index];\r
-    return found->m_Index;\r
-}\r
-int GetTTCIndex(FX_LPCBYTE pFontData, FX_DWORD ttc_size, FX_DWORD font_offset)\r
-{\r
-    int face_index = 0;\r
-    FX_LPCBYTE p = pFontData + 8;\r
-    FX_DWORD nfont = GET_TT_LONG(p);\r
-    FX_DWORD index;\r
-    for (index = 0; index < nfont; index ++) {\r
-        p = pFontData + 12 + index * 4;\r
-        if (GET_TT_LONG(p) == font_offset) {\r
-            break;\r
-        }\r
-    }\r
-    if(index >= nfont) {\r
-        face_index = 0;\r
-    } else {\r
-        face_index = index;\r
-    }\r
-    return face_index;\r
-}\r
-FXFT_Face CFX_FontMgr::GetCachedTTCFace(int ttc_size, FX_DWORD checksum,\r
-                                        int font_offset, FX_LPBYTE& pFontData)\r
-{\r
-    CFX_ByteString key;\r
-    key.Format("%d:%d", ttc_size, checksum);\r
-    CTTFontDesc* pFontDesc = NULL;\r
-    m_FaceMap.Lookup(key, (void*&)pFontDesc);\r
-    if (pFontDesc == NULL) {\r
-        return NULL;\r
-    }\r
-    pFontData = pFontDesc->m_pFontData;\r
-    pFontDesc->m_RefCount ++;\r
-    int face_index = GetTTCIndex(pFontDesc->m_pFontData, ttc_size, font_offset);\r
-    if (pFontDesc->m_TTCFace.m_pFaces[face_index] == NULL) {\r
-        pFontDesc->m_TTCFace.m_pFaces[face_index] = GetFixedFace(pFontDesc->m_pFontData, ttc_size, face_index);\r
-    }\r
-    return pFontDesc->m_TTCFace.m_pFaces[face_index];\r
-}\r
-FXFT_Face CFX_FontMgr::AddCachedTTCFace(int ttc_size, FX_DWORD checksum,\r
-                                        FX_LPBYTE pData, FX_DWORD size, int font_offset)\r
-{\r
-    CFX_ByteString key;\r
-    key.Format("%d:%d", ttc_size, checksum);\r
-    CTTFontDesc* pFontDesc = FX_NEW CTTFontDesc;\r
-    if (!pFontDesc) {\r
-        return NULL;\r
-    }\r
-    pFontDesc->m_Type = 2;\r
-    pFontDesc->m_pFontData = pData;\r
-    for (int i = 0; i < 16; i ++) {\r
-        pFontDesc->m_TTCFace.m_pFaces[i] = NULL;\r
-    }\r
-    pFontDesc->m_RefCount ++;\r
-    key.Format("%d:%d", ttc_size, checksum);\r
-    m_FaceMap.SetAt(key, pFontDesc);\r
-    int face_index = GetTTCIndex(pFontDesc->m_pFontData, ttc_size, font_offset);\r
-    pFontDesc->m_TTCFace.m_pFaces[face_index] = GetFixedFace(pFontDesc->m_pFontData, ttc_size, face_index);\r
-    return pFontDesc->m_TTCFace.m_pFaces[face_index];\r
-}\r
-FXFT_Face CFX_FontMgr::GetFixedFace(FX_LPCBYTE pData, FX_DWORD size, int face_index)\r
-{\r
-    FXFT_Library library;\r
-    if (m_FTLibrary == NULL) {\r
-        FXFT_Init_FreeType(&m_FTLibrary);\r
-    }\r
-    library = m_FTLibrary;\r
-    FXFT_Face face = NULL;\r
-    int ret = FXFT_New_Memory_Face(library, pData, size, face_index, &face);\r
-    if (ret) {\r
-        return NULL;\r
-    }\r
-    ret = FXFT_Set_Pixel_Sizes(face, 64, 64);\r
-    if (ret) {\r
-        return NULL;\r
-    }\r
-    return face;\r
-}\r
-FXFT_Face CFX_FontMgr::GetFileFace(FX_LPCSTR filename, int face_index)\r
-{\r
-    FXFT_Library library;\r
-    if (m_FTLibrary == NULL) {\r
-        FXFT_Init_FreeType(&m_FTLibrary);\r
-    }\r
-    library = m_FTLibrary;\r
-    FXFT_Face face = NULL;\r
-    int ret = FXFT_New_Face(library, filename, face_index, &face);\r
-    if (ret) {\r
-        return NULL;\r
-    }\r
-    ret = FXFT_Set_Pixel_Sizes(face, 64, 64);\r
-    if (ret) {\r
-        return NULL;\r
-    }\r
-    return face;\r
-}\r
-void CFX_FontMgr::ReleaseFace(FXFT_Face face)\r
-{\r
-    if (face == NULL) {\r
-        return;\r
-    }\r
-    FX_POSITION pos = m_FaceMap.GetStartPosition();\r
-    while(pos) {\r
-        CFX_ByteString Key;\r
-        CTTFontDesc* ttface;\r
-        m_FaceMap.GetNextAssoc(pos, Key, (void*&)ttface);\r
-        if (ttface->ReleaseFace(face)) {\r
-            m_FaceMap.RemoveKey(Key);\r
-        }\r
-    }\r
-}\r
-extern "C" {\r
-    extern const unsigned char g_FoxitFixedItalicFontData [18746];\r
-    extern const unsigned char g_FoxitFixedFontData [17597];\r
-    extern const unsigned char g_FoxitSansItalicFontData [16339];\r
-    extern const unsigned char g_FoxitSansFontData [15025];\r
-    extern const unsigned char g_FoxitSerifItalicFontData [21227];\r
-    extern const unsigned char g_FoxitSerifFontData [19469];\r
-    extern const unsigned char g_FoxitFixedBoldItalicFontData [19151];\r
-    extern const unsigned char g_FoxitFixedBoldFontData [18055];\r
-    extern const unsigned char g_FoxitSansBoldItalicFontData [16418];\r
-    extern const unsigned char g_FoxitSansBoldFontData [16344];\r
-    extern const unsigned char g_FoxitSerifBoldItalicFontData [20733];\r
-    extern const unsigned char g_FoxitSerifBoldFontData [19395];\r
-    extern const unsigned char g_FoxitSymbolFontData[16729];\r
-    extern const unsigned char g_FoxitDingbatsFontData[29513];\r
-    extern const unsigned char g_FoxitSerifMMFontData[113417];\r
-    extern const unsigned char g_FoxitSansMMFontData[66919];\r
-};\r
-const FoxitFonts g_FoxitFonts[14] = {\r
-    {g_FoxitFixedFontData, 17597},\r
-    {g_FoxitFixedBoldFontData, 18055},\r
-    {g_FoxitFixedBoldItalicFontData, 19151},\r
-    {g_FoxitFixedItalicFontData, 18746},\r
-    {g_FoxitSansFontData, 15025},\r
-    {g_FoxitSansBoldFontData, 16344},\r
-    {g_FoxitSansBoldItalicFontData, 16418},\r
-    {g_FoxitSansItalicFontData, 16339},\r
-    {g_FoxitSerifFontData, 19469},\r
-    {g_FoxitSerifBoldFontData, 19395},\r
-    {g_FoxitSerifBoldItalicFontData, 20733},\r
-    {g_FoxitSerifItalicFontData, 21227},\r
-    {g_FoxitSymbolFontData, 16729},\r
-    {g_FoxitDingbatsFontData, 29513},\r
-};\r
-void _FPDFAPI_GetInternalFontData(int id, FX_LPCBYTE& data, FX_DWORD& size)\r
-{\r
-    CFX_GEModule::Get()->GetFontMgr()->GetStandardFont(data, size, id);\r
-}\r
-FX_BOOL CFX_FontMgr::GetStandardFont(FX_LPCBYTE& pFontData, FX_DWORD& size, int index)\r
-{\r
-    if (index > 15 || index < 0) {\r
-        return FALSE;\r
-    }\r
-    {\r
-        if (index >= 14) {\r
-            if (index == 14) {\r
-                pFontData = g_FoxitSerifMMFontData;\r
-                size = 113417;\r
-            } else {\r
-                pFontData = g_FoxitSansMMFontData;\r
-                size = 66919;\r
-            }\r
-        } else {\r
-            pFontData = g_FoxitFonts[index].m_pFontData;\r
-            size = g_FoxitFonts[index].m_dwSize;\r
-        }\r
-    }\r
-    return TRUE;\r
-}\r
-CFX_FontMapper::CFX_FontMapper()\r
-{\r
-    FXSYS_memset32(m_FoxitFaces, 0, sizeof m_FoxitFaces);\r
-    m_MMFaces[0] = m_MMFaces[1] = NULL;\r
-    m_pFontInfo = NULL;\r
-    m_bListLoaded = FALSE;\r
-    m_pFontEnumerator = NULL;\r
-}\r
-CFX_FontMapper::~CFX_FontMapper()\r
-{\r
-    for (int i = 0; i < 14; i ++)\r
-        if (m_FoxitFaces[i]) {\r
-            FXFT_Done_Face(m_FoxitFaces[i]);\r
-        }\r
-    if (m_MMFaces[0]) {\r
-        FXFT_Done_Face(m_MMFaces[0]);\r
-    }\r
-    if (m_MMFaces[1]) {\r
-        FXFT_Done_Face(m_MMFaces[1]);\r
-    }\r
-    if (m_pFontInfo) {\r
-        m_pFontInfo->Release();\r
-    }\r
-}\r
-void CFX_FontMapper::SetSystemFontInfo(IFX_SystemFontInfo* pFontInfo)\r
-{\r
-    if (pFontInfo == NULL) {\r
-        return;\r
-    }\r
-    if (m_pFontInfo) {\r
-        m_pFontInfo->Release();\r
-    }\r
-    m_pFontInfo = pFontInfo;\r
-}\r
-static CFX_ByteString _TT_NormalizeName(FX_LPCSTR family)\r
-{\r
-    CFX_ByteString norm(family, -1);\r
-    norm.Remove(' ');\r
-    norm.Remove('-');\r
-    norm.Remove(',');\r
-    int pos = norm.Find('+');\r
-    if (pos > 0) {\r
-        norm = norm.Left(pos);\r
-    }\r
-    norm.MakeLower();\r
-    return norm;\r
-}\r
-CFX_ByteString _FPDF_GetNameFromTT(FX_LPCBYTE name_table, FX_DWORD name_id)\r
-{\r
-    FX_LPCBYTE ptr = name_table + 2;\r
-    int name_count = GET_TT_SHORT(ptr);\r
-    int string_offset = GET_TT_SHORT(ptr + 2);\r
-    FX_LPCBYTE string_ptr = name_table + string_offset;\r
-    ptr += 4;\r
-    for (int i = 0; i < name_count; i ++) {\r
-        if (GET_TT_SHORT(ptr + 6) == name_id && GET_TT_SHORT(ptr) == 1 && GET_TT_SHORT(ptr + 2) == 0) {\r
-            return CFX_ByteStringC(string_ptr + GET_TT_SHORT(ptr + 10), GET_TT_SHORT(ptr + 8));\r
-        }\r
-        ptr += 12;\r
-    }\r
-    return CFX_ByteString();\r
-}\r
-static CFX_ByteString _FPDF_ReadStringFromFile(FXSYS_FILE* pFile, FX_DWORD size)\r
-{\r
-    CFX_ByteString buffer;\r
-    if (!FXSYS_fread(buffer.GetBuffer(size), size, 1, pFile)) {\r
-        return CFX_ByteString();\r
-    }\r
-    buffer.ReleaseBuffer(size);\r
-    return buffer;\r
-}\r
-static CFX_ByteString _FPDF_ReadStringFromStreamFile(IFX_FileStream* pFile, FX_DWORD size)\r
-{\r
-    CFX_ByteString buffer;\r
-    if (!pFile->ReadBlock(buffer.GetBuffer(size), size)) {\r
-        return CFX_ByteString();\r
-    }\r
-    buffer.ReleaseBuffer(size);\r
-    return buffer;\r
-}\r
-CFX_ByteString _FPDF_LoadTableFromTT(FXSYS_FILE* pFile, FX_LPCBYTE pTables, FX_DWORD nTables, FX_DWORD tag)\r
-{\r
-    for (FX_DWORD i = 0; i < nTables; i ++) {\r
-        FX_LPCBYTE p = pTables + i * 16;\r
-        if (GET_TT_LONG(p) == tag) {\r
-            FX_DWORD offset = GET_TT_LONG(p + 8);\r
-            FX_DWORD size = GET_TT_LONG(p + 12);\r
-            FXSYS_fseek(pFile, offset, FXSYS_SEEK_SET);\r
-            return _FPDF_ReadStringFromFile(pFile, size);\r
-        }\r
-    }\r
-    return CFX_ByteString();\r
-}\r
-CFX_ByteString _FPDF_LoadTableFromTTStreamFile(IFX_FileStream* pFile, FX_LPCBYTE pTables, FX_DWORD nTables, FX_DWORD tag)\r
-{\r
-    for (FX_DWORD i = 0; i < nTables; i ++) {\r
-        FX_LPCBYTE p = pTables + i * 16;\r
-        if (GET_TT_LONG(p) == tag) {\r
-            FX_DWORD offset = GET_TT_LONG(p + 8);\r
-            FX_DWORD size = GET_TT_LONG(p + 12);\r
-            CFX_ByteString buffer;\r
-            if (!pFile->ReadBlock(buffer.GetBuffer(size), offset, size)) {\r
-                return CFX_ByteString();\r
-            }\r
-            buffer.ReleaseBuffer(size);\r
-            return buffer;\r
-        }\r
-    }\r
-    return CFX_ByteString();\r
-}\r
-CFX_ByteString CFX_FontMapper::GetPSNameFromTT(void* hFont)\r
-{\r
-    if (m_pFontInfo == NULL) {\r
-        CFX_ByteString();\r
-    }\r
-    CFX_ByteString result;\r
-    FX_DWORD size = m_pFontInfo->GetFontData(hFont, 0x6e616d65, NULL, 0);\r
-    if (size) {\r
-        FX_LPBYTE buffer = FX_Alloc(FX_BYTE, size);\r
-        if (!buffer) {\r
-            return result;\r
-        }\r
-        m_pFontInfo->GetFontData(hFont, 0x6e616d65, buffer, size);\r
-        result = _FPDF_GetNameFromTT(buffer, 6);\r
-        FX_Free(buffer);\r
-    }\r
-    return result;\r
-}\r
-void CFX_FontMapper::AddInstalledFont(const CFX_ByteString& name, int charset)\r
-{\r
-    if (m_pFontInfo == NULL) {\r
-        return;\r
-    }\r
-    if (m_CharsetArray.Find((FX_DWORD)charset) == -1) {\r
-        m_CharsetArray.Add((FX_DWORD)charset);\r
-        m_FaceArray.Add(name);\r
-    }\r
-    if (name == m_LastFamily) {\r
-        return;\r
-    }\r
-    FX_LPCBYTE ptr = name;\r
-    FX_BOOL bLocalized = FALSE;\r
-    for (int i = 0; i < name.GetLength(); i ++)\r
-        if (ptr[i] > 0x80) {\r
-            bLocalized = TRUE;\r
-            break;\r
-        }\r
-    if (bLocalized) {\r
-        void* hFont = m_pFontInfo->GetFont(name);\r
-        if (hFont == NULL) {\r
-            FX_BOOL bExact;\r
-            hFont = m_pFontInfo->MapFont(0, 0, FXFONT_DEFAULT_CHARSET, 0, name, bExact);\r
-            if (hFont == NULL) {\r
-                return;\r
-            }\r
-        }\r
-        CFX_ByteString new_name = GetPSNameFromTT(hFont);\r
-        if (!new_name.IsEmpty()) {\r
-            new_name.Insert(0, ' ');\r
-            m_InstalledTTFonts.Add(new_name);\r
-        }\r
-        m_pFontInfo->DeleteFont(hFont);\r
-    }\r
-    m_InstalledTTFonts.Add(name);\r
-    m_LastFamily = name;\r
-}\r
-void CFX_FontMapper::LoadInstalledFonts()\r
-{\r
-    if (m_pFontInfo == NULL) {\r
-        return;\r
-    }\r
-    if (m_bListLoaded) {\r
-        return;\r
-    }\r
-    if (m_bListLoaded) {\r
-        return;\r
-    }\r
-    m_pFontInfo->EnumFontList(this);\r
-    m_bListLoaded = TRUE;\r
-}\r
-CFX_ByteString CFX_FontMapper::MatchInstalledFonts(const CFX_ByteString& norm_name)\r
-{\r
-    LoadInstalledFonts();\r
-    int i;\r
-    for (i = m_InstalledTTFonts.GetSize() - 1; i >= 0; i --) {\r
-        CFX_ByteString norm1 = _TT_NormalizeName(m_InstalledTTFonts[i]);\r
-        if (norm1 == norm_name) {\r
-            break;\r
-        }\r
-    }\r
-    if (i < 0) {\r
-        return CFX_ByteString();\r
-    }\r
-    CFX_ByteString match = m_InstalledTTFonts[i];\r
-    if (match[0] == ' ') {\r
-        match = m_InstalledTTFonts[i + 1];\r
-    }\r
-    return match;\r
-}\r
-typedef struct _CHARSET_MAP_ {\r
-    FX_BYTE charset;\r
-    FX_WORD codepage;\r
-} CHARSET_MAP;\r
-static const CHARSET_MAP g_Codepage2CharsetTable[] = {\r
-    { 1         , 0    },\r
-    { 2         , 42   },\r
-    { 254, 437 },\r
-    { 255, 850 },\r
-    { 222, 874 },\r
-    { 128, 932 },\r
-    { 134, 936 },\r
-    { 129, 949 },\r
-    { 136, 950 },\r
-    { 238, 1250        },\r
-    { 204, 1251        },\r
-    { 0,   1252        },\r
-    { 161, 1253        },\r
-    { 162, 1254        },\r
-    { 177, 1255        },\r
-    { 178, 1256        },\r
-    { 186, 1257        },\r
-    { 163, 1258 },\r
-    { 130, 1361 },\r
-    { 77, 10000 },\r
-    { 78, 10001 },\r
-    { 79, 10003 },\r
-    { 80, 10008 },\r
-    { 81, 10002 },\r
-    { 83, 10005 },\r
-    { 84, 10004 },\r
-    { 85, 10006 },\r
-    { 86, 10081 },\r
-    { 87, 10021 },\r
-    { 88, 10029 },\r
-    { 89, 10007 },\r
-};\r
-FX_BYTE _GetCharsetFromCodePage(FX_WORD codepage)\r
-{\r
-    FX_INT32 iEnd = sizeof(g_Codepage2CharsetTable) / sizeof(CHARSET_MAP) - 1;\r
-    FXSYS_assert(iEnd >= 0);\r
-    FX_INT32 iStart = 0, iMid;\r
-    do {\r
-        iMid = (iStart + iEnd) / 2;\r
-        const CHARSET_MAP & cp = g_Codepage2CharsetTable[iMid];\r
-        if (codepage == cp.codepage) {\r
-            return cp.charset;\r
-        } else if (codepage < cp.codepage) {\r
-            iEnd = iMid - 1;\r
-        } else {\r
-            iStart = iMid + 1;\r
-        }\r
-    } while (iStart <= iEnd);\r
-    return 1;\r
-}\r
-FX_DWORD _GetCodePageRangeFromCharset(int charset)\r
-{\r
-    if (charset == FXFONT_EASTEUROPE_CHARSET) {\r
-        return 1 << 1;\r
-    }\r
-    if (charset == FXFONT_GREEK_CHARSET) {\r
-        return 1 << 3;\r
-    }\r
-    if (charset == FXFONT_TURKISH_CHARSET) {\r
-        return 1 << 4;\r
-    }\r
-    if (charset == FXFONT_HEBREW_CHARSET) {\r
-        return 1 << 5;\r
-    }\r
-    if (charset == FXFONT_ARABIC_CHARSET) {\r
-        return 1 << 6;\r
-    }\r
-    if (charset == FXFONT_BALTIC_CHARSET) {\r
-        return 1 << 7;\r
-    }\r
-    if (charset == FXFONT_THAI_CHARSET) {\r
-        return 1 << 16;\r
-    }\r
-    if (charset == FXFONT_SHIFTJIS_CHARSET) {\r
-        return 1 << 17;\r
-    }\r
-    if (charset == FXFONT_GB2312_CHARSET) {\r
-        return 1 << 18;\r
-    }\r
-    if (charset == FXFONT_CHINESEBIG5_CHARSET) {\r
-        return 1 << 20;\r
-    }\r
-    if (charset == FXFONT_HANGEUL_CHARSET) {\r
-        return 1 << 19;\r
-    }\r
-    if (charset == FXFONT_SYMBOL_CHARSET) {\r
-        return 1 << 31;\r
-    }\r
-    return 1 << 21;\r
-}\r
-static int CP2CharSet(int cp)\r
-{\r
-    if(cp == 932) {\r
-        return FXFONT_SHIFTJIS_CHARSET;\r
-    } else if(cp == 936) {\r
-        return FXFONT_GB2312_CHARSET;\r
-    } else if(cp == 949) {\r
-        return FXFONT_HANGEUL_CHARSET;\r
-    } else if(cp == 950) {\r
-        return FXFONT_CHINESEBIG5_CHARSET;\r
-    }\r
-    return FXFONT_DEFAULT_CHARSET;\r
-}\r
-FXFT_Face CFX_FontMapper::UseInternalSubst(CFX_SubstFont* pSubstFont, int iBaseFont, int italic_angle, int weight, int picthfamily)\r
-{\r
-    if (iBaseFont < 12) {\r
-        if (m_FoxitFaces[iBaseFont]) {\r
-            return m_FoxitFaces[iBaseFont];\r
-        }\r
-        FX_LPCBYTE pFontData = NULL;\r
-        FX_DWORD size = 0;\r
-        if (m_pFontMgr->GetStandardFont(pFontData, size, iBaseFont)) {\r
-            m_FoxitFaces[iBaseFont] = m_pFontMgr->GetFixedFace(pFontData, size, 0);\r
-            return m_FoxitFaces[iBaseFont];\r
-        }\r
-    }\r
-    pSubstFont->m_SubstFlags |= FXFONT_SUBST_MM;\r
-    pSubstFont->m_ItalicAngle = italic_angle;\r
-    if (weight) {\r
-        pSubstFont->m_Weight = weight;\r
-    }\r
-    if (picthfamily & FXFONT_FF_ROMAN) {\r
-        pSubstFont->m_Weight = pSubstFont->m_Weight * 4 / 5;\r
-        pSubstFont->m_Family = "Chrome Serif";\r
-        if (m_MMFaces[1]) {\r
-            return m_MMFaces[1];\r
-        }\r
-        FX_LPCBYTE pFontData = NULL;\r
-        FX_DWORD size;\r
-        m_pFontMgr->GetStandardFont(pFontData, size, 14);\r
-        m_MMFaces[1] = m_pFontMgr->GetFixedFace(pFontData, size, 0);\r
-        return m_MMFaces[1];\r
-    }\r
-    pSubstFont->m_Family = "Chrome Sans";\r
-    if (m_MMFaces[0]) {\r
-        return m_MMFaces[0];\r
-    }\r
-    FX_LPCBYTE pFontData = NULL;\r
-    FX_DWORD size = 0;\r
-    m_pFontMgr->GetStandardFont(pFontData, size, 15);\r
-    m_MMFaces[0] = m_pFontMgr->GetFixedFace(pFontData, size, 0);\r
-    return m_MMFaces[0];\r
-}\r
-const struct _AltFontFamily {\r
-    FX_LPCSTR m_pFontName;\r
-    FX_LPCSTR m_pFontFamily;\r
-}\r
-g_AltFontFamilies[] = {\r
-    {"AGaramondPro", "Adobe Garamond Pro"},\r
-    {"BankGothicBT-Medium", "BankGothic Md BT"},\r
-    {"ForteMT", "Forte"},\r
-};\r
-extern "C" {\r
-    static int compareFontFamilyString(const void* key, const void* element)\r
-    {\r
-        CFX_ByteString str_key((FX_LPCSTR)key);\r
-        if (str_key.Find(((_AltFontFamily*)element)->m_pFontName) != -1) {\r
-            return 0;\r
-        }\r
-        return FXSYS_stricmp((FX_LPCSTR)key, ((_AltFontFamily*)element)->m_pFontName);\r
-    }\r
-}\r
-#define FX_FONT_STYLE_None             0x00\r
-#define FX_FONT_STYLE_Bold             0x01\r
-#define FX_FONT_STYLE_Italic   0x02\r
-#define FX_FONT_STYLE_BoldBold 0x04\r
-static CFX_ByteString _GetFontFamily(CFX_ByteString fontName, int nStyle)\r
-{\r
-    if (fontName.Find("Script") >= 0) {\r
-        if ((nStyle & FX_FONT_STYLE_Bold) == FX_FONT_STYLE_Bold) {\r
-            fontName = "ScriptMTBold";\r
-        } else if (fontName.Find("Palace") >= 0) {\r
-            fontName = "PalaceScriptMT";\r
-        } else if (fontName.Find("French") >= 0) {\r
-            fontName = "FrenchScriptMT";\r
-        } else if (fontName.Find("FreeStyle") >= 0) {\r
-            fontName = "FreeStyleScript";\r
-        }\r
-        return fontName;\r
-    }\r
-    _AltFontFamily* found = (_AltFontFamily*)FXSYS_bsearch((FX_LPCSTR)fontName, g_AltFontFamilies,\r
-                            sizeof g_AltFontFamilies / sizeof (_AltFontFamily), sizeof (_AltFontFamily), compareFontFamilyString);\r
-    if (found == NULL) {\r
-        return fontName;\r
-    }\r
-    return found->m_pFontFamily;\r
-};\r
-typedef struct _FX_FontStyle {\r
-    FX_LPCSTR style;\r
-    FX_INT32 len;\r
-} FX_FontStyle;\r
-const FX_FontStyle g_FontStyles[] = {\r
-    "Bold", 4,\r
-    "Italic", 6,\r
-    "BoldItalic", 10,\r
-    "Reg", 3,\r
-    "Regular", 7,\r
-};\r
-CFX_ByteString ParseStyle(FX_LPCSTR pStyle, int iLen, int iIndex)\r
-{\r
-    CFX_ByteTextBuf buf;\r
-    if (!iLen || iLen <= iIndex) {\r
-        return buf.GetByteString();\r
-    }\r
-    while (iIndex < iLen) {\r
-        if (pStyle[iIndex] == ',') {\r
-            break;\r
-        }\r
-        buf.AppendChar(pStyle[iIndex]);\r
-        ++iIndex;\r
-    }\r
-    return buf.GetByteString();\r
-}\r
-FX_INT32 GetStyleType(const CFX_ByteString &bsStyle, FX_BOOL bRevert)\r
-{\r
-    FX_INT32 iLen = bsStyle.GetLength();\r
-    if (!iLen) {\r
-        return -1;\r
-    }\r
-    int iSize = sizeof(g_FontStyles) / sizeof(FX_FontStyle);\r
-    const FX_FontStyle *pStyle = NULL;\r
-    for (int i = iSize - 1; i >= 0; --i) {\r
-        pStyle = g_FontStyles + i;\r
-        if (!pStyle || pStyle->len > iLen) {\r
-            continue;\r
-        }\r
-        if (!bRevert) {\r
-            if (bsStyle.Left(pStyle->len).Compare(pStyle->style) == 0) {\r
-                return i;\r
-            }\r
-        } else {\r
-            if (bsStyle.Right(pStyle->len).Compare(pStyle->style) == 0) {\r
-                return i;\r
-            }\r
-        }\r
-    }\r
-    return -1;\r
-}\r
-FX_BOOL CheckSupportThirdPartFont(CFX_ByteString name, int &PitchFamily)\r
-{\r
-    if (name == FX_BSTRC("MyriadPro")) {\r
-        PitchFamily &= ~FXFONT_FF_ROMAN;\r
-        return TRUE;\r
-    }\r
-    return FALSE;\r
-}\r
-FXFT_Face CFX_FontMapper::FindSubstFont(const CFX_ByteString& name, FX_BOOL bTrueType, FX_DWORD flags,\r
-                                        int weight, int italic_angle, int WindowCP, CFX_SubstFont* pSubstFont)\r
-{\r
-    if (!(flags & FXFONT_USEEXTERNATTR)) {\r
-        weight = FXFONT_FW_NORMAL;\r
-        italic_angle = 0;\r
-    }\r
-    CFX_ByteString SubstName = name;\r
-    SubstName.Remove(0x20);\r
-    if (bTrueType) {\r
-        if (name[0] == '@') {\r
-            SubstName = name.Mid(1);\r
-        }\r
-    }\r
-    _PDF_GetStandardFontName(SubstName);\r
-    if (SubstName == FX_BSTRC("Symbol") && !bTrueType) {\r
-        pSubstFont->m_Family = "Chrome Symbol";\r
-        pSubstFont->m_Charset = FXFONT_SYMBOL_CHARSET;\r
-        pSubstFont->m_SubstFlags |= FXFONT_SUBST_STANDARD;\r
-        if (m_FoxitFaces[12]) {\r
-            return m_FoxitFaces[12];\r
-        }\r
-        FX_LPCBYTE pFontData = NULL;\r
-        FX_DWORD size = 0;\r
-        m_pFontMgr->GetStandardFont(pFontData, size, 12);\r
-        m_FoxitFaces[12] = m_pFontMgr->GetFixedFace(pFontData, size, 0);\r
-        return m_FoxitFaces[12];\r
-    }\r
-    if (SubstName == FX_BSTRC("ZapfDingbats")) {\r
-        pSubstFont->m_Family = "Chrome Dingbats";\r
-        pSubstFont->m_Charset = FXFONT_SYMBOL_CHARSET;\r
-        pSubstFont->m_SubstFlags |= FXFONT_SUBST_STANDARD;\r
-        if (m_FoxitFaces[13]) {\r
-            return m_FoxitFaces[13];\r
-        }\r
-        FX_LPCBYTE pFontData = NULL;\r
-        FX_DWORD size = 0;\r
-        m_pFontMgr->GetStandardFont(pFontData, size, 13);\r
-        m_FoxitFaces[13] = m_pFontMgr->GetFixedFace(pFontData, size, 0);\r
-        return m_FoxitFaces[13];\r
-    }\r
-    int iBaseFont = 0;\r
-    CFX_ByteString family, style;\r
-    FX_BOOL    bHasComma = FALSE;\r
-    FX_BOOL bHasHypen = FALSE;\r
-    int find = SubstName.Find(FX_BSTRC(","), 0);\r
-    if (find >= 0) {\r
-        family = SubstName.Left(find);\r
-        _PDF_GetStandardFontName(family);\r
-        style = SubstName.Mid(find + 1);\r
-        bHasComma = TRUE;\r
-    } else {\r
-        family = SubstName;\r
-    }\r
-    for (; iBaseFont < 12; iBaseFont ++)\r
-        if (family == CFX_ByteStringC(g_Base14FontNames[iBaseFont])) {\r
-            break;\r
-        }\r
-    int PitchFamily = 0;\r
-    FX_BOOL bItalic = FALSE;\r
-    FX_DWORD nStyle = 0;\r
-    FX_BOOL bStyleAvail = FALSE;\r
-    FX_BOOL bFamilyStyleIsWhole = FALSE;\r
-    FX_BOOL bNextF = FALSE;\r
-    if (iBaseFont < 12) {\r
-        family = g_Base14FontNames[iBaseFont];\r
-        if ((iBaseFont % 4) == 1 || (iBaseFont % 4) == 2) {\r
-            nStyle |= FX_FONT_STYLE_Bold;\r
-        }\r
-        if ((iBaseFont % 4) / 2) {\r
-            nStyle |= FX_FONT_STYLE_Italic;\r
-        }\r
-        if (iBaseFont < 4) {\r
-            PitchFamily |= FXFONT_FF_FIXEDPITCH;\r
-        }\r
-        if (iBaseFont >= 8) {\r
-            PitchFamily |= FXFONT_FF_ROMAN;\r
-        }\r
-    } else {\r
-        if (!bHasComma) {\r
-            find = family.ReverseFind('-');\r
-            if (find >= 0) {\r
-                style = family.Mid(find + 1);\r
-                family = family.Left(find);\r
-                bHasHypen = TRUE;\r
-            }\r
-        }\r
-        if (!bHasHypen) {\r
-            int nLen = family.GetLength();\r
-            FX_INT32 nRet = GetStyleType(family, TRUE);\r
-            if (nRet > -1) {\r
-                family = family.Left(nLen - g_FontStyles[nRet].len);\r
-                if (nRet == 0) {\r
-                    nStyle |= FX_FONT_STYLE_Bold;\r
-                }\r
-                if (nRet == 1) {\r
-                    nStyle |= FX_FONT_STYLE_Italic;\r
-                }\r
-                if (nRet == 2) {\r
-                    nStyle |= (FX_FONT_STYLE_Bold | FX_FONT_STYLE_Italic);\r
-                }\r
-            }\r
-        }\r
-        if (flags & FXFONT_SERIF) {\r
-            PitchFamily |= FXFONT_FF_ROMAN;\r
-        }\r
-        if (flags & FXFONT_SCRIPT) {\r
-            PitchFamily |= FXFONT_FF_SCRIPT;\r
-        }\r
-        if (flags & FXFONT_FIXED_PITCH) {\r
-            PitchFamily |= FXFONT_FF_FIXEDPITCH;\r
-        }\r
-    }\r
-    if (!style.IsEmpty()) {\r
-        int nLen = style.GetLength();\r
-        FX_LPCSTR pStyle = style;\r
-        int i = 0;\r
-        FX_BOOL bFirstItem = TRUE;\r
-        CFX_ByteString buf;\r
-        while (i < nLen) {\r
-            buf = ParseStyle(pStyle, nLen, i);\r
-            FX_INT32 nRet = GetStyleType(buf, FALSE);\r
-            if ((i && !bStyleAvail) || (!i && nRet < 0)) {\r
-                family = SubstName;\r
-                iBaseFont = 12;\r
-                break;\r
-            } else if (nRet >= 0) {\r
-                bStyleAvail = TRUE;\r
-            }\r
-            if (nRet == 0) {\r
-                if (nStyle & FX_FONT_STYLE_Bold) {\r
-                    nStyle |= FX_FONT_STYLE_BoldBold;\r
-                } else {\r
-                    nStyle |= FX_FONT_STYLE_Bold;\r
-                }\r
-                bFirstItem = FALSE;\r
-            }\r
-            if (nRet == 1) {\r
-                if (bFirstItem) {\r
-                    nStyle |= FX_FONT_STYLE_Italic;\r
-                } else {\r
-                    family = SubstName;\r
-                    iBaseFont = 12;\r
-                }\r
-                break;\r
-            }\r
-            if (nRet == 2) {\r
-                nStyle |= FX_FONT_STYLE_Italic;\r
-                if (nStyle & FX_FONT_STYLE_Bold) {\r
-                    nStyle |= FX_FONT_STYLE_BoldBold;\r
-                } else {\r
-                    nStyle |= FX_FONT_STYLE_Bold;\r
-                }\r
-                bFirstItem = FALSE;\r
-            }\r
-            i += buf.GetLength() + 1;\r
-        }\r
-    }\r
-    weight = weight ? weight : FXFONT_FW_NORMAL;\r
-    int old_weight = weight;\r
-    if (nStyle) {\r
-        weight = nStyle & FX_FONT_STYLE_BoldBold ? 900 : (nStyle & FX_FONT_STYLE_Bold ? FXFONT_FW_BOLD : FXFONT_FW_NORMAL);\r
-    }\r
-    if (nStyle & FX_FONT_STYLE_Italic) {\r
-        bItalic = TRUE;\r
-    }\r
-    FX_BOOL bCJK = FALSE;\r
-    FX_BOOL bExact = FALSE;\r
-    int Charset = FXFONT_ANSI_CHARSET;\r
-    if (WindowCP) {\r
-        Charset = _GetCharsetFromCodePage(WindowCP);\r
-    } else if (iBaseFont == 12 && (flags & FXFONT_SYMBOLIC)) {\r
-        Charset = FXFONT_SYMBOL_CHARSET;\r
-    }\r
-    if (Charset == FXFONT_SHIFTJIS_CHARSET || Charset == FXFONT_GB2312_CHARSET ||\r
-            Charset == FXFONT_HANGEUL_CHARSET || Charset == FXFONT_CHINESEBIG5_CHARSET) {\r
-        bCJK = TRUE;\r
-    }\r
-    if (m_pFontInfo == NULL) {\r
-        pSubstFont->m_SubstFlags |= FXFONT_SUBST_STANDARD;\r
-        return UseInternalSubst(pSubstFont, iBaseFont, italic_angle, old_weight, PitchFamily);\r
-    }\r
-    family = _GetFontFamily(family, nStyle);\r
-    CFX_ByteString match = MatchInstalledFonts(_TT_NormalizeName(family));\r
-    if (match.IsEmpty() && family != SubstName && (!bHasComma && (!bHasHypen || (bHasHypen && !bStyleAvail)))) {\r
-        match = MatchInstalledFonts(_TT_NormalizeName(SubstName));\r
-    }\r
-    if (match.IsEmpty() && iBaseFont >= 12) {\r
-        if (!bCJK) {\r
-            if (!CheckSupportThirdPartFont(family, PitchFamily)) {\r
-                if (italic_angle != 0) {\r
-                    bItalic = TRUE;\r
-                } else {\r
-                    bItalic = FALSE;\r
-                }\r
-                weight = old_weight;\r
-            }\r
-        } else {\r
-            pSubstFont->m_bSubstOfCJK = TRUE;\r
-            if (nStyle) {\r
-                pSubstFont->m_WeightCJK = weight;\r
-            } else {\r
-                pSubstFont->m_WeightCJK = FXFONT_FW_NORMAL;\r
-            }\r
-            if (nStyle & FX_FONT_STYLE_Italic) {\r
-                pSubstFont->m_bItlicCJK = TRUE;\r
-            }\r
-        }\r
-    } else {\r
-        italic_angle = 0;\r
-        weight = nStyle & FX_FONT_STYLE_BoldBold ? 900 : (nStyle & FX_FONT_STYLE_Bold ? FXFONT_FW_BOLD : FXFONT_FW_NORMAL);\r
-    }\r
-    if (!match.IsEmpty() || iBaseFont < 12) {\r
-        pSubstFont->m_SubstFlags |= FXFONT_SUBST_EXACT;\r
-        if (!match.IsEmpty()) {\r
-            family = match;\r
-        }\r
-        if (iBaseFont < 12) {\r
-            if (nStyle && !(iBaseFont % 4)) {\r
-                if ((nStyle & 0x3) == 1) {\r
-                    iBaseFont += 1;\r
-                }\r
-                if ((nStyle & 0x3) == 2) {\r
-                    iBaseFont += 3;\r
-                }\r
-                if ((nStyle & 0x3) == 3) {\r
-                    iBaseFont += 2;\r
-                }\r
-            }\r
-            if (m_pFontMgr->m_ExternalFonts[iBaseFont].m_pFontData) {\r
-                if (m_FoxitFaces[iBaseFont]) {\r
-                    return m_FoxitFaces[iBaseFont];\r
-                }\r
-                m_FoxitFaces[iBaseFont] = m_pFontMgr->GetFixedFace(m_pFontMgr->m_ExternalFonts[iBaseFont].m_pFontData,\r
-                                          m_pFontMgr->m_ExternalFonts[iBaseFont].m_dwSize, 0);\r
-                if (m_FoxitFaces[iBaseFont]) {\r
-                    return m_FoxitFaces[iBaseFont];\r
-                }\r
-            } else {\r
-                family = g_Base14FontNames[iBaseFont];\r
-            }\r
-            pSubstFont->m_SubstFlags |= FXFONT_SUBST_STANDARD;\r
-        }\r
-    } else {\r
-        if (flags & FXFONT_ITALIC) {\r
-            bItalic = TRUE;\r
-        }\r
-    }\r
-    bExact = !match.IsEmpty();\r
-    void* hFont = m_pFontInfo->MapFont(weight, bItalic, Charset, PitchFamily, family, bExact);\r
-    if (bExact) {\r
-        pSubstFont->m_SubstFlags |= FXFONT_SUBST_EXACT;\r
-    }\r
-    if (hFont == NULL) {\r
-        if (bCJK) {\r
-            if (italic_angle != 0) {\r
-                bItalic = TRUE;\r
-            } else {\r
-                bItalic = FALSE;\r
-            }\r
-            weight = old_weight;\r
-        }\r
-        if (!match.IsEmpty()) {\r
-            hFont = m_pFontInfo->GetFont(match);\r
-            if (hFont == NULL) {\r
-                return UseInternalSubst(pSubstFont, iBaseFont, italic_angle, old_weight, PitchFamily);\r
-            }\r
-        } else {\r
-            if (Charset == FXFONT_SYMBOL_CHARSET) {\r
-#if _FXM_PLATFORM_  == _FXM_PLATFORM_APPLE_ || _FXM_PLATFORM_  == _FXM_PLATFORM_ANDROID_\r
-                if (SubstName == FX_BSTRC("Symbol")) {\r
-                    pSubstFont->m_Family = "Chrome Symbol";\r
-                    pSubstFont->m_SubstFlags |= FXFONT_SUBST_STANDARD;\r
-                    pSubstFont->m_Charset = FXFONT_SYMBOL_CHARSET;\r
-                    if (m_FoxitFaces[12]) {\r
-                        return m_FoxitFaces[12];\r
-                    }\r
-                    FX_LPCBYTE pFontData = NULL;\r
-                    FX_DWORD size = 0;\r
-                    m_pFontMgr->GetStandardFont(pFontData, size, 12);\r
-                    m_FoxitFaces[12] = m_pFontMgr->GetFixedFace(pFontData, size, 0);\r
-                    return m_FoxitFaces[12];\r
-                } else {\r
-                    pSubstFont->m_SubstFlags |= FXFONT_SUBST_NONSYMBOL;\r
-                    return FindSubstFont(family, bTrueType, flags & ~FXFONT_SYMBOLIC, weight, italic_angle, 0, pSubstFont);\r
-                }\r
-#else\r
-                pSubstFont->m_SubstFlags |= FXFONT_SUBST_NONSYMBOL;\r
-                return FindSubstFont(family, bTrueType, flags & ~FXFONT_SYMBOLIC, weight, italic_angle, 0, pSubstFont);\r
-#endif\r
-            }\r
-            if (Charset == FXFONT_ANSI_CHARSET) {\r
-                pSubstFont->m_SubstFlags |= FXFONT_SUBST_STANDARD;\r
-                return UseInternalSubst(pSubstFont, iBaseFont, italic_angle, old_weight, PitchFamily);\r
-            }\r
-            int index = m_CharsetArray.Find(Charset);\r
-            if (index < 0) {\r
-                return UseInternalSubst(pSubstFont, iBaseFont, italic_angle, old_weight, PitchFamily);\r
-            } else {\r
-                hFont = m_pFontInfo->GetFont(m_FaceArray[index]);\r
-            }\r
-        }\r
-    }\r
-    pSubstFont->m_ExtHandle = m_pFontInfo->RetainFont(hFont);\r
-    if (hFont == NULL) {\r
-        return NULL;\r
-    }\r
-    m_pFontInfo->GetFaceName(hFont, SubstName);\r
-    if (Charset == FXFONT_DEFAULT_CHARSET) {\r
-        m_pFontInfo->GetFontCharset(hFont, Charset);\r
-    }\r
-    FX_DWORD ttc_size = m_pFontInfo->GetFontData(hFont, 0x74746366, NULL, 0);\r
-    FX_DWORD font_size = m_pFontInfo->GetFontData(hFont, 0, NULL, 0);\r
-    if(font_size == 0 && ttc_size == 0) {\r
-        m_pFontInfo->DeleteFont(hFont);\r
-        return NULL;\r
-    }\r
-    FXFT_Face face = NULL;\r
-    if (ttc_size) {\r
-        FX_BYTE temp[1024];\r
-        m_pFontInfo->GetFontData(hFont, 0x74746366, temp, 1024);\r
-        FX_DWORD checksum = 0;\r
-        for (int i = 0; i < 256; i ++) {\r
-            checksum += ((FX_DWORD*)temp)[i];\r
-        }\r
-        FX_LPBYTE pFontData;\r
-        face = m_pFontMgr->GetCachedTTCFace(ttc_size, checksum, ttc_size - font_size, pFontData);\r
-        if (face == NULL) {\r
-            pFontData = FX_Alloc(FX_BYTE, ttc_size);\r
-            if (pFontData) {\r
-                m_pFontInfo->GetFontData(hFont, 0x74746366, pFontData, ttc_size);\r
-                face = m_pFontMgr->AddCachedTTCFace(ttc_size, checksum, pFontData, ttc_size,\r
-                                                    ttc_size - font_size);\r
-            }\r
-        }\r
-    } else {\r
-        FX_LPBYTE pFontData;\r
-        face = m_pFontMgr->GetCachedFace(SubstName, weight, bItalic, pFontData);\r
-        if (face == NULL) {\r
-            pFontData = FX_Alloc(FX_BYTE, font_size);\r
-            if (!pFontData) {\r
-                m_pFontInfo->DeleteFont(hFont);\r
-                return NULL;\r
-            }\r
-            m_pFontInfo->GetFontData(hFont, 0, pFontData, font_size);\r
-            face = m_pFontMgr->AddCachedFace(SubstName, weight, bItalic, pFontData, font_size, m_pFontInfo->GetFaceIndex(hFont));\r
-        }\r
-    }\r
-    if (face == NULL) {\r
-        m_pFontInfo->DeleteFont(hFont);\r
-        return NULL;\r
-    }\r
-    pSubstFont->m_Family = SubstName;\r
-    pSubstFont->m_Charset = Charset;\r
-    FX_BOOL bNeedUpdateWeight = FALSE;\r
-    if (FXFT_Is_Face_Bold(face)) {\r
-        if (weight == FXFONT_FW_BOLD) {\r
-            bNeedUpdateWeight = FALSE;\r
-        } else {\r
-            bNeedUpdateWeight = TRUE;\r
-        }\r
-    } else {\r
-        if (weight == FXFONT_FW_NORMAL) {\r
-            bNeedUpdateWeight = FALSE;\r
-        } else {\r
-            bNeedUpdateWeight = TRUE;\r
-        }\r
-    }\r
-    if (bNeedUpdateWeight) {\r
-        pSubstFont->m_Weight = weight;\r
-    }\r
-    if (bItalic && !FXFT_Is_Face_Italic(face)) {\r
-        if (italic_angle == 0) {\r
-            italic_angle = -12;\r
-        } else if (FXSYS_abs(italic_angle) < 5) {\r
-            italic_angle = 0;\r
-        }\r
-        pSubstFont->m_ItalicAngle = italic_angle;\r
-    }\r
-    m_pFontInfo->DeleteFont(hFont);\r
-    return face;\r
-}\r
-extern "C" {\r
-    unsigned long _FTStreamRead(FXFT_Stream stream, unsigned long offset,\r
-                                unsigned char* buffer, unsigned long count);\r
-    void _FTStreamClose(FXFT_Stream stream);\r
-};\r
-CFontFileFaceInfo::CFontFileFaceInfo()\r
-{\r
-    m_pFile = NULL;\r
-    m_Face = NULL;\r
-    m_Charsets = 0;\r
-    m_FileSize = 0;\r
-    m_FontOffset = 0;\r
-    m_Weight = 0;\r
-    m_bItalic = FALSE;\r
-    m_PitchFamily = 0;\r
-}\r
-CFontFileFaceInfo::~CFontFileFaceInfo()\r
-{\r
-    if (m_Face) {\r
-        FXFT_Done_Face(m_Face);\r
-    }\r
-    m_Face = NULL;\r
-}\r
-extern FX_BOOL _LoadFile(FXFT_Library library, FXFT_Face* Face, IFX_FileRead* pFile, FXFT_Stream* stream);\r
-#if defined(_FPDFAPI_MINI_) || _FX_OS_ == _FX_ANDROID_\r
-IFX_SystemFontInfo* IFX_SystemFontInfo::CreateDefault()\r
-{\r
-    return NULL;\r
-}\r
-#endif\r
-#if !defined(_FPDFAPI_MINI_)\r
-CFX_FolderFontInfo::CFX_FolderFontInfo()\r
-{\r
-}\r
-CFX_FolderFontInfo::~CFX_FolderFontInfo()\r
-{\r
-    FX_POSITION pos = m_FontList.GetStartPosition();\r
-    while (pos) {\r
-        CFX_ByteString key;\r
-        FX_LPVOID value;\r
-        m_FontList.GetNextAssoc(pos, key, value);\r
-        delete (CFontFaceInfo*)value;\r
-    }\r
-}\r
-void CFX_FolderFontInfo::AddPath(FX_BSTR path)\r
-{\r
-    m_PathList.Add(path);\r
-}\r
-void CFX_FolderFontInfo::Release()\r
-{\r
-    delete this;\r
-}\r
-FX_BOOL CFX_FolderFontInfo::EnumFontList(CFX_FontMapper* pMapper)\r
-{\r
-    m_pMapper = pMapper;\r
-    for (int i = 0; i < m_PathList.GetSize(); i ++) {\r
-        ScanPath(m_PathList[i]);\r
-    }\r
-    return TRUE;\r
-}\r
-void CFX_FolderFontInfo::ScanPath(CFX_ByteString& path)\r
-{\r
-    void* handle = FX_OpenFolder(path);\r
-    if (handle == NULL) {\r
-        return;\r
-    }\r
-    CFX_ByteString filename;\r
-    FX_BOOL bFolder;\r
-    while (FX_GetNextFile(handle, filename, bFolder)) {\r
-        if (bFolder) {\r
-            if (filename == "." || filename == "..") {\r
-                continue;\r
-            }\r
-        } else {\r
-            CFX_ByteString ext = filename.Right(4);\r
-            ext.MakeUpper();\r
-            if (ext != ".TTF" && ext != ".OTF" && ext != ".TTC") {\r
-                continue;\r
-            }\r
-        }\r
-        CFX_ByteString fullpath = path;\r
-#if _FXM_PLATFORM_  == _FXM_PLATFORM_WINDOWS_\r
-        fullpath += "\\";\r
-#else\r
-        fullpath += "/";\r
-#endif\r
-        fullpath += filename;\r
-        if (bFolder) {\r
-            ScanPath(fullpath);\r
-        } else {\r
-            ScanFile(fullpath);\r
-        }\r
-    }\r
-    FX_CloseFolder(handle);\r
-}\r
-void CFX_FolderFontInfo::ScanFile(CFX_ByteString& path)\r
-{\r
-    FXSYS_FILE* pFile = FXSYS_fopen(path, "rb");\r
-    if (pFile == NULL) {\r
-        return;\r
-    }\r
-    FXSYS_fseek(pFile, 0, FXSYS_SEEK_END);\r
-    FX_DWORD filesize = FXSYS_ftell(pFile);\r
-    FX_BYTE buffer[16];\r
-    FXSYS_fseek(pFile, 0, FXSYS_SEEK_SET);\r
-    size_t readCnt = FXSYS_fread(buffer, 12, 1, pFile);\r
-    if (GET_TT_LONG(buffer) == 0x74746366) {\r
-        FX_DWORD nFaces = GET_TT_LONG(buffer + 8);\r
-        FX_LPBYTE offsets = FX_Alloc(FX_BYTE, nFaces * 4);\r
-        if (!offsets) {\r
-            FXSYS_fclose(pFile);\r
-            return;\r
-        }\r
-        readCnt = FXSYS_fread(offsets, nFaces * 4, 1, pFile);\r
-        for (FX_DWORD i = 0; i < nFaces; i ++) {\r
-            FX_LPBYTE p = offsets + i * 4;\r
-            ReportFace(path, pFile, filesize, GET_TT_LONG(p));\r
-        }\r
-        FX_Free(offsets);\r
-    } else {\r
-        ReportFace(path, pFile, filesize, 0);\r
-    }\r
-    FXSYS_fclose(pFile);\r
-}\r
-void CFX_FolderFontInfo::ReportFace(CFX_ByteString& path, FXSYS_FILE* pFile, FX_DWORD filesize, FX_DWORD offset)\r
-{\r
-    FXSYS_fseek(pFile, offset, FXSYS_SEEK_SET);\r
-    char buffer[16];\r
-    if (!FXSYS_fread(buffer, 12, 1, pFile)) {\r
-        return;\r
-    }\r
-    FX_DWORD nTables = GET_TT_SHORT(buffer + 4);\r
-    CFX_ByteString tables = _FPDF_ReadStringFromFile(pFile, nTables * 16);\r
-    CFX_ByteString names = _FPDF_LoadTableFromTT(pFile, tables, nTables, 0x6e616d65);\r
-    CFX_ByteString facename = _FPDF_GetNameFromTT(names, 1);\r
-    CFX_ByteString style = _FPDF_GetNameFromTT(names, 2);\r
-    if (style != "Regular") {\r
-        facename += " " + style;\r
-    }\r
-    FX_LPVOID p;\r
-    if (m_FontList.Lookup(facename, p)) {\r
-        return;\r
-    }\r
-    CFontFaceInfo* pInfo = FX_NEW CFontFaceInfo;\r
-    if (!pInfo) {\r
-        return;\r
-    }\r
-    pInfo->m_FilePath = path;\r
-    pInfo->m_FaceName = facename;\r
-    pInfo->m_FontTables = tables;\r
-    pInfo->m_FontOffset = offset;\r
-    pInfo->m_FileSize = filesize;\r
-    pInfo->m_Charsets = 0;\r
-    CFX_ByteString os2 = _FPDF_LoadTableFromTT(pFile, tables, nTables, 0x4f532f32);\r
-    if (os2.GetLength() >= 86) {\r
-        FX_LPCBYTE p = (FX_LPCBYTE)os2 + 78;\r
-        FX_DWORD codepages = GET_TT_LONG(p);\r
-        if (codepages & (1 << 17)) {\r
-            m_pMapper->AddInstalledFont(facename, FXFONT_SHIFTJIS_CHARSET);\r
-            pInfo->m_Charsets |= CHARSET_FLAG_SHIFTJIS;\r
-        }\r
-        if (codepages & (1 << 18)) {\r
-            m_pMapper->AddInstalledFont(facename, FXFONT_GB2312_CHARSET);\r
-            pInfo->m_Charsets |= CHARSET_FLAG_GB;\r
-        }\r
-        if (codepages & (1 << 20)) {\r
-            m_pMapper->AddInstalledFont(facename, FXFONT_CHINESEBIG5_CHARSET);\r
-            pInfo->m_Charsets |= CHARSET_FLAG_BIG5;\r
-        }\r
-        if ((codepages & (1 << 19)) || (codepages & (1 << 21))) {\r
-            m_pMapper->AddInstalledFont(facename, FXFONT_HANGEUL_CHARSET);\r
-            pInfo->m_Charsets |= CHARSET_FLAG_KOREAN;\r
-        }\r
-        if (codepages & (1 << 31)) {\r
-            m_pMapper->AddInstalledFont(facename, FXFONT_SYMBOL_CHARSET);\r
-            pInfo->m_Charsets |= CHARSET_FLAG_SYMBOL;\r
-        }\r
-    }\r
-    m_pMapper->AddInstalledFont(facename, FXFONT_ANSI_CHARSET);\r
-    pInfo->m_Charsets |= CHARSET_FLAG_ANSI;\r
-    pInfo->m_Styles = 0;\r
-    if (style.Find(FX_BSTRC("Bold")) > -1) {\r
-        pInfo->m_Styles |= FXFONT_BOLD;\r
-    }\r
-    if (style.Find(FX_BSTRC("Italic")) > -1 || style.Find(FX_BSTRC("Oblique")) > -1) {\r
-        pInfo->m_Styles |= FXFONT_ITALIC;\r
-    }\r
-    if (facename.Find(FX_BSTRC("Serif")) > -1) {\r
-        pInfo->m_Styles |= FXFONT_SERIF;\r
-    }\r
-    m_FontList.SetAt(facename, pInfo);\r
-}\r
-void* CFX_FolderFontInfo::MapFont(int weight, FX_BOOL bItalic, int charset, int pitch_family, FX_LPCSTR family, FX_BOOL& bExact)\r
-{\r
-    return NULL;\r
-}\r
-void* CFX_FolderFontInfo::GetFont(FX_LPCSTR face)\r
-{\r
-    FX_LPVOID p;\r
-    if (!m_FontList.Lookup(face, p)) {\r
-        return NULL;\r
-    }\r
-    return p;\r
-}\r
-FX_DWORD CFX_FolderFontInfo::GetFontData(void* hFont, FX_DWORD table, FX_LPBYTE buffer, FX_DWORD size)\r
-{\r
-    if (hFont == NULL) {\r
-        return 0;\r
-    }\r
-    CFontFaceInfo* pFont = (CFontFaceInfo*)hFont;\r
-    FXSYS_FILE* pFile = NULL;\r
-    if (size > 0) {\r
-        pFile = FXSYS_fopen(pFont->m_FilePath, "rb");\r
-        if (pFile == NULL) {\r
-            return 0;\r
-        }\r
-    }\r
-    FX_DWORD datasize = 0;\r
-    FX_DWORD offset;\r
-    if (table == 0)    {\r
-        datasize = pFont->m_FontOffset ? 0 : pFont->m_FileSize;\r
-        offset = 0;\r
-    } else if (table == 0x74746366)    {\r
-        datasize = pFont->m_FontOffset ? pFont->m_FileSize : 0;\r
-        offset = 0;\r
-    } else {\r
-        FX_DWORD nTables = pFont->m_FontTables.GetLength() / 16;\r
-        for (FX_DWORD i = 0; i < nTables; i ++) {\r
-            FX_LPCBYTE p = (FX_LPCBYTE)pFont->m_FontTables + i * 16;\r
-            if (GET_TT_LONG(p) == table) {\r
-                offset = GET_TT_LONG(p + 8);\r
-                datasize = GET_TT_LONG(p + 12);\r
-            }\r
-        }\r
-    }\r
-    if (datasize && size >= datasize && pFile) {\r
-        FXSYS_fseek(pFile, offset, FXSYS_SEEK_SET);\r
-        size_t readCnt = FXSYS_fread(buffer, datasize, 1, pFile);\r
-    }\r
-    if (pFile) {\r
-        FXSYS_fclose(pFile);\r
-    }\r
-    return datasize;\r
-}\r
-void CFX_FolderFontInfo::DeleteFont(void* hFont)\r
-{\r
-}\r
-FX_BOOL CFX_FolderFontInfo::GetFaceName(void* hFont, CFX_ByteString& name)\r
-{\r
-    if (hFont == NULL) {\r
-        return FALSE;\r
-    }\r
-    CFontFaceInfo* pFont = (CFontFaceInfo*)hFont;\r
-    name = pFont->m_FaceName;\r
-    return TRUE;\r
-}\r
-FX_BOOL CFX_FolderFontInfo::GetFontCharset(void* hFont, int& charset)\r
-{\r
-    return FALSE;\r
-}\r
-#endif\r
+// Copyright 2014 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include <limits>
+
+#include "../../../include/fxge/fx_ge.h"
+#include "../../../include/fxge/fx_freetype.h"
+#include "../fontdata/chromefontdata/chromefontdata.h"
+#include "text_int.h"
+
+#define GET_TT_SHORT(w) (FX_WORD)(((w)[0] << 8) | (w)[1])
+#define GET_TT_LONG(w) \
+  (FX_DWORD)(((w)[0] << 24) | ((w)[1] << 16) | ((w)[2] << 8) | (w)[3])
+
+namespace {
+
+CFX_ByteString KeyNameFromFace(const CFX_ByteString& face_name,
+                               int weight,
+                               FX_BOOL bItalic) {
+  CFX_ByteString key(face_name);
+  key += ',';
+  key += CFX_ByteString::FormatInteger(weight);
+  key += bItalic ? 'I' : 'N';
+  return key;
+}
+
+CFX_ByteString KeyNameFromSize(int ttc_size, FX_DWORD checksum) {
+  CFX_ByteString key;
+  key.Format("%d:%d", ttc_size, checksum);
+  return key;
+}
+
+}  // namespace
+
+CFX_SubstFont::CFX_SubstFont() {
+  m_ExtHandle = NULL;
+  m_Charset = 0;
+  m_SubstFlags = 0;
+  m_Weight = 0;
+  m_ItalicAngle = 0;
+  m_bSubstOfCJK = FALSE;
+  m_WeightCJK = 0;
+  m_bItlicCJK = FALSE;
+}
+CTTFontDesc::~CTTFontDesc() {
+  if (m_Type == 1) {
+    if (m_SingleFace.m_pFace) {
+      FXFT_Done_Face(m_SingleFace.m_pFace);
+    }
+  } else if (m_Type == 2) {
+    for (int i = 0; i < 16; i++)
+      if (m_TTCFace.m_pFaces[i]) {
+        FXFT_Done_Face(m_TTCFace.m_pFaces[i]);
+      }
+  }
+  FX_Free(m_pFontData);
+}
+FX_BOOL CTTFontDesc::ReleaseFace(FXFT_Face face) {
+  if (m_Type == 1) {
+    if (m_SingleFace.m_pFace != face) {
+      return FALSE;
+    }
+  } else if (m_Type == 2) {
+    int i;
+    for (i = 0; i < 16; i++)
+      if (m_TTCFace.m_pFaces[i] == face) {
+        break;
+      }
+    if (i == 16) {
+      return FALSE;
+    }
+  }
+  m_RefCount--;
+  if (m_RefCount) {
+    return FALSE;
+  }
+  delete this;
+  return TRUE;
+}
+CFX_FontMgr::CFX_FontMgr() : m_FTLibrary(nullptr) {
+  m_pBuiltinMapper = new CFX_FontMapper(this);
+  FXSYS_memset(m_ExternalFonts, 0, sizeof m_ExternalFonts);
+}
+CFX_FontMgr::~CFX_FontMgr() {
+  delete m_pBuiltinMapper;
+  FreeCache();
+  if (m_FTLibrary) {
+    FXFT_Done_FreeType(m_FTLibrary);
+  }
+}
+void CFX_FontMgr::InitFTLibrary() {
+  if (m_FTLibrary == NULL) {
+    FXFT_Init_FreeType(&m_FTLibrary);
+  }
+}
+void CFX_FontMgr::FreeCache() {
+  for (const auto& pair : m_FaceMap) {
+    delete pair.second;
+  }
+  m_FaceMap.clear();
+}
+void CFX_FontMgr::SetSystemFontInfo(IFX_SystemFontInfo* pFontInfo) {
+  m_pBuiltinMapper->SetSystemFontInfo(pFontInfo);
+}
+FXFT_Face CFX_FontMgr::FindSubstFont(const CFX_ByteString& face_name,
+                                     FX_BOOL bTrueType,
+                                     FX_DWORD flags,
+                                     int weight,
+                                     int italic_angle,
+                                     int CharsetCP,
+                                     CFX_SubstFont* pSubstFont) {
+  if (!m_FTLibrary) {
+    FXFT_Init_FreeType(&m_FTLibrary);
+  }
+  return m_pBuiltinMapper->FindSubstFont(face_name, bTrueType, flags, weight,
+                                         italic_angle, CharsetCP, pSubstFont);
+}
+FXFT_Face CFX_FontMgr::GetCachedFace(const CFX_ByteString& face_name,
+                                     int weight,
+                                     FX_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;
+  pFontData = pFontDesc->m_pFontData;
+  pFontDesc->m_RefCount++;
+  return pFontDesc->m_SingleFace.m_pFace;
+}
+FXFT_Face CFX_FontMgr::AddCachedFace(const CFX_ByteString& face_name,
+                                     int weight,
+                                     FX_BOOL bItalic,
+                                     uint8_t* pData,
+                                     FX_DWORD size,
+                                     int face_index) {
+  CTTFontDesc* pFontDesc = new CTTFontDesc;
+  pFontDesc->m_Type = 1;
+  pFontDesc->m_SingleFace.m_pFace = NULL;
+  pFontDesc->m_SingleFace.m_bBold = weight;
+  pFontDesc->m_SingleFace.m_bItalic = bItalic;
+  pFontDesc->m_pFontData = pData;
+  pFontDesc->m_RefCount = 1;
+  FXFT_Library library;
+  if (m_FTLibrary == NULL) {
+    FXFT_Init_FreeType(&m_FTLibrary);
+  }
+  library = m_FTLibrary;
+  int ret = FXFT_New_Memory_Face(library, pData, size, face_index,
+                                 &pFontDesc->m_SingleFace.m_pFace);
+  if (ret) {
+    delete pFontDesc;
+    return NULL;
+  }
+  ret = FXFT_Set_Pixel_Sizes(pFontDesc->m_SingleFace.m_pFace, 64, 64);
+  if (ret) {
+    delete pFontDesc;
+    return NULL;
+  }
+  m_FaceMap[KeyNameFromFace(face_name, weight, bItalic)] = pFontDesc;
+  return pFontDesc->m_SingleFace.m_pFace;
+}
+const FX_CHAR* const g_Base14FontNames[14] = {
+    "Courier",
+    "Courier-Bold",
+    "Courier-BoldOblique",
+    "Courier-Oblique",
+    "Helvetica",
+    "Helvetica-Bold",
+    "Helvetica-BoldOblique",
+    "Helvetica-Oblique",
+    "Times-Roman",
+    "Times-Bold",
+    "Times-BoldItalic",
+    "Times-Italic",
+    "Symbol",
+    "ZapfDingbats",
+};
+const struct AltFontName {
+  const FX_CHAR* m_pName;
+  int m_Index;
+} g_AltFontNames[] = {
+    {"Arial", 4},
+    {"Arial,Bold", 5},
+    {"Arial,BoldItalic", 6},
+    {"Arial,Italic", 7},
+    {"Arial-Bold", 5},
+    {"Arial-BoldItalic", 6},
+    {"Arial-BoldItalicMT", 6},
+    {"Arial-BoldMT", 5},
+    {"Arial-Italic", 7},
+    {"Arial-ItalicMT", 7},
+    {"ArialBold", 5},
+    {"ArialBoldItalic", 6},
+    {"ArialItalic", 7},
+    {"ArialMT", 4},
+    {"ArialMT,Bold", 5},
+    {"ArialMT,BoldItalic", 6},
+    {"ArialMT,Italic", 7},
+    {"ArialRoundedMTBold", 5},
+    {"Courier", 0},
+    {"Courier,Bold", 1},
+    {"Courier,BoldItalic", 2},
+    {"Courier,Italic", 3},
+    {"Courier-Bold", 1},
+    {"Courier-BoldOblique", 2},
+    {"Courier-Oblique", 3},
+    {"CourierBold", 1},
+    {"CourierBoldItalic", 2},
+    {"CourierItalic", 3},
+    {"CourierNew", 0},
+    {"CourierNew,Bold", 1},
+    {"CourierNew,BoldItalic", 2},
+    {"CourierNew,Italic", 3},
+    {"CourierNew-Bold", 1},
+    {"CourierNew-BoldItalic", 2},
+    {"CourierNew-Italic", 3},
+    {"CourierNewBold", 1},
+    {"CourierNewBoldItalic", 2},
+    {"CourierNewItalic", 3},
+    {"CourierNewPS-BoldItalicMT", 2},
+    {"CourierNewPS-BoldMT", 1},
+    {"CourierNewPS-ItalicMT", 3},
+    {"CourierNewPSMT", 0},
+    {"CourierStd", 0},
+    {"CourierStd-Bold", 1},
+    {"CourierStd-BoldOblique", 2},
+    {"CourierStd-Oblique", 3},
+    {"Helvetica", 4},
+    {"Helvetica,Bold", 5},
+    {"Helvetica,BoldItalic", 6},
+    {"Helvetica,Italic", 7},
+    {"Helvetica-Bold", 5},
+    {"Helvetica-BoldItalic", 6},
+    {"Helvetica-BoldOblique", 6},
+    {"Helvetica-Italic", 7},
+    {"Helvetica-Oblique", 7},
+    {"HelveticaBold", 5},
+    {"HelveticaBoldItalic", 6},
+    {"HelveticaItalic", 7},
+    {"Symbol", 12},
+    {"SymbolMT", 12},
+    {"Times-Bold", 9},
+    {"Times-BoldItalic", 10},
+    {"Times-Italic", 11},
+    {"Times-Roman", 8},
+    {"TimesBold", 9},
+    {"TimesBoldItalic", 10},
+    {"TimesItalic", 11},
+    {"TimesNewRoman", 8},
+    {"TimesNewRoman,Bold", 9},
+    {"TimesNewRoman,BoldItalic", 10},
+    {"TimesNewRoman,Italic", 11},
+    {"TimesNewRoman-Bold", 9},
+    {"TimesNewRoman-BoldItalic", 10},
+    {"TimesNewRoman-Italic", 11},
+    {"TimesNewRomanBold", 9},
+    {"TimesNewRomanBoldItalic", 10},
+    {"TimesNewRomanItalic", 11},
+    {"TimesNewRomanPS", 8},
+    {"TimesNewRomanPS-Bold", 9},
+    {"TimesNewRomanPS-BoldItalic", 10},
+    {"TimesNewRomanPS-BoldItalicMT", 10},
+    {"TimesNewRomanPS-BoldMT", 9},
+    {"TimesNewRomanPS-Italic", 11},
+    {"TimesNewRomanPS-ItalicMT", 11},
+    {"TimesNewRomanPSMT", 8},
+    {"TimesNewRomanPSMT,Bold", 9},
+    {"TimesNewRomanPSMT,BoldItalic", 10},
+    {"TimesNewRomanPSMT,Italic", 11},
+    {"ZapfDingbats", 13},
+};
+extern "C" {
+static int compareString(const void* key, const void* element) {
+  return FXSYS_stricmp((const FX_CHAR*)key, ((AltFontName*)element)->m_pName);
+}
+}
+
+int GetTTCIndex(const uint8_t* pFontData,
+                FX_DWORD ttc_size,
+                FX_DWORD font_offset) {
+  int face_index = 0;
+  const uint8_t* p = pFontData + 8;
+  FX_DWORD nfont = GET_TT_LONG(p);
+  FX_DWORD index;
+  for (index = 0; index < nfont; index++) {
+    p = pFontData + 12 + index * 4;
+    if (GET_TT_LONG(p) == font_offset) {
+      break;
+    }
+  }
+  if (index >= nfont) {
+    face_index = 0;
+  } else {
+    face_index = index;
+  }
+  return face_index;
+}
+FXFT_Face CFX_FontMgr::GetCachedTTCFace(int ttc_size,
+                                        FX_DWORD checksum,
+                                        int font_offset,
+                                        uint8_t*& pFontData) {
+  auto it = m_FaceMap.find(KeyNameFromSize(ttc_size, checksum));
+  if (it == m_FaceMap.end())
+    return nullptr;
+
+  CTTFontDesc* pFontDesc = it->second;
+  pFontData = pFontDesc->m_pFontData;
+  pFontDesc->m_RefCount++;
+  int face_index = GetTTCIndex(pFontDesc->m_pFontData, ttc_size, font_offset);
+  if (!pFontDesc->m_TTCFace.m_pFaces[face_index]) {
+    pFontDesc->m_TTCFace.m_pFaces[face_index] =
+        GetFixedFace(pFontDesc->m_pFontData, ttc_size, face_index);
+  }
+  return pFontDesc->m_TTCFace.m_pFaces[face_index];
+}
+FXFT_Face CFX_FontMgr::AddCachedTTCFace(int ttc_size,
+                                        FX_DWORD checksum,
+                                        uint8_t* pData,
+                                        FX_DWORD size,
+                                        int font_offset) {
+  CTTFontDesc* pFontDesc = new CTTFontDesc;
+  pFontDesc->m_Type = 2;
+  pFontDesc->m_pFontData = pData;
+  for (int i = 0; i < 16; i++) {
+    pFontDesc->m_TTCFace.m_pFaces[i] = NULL;
+  }
+  pFontDesc->m_RefCount++;
+  m_FaceMap[KeyNameFromSize(ttc_size, checksum)] = pFontDesc;
+  int face_index = GetTTCIndex(pFontDesc->m_pFontData, ttc_size, font_offset);
+  pFontDesc->m_TTCFace.m_pFaces[face_index] =
+      GetFixedFace(pFontDesc->m_pFontData, ttc_size, face_index);
+  return pFontDesc->m_TTCFace.m_pFaces[face_index];
+}
+FXFT_Face CFX_FontMgr::GetFixedFace(const uint8_t* pData,
+                                    FX_DWORD size,
+                                    int face_index) {
+  FXFT_Library library;
+  if (m_FTLibrary == NULL) {
+    FXFT_Init_FreeType(&m_FTLibrary);
+  }
+  library = m_FTLibrary;
+  FXFT_Face face = NULL;
+  int ret = FXFT_New_Memory_Face(library, pData, size, face_index, &face);
+  if (ret) {
+    return NULL;
+  }
+  ret = FXFT_Set_Pixel_Sizes(face, 64, 64);
+  if (ret) {
+    return NULL;
+  }
+  return face;
+}
+FXFT_Face CFX_FontMgr::GetFileFace(const FX_CHAR* filename, int face_index) {
+  FXFT_Library library;
+  if (m_FTLibrary == NULL) {
+    FXFT_Init_FreeType(&m_FTLibrary);
+  }
+  library = m_FTLibrary;
+  FXFT_Face face = NULL;
+  int ret = FXFT_New_Face(library, filename, face_index, &face);
+  if (ret) {
+    return NULL;
+  }
+  ret = FXFT_Set_Pixel_Sizes(face, 64, 64);
+  if (ret) {
+    return NULL;
+  }
+  return face;
+}
+void CFX_FontMgr::ReleaseFace(FXFT_Face face) {
+  if (!face) {
+    return;
+  }
+  auto it = m_FaceMap.begin();
+  while (it != m_FaceMap.end()) {
+    auto temp = it++;
+    if (temp->second->ReleaseFace(face)) {
+      m_FaceMap.erase(temp);
+    }
+  }
+}
+const FoxitFonts g_FoxitFonts[14] = {
+    {g_FoxitFixedFontData, 17597},
+    {g_FoxitFixedBoldFontData, 18055},
+    {g_FoxitFixedBoldItalicFontData, 19151},
+    {g_FoxitFixedItalicFontData, 18746},
+    {g_FoxitSansFontData, 15025},
+    {g_FoxitSansBoldFontData, 16344},
+    {g_FoxitSansBoldItalicFontData, 16418},
+    {g_FoxitSansItalicFontData, 16339},
+    {g_FoxitSerifFontData, 19469},
+    {g_FoxitSerifBoldFontData, 19395},
+    {g_FoxitSerifBoldItalicFontData, 20733},
+    {g_FoxitSerifItalicFontData, 21227},
+    {g_FoxitSymbolFontData, 16729},
+    {g_FoxitDingbatsFontData, 29513},
+};
+FX_BOOL CFX_FontMgr::GetStandardFont(const uint8_t*& pFontData,
+                                     FX_DWORD& size,
+                                     int index) {
+  if (index > 15 || index < 0) {
+    return FALSE;
+  }
+  {
+    if (index >= 14) {
+      if (index == 14) {
+        pFontData = g_FoxitSerifMMFontData;
+        size = 113417;
+      } else {
+        pFontData = g_FoxitSansMMFontData;
+        size = 66919;
+      }
+    } else {
+      pFontData = g_FoxitFonts[index].m_pFontData;
+      size = g_FoxitFonts[index].m_dwSize;
+    }
+  }
+  return TRUE;
+}
+CFX_FontMapper::CFX_FontMapper(CFX_FontMgr* mgr)
+    : m_bListLoaded(FALSE),
+      m_pFontInfo(nullptr),
+      m_pFontEnumerator(nullptr),
+      m_pFontMgr(mgr) {
+  m_MMFaces[0] = nullptr;
+  m_MMFaces[1] = nullptr;
+  FXSYS_memset(m_FoxitFaces, 0, sizeof(m_FoxitFaces));
+}
+CFX_FontMapper::~CFX_FontMapper() {
+  for (int i = 0; i < 14; i++)
+    if (m_FoxitFaces[i]) {
+      FXFT_Done_Face(m_FoxitFaces[i]);
+    }
+  if (m_MMFaces[0]) {
+    FXFT_Done_Face(m_MMFaces[0]);
+  }
+  if (m_MMFaces[1]) {
+    FXFT_Done_Face(m_MMFaces[1]);
+  }
+  if (m_pFontInfo) {
+    m_pFontInfo->Release();
+  }
+}
+void CFX_FontMapper::SetSystemFontInfo(IFX_SystemFontInfo* pFontInfo) {
+  if (pFontInfo == NULL) {
+    return;
+  }
+  if (m_pFontInfo) {
+    m_pFontInfo->Release();
+  }
+  m_pFontInfo = pFontInfo;
+}
+static CFX_ByteString _TT_NormalizeName(const FX_CHAR* family) {
+  CFX_ByteString norm(family);
+  norm.Remove(' ');
+  norm.Remove('-');
+  norm.Remove(',');
+  int pos = norm.Find('+');
+  if (pos > 0) {
+    norm = norm.Left(pos);
+  }
+  norm.MakeLower();
+  return norm;
+}
+CFX_ByteString GetNameFromTT(const uint8_t* name_table, FX_DWORD name_id) {
+  const uint8_t* ptr = name_table + 2;
+  int name_count = GET_TT_SHORT(ptr);
+  int string_offset = GET_TT_SHORT(ptr + 2);
+  const uint8_t* string_ptr = name_table + string_offset;
+  ptr += 4;
+  for (int i = 0; i < name_count; i++) {
+    if (GET_TT_SHORT(ptr + 6) == name_id && GET_TT_SHORT(ptr) == 1 &&
+        GET_TT_SHORT(ptr + 2) == 0) {
+      return CFX_ByteStringC(string_ptr + GET_TT_SHORT(ptr + 10),
+                             GET_TT_SHORT(ptr + 8));
+    }
+    ptr += 12;
+  }
+  return CFX_ByteString();
+}
+static CFX_ByteString _FPDF_ReadStringFromFile(FXSYS_FILE* pFile,
+                                               FX_DWORD size) {
+  CFX_ByteString buffer;
+  if (!FXSYS_fread(buffer.GetBuffer(size), size, 1, pFile)) {
+    return CFX_ByteString();
+  }
+  buffer.ReleaseBuffer(size);
+  return buffer;
+}
+CFX_ByteString _FPDF_LoadTableFromTT(FXSYS_FILE* pFile,
+                                     const uint8_t* pTables,
+                                     FX_DWORD nTables,
+                                     FX_DWORD tag) {
+  for (FX_DWORD i = 0; i < nTables; i++) {
+    const uint8_t* p = pTables + i * 16;
+    if (GET_TT_LONG(p) == tag) {
+      FX_DWORD offset = GET_TT_LONG(p + 8);
+      FX_DWORD size = GET_TT_LONG(p + 12);
+      FXSYS_fseek(pFile, offset, FXSYS_SEEK_SET);
+      return _FPDF_ReadStringFromFile(pFile, size);
+    }
+  }
+  return CFX_ByteString();
+}
+CFX_ByteString _FPDF_LoadTableFromTTStreamFile(IFX_FileStream* pFile,
+                                               const uint8_t* pTables,
+                                               FX_DWORD nTables,
+                                               FX_DWORD tag) {
+  for (FX_DWORD i = 0; i < nTables; i++) {
+    const uint8_t* p = pTables + i * 16;
+    if (GET_TT_LONG(p) == tag) {
+      FX_DWORD offset = GET_TT_LONG(p + 8);
+      FX_DWORD size = GET_TT_LONG(p + 12);
+      CFX_ByteString buffer;
+      if (!pFile->ReadBlock(buffer.GetBuffer(size), offset, size)) {
+        return CFX_ByteString();
+      }
+      buffer.ReleaseBuffer(size);
+      return buffer;
+    }
+  }
+  return CFX_ByteString();
+}
+CFX_ByteString CFX_FontMapper::GetPSNameFromTT(void* hFont) {
+  if (m_pFontInfo == NULL) {
+    return CFX_ByteString();
+  }
+  CFX_ByteString result;
+  FX_DWORD size = m_pFontInfo->GetFontData(hFont, 0x6e616d65, NULL, 0);
+  if (size) {
+    uint8_t* buffer = FX_Alloc(uint8_t, size);
+    m_pFontInfo->GetFontData(hFont, 0x6e616d65, buffer, size);
+    result = GetNameFromTT(buffer, 6);
+    FX_Free(buffer);
+  }
+  return result;
+}
+void CFX_FontMapper::AddInstalledFont(const CFX_ByteString& name, int charset) {
+  if (m_pFontInfo == NULL) {
+    return;
+  }
+  if (m_CharsetArray.Find((FX_DWORD)charset) == -1) {
+    m_CharsetArray.Add((FX_DWORD)charset);
+    m_FaceArray.Add(name);
+  }
+  if (name == m_LastFamily) {
+    return;
+  }
+  const uint8_t* ptr = name;
+  FX_BOOL bLocalized = FALSE;
+  for (int i = 0; i < name.GetLength(); i++)
+    if (ptr[i] > 0x80) {
+      bLocalized = TRUE;
+      break;
+    }
+  if (bLocalized) {
+    void* hFont = m_pFontInfo->GetFont(name);
+    if (hFont == NULL) {
+      int iExact;
+      hFont =
+          m_pFontInfo->MapFont(0, 0, FXFONT_DEFAULT_CHARSET, 0, name, iExact);
+      if (hFont == NULL) {
+        return;
+      }
+    }
+    CFX_ByteString new_name = GetPSNameFromTT(hFont);
+    if (!new_name.IsEmpty()) {
+      new_name.Insert(0, ' ');
+      m_InstalledTTFonts.Add(new_name);
+    }
+    m_pFontInfo->DeleteFont(hFont);
+  }
+  m_InstalledTTFonts.Add(name);
+  m_LastFamily = name;
+}
+void CFX_FontMapper::LoadInstalledFonts() {
+  if (m_pFontInfo == NULL) {
+    return;
+  }
+  if (m_bListLoaded) {
+    return;
+  }
+  if (m_bListLoaded) {
+    return;
+  }
+  m_pFontInfo->EnumFontList(this);
+  m_bListLoaded = TRUE;
+}
+CFX_ByteString CFX_FontMapper::MatchInstalledFonts(
+    const CFX_ByteString& norm_name) {
+  LoadInstalledFonts();
+  int i;
+  for (i = m_InstalledTTFonts.GetSize() - 1; i >= 0; i--) {
+    CFX_ByteString norm1 = _TT_NormalizeName(m_InstalledTTFonts[i]);
+    if (norm1 == norm_name) {
+      break;
+    }
+  }
+  if (i < 0) {
+    return CFX_ByteString();
+  }
+  CFX_ByteString match = m_InstalledTTFonts[i];
+  if (match[0] == ' ') {
+    match = m_InstalledTTFonts[i + 1];
+  }
+  return match;
+}
+typedef struct _CHARSET_MAP_ {
+  uint8_t charset;
+  FX_WORD codepage;
+} CHARSET_MAP;
+static const CHARSET_MAP g_Codepage2CharsetTable[] = {
+    {1, 0},      {2, 42},     {254, 437},  {255, 850},  {222, 874},
+    {128, 932},  {134, 936},  {129, 949},  {136, 950},  {238, 1250},
+    {204, 1251}, {0, 1252},   {161, 1253}, {162, 1254}, {177, 1255},
+    {178, 1256}, {186, 1257}, {163, 1258}, {130, 1361}, {77, 10000},
+    {78, 10001}, {79, 10003}, {80, 10008}, {81, 10002}, {83, 10005},
+    {84, 10004}, {85, 10006}, {86, 10081}, {87, 10021}, {88, 10029},
+    {89, 10007},
+};
+uint8_t _GetCharsetFromCodePage(FX_WORD codepage) {
+  int32_t iEnd = sizeof(g_Codepage2CharsetTable) / sizeof(CHARSET_MAP) - 1;
+  FXSYS_assert(iEnd >= 0);
+  int32_t iStart = 0, iMid;
+  do {
+    iMid = (iStart + iEnd) / 2;
+    const CHARSET_MAP& cp = g_Codepage2CharsetTable[iMid];
+    if (codepage == cp.codepage) {
+      return cp.charset;
+    }
+    if (codepage < cp.codepage) {
+      iEnd = iMid - 1;
+    } else {
+      iStart = iMid + 1;
+    }
+  } while (iStart <= iEnd);
+  return 1;
+}
+FX_DWORD _GetCodePageRangeFromCharset(int charset) {
+  if (charset == FXFONT_EASTEUROPE_CHARSET) {
+    return 1 << 1;
+  }
+  if (charset == FXFONT_GREEK_CHARSET) {
+    return 1 << 3;
+  }
+  if (charset == FXFONT_TURKISH_CHARSET) {
+    return 1 << 4;
+  }
+  if (charset == FXFONT_HEBREW_CHARSET) {
+    return 1 << 5;
+  }
+  if (charset == FXFONT_ARABIC_CHARSET) {
+    return 1 << 6;
+  }
+  if (charset == FXFONT_BALTIC_CHARSET) {
+    return 1 << 7;
+  }
+  if (charset == FXFONT_THAI_CHARSET) {
+    return 1 << 16;
+  }
+  if (charset == FXFONT_SHIFTJIS_CHARSET) {
+    return 1 << 17;
+  }
+  if (charset == FXFONT_GB2312_CHARSET) {
+    return 1 << 18;
+  }
+  if (charset == FXFONT_CHINESEBIG5_CHARSET) {
+    return 1 << 20;
+  }
+  if (charset == FXFONT_HANGEUL_CHARSET) {
+    return 1 << 19;
+  }
+  if (charset == FXFONT_SYMBOL_CHARSET) {
+    return 1 << 31;
+  }
+  return 1 << 21;
+}
+FXFT_Face CFX_FontMapper::UseInternalSubst(CFX_SubstFont* pSubstFont,
+                                           int iBaseFont,
+                                           int italic_angle,
+                                           int weight,
+                                           int picthfamily) {
+  if (iBaseFont < 12) {
+    if (m_FoxitFaces[iBaseFont]) {
+      return m_FoxitFaces[iBaseFont];
+    }
+    const uint8_t* pFontData = NULL;
+    FX_DWORD size = 0;
+    if (m_pFontMgr->GetStandardFont(pFontData, size, iBaseFont)) {
+      m_FoxitFaces[iBaseFont] = m_pFontMgr->GetFixedFace(pFontData, size, 0);
+      return m_FoxitFaces[iBaseFont];
+    }
+  }
+  pSubstFont->m_SubstFlags |= FXFONT_SUBST_MM;
+  pSubstFont->m_ItalicAngle = italic_angle;
+  if (weight) {
+    pSubstFont->m_Weight = weight;
+  }
+  if (picthfamily & FXFONT_FF_ROMAN) {
+    pSubstFont->m_Weight = pSubstFont->m_Weight * 4 / 5;
+    pSubstFont->m_Family = "Chrome Serif";
+    if (m_MMFaces[1]) {
+      return m_MMFaces[1];
+    }
+    const uint8_t* pFontData = NULL;
+    FX_DWORD size;
+    m_pFontMgr->GetStandardFont(pFontData, size, 14);
+    m_MMFaces[1] = m_pFontMgr->GetFixedFace(pFontData, size, 0);
+    return m_MMFaces[1];
+  }
+  pSubstFont->m_Family = "Chrome Sans";
+  if (m_MMFaces[0]) {
+    return m_MMFaces[0];
+  }
+  const uint8_t* pFontData = NULL;
+  FX_DWORD size = 0;
+  m_pFontMgr->GetStandardFont(pFontData, size, 15);
+  m_MMFaces[0] = m_pFontMgr->GetFixedFace(pFontData, size, 0);
+  return m_MMFaces[0];
+}
+const struct _AltFontFamily {
+  const FX_CHAR* m_pFontName;
+  const FX_CHAR* m_pFontFamily;
+} g_AltFontFamilies[] = {
+    {"AGaramondPro", "Adobe Garamond Pro"},
+    {"BankGothicBT-Medium", "BankGothic Md BT"},
+    {"ForteMT", "Forte"},
+};
+extern "C" {
+static int compareFontFamilyString(const void* key, const void* element) {
+  CFX_ByteString str_key((const FX_CHAR*)key);
+  if (str_key.Find(((_AltFontFamily*)element)->m_pFontName) != -1) {
+    return 0;
+  }
+  return FXSYS_stricmp((const FX_CHAR*)key,
+                       ((_AltFontFamily*)element)->m_pFontName);
+}
+}
+#define FX_FONT_STYLE_None 0x00
+#define FX_FONT_STYLE_Bold 0x01
+#define FX_FONT_STYLE_Italic 0x02
+#define FX_FONT_STYLE_BoldBold 0x04
+static CFX_ByteString _GetFontFamily(CFX_ByteString fontName, int nStyle) {
+  if (fontName.Find("Script") >= 0) {
+    if ((nStyle & FX_FONT_STYLE_Bold) == FX_FONT_STYLE_Bold) {
+      fontName = "ScriptMTBold";
+    } else if (fontName.Find("Palace") >= 0) {
+      fontName = "PalaceScriptMT";
+    } else if (fontName.Find("French") >= 0) {
+      fontName = "FrenchScriptMT";
+    } else if (fontName.Find("FreeStyle") >= 0) {
+      fontName = "FreeStyleScript";
+    }
+    return fontName;
+  }
+  _AltFontFamily* found = (_AltFontFamily*)FXSYS_bsearch(
+      fontName.c_str(), g_AltFontFamilies,
+      sizeof g_AltFontFamilies / sizeof(_AltFontFamily), sizeof(_AltFontFamily),
+      compareFontFamilyString);
+  if (found == NULL) {
+    return fontName;
+  }
+  return found->m_pFontFamily;
+};
+typedef struct _FX_FontStyle {
+  const FX_CHAR* style;
+  int32_t len;
+} FX_FontStyle;
+const FX_FontStyle g_FontStyles[] = {
+    {"Bold", 4}, {"Italic", 6}, {"BoldItalic", 10}, {"Reg", 3}, {"Regular", 7},
+};
+CFX_ByteString ParseStyle(const FX_CHAR* pStyle, int iLen, int iIndex) {
+  CFX_ByteTextBuf buf;
+  if (!iLen || iLen <= iIndex) {
+    return buf.GetByteString();
+  }
+  while (iIndex < iLen) {
+    if (pStyle[iIndex] == ',') {
+      break;
+    }
+    buf.AppendChar(pStyle[iIndex]);
+    ++iIndex;
+  }
+  return buf.GetByteString();
+}
+int32_t GetStyleType(const CFX_ByteString& bsStyle, FX_BOOL bRevert) {
+  int32_t iLen = bsStyle.GetLength();
+  if (!iLen) {
+    return -1;
+  }
+  int iSize = sizeof(g_FontStyles) / sizeof(FX_FontStyle);
+  const FX_FontStyle* pStyle = NULL;
+  for (int i = iSize - 1; i >= 0; --i) {
+    pStyle = g_FontStyles + i;
+    if (!pStyle || pStyle->len > iLen) {
+      continue;
+    }
+    if (!bRevert) {
+      if (bsStyle.Left(pStyle->len).Compare(pStyle->style) == 0) {
+        return i;
+      }
+    } else {
+      if (bsStyle.Right(pStyle->len).Compare(pStyle->style) == 0) {
+        return i;
+      }
+    }
+  }
+  return -1;
+}
+FX_BOOL CheckSupportThirdPartFont(CFX_ByteString name, int& PitchFamily) {
+  if (name == FX_BSTRC("MyriadPro")) {
+    PitchFamily &= ~FXFONT_FF_ROMAN;
+    return TRUE;
+  }
+  return FALSE;
+}
+FXFT_Face CFX_FontMapper::FindSubstFont(const CFX_ByteString& name,
+                                        FX_BOOL bTrueType,
+                                        FX_DWORD flags,
+                                        int weight,
+                                        int italic_angle,
+                                        int WindowCP,
+                                        CFX_SubstFont* pSubstFont) {
+  if (!(flags & FXFONT_USEEXTERNATTR)) {
+    weight = FXFONT_FW_NORMAL;
+    italic_angle = 0;
+  }
+  CFX_ByteString SubstName = name;
+  SubstName.Remove(0x20);
+  if (bTrueType) {
+    if (name[0] == '@') {
+      SubstName = name.Mid(1);
+    }
+  }
+  PDF_GetStandardFontName(&SubstName);
+  if (SubstName == FX_BSTRC("Symbol") && !bTrueType) {
+    pSubstFont->m_Family = "Chrome Symbol";
+    pSubstFont->m_Charset = FXFONT_SYMBOL_CHARSET;
+    pSubstFont->m_SubstFlags |= FXFONT_SUBST_STANDARD;
+    if (m_FoxitFaces[12]) {
+      return m_FoxitFaces[12];
+    }
+    const uint8_t* pFontData = NULL;
+    FX_DWORD size = 0;
+    m_pFontMgr->GetStandardFont(pFontData, size, 12);
+    m_FoxitFaces[12] = m_pFontMgr->GetFixedFace(pFontData, size, 0);
+    return m_FoxitFaces[12];
+  }
+  if (SubstName == FX_BSTRC("ZapfDingbats")) {
+    pSubstFont->m_Family = "Chrome Dingbats";
+    pSubstFont->m_Charset = FXFONT_SYMBOL_CHARSET;
+    pSubstFont->m_SubstFlags |= FXFONT_SUBST_STANDARD;
+    if (m_FoxitFaces[13]) {
+      return m_FoxitFaces[13];
+    }
+    const uint8_t* pFontData = NULL;
+    FX_DWORD size = 0;
+    m_pFontMgr->GetStandardFont(pFontData, size, 13);
+    m_FoxitFaces[13] = m_pFontMgr->GetFixedFace(pFontData, size, 0);
+    return m_FoxitFaces[13];
+  }
+  int iBaseFont = 0;
+  CFX_ByteString family, style;
+  FX_BOOL bHasComma = FALSE;
+  FX_BOOL bHasHypen = FALSE;
+  int find = SubstName.Find(FX_BSTRC(","), 0);
+  if (find >= 0) {
+    family = SubstName.Left(find);
+    PDF_GetStandardFontName(&family);
+    style = SubstName.Mid(find + 1);
+    bHasComma = TRUE;
+  } else {
+    family = SubstName;
+  }
+  for (; iBaseFont < 12; iBaseFont++)
+    if (family == CFX_ByteStringC(g_Base14FontNames[iBaseFont])) {
+      break;
+    }
+  int PitchFamily = 0;
+  FX_BOOL bItalic = FALSE;
+  FX_DWORD nStyle = 0;
+  FX_BOOL bStyleAvail = FALSE;
+  if (iBaseFont < 12) {
+    family = g_Base14FontNames[iBaseFont];
+    if ((iBaseFont % 4) == 1 || (iBaseFont % 4) == 2) {
+      nStyle |= FX_FONT_STYLE_Bold;
+    }
+    if ((iBaseFont % 4) / 2) {
+      nStyle |= FX_FONT_STYLE_Italic;
+    }
+    if (iBaseFont < 4) {
+      PitchFamily |= FXFONT_FF_FIXEDPITCH;
+    }
+    if (iBaseFont >= 8) {
+      PitchFamily |= FXFONT_FF_ROMAN;
+    }
+  } else {
+    if (!bHasComma) {
+      find = family.ReverseFind('-');
+      if (find >= 0) {
+        style = family.Mid(find + 1);
+        family = family.Left(find);
+        bHasHypen = TRUE;
+      }
+    }
+    if (!bHasHypen) {
+      int nLen = family.GetLength();
+      int32_t nRet = GetStyleType(family, TRUE);
+      if (nRet > -1) {
+        family = family.Left(nLen - g_FontStyles[nRet].len);
+        if (nRet == 0) {
+          nStyle |= FX_FONT_STYLE_Bold;
+        }
+        if (nRet == 1) {
+          nStyle |= FX_FONT_STYLE_Italic;
+        }
+        if (nRet == 2) {
+          nStyle |= (FX_FONT_STYLE_Bold | FX_FONT_STYLE_Italic);
+        }
+      }
+    }
+    if (flags & FXFONT_SERIF) {
+      PitchFamily |= FXFONT_FF_ROMAN;
+    }
+    if (flags & FXFONT_SCRIPT) {
+      PitchFamily |= FXFONT_FF_SCRIPT;
+    }
+    if (flags & FXFONT_FIXED_PITCH) {
+      PitchFamily |= FXFONT_FF_FIXEDPITCH;
+    }
+  }
+  if (!style.IsEmpty()) {
+    int nLen = style.GetLength();
+    const FX_CHAR* pStyle = style;
+    int i = 0;
+    FX_BOOL bFirstItem = TRUE;
+    CFX_ByteString buf;
+    while (i < nLen) {
+      buf = ParseStyle(pStyle, nLen, i);
+      int32_t nRet = GetStyleType(buf, FALSE);
+      if ((i && !bStyleAvail) || (!i && nRet < 0)) {
+        family = SubstName;
+        iBaseFont = 12;
+        break;
+      } else if (nRet >= 0) {
+        bStyleAvail = TRUE;
+      }
+      if (nRet == 0) {
+        if (nStyle & FX_FONT_STYLE_Bold) {
+          nStyle |= FX_FONT_STYLE_BoldBold;
+        } else {
+          nStyle |= FX_FONT_STYLE_Bold;
+        }
+        bFirstItem = FALSE;
+      }
+      if (nRet == 1) {
+        if (bFirstItem) {
+          nStyle |= FX_FONT_STYLE_Italic;
+        } else {
+          family = SubstName;
+          iBaseFont = 12;
+        }
+        break;
+      }
+      if (nRet == 2) {
+        nStyle |= FX_FONT_STYLE_Italic;
+        if (nStyle & FX_FONT_STYLE_Bold) {
+          nStyle |= FX_FONT_STYLE_BoldBold;
+        } else {
+          nStyle |= FX_FONT_STYLE_Bold;
+        }
+        bFirstItem = FALSE;
+      }
+      i += buf.GetLength() + 1;
+    }
+  }
+  weight = weight ? weight : FXFONT_FW_NORMAL;
+  int old_weight = weight;
+  if (nStyle) {
+    weight =
+        nStyle & FX_FONT_STYLE_BoldBold
+            ? 900
+            : (nStyle & FX_FONT_STYLE_Bold ? FXFONT_FW_BOLD : FXFONT_FW_NORMAL);
+  }
+  if (nStyle & FX_FONT_STYLE_Italic) {
+    bItalic = TRUE;
+  }
+  FX_BOOL bCJK = FALSE;
+  int iExact = 0;
+  int Charset = FXFONT_ANSI_CHARSET;
+  if (WindowCP) {
+    Charset = _GetCharsetFromCodePage(WindowCP);
+  } else if (iBaseFont == 12 && (flags & FXFONT_SYMBOLIC)) {
+    Charset = FXFONT_SYMBOL_CHARSET;
+  }
+  if (Charset == FXFONT_SHIFTJIS_CHARSET || Charset == FXFONT_GB2312_CHARSET ||
+      Charset == FXFONT_HANGEUL_CHARSET ||
+      Charset == FXFONT_CHINESEBIG5_CHARSET) {
+    bCJK = TRUE;
+  }
+  if (m_pFontInfo == NULL) {
+    pSubstFont->m_SubstFlags |= FXFONT_SUBST_STANDARD;
+    return UseInternalSubst(pSubstFont, iBaseFont, italic_angle, old_weight,
+                            PitchFamily);
+  }
+  family = _GetFontFamily(family, nStyle);
+  CFX_ByteString match = MatchInstalledFonts(_TT_NormalizeName(family));
+  if (match.IsEmpty() && family != SubstName &&
+      (!bHasComma && (!bHasHypen || (bHasHypen && !bStyleAvail)))) {
+    match = MatchInstalledFonts(_TT_NormalizeName(SubstName));
+  }
+  if (match.IsEmpty() && iBaseFont >= 12) {
+    if (!bCJK) {
+      if (!CheckSupportThirdPartFont(family, PitchFamily)) {
+        if (italic_angle != 0) {
+          bItalic = TRUE;
+        } else {
+          bItalic = FALSE;
+        }
+        weight = old_weight;
+      }
+    } else {
+      pSubstFont->m_bSubstOfCJK = TRUE;
+      if (nStyle) {
+        pSubstFont->m_WeightCJK = weight;
+      } else {
+        pSubstFont->m_WeightCJK = FXFONT_FW_NORMAL;
+      }
+      if (nStyle & FX_FONT_STYLE_Italic) {
+        pSubstFont->m_bItlicCJK = TRUE;
+      }
+    }
+  } else {
+    italic_angle = 0;
+    weight =
+        nStyle & FX_FONT_STYLE_BoldBold
+            ? 900
+            : (nStyle & FX_FONT_STYLE_Bold ? FXFONT_FW_BOLD : FXFONT_FW_NORMAL);
+  }
+  if (!match.IsEmpty() || iBaseFont < 12) {
+    pSubstFont->m_SubstFlags |= FXFONT_SUBST_EXACT;
+    if (!match.IsEmpty()) {
+      family = match;
+    }
+    if (iBaseFont < 12) {
+      if (nStyle && !(iBaseFont % 4)) {
+        if ((nStyle & 0x3) == 1) {
+          iBaseFont += 1;
+        }
+        if ((nStyle & 0x3) == 2) {
+          iBaseFont += 3;
+        }
+        if ((nStyle & 0x3) == 3) {
+          iBaseFont += 2;
+        }
+      }
+      if (m_pFontMgr->m_ExternalFonts[iBaseFont].m_pFontData) {
+        if (m_FoxitFaces[iBaseFont]) {
+          return m_FoxitFaces[iBaseFont];
+        }
+        m_FoxitFaces[iBaseFont] = m_pFontMgr->GetFixedFace(
+            m_pFontMgr->m_ExternalFonts[iBaseFont].m_pFontData,
+            m_pFontMgr->m_ExternalFonts[iBaseFont].m_dwSize, 0);
+        if (m_FoxitFaces[iBaseFont]) {
+          return m_FoxitFaces[iBaseFont];
+        }
+      } else {
+        family = g_Base14FontNames[iBaseFont];
+      }
+      pSubstFont->m_SubstFlags |= FXFONT_SUBST_STANDARD;
+    }
+  } else {
+    if (flags & FXFONT_ITALIC) {
+      bItalic = TRUE;
+    }
+  }
+  iExact = !match.IsEmpty();
+  void* hFont = m_pFontInfo->MapFont(weight, bItalic, Charset, PitchFamily,
+                                     family, iExact);
+  if (iExact) {
+    pSubstFont->m_SubstFlags |= FXFONT_SUBST_EXACT;
+  }
+  if (hFont == NULL) {
+    if (bCJK) {
+      if (italic_angle != 0) {
+        bItalic = TRUE;
+      } else {
+        bItalic = FALSE;
+      }
+      weight = old_weight;
+    }
+    if (!match.IsEmpty()) {
+      hFont = m_pFontInfo->GetFont(match);
+      if (hFont == NULL) {
+        return UseInternalSubst(pSubstFont, iBaseFont, italic_angle, old_weight,
+                                PitchFamily);
+      }
+    } else {
+      if (Charset == FXFONT_SYMBOL_CHARSET) {
+#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ || \
+    _FXM_PLATFORM_ == _FXM_PLATFORM_ANDROID_
+        if (SubstName == FX_BSTRC("Symbol")) {
+          pSubstFont->m_Family = "Chrome Symbol";
+          pSubstFont->m_SubstFlags |= FXFONT_SUBST_STANDARD;
+          pSubstFont->m_Charset = FXFONT_SYMBOL_CHARSET;
+          if (m_FoxitFaces[12]) {
+            return m_FoxitFaces[12];
+          }
+          const uint8_t* pFontData = NULL;
+          FX_DWORD size = 0;
+          m_pFontMgr->GetStandardFont(pFontData, size, 12);
+          m_FoxitFaces[12] = m_pFontMgr->GetFixedFace(pFontData, size, 0);
+          return m_FoxitFaces[12];
+        }
+#endif
+        pSubstFont->m_SubstFlags |= FXFONT_SUBST_NONSYMBOL;
+        return FindSubstFont(family, bTrueType, flags & ~FXFONT_SYMBOLIC,
+                             weight, italic_angle, 0, pSubstFont);
+      }
+      if (Charset == FXFONT_ANSI_CHARSET) {
+        pSubstFont->m_SubstFlags |= FXFONT_SUBST_STANDARD;
+        return UseInternalSubst(pSubstFont, iBaseFont, italic_angle, old_weight,
+                                PitchFamily);
+      }
+      int index = m_CharsetArray.Find(Charset);
+      if (index < 0) {
+        return UseInternalSubst(pSubstFont, iBaseFont, italic_angle, old_weight,
+                                PitchFamily);
+      }
+      hFont = m_pFontInfo->GetFont(m_FaceArray[index]);
+    }
+  }
+  pSubstFont->m_ExtHandle = m_pFontInfo->RetainFont(hFont);
+  if (hFont == NULL) {
+    return NULL;
+  }
+  m_pFontInfo->GetFaceName(hFont, SubstName);
+  if (Charset == FXFONT_DEFAULT_CHARSET) {
+    m_pFontInfo->GetFontCharset(hFont, Charset);
+  }
+  FX_DWORD ttc_size = m_pFontInfo->GetFontData(hFont, 0x74746366, NULL, 0);
+  FX_DWORD font_size = m_pFontInfo->GetFontData(hFont, 0, NULL, 0);
+  if (font_size == 0 && ttc_size == 0) {
+    m_pFontInfo->DeleteFont(hFont);
+    return NULL;
+  }
+  FXFT_Face face = NULL;
+  if (ttc_size) {
+    uint8_t temp[1024];
+    m_pFontInfo->GetFontData(hFont, 0x74746366, temp, 1024);
+    FX_DWORD checksum = 0;
+    for (int i = 0; i < 256; i++) {
+      checksum += ((FX_DWORD*)temp)[i];
+    }
+    uint8_t* pFontData;
+    face = m_pFontMgr->GetCachedTTCFace(ttc_size, checksum,
+                                        ttc_size - font_size, pFontData);
+    if (face == NULL) {
+      pFontData = FX_Alloc(uint8_t, ttc_size);
+      m_pFontInfo->GetFontData(hFont, 0x74746366, pFontData, ttc_size);
+      face = m_pFontMgr->AddCachedTTCFace(ttc_size, checksum, pFontData,
+                                          ttc_size, ttc_size - font_size);
+    }
+  } else {
+    uint8_t* pFontData;
+    face = m_pFontMgr->GetCachedFace(SubstName, weight, bItalic, pFontData);
+    if (face == NULL) {
+      pFontData = FX_Alloc(uint8_t, font_size);
+      m_pFontInfo->GetFontData(hFont, 0, pFontData, font_size);
+      face = m_pFontMgr->AddCachedFace(SubstName, weight, bItalic, pFontData,
+                                       font_size,
+                                       m_pFontInfo->GetFaceIndex(hFont));
+    }
+  }
+  if (face == NULL) {
+    m_pFontInfo->DeleteFont(hFont);
+    return NULL;
+  }
+  pSubstFont->m_Family = SubstName;
+  pSubstFont->m_Charset = Charset;
+  FX_BOOL bNeedUpdateWeight = FALSE;
+  if (FXFT_Is_Face_Bold(face)) {
+    if (weight == FXFONT_FW_BOLD) {
+      bNeedUpdateWeight = FALSE;
+    } else {
+      bNeedUpdateWeight = TRUE;
+    }
+  } else {
+    if (weight == FXFONT_FW_NORMAL) {
+      bNeedUpdateWeight = FALSE;
+    } else {
+      bNeedUpdateWeight = TRUE;
+    }
+  }
+  if (bNeedUpdateWeight) {
+    pSubstFont->m_Weight = weight;
+  }
+  if (bItalic && !FXFT_Is_Face_Italic(face)) {
+    if (italic_angle == 0) {
+      italic_angle = -12;
+    } else if (FXSYS_abs(italic_angle) < 5) {
+      italic_angle = 0;
+    }
+    pSubstFont->m_ItalicAngle = italic_angle;
+  }
+  m_pFontInfo->DeleteFont(hFont);
+  return face;
+}
+extern "C" {
+unsigned long _FTStreamRead(FXFT_Stream stream,
+                            unsigned long offset,
+                            unsigned char* buffer,
+                            unsigned long count);
+void _FTStreamClose(FXFT_Stream stream);
+};
+CFontFileFaceInfo::CFontFileFaceInfo() {
+  m_pFile = NULL;
+  m_Face = NULL;
+  m_Charsets = 0;
+  m_FileSize = 0;
+  m_FontOffset = 0;
+  m_Weight = 0;
+  m_bItalic = FALSE;
+  m_PitchFamily = 0;
+}
+CFontFileFaceInfo::~CFontFileFaceInfo() {
+  if (m_Face) {
+    FXFT_Done_Face(m_Face);
+  }
+  m_Face = NULL;
+}
+#if _FX_OS_ == _FX_ANDROID_
+IFX_SystemFontInfo* IFX_SystemFontInfo::CreateDefault(const char** pUnused) {
+  return NULL;
+}
+#endif
+CFX_FolderFontInfo::CFX_FolderFontInfo() {}
+CFX_FolderFontInfo::~CFX_FolderFontInfo() {
+  for (const auto& pair : m_FontList) {
+    delete pair.second;
+  }
+}
+void CFX_FolderFontInfo::AddPath(const CFX_ByteStringC& path) {
+  m_PathList.Add(path);
+}
+void CFX_FolderFontInfo::Release() {
+  delete this;
+}
+FX_BOOL CFX_FolderFontInfo::EnumFontList(CFX_FontMapper* pMapper) {
+  m_pMapper = pMapper;
+  for (int i = 0; i < m_PathList.GetSize(); i++) {
+    ScanPath(m_PathList[i]);
+  }
+  return TRUE;
+}
+void CFX_FolderFontInfo::ScanPath(CFX_ByteString& path) {
+  void* handle = FX_OpenFolder(path);
+  if (handle == NULL) {
+    return;
+  }
+  CFX_ByteString filename;
+  FX_BOOL bFolder;
+  while (FX_GetNextFile(handle, filename, bFolder)) {
+    if (bFolder) {
+      if (filename == "." || filename == "..") {
+        continue;
+      }
+    } else {
+      CFX_ByteString ext = filename.Right(4);
+      ext.MakeUpper();
+      if (ext != ".TTF" && ext != ".OTF" && ext != ".TTC") {
+        continue;
+      }
+    }
+    CFX_ByteString fullpath = path;
+#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
+    fullpath += "\\";
+#else
+    fullpath += "/";
+#endif
+    fullpath += filename;
+    if (bFolder) {
+      ScanPath(fullpath);
+    } else {
+      ScanFile(fullpath);
+    }
+  }
+  FX_CloseFolder(handle);
+}
+void CFX_FolderFontInfo::ScanFile(CFX_ByteString& path) {
+  FXSYS_FILE* pFile = FXSYS_fopen(path, "rb");
+  if (pFile == NULL) {
+    return;
+  }
+  FXSYS_fseek(pFile, 0, FXSYS_SEEK_END);
+  FX_DWORD filesize = FXSYS_ftell(pFile);
+  uint8_t buffer[16];
+  FXSYS_fseek(pFile, 0, FXSYS_SEEK_SET);
+  size_t readCnt = FXSYS_fread(buffer, 12, 1, pFile);
+  if (readCnt != 1) {
+    FXSYS_fclose(pFile);
+    return;
+  }
+
+  if (GET_TT_LONG(buffer) == 0x74746366) {
+    FX_DWORD nFaces = GET_TT_LONG(buffer + 8);
+    if (nFaces > std::numeric_limits<FX_DWORD>::max() / 4) {
+      FXSYS_fclose(pFile);
+      return;
+    }
+    FX_DWORD face_bytes = nFaces * 4;
+    uint8_t* offsets = FX_Alloc(uint8_t, face_bytes);
+    readCnt = FXSYS_fread(offsets, 1, face_bytes, pFile);
+    if (readCnt != face_bytes) {
+      FX_Free(offsets);
+      FXSYS_fclose(pFile);
+      return;
+    }
+    for (FX_DWORD i = 0; i < nFaces; i++) {
+      uint8_t* p = offsets + i * 4;
+      ReportFace(path, pFile, filesize, GET_TT_LONG(p));
+    }
+    FX_Free(offsets);
+  } else {
+    ReportFace(path, pFile, filesize, 0);
+  }
+  FXSYS_fclose(pFile);
+}
+void CFX_FolderFontInfo::ReportFace(CFX_ByteString& path,
+                                    FXSYS_FILE* pFile,
+                                    FX_DWORD filesize,
+                                    FX_DWORD offset) {
+  FXSYS_fseek(pFile, offset, FXSYS_SEEK_SET);
+  char buffer[16];
+  if (!FXSYS_fread(buffer, 12, 1, pFile)) {
+    return;
+  }
+  FX_DWORD nTables = GET_TT_SHORT(buffer + 4);
+  CFX_ByteString tables = _FPDF_ReadStringFromFile(pFile, nTables * 16);
+  if (tables.IsEmpty()) {
+    return;
+  }
+  CFX_ByteString names =
+      _FPDF_LoadTableFromTT(pFile, tables, nTables, 0x6e616d65);
+  CFX_ByteString facename = GetNameFromTT(names, 1);
+  CFX_ByteString style = GetNameFromTT(names, 2);
+  if (style != "Regular") {
+    facename += " " + style;
+  }
+  if (m_FontList.find(facename) != m_FontList.end()) {
+    return;
+  }
+  CFX_FontFaceInfo* pInfo =
+      new CFX_FontFaceInfo(path, facename, tables, offset, filesize);
+  CFX_ByteString os2 =
+      _FPDF_LoadTableFromTT(pFile, tables, nTables, 0x4f532f32);
+  if (os2.GetLength() >= 86) {
+    const uint8_t* p = (const uint8_t*)os2 + 78;
+    FX_DWORD codepages = GET_TT_LONG(p);
+    if (codepages & (1 << 17)) {
+      m_pMapper->AddInstalledFont(facename, FXFONT_SHIFTJIS_CHARSET);
+      pInfo->m_Charsets |= CHARSET_FLAG_SHIFTJIS;
+    }
+    if (codepages & (1 << 18)) {
+      m_pMapper->AddInstalledFont(facename, FXFONT_GB2312_CHARSET);
+      pInfo->m_Charsets |= CHARSET_FLAG_GB;
+    }
+    if (codepages & (1 << 20)) {
+      m_pMapper->AddInstalledFont(facename, FXFONT_CHINESEBIG5_CHARSET);
+      pInfo->m_Charsets |= CHARSET_FLAG_BIG5;
+    }
+    if ((codepages & (1 << 19)) || (codepages & (1 << 21))) {
+      m_pMapper->AddInstalledFont(facename, FXFONT_HANGEUL_CHARSET);
+      pInfo->m_Charsets |= CHARSET_FLAG_KOREAN;
+    }
+    if (codepages & (1 << 31)) {
+      m_pMapper->AddInstalledFont(facename, FXFONT_SYMBOL_CHARSET);
+      pInfo->m_Charsets |= CHARSET_FLAG_SYMBOL;
+    }
+  }
+  m_pMapper->AddInstalledFont(facename, FXFONT_ANSI_CHARSET);
+  pInfo->m_Charsets |= CHARSET_FLAG_ANSI;
+  pInfo->m_Styles = 0;
+  if (style.Find(FX_BSTRC("Bold")) > -1) {
+    pInfo->m_Styles |= FXFONT_BOLD;
+  }
+  if (style.Find(FX_BSTRC("Italic")) > -1 ||
+      style.Find(FX_BSTRC("Oblique")) > -1) {
+    pInfo->m_Styles |= FXFONT_ITALIC;
+  }
+  if (facename.Find(FX_BSTRC("Serif")) > -1) {
+    pInfo->m_Styles |= FXFONT_SERIF;
+  }
+  m_FontList[facename] = pInfo;
+}
+static const struct {
+  const FX_CHAR* m_pName;
+  const FX_CHAR* m_pSubstName;
+} Base14Substs[] = {
+    {"Courier", "Courier New"},
+    {"Courier-Bold", "Courier New Bold"},
+    {"Courier-BoldOblique", "Courier New Bold Italic"},
+    {"Courier-Oblique", "Courier New Italic"},
+    {"Helvetica", "Arial"},
+    {"Helvetica-Bold", "Arial Bold"},
+    {"Helvetica-BoldOblique", "Arial Bold Italic"},
+    {"Helvetica-Oblique", "Arial Italic"},
+    {"Times-Roman", "Times New Roman"},
+    {"Times-Bold", "Times New Roman Bold"},
+    {"Times-BoldItalic", "Times New Roman Bold Italic"},
+    {"Times-Italic", "Times New Roman Italic"},
+};
+void* CFX_FolderFontInfo::GetSubstFont(const CFX_ByteString& face) {
+  for (size_t iBaseFont = 0; iBaseFont < FX_ArraySize(Base14Substs);
+       iBaseFont++) {
+    if (face == Base14Substs[iBaseFont].m_pName) {
+      return GetFont(Base14Substs[iBaseFont].m_pSubstName);
+    }
+  }
+  return nullptr;
+}
+static FX_DWORD _GetCharset(int charset) {
+  switch (charset) {
+    case FXFONT_SHIFTJIS_CHARSET:
+      return CHARSET_FLAG_SHIFTJIS;
+    case FXFONT_GB2312_CHARSET:
+      return CHARSET_FLAG_GB;
+    case FXFONT_CHINESEBIG5_CHARSET:
+      return CHARSET_FLAG_BIG5;
+    case FXFONT_HANGEUL_CHARSET:
+      return CHARSET_FLAG_KOREAN;
+    case FXFONT_SYMBOL_CHARSET:
+      return CHARSET_FLAG_SYMBOL;
+    case FXFONT_ANSI_CHARSET:
+      return CHARSET_FLAG_ANSI;
+    default:
+      break;
+  }
+  return 0;
+}
+static int32_t _GetSimilarValue(int weight,
+                                FX_BOOL bItalic,
+                                int pitch_family,
+                                FX_DWORD style) {
+  int32_t iSimilarValue = 0;
+  if ((style & FXFONT_BOLD) == (weight > 400)) {
+    iSimilarValue += 16;
+  }
+  if ((style & FXFONT_ITALIC) == bItalic) {
+    iSimilarValue += 16;
+  }
+  if ((style & FXFONT_SERIF) == (pitch_family & FXFONT_FF_ROMAN)) {
+    iSimilarValue += 16;
+  }
+  if ((style & FXFONT_SCRIPT) == (pitch_family & FXFONT_FF_SCRIPT)) {
+    iSimilarValue += 8;
+  }
+  if ((style & FXFONT_FIXED_PITCH) == (pitch_family & FXFONT_FF_FIXEDPITCH)) {
+    iSimilarValue += 8;
+  }
+  return iSimilarValue;
+}
+void* CFX_FolderFontInfo::FindFont(int weight,
+                                   FX_BOOL bItalic,
+                                   int charset,
+                                   int pitch_family,
+                                   const FX_CHAR* family,
+                                   FX_BOOL bMatchName) {
+  CFX_FontFaceInfo* pFind = nullptr;
+  if (charset == FXFONT_ANSI_CHARSET && (pitch_family & FXFONT_FF_FIXEDPITCH)) {
+    return GetFont("Courier New");
+  }
+  FX_DWORD charset_flag = _GetCharset(charset);
+  int32_t iBestSimilar = 0;
+  for (const auto& it : m_FontList) {
+    const CFX_ByteString& bsName = it.first;
+    CFX_FontFaceInfo* pFont = it.second;
+    if (!(pFont->m_Charsets & charset_flag) &&
+        charset != FXFONT_DEFAULT_CHARSET) {
+      continue;
+    }
+    int32_t index = bsName.Find(family);
+    if (bMatchName && index < 0) {
+      continue;
+    }
+    int32_t iSimilarValue =
+        _GetSimilarValue(weight, bItalic, pitch_family, pFont->m_Styles);
+    if (iSimilarValue > iBestSimilar) {
+      iBestSimilar = iSimilarValue;
+      pFind = pFont;
+    }
+  }
+  return pFind;
+}
+void* CFX_FolderFontInfo::MapFont(int weight,
+                                  FX_BOOL bItalic,
+                                  int charset,
+                                  int pitch_family,
+                                  const FX_CHAR* family,
+                                  int& iExact) {
+  return NULL;
+}
+void* CFX_FolderFontInfo::GetFont(const FX_CHAR* face) {
+  auto it = m_FontList.find(face);
+  return it != m_FontList.end() ? it->second : nullptr;
+}
+FX_DWORD CFX_FolderFontInfo::GetFontData(void* hFont,
+                                         FX_DWORD table,
+                                         uint8_t* buffer,
+                                         FX_DWORD size) {
+  if (hFont == NULL) {
+    return 0;
+  }
+  CFX_FontFaceInfo* pFont = (CFX_FontFaceInfo*)hFont;
+  FXSYS_FILE* pFile = NULL;
+  if (size > 0) {
+    pFile = FXSYS_fopen(pFont->m_FilePath, "rb");
+    if (pFile == NULL) {
+      return 0;
+    }
+  }
+  FX_DWORD datasize = 0;
+  FX_DWORD offset = 0;
+  if (table == 0) {
+    datasize = pFont->m_FontOffset ? 0 : pFont->m_FileSize;
+  } else if (table == 0x74746366) {
+    datasize = pFont->m_FontOffset ? pFont->m_FileSize : 0;
+  } else {
+    FX_DWORD nTables = pFont->m_FontTables.GetLength() / 16;
+    for (FX_DWORD i = 0; i < nTables; i++) {
+      const uint8_t* p = (const uint8_t*)pFont->m_FontTables + i * 16;
+      if (GET_TT_LONG(p) == table) {
+        offset = GET_TT_LONG(p + 8);
+        datasize = GET_TT_LONG(p + 12);
+      }
+    }
+  }
+  if (datasize && size >= datasize && pFile) {
+    FXSYS_fseek(pFile, offset, FXSYS_SEEK_SET);
+    FXSYS_fread(buffer, datasize, 1, pFile);
+  }
+  if (pFile) {
+    FXSYS_fclose(pFile);
+  }
+  return datasize;
+}
+void CFX_FolderFontInfo::DeleteFont(void* hFont) {}
+FX_BOOL CFX_FolderFontInfo::GetFaceName(void* hFont, CFX_ByteString& name) {
+  if (hFont == NULL) {
+    return FALSE;
+  }
+  CFX_FontFaceInfo* pFont = (CFX_FontFaceInfo*)hFont;
+  name = pFont->m_FaceName;
+  return TRUE;
+}
+FX_BOOL CFX_FolderFontInfo::GetFontCharset(void* hFont, int& charset) {
+  return FALSE;
+}
+
+int PDF_GetStandardFontName(CFX_ByteString* name) {
+  AltFontName* found = static_cast<AltFontName*>(
+      FXSYS_bsearch(name->c_str(), g_AltFontNames, FX_ArraySize(g_AltFontNames),
+                    sizeof(AltFontName), compareString));
+  if (!found)
+    return -1;
+
+  *name = g_Base14FontNames[found->m_Index];
+  return found->m_Index;
+}