// 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 "../../../include/fxge/fx_ge.h"
#include "../../../include/fxge/fx_freetype.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])
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]);
            }
    }
    if (m_pFontData) {
        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_pBuiltinMapper = FX_NEW CFX_FontMapper;
    if (!m_pBuiltinMapper) {
        return;
    }
    m_pBuiltinMapper->m_pFontMgr = this;
    m_pExtMapper = NULL;
    m_FTLibrary = NULL;
    FXSYS_memset32(m_ExternalFonts, 0, sizeof m_ExternalFonts);
}
CFX_FontMgr::~CFX_FontMgr()
{
    if (m_pBuiltinMapper) {
        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()
{
    FX_POSITION pos = m_FaceMap.GetStartPosition();
    while(pos) {
        CFX_ByteString Key;
        CTTFontDesc* face;
        m_FaceMap.GetNextAssoc(pos, Key, (void*&)face);
        delete face;
    }
    m_FaceMap.RemoveAll();
}
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 == NULL) {
        FXFT_Init_FreeType(&m_FTLibrary);
    }
    if (m_pExtMapper) {
        FXFT_Face face = m_pExtMapper->FindSubstFont(face_name, bTrueType, flags, weight, italic_angle,
                         CharsetCP, pSubstFont);
        if (face) {
            return face;
        }
    }
    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, FX_LPBYTE& pFontData)
{
    CFX_ByteString key(face_name);
    key += ',';
    key += CFX_ByteString::FormatInteger(weight);
    key += bItalic ? 'I' : 'N';
    CTTFontDesc* pFontDesc = NULL;
    m_FaceMap.Lookup(key, (void*&)pFontDesc);
    if(pFontDesc) {
        pFontData = pFontDesc->m_pFontData;
        pFontDesc->m_RefCount ++;
        return pFontDesc->m_SingleFace.m_pFace;
    }
    return NULL;
}
FXFT_Face CFX_FontMgr::AddCachedFace(const CFX_ByteString& face_name,
                                     int weight, FX_BOOL bItalic, FX_LPBYTE pData, FX_DWORD size, int face_index)
{
    CTTFontDesc* pFontDesc = FX_NEW CTTFontDesc;
    if (!pFontDesc) {
        return NULL;
    }
    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;
    }
    CFX_ByteString key(face_name);
    key += ',';
    key += CFX_ByteString::FormatInteger(weight);
    key += bItalic ? 'I' : 'N';
    m_FaceMap.SetAt(key, pFontDesc);
    return pFontDesc->m_SingleFace.m_pFace;
}
const FX_LPCSTR 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((FX_LPCSTR)key, ((_AltFontName*)element)->m_pName);
    }
}
int _PDF_GetStandardFontName(CFX_ByteString& name)
{
    _AltFontName* found = (_AltFontName*)FXSYS_bsearch((FX_LPCSTR)name, g_AltFontNames,
                          sizeof g_AltFontNames / sizeof (_AltFontName), sizeof (_AltFontName), compareString);
    if (found == NULL) {
        return -1;
    }
    name = g_Base14FontNames[found->m_Index];
    return found->m_Index;
}
int GetTTCIndex(FX_LPCBYTE pFontData, FX_DWORD ttc_size, FX_DWORD font_offset)
{
    int face_index = 0;
    FX_LPCBYTE 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, FX_LPBYTE& pFontData)
{
    CFX_ByteString key;
    key.Format("%d:%d", ttc_size, checksum);
    CTTFontDesc* pFontDesc = NULL;
    m_FaceMap.Lookup(key, (void*&)pFontDesc);
    if (pFontDesc == NULL) {
        return NULL;
    }
    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] == NULL) {
        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,
                                        FX_LPBYTE pData, FX_DWORD size, int font_offset)
{
    CFX_ByteString key;
    key.Format("%d:%d", ttc_size, checksum);
    CTTFontDesc* pFontDesc = FX_NEW CTTFontDesc;
    if (!pFontDesc) {
        return NULL;
    }
    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 ++;
    key.Format("%d:%d", ttc_size, checksum);
    m_FaceMap.SetAt(key, 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(FX_LPCBYTE 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(FX_LPCSTR 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 == NULL) {
        return;
    }
    FX_POSITION pos = m_FaceMap.GetStartPosition();
    while(pos) {
        CFX_ByteString Key;
        CTTFontDesc* ttface;
        m_FaceMap.GetNextAssoc(pos, Key, (void*&)ttface);
        if (ttface->ReleaseFace(face)) {
            m_FaceMap.RemoveKey(Key);
        }
    }
}
extern "C" {
    extern const unsigned char g_FoxitFixedItalicFontData [18746];
    extern const unsigned char g_FoxitFixedFontData [17597];
    extern const unsigned char g_FoxitSansItalicFontData [16339];
    extern const unsigned char g_FoxitSansFontData [15025];
    extern const unsigned char g_FoxitSerifItalicFontData [21227];
    extern const unsigned char g_FoxitSerifFontData [19469];
    extern const unsigned char g_FoxitFixedBoldItalicFontData [19151];
    extern const unsigned char g_FoxitFixedBoldFontData [18055];
    extern const unsigned char g_FoxitSansBoldItalicFontData [16418];
    extern const unsigned char g_FoxitSansBoldFontData [16344];
    extern const unsigned char g_FoxitSerifBoldItalicFontData [20733];
    extern const unsigned char g_FoxitSerifBoldFontData [19395];
    extern const unsigned char g_FoxitSymbolFontData[16729];
    extern const unsigned char g_FoxitDingbatsFontData[29513];
    extern const unsigned char g_FoxitSerifMMFontData[113417];
    extern const unsigned char g_FoxitSansMMFontData[66919];
};
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},
};
void _FPDFAPI_GetInternalFontData(int id, FX_LPCBYTE& data, FX_DWORD& size)
{
    CFX_GEModule::Get()->GetFontMgr()->GetStandardFont(data, size, id);
}
FX_BOOL CFX_FontMgr::GetStandardFont(FX_LPCBYTE& 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()
{
    FXSYS_memset32(m_FoxitFaces, 0, sizeof m_FoxitFaces);
    m_MMFaces[0] = m_MMFaces[1] = NULL;
    m_pFontInfo = NULL;
    m_bListLoaded = FALSE;
    m_pFontEnumerator = NULL;
}
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(FX_LPCSTR family)
{
    CFX_ByteString norm(family, -1);
    norm.Remove(' ');
    norm.Remove('-');
    norm.Remove(',');
    int pos = norm.Find('+');
    if (pos > 0) {
        norm = norm.Left(pos);
    }
    norm.MakeLower();
    return norm;
}
CFX_ByteString _FPDF_GetNameFromTT(FX_LPCBYTE name_table, FX_DWORD name_id)
{
    FX_LPCBYTE ptr = name_table + 2;
    int name_count = GET_TT_SHORT(ptr);
    int string_offset = GET_TT_SHORT(ptr + 2);
    FX_LPCBYTE 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;
}
static CFX_ByteString _FPDF_ReadStringFromStreamFile(IFX_FileStream* pFile, FX_DWORD size)
{
    CFX_ByteString buffer;
    if (!pFile->ReadBlock(buffer.GetBuffer(size), size)) {
        return CFX_ByteString();
    }
    buffer.ReleaseBuffer(size);
    return buffer;
}
CFX_ByteString _FPDF_LoadTableFromTT(FXSYS_FILE* pFile, FX_LPCBYTE pTables, FX_DWORD nTables, FX_DWORD tag)
{
    for (FX_DWORD i = 0; i < nTables; i ++) {
        FX_LPCBYTE 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, FX_LPCBYTE pTables, FX_DWORD nTables, FX_DWORD tag)
{
    for (FX_DWORD i = 0; i < nTables; i ++) {
        FX_LPCBYTE 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) {
        CFX_ByteString();
    }
    CFX_ByteString result;
    FX_DWORD size = m_pFontInfo->GetFontData(hFont, 0x6e616d65, NULL, 0);
    if (size) {
        FX_LPBYTE buffer = FX_Alloc(FX_BYTE, size);
        if (!buffer) {
            return result;
        }
        m_pFontInfo->GetFontData(hFont, 0x6e616d65, buffer, size);
        result = _FPDF_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;
    }
    FX_LPCBYTE 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) {
            FX_BOOL bExact;
            hFont = m_pFontInfo->MapFont(0, 0, FXFONT_DEFAULT_CHARSET, 0, name, bExact);
            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_ {
    FX_BYTE 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 },
};
FX_BYTE _GetCharsetFromCodePage(FX_WORD codepage)
{
    FX_INT32 iEnd = sizeof(g_Codepage2CharsetTable) / sizeof(CHARSET_MAP) - 1;
    FXSYS_assert(iEnd >= 0);
    FX_INT32 iStart = 0, iMid;
    do {
        iMid = (iStart + iEnd) / 2;
        const CHARSET_MAP & cp = g_Codepage2CharsetTable[iMid];
        if (codepage == cp.codepage) {
            return cp.charset;
        } else 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;
}
static int CP2CharSet(int cp)
{
    if(cp == 932) {
        return FXFONT_SHIFTJIS_CHARSET;
    } else if(cp == 936) {
        return FXFONT_GB2312_CHARSET;
    } else if(cp == 949) {
        return FXFONT_HANGEUL_CHARSET;
    } else if(cp == 950) {
        return FXFONT_CHINESEBIG5_CHARSET;
    }
    return FXFONT_DEFAULT_CHARSET;
}
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];
        }
        FX_LPCBYTE 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];
        }
        FX_LPCBYTE 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];
    }
    FX_LPCBYTE 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 {
    FX_LPCSTR m_pFontName;
    FX_LPCSTR 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((FX_LPCSTR)key);
        if (str_key.Find(((_AltFontFamily*)element)->m_pFontName) != -1) {
            return 0;
        }
        return FXSYS_stricmp((FX_LPCSTR)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((FX_LPCSTR)fontName, g_AltFontFamilies,
                            sizeof g_AltFontFamilies / sizeof (_AltFontFamily), sizeof (_AltFontFamily), compareFontFamilyString);
    if (found == NULL) {
        return fontName;
    }
    return found->m_pFontFamily;
};
typedef struct _FX_FontStyle {
    FX_LPCSTR style;
    FX_INT32 len;
} FX_FontStyle;
const FX_FontStyle g_FontStyles[] = {
    "Bold", 4,
    "Italic", 6,
    "BoldItalic", 10,
    "Reg", 3,
    "Regular", 7,
};
CFX_ByteString ParseStyle(FX_LPCSTR 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();
}
FX_INT32 GetStyleType(const CFX_ByteString &bsStyle, FX_BOOL bRevert)
{
    FX_INT32 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];
        }
        FX_LPCBYTE 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];
        }
        FX_LPCBYTE 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;
    FX_BOOL bFamilyStyleIsWhole = FALSE;
    FX_BOOL bNextF = 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();
            FX_INT32 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();
        FX_LPCSTR pStyle = style;
        int i = 0;
        FX_BOOL bFirstItem = TRUE;
        CFX_ByteString buf;
        while (i < nLen) {
            buf = ParseStyle(pStyle, nLen, i);
            FX_INT32 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;
    FX_BOOL bExact = FALSE;
    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;
        }
    }
    bExact = !match.IsEmpty();
    void* hFont = m_pFontInfo->MapFont(weight, bItalic, Charset, PitchFamily, family, bExact);
    if (bExact) {
        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];
                    }
                    FX_LPCBYTE 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];
                } else {
                    pSubstFont->m_SubstFlags |= FXFONT_SUBST_NONSYMBOL;
                    return FindSubstFont(family, bTrueType, flags & ~FXFONT_SYMBOLIC, weight, italic_angle, 0, pSubstFont);
                }
#else
                pSubstFont->m_SubstFlags |= FXFONT_SUBST_NONSYMBOL;
                return FindSubstFont(family, bTrueType, flags & ~FXFONT_SYMBOLIC, weight, italic_angle, 0, pSubstFont);
#endif
            }
            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);
            } else {
                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) {
        FX_BYTE 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];
        }
        FX_LPBYTE pFontData;
        face = m_pFontMgr->GetCachedTTCFace(ttc_size, checksum, ttc_size - font_size, pFontData);
        if (face == NULL) {
            pFontData = FX_Alloc(FX_BYTE, ttc_size);
            if (pFontData) {
                m_pFontInfo->GetFontData(hFont, 0x74746366, pFontData, ttc_size);
                face = m_pFontMgr->AddCachedTTCFace(ttc_size, checksum, pFontData, ttc_size,
                                                    ttc_size - font_size);
            }
        }
    } else {
        FX_LPBYTE pFontData;
        face = m_pFontMgr->GetCachedFace(SubstName, weight, bItalic, pFontData);
        if (face == NULL) {
            pFontData = FX_Alloc(FX_BYTE, font_size);
            if (!pFontData) {
                m_pFontInfo->DeleteFont(hFont);
                return NULL;
            }
            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;
}
extern FX_BOOL _LoadFile(FXFT_Library library, FXFT_Face* Face, IFX_FileRead* pFile, FXFT_Stream* stream);
#if defined(_FPDFAPI_MINI_) || _FX_OS_ == _FX_ANDROID_
IFX_SystemFontInfo* IFX_SystemFontInfo::CreateDefault()
{
    return NULL;
}
#endif
#if !defined(_FPDFAPI_MINI_)
CFX_FolderFontInfo::CFX_FolderFontInfo()
{
}
CFX_FolderFontInfo::~CFX_FolderFontInfo()
{
    FX_POSITION pos = m_FontList.GetStartPosition();
    while (pos) {
        CFX_ByteString key;
        FX_LPVOID value;
        m_FontList.GetNextAssoc(pos, key, value);
        delete (CFontFaceInfo*)value;
    }
}
void CFX_FolderFontInfo::AddPath(FX_BSTR 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);
    FX_BYTE buffer[16];
    FXSYS_fseek(pFile, 0, FXSYS_SEEK_SET);
    size_t readCnt = FXSYS_fread(buffer, 12, 1, pFile);
    if (GET_TT_LONG(buffer) == 0x74746366) {
        FX_DWORD nFaces = GET_TT_LONG(buffer + 8);
        FX_LPBYTE offsets = FX_Alloc(FX_BYTE, nFaces * 4);
        if (!offsets) {
            FXSYS_fclose(pFile);
            return;
        }
        readCnt = FXSYS_fread(offsets, nFaces * 4, 1, pFile);
        for (FX_DWORD i = 0; i < nFaces; i ++) {
            FX_LPBYTE 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);
    CFX_ByteString names = _FPDF_LoadTableFromTT(pFile, tables, nTables, 0x6e616d65);
    CFX_ByteString facename = _FPDF_GetNameFromTT(names, 1);
    CFX_ByteString style = _FPDF_GetNameFromTT(names, 2);
    if (style != "Regular") {
        facename += " " + style;
    }
    FX_LPVOID p;
    if (m_FontList.Lookup(facename, p)) {
        return;
    }
    CFontFaceInfo* pInfo = FX_NEW CFontFaceInfo;
    if (!pInfo) {
        return;
    }
    pInfo->m_FilePath = path;
    pInfo->m_FaceName = facename;
    pInfo->m_FontTables = tables;
    pInfo->m_FontOffset = offset;
    pInfo->m_FileSize = filesize;
    pInfo->m_Charsets = 0;
    CFX_ByteString os2 = _FPDF_LoadTableFromTT(pFile, tables, nTables, 0x4f532f32);
    if (os2.GetLength() >= 86) {
        FX_LPCBYTE p = (FX_LPCBYTE)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.SetAt(facename, pInfo);
}
void* CFX_FolderFontInfo::MapFont(int weight, FX_BOOL bItalic, int charset, int pitch_family, FX_LPCSTR family, FX_BOOL& bExact)
{
    return NULL;
}
void* CFX_FolderFontInfo::GetFont(FX_LPCSTR face)
{
    FX_LPVOID p;
    if (!m_FontList.Lookup(face, p)) {
        return NULL;
    }
    return p;
}
FX_DWORD CFX_FolderFontInfo::GetFontData(void* hFont, FX_DWORD table, FX_LPBYTE buffer, FX_DWORD size)
{
    if (hFont == NULL) {
        return 0;
    }
    CFontFaceInfo* pFont = (CFontFaceInfo*)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;
    if (table == 0)	{
        datasize = pFont->m_FontOffset ? 0 : pFont->m_FileSize;
        offset = 0;
    } else if (table == 0x74746366)	{
        datasize = pFont->m_FontOffset ? pFont->m_FileSize : 0;
        offset = 0;
    } else {
        FX_DWORD nTables = pFont->m_FontTables.GetLength() / 16;
        for (FX_DWORD i = 0; i < nTables; i ++) {
            FX_LPCBYTE p = (FX_LPCBYTE)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);
        size_t readCnt = 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;
    }
    CFontFaceInfo* pFont = (CFontFaceInfo*)hFont;
    name = pFont->m_FaceName;
    return TRUE;
}
FX_BOOL CFX_FolderFontInfo::GetFontCharset(void* hFont, int& charset)
{
    return FALSE;
}
#endif