Home | History | Annotate | Download | only in font
      1 // Copyright 2014 PDFium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #include "xfa/src/fgas/src/fgas_base.h"
      8 #include "fx_stdfontmgr.h"
      9 #include "fx_fontutils.h"
     10 #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
     11 IFX_FontMgr* IFX_FontMgr::Create(FX_LPEnumAllFonts pEnumerator,
     12                                  FX_LPMatchFont pMatcher,
     13                                  void* pUserData) {
     14   return new CFX_StdFontMgrImp(pEnumerator, pMatcher, pUserData);
     15 }
     16 CFX_StdFontMgrImp::CFX_StdFontMgrImp(FX_LPEnumAllFonts pEnumerator,
     17                                      FX_LPMatchFont pMatcher,
     18                                      void* pUserData)
     19     : m_pMatcher(pMatcher),
     20       m_pEnumerator(pEnumerator),
     21       m_FontFaces(),
     22       m_Fonts(),
     23       m_CPFonts(8),
     24       m_FamilyFonts(16),
     25       m_UnicodeFonts(16),
     26       m_BufferFonts(4),
     27       m_FileFonts(4),
     28       m_StreamFonts(4),
     29       m_DeriveFonts(4),
     30       m_pUserData(pUserData) {
     31   if (m_pEnumerator != NULL) {
     32     m_pEnumerator(m_FontFaces, m_pUserData, NULL, 0xFEFF);
     33   }
     34   if (m_pMatcher == NULL) {
     35     m_pMatcher = FX_DefFontMatcher;
     36   }
     37   FXSYS_assert(m_pMatcher != NULL);
     38 }
     39 CFX_StdFontMgrImp::~CFX_StdFontMgrImp() {
     40   m_FontFaces.RemoveAll();
     41   m_CPFonts.RemoveAll();
     42   m_FamilyFonts.RemoveAll();
     43   m_UnicodeFonts.RemoveAll();
     44   m_BufferFonts.RemoveAll();
     45   m_FileFonts.RemoveAll();
     46   m_StreamFonts.RemoveAll();
     47   m_DeriveFonts.RemoveAll();
     48   for (int32_t i = m_Fonts.GetUpperBound(); i >= 0; i--) {
     49     IFX_Font* pFont = (IFX_Font*)m_Fonts[i];
     50     if (pFont != NULL) {
     51       pFont->Release();
     52     }
     53   }
     54   m_Fonts.RemoveAll();
     55 }
     56 IFX_Font* CFX_StdFontMgrImp::GetDefFontByCodePage(
     57     FX_WORD wCodePage,
     58     FX_DWORD dwFontStyles,
     59     const FX_WCHAR* pszFontFamily) {
     60   FX_DWORD dwHash = FGAS_GetFontHashCode(wCodePage, dwFontStyles);
     61   IFX_Font* pFont = NULL;
     62   if (m_CPFonts.Lookup((void*)(uintptr_t)dwHash, (void*&)pFont)) {
     63     return pFont ? LoadFont(pFont, dwFontStyles, wCodePage) : NULL;
     64   }
     65   FX_LPCFONTDESCRIPTOR pFD;
     66   if ((pFD = FindFont(pszFontFamily, dwFontStyles, TRUE, wCodePage)) == NULL)
     67     if ((pFD = FindFont(NULL, dwFontStyles, TRUE, wCodePage)) == NULL)
     68       if ((pFD = FindFont(NULL, dwFontStyles, FALSE, wCodePage)) == NULL) {
     69         return NULL;
     70       }
     71   FXSYS_assert(pFD != NULL);
     72   pFont = IFX_Font::LoadFont(pFD->wsFontFace, dwFontStyles, wCodePage, this);
     73   if (pFont != NULL) {
     74     m_Fonts.Add(pFont);
     75     m_CPFonts.SetAt((void*)(uintptr_t)dwHash, (void*)pFont);
     76     dwHash = FGAS_GetFontFamilyHash(pFD->wsFontFace, dwFontStyles, wCodePage);
     77     m_FamilyFonts.SetAt((void*)(uintptr_t)dwHash, (void*)pFont);
     78     return LoadFont(pFont, dwFontStyles, wCodePage);
     79   }
     80   return NULL;
     81 }
     82 IFX_Font* CFX_StdFontMgrImp::GetDefFontByCharset(
     83     uint8_t nCharset,
     84     FX_DWORD dwFontStyles,
     85     const FX_WCHAR* pszFontFamily) {
     86   return GetDefFontByCodePage(FX_GetCodePageFromCharset(nCharset), dwFontStyles,
     87                               pszFontFamily);
     88 }
     89 #define _FX_USEGASFONTMGR_
     90 IFX_Font* CFX_StdFontMgrImp::GetDefFontByUnicode(
     91     FX_WCHAR wUnicode,
     92     FX_DWORD dwFontStyles,
     93     const FX_WCHAR* pszFontFamily) {
     94   FGAS_LPCFONTUSB pRet = FGAS_GetUnicodeBitField(wUnicode);
     95   if (pRet->wBitField == 999) {
     96     return NULL;
     97   }
     98   FX_DWORD dwHash =
     99       FGAS_GetFontFamilyHash(pszFontFamily, dwFontStyles, pRet->wBitField);
    100   IFX_Font* pFont = NULL;
    101   if (m_UnicodeFonts.Lookup((void*)(uintptr_t)dwHash, (void*&)pFont)) {
    102     return pFont ? LoadFont(pFont, dwFontStyles, pRet->wCodePage) : NULL;
    103   }
    104 #ifdef _FX_USEGASFONTMGR_
    105   FX_LPCFONTDESCRIPTOR pFD =
    106       FindFont(pszFontFamily, dwFontStyles, FALSE, pRet->wCodePage,
    107                pRet->wBitField, wUnicode);
    108   if (pFD == NULL && pszFontFamily) {
    109     pFD = FindFont(NULL, dwFontStyles, FALSE, pRet->wCodePage, pRet->wBitField,
    110                    wUnicode);
    111   }
    112   if (pFD == NULL) {
    113     return NULL;
    114   }
    115   FXSYS_assert(pFD);
    116   FX_WORD wCodePage = FX_GetCodePageFromCharset(pFD->uCharSet);
    117   const FX_WCHAR* pFontFace = pFD->wsFontFace;
    118   pFont = IFX_Font::LoadFont(pFontFace, dwFontStyles, wCodePage, this);
    119 #else
    120   CFX_FontMapper* pBuiltinMapper =
    121       CFX_GEModule::Get()->GetFontMgr()->m_pBuiltinMapper;
    122   if (pBuiltinMapper == NULL) {
    123     return NULL;
    124   }
    125   int32_t iWeight =
    126       (dwFontStyles & FX_FONTSTYLE_Bold) ? FXFONT_FW_BOLD : FXFONT_FW_NORMAL;
    127   int italic_angle = 0;
    128   FXFT_Face ftFace = pBuiltinMapper->FindSubstFontByUnicode(
    129       wUnicode, dwFontStyles, iWeight, italic_angle);
    130   if (ftFace == NULL) {
    131     return NULL;
    132   }
    133   CFX_Font* pFXFont = new CFX_Font;
    134   pFXFont->m_Face = ftFace;
    135   pFXFont->m_pFontData = FXFT_Get_Face_Stream_Base(ftFace);
    136   pFXFont->m_dwSize = FXFT_Get_Face_Stream_Size(ftFace);
    137   pFont = IFX_Font::LoadFont(pFXFont, this);
    138   FX_WORD wCodePage = pRet->wCodePage;
    139   CFX_WideString wsPsName = pFXFont->GetPsName();
    140   const FX_WCHAR* pFontFace = wsPsName;
    141 #endif
    142   if (pFont != NULL) {
    143     m_Fonts.Add(pFont);
    144     m_UnicodeFonts.SetAt((void*)(uintptr_t)dwHash, (void*)pFont);
    145     dwHash = FGAS_GetFontHashCode(wCodePage, dwFontStyles);
    146     m_CPFonts.SetAt((void*)(uintptr_t)dwHash, (void*)pFont);
    147     dwHash = FGAS_GetFontFamilyHash(pFontFace, dwFontStyles, wCodePage);
    148     m_FamilyFonts.SetAt((void*)(uintptr_t)dwHash, (void*)pFont);
    149     return LoadFont(pFont, dwFontStyles, wCodePage);
    150   }
    151   return NULL;
    152 }
    153 IFX_Font* CFX_StdFontMgrImp::GetDefFontByLanguage(
    154     FX_WORD wLanguage,
    155     FX_DWORD dwFontStyles,
    156     const FX_WCHAR* pszFontFamily) {
    157   return GetDefFontByCodePage(FX_GetDefCodePageByLanguage(wLanguage),
    158                               dwFontStyles, pszFontFamily);
    159 }
    160 IFX_Font* CFX_StdFontMgrImp::LoadFont(const FX_WCHAR* pszFontFamily,
    161                                       FX_DWORD dwFontStyles,
    162                                       FX_WORD wCodePage) {
    163   FX_DWORD dwHash =
    164       FGAS_GetFontFamilyHash(pszFontFamily, dwFontStyles, wCodePage);
    165   IFX_Font* pFont = NULL;
    166   if (m_FamilyFonts.Lookup((void*)(uintptr_t)dwHash, (void*&)pFont)) {
    167     return pFont ? LoadFont(pFont, dwFontStyles, wCodePage) : NULL;
    168   }
    169   FX_LPCFONTDESCRIPTOR pFD = NULL;
    170   if ((pFD = FindFont(pszFontFamily, dwFontStyles, TRUE, wCodePage)) == NULL)
    171     if ((pFD = FindFont(pszFontFamily, dwFontStyles, FALSE, wCodePage)) ==
    172         NULL) {
    173       return NULL;
    174     }
    175   FXSYS_assert(pFD != NULL);
    176   if (wCodePage == 0xFFFF) {
    177     wCodePage = FX_GetCodePageFromCharset(pFD->uCharSet);
    178   }
    179   pFont = IFX_Font::LoadFont(pFD->wsFontFace, dwFontStyles, wCodePage, this);
    180   if (pFont != NULL) {
    181     m_Fonts.Add(pFont);
    182     m_FamilyFonts.SetAt((void*)(uintptr_t)dwHash, (void*)pFont);
    183     dwHash = FGAS_GetFontHashCode(wCodePage, dwFontStyles);
    184     m_CPFonts.SetAt((void*)(uintptr_t)dwHash, (void*)pFont);
    185     return LoadFont(pFont, dwFontStyles, wCodePage);
    186   }
    187   return NULL;
    188 }
    189 IFX_Font* CFX_StdFontMgrImp::LoadFont(const uint8_t* pBuffer, int32_t iLength) {
    190   FXSYS_assert(pBuffer != NULL && iLength > 0);
    191   IFX_Font* pFont = NULL;
    192   if (m_BufferFonts.Lookup((void*)pBuffer, (void*&)pFont)) {
    193     if (pFont != NULL) {
    194       return pFont->Retain();
    195     }
    196   }
    197   pFont = IFX_Font::LoadFont(pBuffer, iLength, this);
    198   if (pFont != NULL) {
    199     m_Fonts.Add(pFont);
    200     m_BufferFonts.SetAt((void*)pBuffer, pFont);
    201     return pFont->Retain();
    202   }
    203   return NULL;
    204 }
    205 IFX_Font* CFX_StdFontMgrImp::LoadFont(const FX_WCHAR* pszFileName) {
    206   FXSYS_assert(pszFileName != NULL);
    207   FX_DWORD dwHash = FX_HashCode_String_GetW(pszFileName, -1);
    208   IFX_Font* pFont = NULL;
    209   if (m_FileFonts.Lookup((void*)(uintptr_t)dwHash, (void*&)pFont)) {
    210     if (pFont != NULL) {
    211       return pFont->Retain();
    212     }
    213   }
    214   pFont = IFX_Font::LoadFont(pszFileName, NULL);
    215   if (pFont != NULL) {
    216     m_Fonts.Add(pFont);
    217     m_FileFonts.SetAt((void*)(uintptr_t)dwHash, (void*)pFont);
    218     return pFont->Retain();
    219   }
    220   return NULL;
    221 }
    222 IFX_Font* CFX_StdFontMgrImp::LoadFont(IFX_Stream* pFontStream,
    223                                       const FX_WCHAR* pszFontAlias,
    224                                       FX_DWORD dwFontStyles,
    225                                       FX_WORD wCodePage,
    226                                       FX_BOOL bSaveStream) {
    227   FXSYS_assert(pFontStream != NULL && pFontStream->GetLength() > 0);
    228   IFX_Font* pFont = NULL;
    229   if (m_StreamFonts.Lookup((void*)pFontStream, (void*&)pFont)) {
    230     if (pFont != NULL) {
    231       if (pszFontAlias != NULL) {
    232         FX_DWORD dwHash =
    233             FGAS_GetFontFamilyHash(pszFontAlias, dwFontStyles, wCodePage);
    234         m_FamilyFonts.SetAt((void*)(uintptr_t)dwHash, (void*)pFont);
    235       }
    236       return LoadFont(pFont, dwFontStyles, wCodePage);
    237     }
    238   }
    239   pFont = IFX_Font::LoadFont(pFontStream, this, bSaveStream);
    240   if (pFont != NULL) {
    241     m_Fonts.Add(pFont);
    242     m_StreamFonts.SetAt((void*)pFontStream, (void*)pFont);
    243     if (pszFontAlias != NULL) {
    244       FX_DWORD dwHash =
    245           FGAS_GetFontFamilyHash(pszFontAlias, dwFontStyles, wCodePage);
    246       m_FamilyFonts.SetAt((void*)(uintptr_t)dwHash, (void*)pFont);
    247     }
    248     return LoadFont(pFont, dwFontStyles, wCodePage);
    249   }
    250   return NULL;
    251 }
    252 IFX_Font* CFX_StdFontMgrImp::LoadFont(IFX_Font* pSrcFont,
    253                                       FX_DWORD dwFontStyles,
    254                                       FX_WORD wCodePage) {
    255   FXSYS_assert(pSrcFont != NULL);
    256   if (pSrcFont->GetFontStyles() == dwFontStyles) {
    257     return pSrcFont->Retain();
    258   }
    259   void* buffer[3] = {pSrcFont, (void*)(uintptr_t)dwFontStyles,
    260                      (void*)(uintptr_t)wCodePage};
    261   FX_DWORD dwHash =
    262       FX_HashCode_String_GetA((const FX_CHAR*)buffer, 3 * sizeof(void*));
    263   IFX_Font* pFont = NULL;
    264   if (m_DeriveFonts.GetCount() > 0) {
    265     m_DeriveFonts.Lookup((void*)(uintptr_t)dwHash, (void*&)pFont);
    266     if (pFont != NULL) {
    267       return pFont->Retain();
    268     }
    269   }
    270   pFont = pSrcFont->Derive(dwFontStyles, wCodePage);
    271   if (pFont != NULL) {
    272     m_DeriveFonts.SetAt((void*)(uintptr_t)dwHash, (void*)pFont);
    273     int32_t index = m_Fonts.Find(pFont);
    274     if (index < 0) {
    275       m_Fonts.Add(pFont);
    276       pFont->Retain();
    277     }
    278     return pFont;
    279   }
    280   return NULL;
    281 }
    282 void CFX_StdFontMgrImp::ClearFontCache() {
    283   int32_t iCount = m_Fonts.GetSize();
    284   for (int32_t i = 0; i < iCount; i++) {
    285     IFX_Font* pFont = (IFX_Font*)m_Fonts[i];
    286     if (pFont != NULL) {
    287       pFont->Reset();
    288     }
    289   }
    290 }
    291 void CFX_StdFontMgrImp::RemoveFont(CFX_MapPtrToPtr& fontMap, IFX_Font* pFont) {
    292   FX_POSITION pos = fontMap.GetStartPosition();
    293   void* pKey;
    294   void* pFind;
    295   while (pos != NULL) {
    296     pFind = NULL;
    297     fontMap.GetNextAssoc(pos, pKey, pFind);
    298     if (pFind != (void*)pFont) {
    299       continue;
    300     }
    301     fontMap.RemoveKey(pKey);
    302     break;
    303   }
    304 }
    305 void CFX_StdFontMgrImp::RemoveFont(IFX_Font* pFont) {
    306   RemoveFont(m_CPFonts, pFont);
    307   RemoveFont(m_FamilyFonts, pFont);
    308   RemoveFont(m_UnicodeFonts, pFont);
    309   RemoveFont(m_BufferFonts, pFont);
    310   RemoveFont(m_FileFonts, pFont);
    311   RemoveFont(m_StreamFonts, pFont);
    312   RemoveFont(m_DeriveFonts, pFont);
    313   int32_t iFind = m_Fonts.Find(pFont);
    314   if (iFind > -1) {
    315     m_Fonts.RemoveAt(iFind, 1);
    316   }
    317 }
    318 FX_LPCFONTDESCRIPTOR CFX_StdFontMgrImp::FindFont(const FX_WCHAR* pszFontFamily,
    319                                                  FX_DWORD dwFontStyles,
    320                                                  FX_DWORD dwMatchFlags,
    321                                                  FX_WORD wCodePage,
    322                                                  FX_DWORD dwUSB,
    323                                                  FX_WCHAR wUnicode) {
    324   if (m_pMatcher == NULL) {
    325     return NULL;
    326   }
    327   FX_FONTMATCHPARAMS params;
    328   FX_memset(&params, 0, sizeof(params));
    329   params.dwUSB = dwUSB;
    330   params.wUnicode = wUnicode;
    331   params.wCodePage = wCodePage;
    332   params.pwsFamily = pszFontFamily;
    333   params.dwFontStyles = dwFontStyles;
    334   params.dwMatchFlags = dwMatchFlags;
    335   FX_LPCFONTDESCRIPTOR pDesc = m_pMatcher(&params, m_FontFaces, m_pUserData);
    336   if (pDesc) {
    337     return pDesc;
    338   }
    339   if (pszFontFamily && m_pEnumerator) {
    340     CFX_FontDescriptors namedFonts;
    341     m_pEnumerator(namedFonts, m_pUserData, pszFontFamily, wUnicode);
    342     params.pwsFamily = NULL;
    343     pDesc = m_pMatcher(&params, namedFonts, m_pUserData);
    344     if (pDesc == NULL) {
    345       return NULL;
    346     }
    347     for (int32_t i = m_FontFaces.GetSize() - 1; i >= 0; i--) {
    348       FX_LPCFONTDESCRIPTOR pMatch = m_FontFaces.GetPtrAt(i);
    349       if (*pMatch == *pDesc) {
    350         return pMatch;
    351       }
    352     }
    353     int index = m_FontFaces.Add(*pDesc);
    354     return m_FontFaces.GetPtrAt(index);
    355   }
    356   return NULL;
    357 }
    358 FX_LPCFONTDESCRIPTOR FX_DefFontMatcher(FX_LPFONTMATCHPARAMS pParams,
    359                                        const CFX_FontDescriptors& fonts,
    360                                        void* pUserData) {
    361   FX_LPCFONTDESCRIPTOR pBestFont = NULL;
    362   int32_t iBestSimilar = 0;
    363   FX_BOOL bMatchStyle =
    364       (pParams->dwMatchFlags & FX_FONTMATCHPARA_MacthStyle) > 0;
    365   int32_t iCount = fonts.GetSize();
    366   for (int32_t i = 0; i < iCount; ++i) {
    367     FX_LPCFONTDESCRIPTOR pFont = fonts.GetPtrAt(i);
    368     if ((pFont->dwFontStyles & FX_FONTSTYLE_BoldItalic) ==
    369         FX_FONTSTYLE_BoldItalic) {
    370       continue;
    371     }
    372     if (pParams->pwsFamily) {
    373       if (FXSYS_wcsicmp(pParams->pwsFamily, pFont->wsFontFace)) {
    374         continue;
    375       }
    376       if (pFont->uCharSet == FX_CHARSET_Symbol) {
    377         return pFont;
    378       }
    379     }
    380     if (pFont->uCharSet == FX_CHARSET_Symbol) {
    381       continue;
    382     }
    383     if (pParams->wCodePage != 0xFFFF) {
    384       if (FX_GetCodePageFromCharset(pFont->uCharSet) != pParams->wCodePage) {
    385         continue;
    386       }
    387     } else {
    388       if (pParams->dwUSB < 128) {
    389         FX_DWORD dwByte = pParams->dwUSB / 32;
    390         FX_DWORD dwUSB = 1 << (pParams->dwUSB % 32);
    391         if ((pFont->FontSignature.fsUsb[dwByte] & dwUSB) == 0) {
    392           continue;
    393         }
    394       }
    395     }
    396     if (bMatchStyle) {
    397       if ((pFont->dwFontStyles & 0x0F) == (pParams->dwFontStyles & 0x0F)) {
    398         return pFont;
    399       } else {
    400         continue;
    401       }
    402     }
    403     if (pParams->pwsFamily != NULL) {
    404       if (FXSYS_wcsicmp(pParams->pwsFamily, pFont->wsFontFace) == 0) {
    405         return pFont;
    406       }
    407     }
    408     int32_t iSimilarValue = FX_GetSimilarValue(pFont, pParams->dwFontStyles);
    409     if (iBestSimilar < iSimilarValue) {
    410       iBestSimilar = iSimilarValue;
    411       pBestFont = pFont;
    412     }
    413   }
    414   return iBestSimilar < 1 ? NULL : pBestFont;
    415 }
    416 int32_t FX_GetSimilarValue(FX_LPCFONTDESCRIPTOR pFont, FX_DWORD dwFontStyles) {
    417   int32_t iValue = 0;
    418   if ((dwFontStyles & FX_FONTSTYLE_Symbolic) ==
    419       (pFont->dwFontStyles & FX_FONTSTYLE_Symbolic)) {
    420     iValue += 64;
    421   }
    422   if ((dwFontStyles & FX_FONTSTYLE_FixedPitch) ==
    423       (pFont->dwFontStyles & FX_FONTSTYLE_FixedPitch)) {
    424     iValue += 32;
    425   }
    426   if ((dwFontStyles & FX_FONTSTYLE_Serif) ==
    427       (pFont->dwFontStyles & FX_FONTSTYLE_Serif)) {
    428     iValue += 16;
    429   }
    430   if ((dwFontStyles & FX_FONTSTYLE_Script) ==
    431       (pFont->dwFontStyles & FX_FONTSTYLE_Script)) {
    432     iValue += 8;
    433   }
    434   return iValue;
    435 }
    436 FX_LPMatchFont FX_GetDefFontMatchor() {
    437   return FX_DefFontMatcher;
    438 }
    439 FX_DWORD FX_GetGdiFontStyles(const LOGFONTW& lf) {
    440   FX_DWORD dwStyles = 0;
    441   if ((lf.lfPitchAndFamily & 0x03) == FIXED_PITCH) {
    442     dwStyles |= FX_FONTSTYLE_FixedPitch;
    443   }
    444   uint8_t nFamilies = lf.lfPitchAndFamily & 0xF0;
    445   if (nFamilies == FF_ROMAN) {
    446     dwStyles |= FX_FONTSTYLE_Serif;
    447   }
    448   if (nFamilies == FF_SCRIPT) {
    449     dwStyles |= FX_FONTSTYLE_Script;
    450   }
    451   if (lf.lfCharSet == SYMBOL_CHARSET) {
    452     dwStyles |= FX_FONTSTYLE_Symbolic;
    453   }
    454   return dwStyles;
    455 }
    456 static int32_t CALLBACK FX_GdiFontEnumProc(ENUMLOGFONTEX* lpelfe,
    457                                            NEWTEXTMETRICEX* lpntme,
    458                                            DWORD dwFontType,
    459                                            LPARAM lParam) {
    460   if (dwFontType != TRUETYPE_FONTTYPE) {
    461     return 1;
    462   }
    463   const LOGFONTW& lf = ((LPENUMLOGFONTEXW)lpelfe)->elfLogFont;
    464   if (lf.lfFaceName[0] == L'@') {
    465     return 1;
    466   }
    467   FX_LPFONTDESCRIPTOR pFont = FX_Alloc(FX_FONTDESCRIPTOR, 1);
    468   FXSYS_memset(pFont, 0, sizeof(FX_FONTDESCRIPTOR));
    469   pFont->uCharSet = lf.lfCharSet;
    470   pFont->dwFontStyles = FX_GetGdiFontStyles(lf);
    471   FXSYS_wcsncpy(pFont->wsFontFace, (const FX_WCHAR*)lf.lfFaceName, 31);
    472   pFont->wsFontFace[31] = 0;
    473   FX_memcpy(&pFont->FontSignature, &lpntme->ntmFontSig,
    474             sizeof(lpntme->ntmFontSig));
    475   ((CFX_FontDescriptors*)lParam)->Add(*pFont);
    476   FX_Free(pFont);
    477   return 1;
    478 }
    479 static void FX_EnumGdiFonts(CFX_FontDescriptors& fonts,
    480                             void* pUserData,
    481                             const FX_WCHAR* pwsFaceName,
    482                             FX_WCHAR wUnicode) {
    483   HDC hDC = ::GetDC(NULL);
    484   LOGFONTW lfFind;
    485   FX_memset(&lfFind, 0, sizeof(lfFind));
    486   lfFind.lfCharSet = DEFAULT_CHARSET;
    487   if (pwsFaceName) {
    488     FXSYS_wcsncpy((FX_WCHAR*)lfFind.lfFaceName, pwsFaceName, 31);
    489     lfFind.lfFaceName[31] = 0;
    490   }
    491   EnumFontFamiliesExW(hDC, (LPLOGFONTW)&lfFind,
    492                       (FONTENUMPROCW)FX_GdiFontEnumProc, (LPARAM)&fonts, 0);
    493   ::ReleaseDC(NULL, hDC);
    494 }
    495 FX_LPEnumAllFonts FX_GetDefFontEnumerator() {
    496   return FX_EnumGdiFonts;
    497 }
    498 #else
    499 const FX_CHAR* g_FontFolders[] = {
    500 #if _FXM_PLATFORM_ == _FXM_PLATFORM_LINUX_
    501     "/usr/share/fonts", "/usr/share/X11/fonts/Type1",
    502     "/usr/share/X11/fonts/TTF", "/usr/local/share/fonts",
    503 #elif _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
    504     "~/Library/Fonts", "/Library/Fonts", "/System/Library/Fonts",
    505 #elif _FXM_PLATFORM_ == _FXM_PLATFORM_ANDROID_
    506     "/system/fonts",
    507 #endif
    508 };
    509 CFX_FontSourceEnum_File::CFX_FontSourceEnum_File() {
    510   for (int32_t i = 0; i < sizeof(g_FontFolders) / sizeof(const FX_CHAR*); i++) {
    511     m_FolderPaths.Add(g_FontFolders[i]);
    512   }
    513 }
    514 CFX_ByteString CFX_FontSourceEnum_File::GetNextFile() {
    515 Restart:
    516   void* pCurHandle =
    517       m_FolderQueue.GetSize() == 0
    518           ? NULL
    519           : m_FolderQueue.GetDataPtr(m_FolderQueue.GetSize() - 1)->pFileHandle;
    520   if (NULL == pCurHandle) {
    521     if (m_FolderPaths.GetSize() < 1) {
    522       return "";
    523     }
    524     pCurHandle = FX_OpenFolder(m_FolderPaths[m_FolderPaths.GetSize() - 1]);
    525     FX_HandleParentPath hpp;
    526     hpp.pFileHandle = pCurHandle;
    527     hpp.bsParentPath = m_FolderPaths[m_FolderPaths.GetSize() - 1];
    528     m_FolderQueue.Add(hpp);
    529   }
    530   CFX_ByteString bsName;
    531   FX_BOOL bFolder;
    532   CFX_ByteString bsFolderSpearator =
    533       CFX_ByteString::FromUnicode(CFX_WideString(FX_GetFolderSeparator()));
    534   while (TRUE) {
    535     if (!FX_GetNextFile(pCurHandle, bsName, bFolder)) {
    536       FX_CloseFolder(pCurHandle);
    537       m_FolderQueue.RemoveAt(m_FolderQueue.GetSize() - 1);
    538       if (m_FolderQueue.GetSize() == 0) {
    539         m_FolderPaths.RemoveAt(m_FolderPaths.GetSize() - 1);
    540         if (m_FolderPaths.GetSize() == 0) {
    541           return "";
    542         } else {
    543           goto Restart;
    544         }
    545       }
    546       pCurHandle =
    547           m_FolderQueue.GetDataPtr(m_FolderQueue.GetSize() - 1)->pFileHandle;
    548       continue;
    549     }
    550     if (bsName == "." || bsName == "..") {
    551       continue;
    552     }
    553     if (bFolder) {
    554       FX_HandleParentPath hpp;
    555       hpp.bsParentPath =
    556           m_FolderQueue.GetDataPtr(m_FolderQueue.GetSize() - 1)->bsParentPath +
    557           bsFolderSpearator + bsName;
    558       hpp.pFileHandle = FX_OpenFolder(hpp.bsParentPath);
    559       if (hpp.pFileHandle == NULL) {
    560         continue;
    561       }
    562       m_FolderQueue.Add(hpp);
    563       pCurHandle = hpp.pFileHandle;
    564       continue;
    565     }
    566     bsName =
    567         m_FolderQueue.GetDataPtr(m_FolderQueue.GetSize() - 1)->bsParentPath +
    568         bsFolderSpearator + bsName;
    569     break;
    570   }
    571   return bsName;
    572 }
    573 FX_POSITION CFX_FontSourceEnum_File::GetStartPosition(void* pUserData) {
    574   m_wsNext = GetNextFile().UTF8Decode();
    575   if (0 == m_wsNext.GetLength()) {
    576     return (FX_POSITION)0;
    577   }
    578   return (FX_POSITION)-1;
    579 }
    580 IFX_FileAccess* CFX_FontSourceEnum_File::GetNext(FX_POSITION& pos,
    581                                                  void* pUserData) {
    582   IFX_FileAccess* pAccess = FX_CreateDefaultFileAccess(m_wsNext);
    583   m_wsNext = GetNextFile().UTF8Decode();
    584   pos = 0 != m_wsNext.GetLength() ? pAccess : NULL;
    585   return (IFX_FileAccess*)pAccess;
    586 }
    587 IFX_FontSourceEnum* FX_CreateDefaultFontSourceEnum() {
    588   return (IFX_FontSourceEnum*)new CFX_FontSourceEnum_File;
    589 }
    590 IFX_FontMgr* IFX_FontMgr::Create(IFX_FontSourceEnum* pFontEnum,
    591                                  IFX_FontMgrDelegate* pDelegate,
    592                                  void* pUserData) {
    593   if (NULL == pFontEnum) {
    594     return NULL;
    595   }
    596   CFX_FontMgrImp* pFontMgr =
    597       new CFX_FontMgrImp(pFontEnum, pDelegate, pUserData);
    598   if (pFontMgr->EnumFonts()) {
    599     return pFontMgr;
    600   }
    601   delete pFontMgr;
    602   return NULL;
    603 }
    604 CFX_FontMgrImp::CFX_FontMgrImp(IFX_FontSourceEnum* pFontEnum,
    605                                IFX_FontMgrDelegate* pDelegate,
    606                                void* pUserData)
    607     : m_pFontSource(pFontEnum),
    608       m_pDelegate(pDelegate),
    609       m_pUserData(pUserData) {}
    610 
    611 FX_BOOL CFX_FontMgrImp::EnumFonts() {
    612   CFX_GEModule::Get()->GetFontMgr()->InitFTLibrary();
    613   FXFT_Face pFace = NULL;
    614   FX_POSITION pos = m_pFontSource->GetStartPosition();
    615   IFX_FileAccess* pFontSource = NULL;
    616   IFX_FileRead* pFontStream = NULL;
    617   while (pos) {
    618     pFontSource = m_pFontSource->GetNext(pos);
    619     pFontStream = pFontSource->CreateFileStream(FX_FILEMODE_ReadOnly);
    620     if (NULL == pFontStream) {
    621       pFontSource->Release();
    622       continue;
    623     }
    624     if (NULL == (pFace = LoadFace(pFontStream, 0))) {
    625       pFontStream->Release();
    626       pFontSource->Release();
    627       continue;
    628     }
    629     int32_t nFaceCount = pFace->num_faces;
    630     ReportFace(pFace, m_InstalledFonts, pFontSource);
    631     if (FXFT_Get_Face_External_Stream(pFace)) {
    632       FXFT_Clear_Face_External_Stream(pFace);
    633     }
    634     FXFT_Done_Face(pFace);
    635     for (int32_t i = 1; i < nFaceCount; i++) {
    636       if (NULL == (pFace = LoadFace(pFontStream, i))) {
    637         continue;
    638       }
    639       ReportFace(pFace, m_InstalledFonts, pFontSource);
    640       if (FXFT_Get_Face_External_Stream(pFace)) {
    641         FXFT_Clear_Face_External_Stream(pFace);
    642       }
    643       FXFT_Done_Face(pFace);
    644     }
    645     pFontStream->Release();
    646     pFontSource->Release();
    647   }
    648   return TRUE;
    649 }
    650 void CFX_FontMgrImp::Release() {
    651   for (int32_t i = 0; i < m_InstalledFonts.GetSize(); i++) {
    652     delete m_InstalledFonts[i];
    653   }
    654   FX_POSITION pos = m_Hash2CandidateList.GetStartPosition();
    655   while (pos) {
    656     FX_DWORD dwHash;
    657     CFX_FontDescriptorInfos* pDescs;
    658     m_Hash2CandidateList.GetNextAssoc(pos, dwHash, pDescs);
    659     if (NULL != pDescs) {
    660       delete pDescs;
    661     }
    662   }
    663   pos = m_Hash2Fonts.GetStartPosition();
    664   while (pos) {
    665     FX_DWORD dwHash;
    666     CFX_ArrayTemplate<IFX_Font*>* pFonts;
    667     m_Hash2Fonts.GetNextAssoc(pos, dwHash, pFonts);
    668     if (NULL != pFonts) {
    669       delete pFonts;
    670     }
    671   }
    672   m_Hash2Fonts.RemoveAll();
    673   pos = m_Hash2FileAccess.GetStartPosition();
    674   while (pos) {
    675     FX_DWORD dwHash;
    676     IFX_FileAccess* pFileAccess;
    677     m_Hash2FileAccess.GetNextAssoc(pos, dwHash, pFileAccess);
    678     if (NULL != pFileAccess) {
    679       pFileAccess->Release();
    680     }
    681   }
    682   pos = m_FileAccess2IFXFont.GetStartPosition();
    683   while (pos) {
    684     FX_DWORD dwHash;
    685     IFX_Font* pFont;
    686     m_FileAccess2IFXFont.GetNextAssoc(pos, dwHash, pFont);
    687     if (NULL != pFont) {
    688       pFont->Release();
    689     }
    690   }
    691   pos = m_IFXFont2FileRead.GetStartPosition();
    692   while (pos) {
    693     IFX_Font* pFont;
    694     IFX_FileRead* pFileRead;
    695     m_IFXFont2FileRead.GetNextAssoc(pos, pFont, pFileRead);
    696     pFileRead->Release();
    697   }
    698   delete this;
    699 }
    700 IFX_Font* CFX_FontMgrImp::GetDefFontByCodePage(FX_WORD wCodePage,
    701                                                FX_DWORD dwFontStyles,
    702                                                const FX_WCHAR* pszFontFamily) {
    703   return NULL == m_pDelegate ? NULL : m_pDelegate->GetDefFontByCodePage(
    704                                           this, wCodePage, dwFontStyles,
    705                                           pszFontFamily);
    706 }
    707 IFX_Font* CFX_FontMgrImp::GetDefFontByCharset(uint8_t nCharset,
    708                                               FX_DWORD dwFontStyles,
    709                                               const FX_WCHAR* pszFontFamily) {
    710   return NULL == m_pDelegate ? NULL
    711                              : m_pDelegate->GetDefFontByCharset(
    712                                    this, nCharset, dwFontStyles, pszFontFamily);
    713 }
    714 IFX_Font* CFX_FontMgrImp::GetDefFontByUnicode(FX_WCHAR wUnicode,
    715                                               FX_DWORD dwFontStyles,
    716                                               const FX_WCHAR* pszFontFamily) {
    717   return NULL == m_pDelegate ? NULL
    718                              : m_pDelegate->GetDefFontByUnicode(
    719                                    this, wUnicode, dwFontStyles, pszFontFamily);
    720 }
    721 IFX_Font* CFX_FontMgrImp::GetDefFontByLanguage(FX_WORD wLanguage,
    722                                                FX_DWORD dwFontStyles,
    723                                                const FX_WCHAR* pszFontFamily) {
    724   return NULL == m_pDelegate ? NULL : m_pDelegate->GetDefFontByLanguage(
    725                                           this, wLanguage, dwFontStyles,
    726                                           pszFontFamily);
    727 }
    728 IFX_Font* CFX_FontMgrImp::GetFontByCodePage(FX_WORD wCodePage,
    729                                             FX_DWORD dwFontStyles,
    730                                             const FX_WCHAR* pszFontFamily) {
    731   CFX_ByteString bsHash;
    732   bsHash.Format("%d, %d", wCodePage, dwFontStyles);
    733   bsHash += CFX_WideString(pszFontFamily).UTF8Encode();
    734   FX_DWORD dwHash = FX_HashCode_String_GetA(bsHash, bsHash.GetLength());
    735   CFX_ArrayTemplate<IFX_Font*>* pFonts = NULL;
    736   IFX_Font* pFont = NULL;
    737   if (m_Hash2Fonts.Lookup(dwHash, pFonts)) {
    738     if (NULL == pFonts) {
    739       return NULL;
    740     }
    741     if (0 != pFonts->GetSize()) {
    742       return pFonts->GetAt(0)->Retain();
    743     }
    744   }
    745   if (!pFonts)
    746     pFonts = new CFX_ArrayTemplate<IFX_Font*>;
    747   m_Hash2Fonts.SetAt(dwHash, pFonts);
    748   CFX_FontDescriptorInfos* sortedFonts = NULL;
    749   if (!m_Hash2CandidateList.Lookup(dwHash, sortedFonts)) {
    750     sortedFonts = new CFX_FontDescriptorInfos;
    751     MatchFonts(*sortedFonts, wCodePage, dwFontStyles,
    752                CFX_WideString(pszFontFamily), 0);
    753     m_Hash2CandidateList.SetAt(dwHash, sortedFonts);
    754   }
    755   if (sortedFonts->GetSize() == 0) {
    756     return NULL;
    757   }
    758   CFX_FontDescriptor* pDesc = sortedFonts->GetAt(0).pFont;
    759   pFont = LoadFont(pDesc->m_pFileAccess, pDesc->m_nFaceIndex, NULL);
    760   if (NULL != pFont) {
    761     pFont->SetLogicalFontStyle(dwFontStyles);
    762   }
    763   pFonts->Add(pFont);
    764   return pFont;
    765 }
    766 IFX_Font* CFX_FontMgrImp::GetFontByCharset(uint8_t nCharset,
    767                                            FX_DWORD dwFontStyles,
    768                                            const FX_WCHAR* pszFontFamily) {
    769   return GetFontByCodePage(FX_GetCodePageFromCharset(nCharset), dwFontStyles,
    770                            pszFontFamily);
    771 }
    772 IFX_Font* CFX_FontMgrImp::GetFontByUnicode(FX_WCHAR wUnicode,
    773                                            FX_DWORD dwFontStyles,
    774                                            const FX_WCHAR* pszFontFamily) {
    775   IFX_Font* pFont = NULL;
    776   if (m_FailedUnicodes2NULL.Lookup(wUnicode, pFont)) {
    777     return NULL;
    778   }
    779   FGAS_LPCFONTUSB x = FGAS_GetUnicodeBitField(wUnicode);
    780   FX_WORD wCodePage = NULL == x ? 0xFFFF : x->wCodePage;
    781   FX_WORD wBitField = NULL == x ? 999 : x->wBitField;
    782   CFX_ByteString bsHash;
    783   if (wCodePage == 0xFFFF) {
    784     bsHash.Format("%d, %d, %d", wCodePage, wBitField, dwFontStyles);
    785   } else {
    786     bsHash.Format("%d, %d", wCodePage, dwFontStyles);
    787   }
    788   bsHash += CFX_WideString(pszFontFamily).UTF8Encode();
    789   FX_DWORD dwHash = FX_HashCode_String_GetA(bsHash, bsHash.GetLength());
    790   CFX_ArrayTemplate<IFX_Font*>* pFonts = NULL;
    791   if (m_Hash2Fonts.Lookup(dwHash, pFonts)) {
    792     if (NULL == pFonts) {
    793       return NULL;
    794     }
    795     if (0 != pFonts->GetSize()) {
    796       for (int32_t i = 0; i < pFonts->GetSize(); i++) {
    797         if (VerifyUnicode(pFonts->GetAt(i), wUnicode)) {
    798           return pFonts->GetAt(i)->Retain();
    799         }
    800       }
    801     }
    802   }
    803   if (!pFonts)
    804     pFonts = new CFX_ArrayTemplate<IFX_Font*>;
    805   m_Hash2Fonts.SetAt(dwHash, pFonts);
    806   CFX_FontDescriptorInfos* sortedFonts = NULL;
    807   if (!m_Hash2CandidateList.Lookup(dwHash, sortedFonts)) {
    808     sortedFonts = new CFX_FontDescriptorInfos;
    809     MatchFonts(*sortedFonts, wCodePage, dwFontStyles,
    810                CFX_WideString(pszFontFamily), wUnicode);
    811     m_Hash2CandidateList.SetAt(dwHash, sortedFonts);
    812   }
    813   for (int32_t i = 0; i < sortedFonts->GetSize(); i++) {
    814     CFX_FontDescriptor* pDesc = sortedFonts->GetAt(i).pFont;
    815     if (VerifyUnicode(pDesc, wUnicode)) {
    816       pFont = LoadFont(pDesc->m_pFileAccess, pDesc->m_nFaceIndex, NULL);
    817       if (NULL != pFont) {
    818         pFont->SetLogicalFontStyle(dwFontStyles);
    819       }
    820       pFonts->Add(pFont);
    821       return pFont;
    822     }
    823   }
    824   if (NULL == pszFontFamily) {
    825     m_FailedUnicodes2NULL.SetAt(wUnicode, NULL);
    826   }
    827   return NULL;
    828 }
    829 FX_BOOL CFX_FontMgrImp::VerifyUnicode(CFX_FontDescriptor* pDesc,
    830                                       FX_WCHAR wcUnicode) {
    831   IFX_FileRead* pFileRead =
    832       pDesc->m_pFileAccess->CreateFileStream(FX_FILEMODE_ReadOnly);
    833   if (NULL == pFileRead) {
    834     return FALSE;
    835   }
    836   FXFT_Face pFace = LoadFace(pFileRead, pDesc->m_nFaceIndex);
    837   if (NULL == pFace) {
    838     goto BadRet;
    839   }
    840   if (0 != FXFT_Select_Charmap(pFace, FXFT_ENCODING_UNICODE)) {
    841     goto BadRet;
    842   }
    843   if (0 == FXFT_Get_Char_Index(pFace, wcUnicode)) {
    844     goto BadRet;
    845   }
    846   pFileRead->Release();
    847   if (FXFT_Get_Face_External_Stream(pFace)) {
    848     FXFT_Clear_Face_External_Stream(pFace);
    849   }
    850   FXFT_Done_Face(pFace);
    851   return TRUE;
    852 BadRet:
    853   if (NULL != pFileRead) {
    854     pFileRead->Release();
    855   }
    856   if (NULL != pFace) {
    857     if (FXFT_Get_Face_External_Stream(pFace)) {
    858       FXFT_Clear_Face_External_Stream(pFace);
    859     }
    860     FXFT_Done_Face(pFace);
    861   }
    862   return FALSE;
    863 }
    864 FX_BOOL CFX_FontMgrImp::VerifyUnicode(IFX_Font* pFont, FX_WCHAR wcUnicode) {
    865   if (NULL == pFont) {
    866     return FALSE;
    867   }
    868   FXFT_Face pFace = ((CFX_Font*)pFont->GetDevFont())->GetFace();
    869   FXFT_CharMap charmap = FXFT_Get_Face_Charmap(pFace);
    870   if (0 != FXFT_Select_Charmap(pFace, FXFT_ENCODING_UNICODE)) {
    871     return FALSE;
    872   }
    873   if (0 == FXFT_Get_Char_Index(pFace, wcUnicode)) {
    874     FXFT_Set_Charmap(pFace, charmap);
    875     return FALSE;
    876   }
    877   return TRUE;
    878 }
    879 IFX_Font* CFX_FontMgrImp::GetFontByLanguage(FX_WORD wLanguage,
    880                                             FX_DWORD dwFontStyles,
    881                                             const FX_WCHAR* pszFontFamily) {
    882   return GetFontByCodePage(FX_GetDefCodePageByLanguage(wLanguage), dwFontStyles,
    883                            pszFontFamily);
    884 }
    885 IFX_Font* CFX_FontMgrImp::LoadFont(const uint8_t* pBuffer,
    886                                    int32_t iLength,
    887                                    int32_t iFaceIndex,
    888                                    int32_t* pFaceCount) {
    889   void* Hash[2] = {(void*)(uintptr_t)pBuffer, (void*)(uintptr_t)iLength};
    890   FX_DWORD dwHash =
    891       FX_HashCode_String_GetA((const FX_CHAR*)Hash, 2 * sizeof(void*));
    892   IFX_FileAccess* pFontAccess = NULL;
    893   if (!m_Hash2FileAccess.Lookup(dwHash, pFontAccess)) {
    894   }
    895   if (NULL != pFontAccess) {
    896     return LoadFont(pFontAccess, iFaceIndex, pFaceCount, TRUE);
    897   } else {
    898     return NULL;
    899   }
    900 }
    901 IFX_Font* CFX_FontMgrImp::LoadFont(const FX_WCHAR* pszFileName,
    902                                    int32_t iFaceIndex,
    903                                    int32_t* pFaceCount) {
    904   CFX_ByteString bsHash;
    905   bsHash += CFX_WideString(pszFileName).UTF8Encode();
    906   FX_DWORD dwHash =
    907       FX_HashCode_String_GetA((const FX_CHAR*)bsHash, bsHash.GetLength());
    908   IFX_FileAccess* pFontAccess = NULL;
    909   if (!m_Hash2FileAccess.Lookup(dwHash, pFontAccess)) {
    910     pFontAccess = FX_CreateDefaultFileAccess(pszFileName);
    911     m_Hash2FileAccess.SetAt(dwHash, pFontAccess);
    912   }
    913   if (NULL != pFontAccess) {
    914     return LoadFont(pFontAccess, iFaceIndex, pFaceCount, TRUE);
    915   } else {
    916     return NULL;
    917   }
    918 }
    919 IFX_Font* CFX_FontMgrImp::LoadFont(IFX_Stream* pFontStream,
    920                                    int32_t iFaceIndex,
    921                                    int32_t* pFaceCount,
    922                                    FX_BOOL bSaveStream) {
    923   void* Hash[1] = {(void*)(uintptr_t)pFontStream};
    924   FX_DWORD dwHash =
    925       FX_HashCode_String_GetA((const FX_CHAR*)Hash, 1 * sizeof(void*));
    926   IFX_FileAccess* pFontAccess = NULL;
    927   if (!m_Hash2FileAccess.Lookup(dwHash, pFontAccess)) {
    928   }
    929   if (NULL != pFontAccess) {
    930     return LoadFont(pFontAccess, iFaceIndex, pFaceCount, TRUE);
    931   } else {
    932     return NULL;
    933   }
    934 }
    935 IFX_Font* CFX_FontMgrImp::LoadFont(IFX_FileAccess* pFontAccess,
    936                                    int32_t iFaceIndex,
    937                                    int32_t* pFaceCount,
    938                                    FX_BOOL bWantCache) {
    939   FX_DWORD dwHash = 0;
    940   IFX_Font* pFont = NULL;
    941   if (bWantCache) {
    942     CFX_ByteString bsHash;
    943     bsHash.Format("%d, %d", (uintptr_t)pFontAccess, iFaceIndex);
    944     dwHash = FX_HashCode_String_GetA(bsHash, bsHash.GetLength());
    945     if (m_FileAccess2IFXFont.Lookup(dwHash, pFont)) {
    946       if (NULL != pFont) {
    947         if (NULL != pFaceCount) {
    948           *pFaceCount = ((CFX_Font*)pFont->GetDevFont())->GetFace()->num_faces;
    949         }
    950         return pFont->Retain();
    951       }
    952     }
    953   }
    954   CFX_Font* pInternalFont = new CFX_Font;
    955   IFX_FileRead* pFontStream =
    956       pFontAccess->CreateFileStream(FX_FILEMODE_ReadOnly);
    957   if (NULL == pFontStream) {
    958     delete pInternalFont;
    959     return NULL;
    960   }
    961   if (!pInternalFont->LoadFile(pFontStream, iFaceIndex)) {
    962     delete pInternalFont;
    963     pFontStream->Release();
    964     return NULL;
    965   }
    966   pFont = IFX_Font::LoadFont(pInternalFont, this, TRUE);
    967   if (NULL == pFont) {
    968     delete pInternalFont;
    969     pFontStream->Release();
    970     return NULL;
    971   }
    972   if (bWantCache) {
    973     m_FileAccess2IFXFont.SetAt(dwHash, pFont);
    974   }
    975   m_IFXFont2FileRead.SetAt(pFont, pFontStream);
    976   if (NULL != pFaceCount) {
    977     *pFaceCount = ((CFX_Font*)pFont->GetDevFont())->GetFace()->num_faces;
    978   }
    979   return pFont;
    980 }
    981 extern "C" {
    982 unsigned long _ftStreamRead(FXFT_Stream stream,
    983                             unsigned long offset,
    984                             unsigned char* buffer,
    985                             unsigned long count) {
    986   if (count == 0) {
    987     return 0;
    988   }
    989   IFX_FileRead* pFile = (IFX_FileRead*)stream->descriptor.pointer;
    990   int res = pFile->ReadBlock(buffer, offset, count);
    991   if (res) {
    992     return count;
    993   }
    994   return 0;
    995 }
    996 void _ftStreamClose(FXFT_Stream stream) {}
    997 };
    998 
    999 FXFT_Face CFX_FontMgrImp::LoadFace(IFX_FileRead* pFontStream,
   1000                                    int32_t iFaceIndex) {
   1001   if (!pFontStream)
   1002     return nullptr;
   1003 
   1004   CFX_FontMgr* pFontMgr = CFX_GEModule::Get()->GetFontMgr();
   1005   pFontMgr->InitFTLibrary();
   1006   FXFT_Library library = pFontMgr->GetFTLibrary();
   1007   if (!library)
   1008     return nullptr;
   1009 
   1010   FXFT_Stream ftStream = FX_Alloc(FXFT_StreamRec, 1);
   1011   FXSYS_memset(ftStream, 0, sizeof(FXFT_StreamRec));
   1012   ftStream->base = NULL;
   1013   ftStream->descriptor.pointer = pFontStream;
   1014   ftStream->pos = 0;
   1015   ftStream->size = (unsigned long)pFontStream->GetSize();
   1016   ftStream->read = _ftStreamRead;
   1017   ftStream->close = _ftStreamClose;
   1018 
   1019   FXFT_Open_Args ftArgs;
   1020   FXSYS_memset(&ftArgs, 0, sizeof(FXFT_Open_Args));
   1021   ftArgs.flags |= FT_OPEN_STREAM;
   1022   ftArgs.stream = ftStream;
   1023 
   1024   FXFT_Face pFace = NULL;
   1025   if (FXFT_Open_Face(library, &ftArgs, iFaceIndex, &pFace)) {
   1026     FX_Free(ftStream);
   1027     return nullptr;
   1028   }
   1029 
   1030   FXFT_Set_Pixel_Sizes(pFace, 0, 64);
   1031   return pFace;
   1032 }
   1033 
   1034 int32_t CFX_FontMgrImp::MatchFonts(CFX_FontDescriptorInfos& MatchedFonts,
   1035                                    FX_WORD wCodePage,
   1036                                    FX_DWORD dwFontStyles,
   1037                                    const CFX_WideString& FontName,
   1038                                    FX_WCHAR wcUnicode) {
   1039   MatchedFonts.RemoveAll();
   1040   CFX_WideString wsNormalizedFontName = FontName;
   1041   NormalizeFontName(wsNormalizedFontName);
   1042   static const int32_t nMax = 0xffff;
   1043   CFX_FontDescriptor* pFont = NULL;
   1044   int32_t nCount = m_InstalledFonts.GetSize();
   1045   for (int32_t i = 0; i < nCount; i++) {
   1046     pFont = m_InstalledFonts[i];
   1047     int32_t nPenalty = CalcPenalty(pFont, wCodePage, dwFontStyles,
   1048                                    wsNormalizedFontName, wcUnicode);
   1049     if (nPenalty >= 0xFFFF) {
   1050       continue;
   1051     }
   1052     FX_FontDescriptorInfo FontInfo;
   1053     FontInfo.pFont = pFont;
   1054     FontInfo.nPenalty = nPenalty;
   1055     MatchedFonts.Add(FontInfo);
   1056     if (MatchedFonts.GetSize() == nMax) {
   1057       break;
   1058     }
   1059   }
   1060   if (MatchedFonts.GetSize() == 0) {
   1061     return 0;
   1062   }
   1063   CFX_SSortTemplate<FX_FontDescriptorInfo> ssort;
   1064   ssort.ShellSort(MatchedFonts.GetData(), MatchedFonts.GetSize());
   1065   return MatchedFonts.GetSize();
   1066 }
   1067 struct FX_BitCodePage {
   1068   FX_WORD wBit;
   1069   FX_WORD wCodePage;
   1070 };
   1071 static const FX_BitCodePage g_Bit2CodePage[] = {
   1072     {0, 1252}, {1, 1250}, {2, 1251}, {3, 1253},  {4, 1254}, {5, 1255},
   1073     {6, 1256}, {7, 1257}, {8, 1258}, {9, 0},     {10, 0},   {11, 0},
   1074     {12, 0},   {13, 0},   {14, 0},   {15, 0},    {16, 874}, {17, 932},
   1075     {18, 936}, {19, 949}, {20, 950}, {21, 1361}, {22, 0},   {23, 0},
   1076     {24, 0},   {25, 0},   {26, 0},   {27, 0},    {28, 0},   {29, 0},
   1077     {30, 0},   {31, 0},   {32, 0},   {33, 0},    {34, 0},   {35, 0},
   1078     {36, 0},   {37, 0},   {38, 0},   {39, 0},    {40, 0},   {41, 0},
   1079     {42, 0},   {43, 0},   {44, 0},   {45, 0},    {46, 0},   {47, 0},
   1080     {48, 869}, {49, 866}, {50, 865}, {51, 864},  {52, 863}, {53, 862},
   1081     {54, 861}, {55, 860}, {56, 857}, {57, 855},  {58, 852}, {59, 775},
   1082     {60, 737}, {61, 708}, {62, 850}, {63, 437},
   1083 };
   1084 FX_WORD FX_GetCodePageBit(FX_WORD wCodePage) {
   1085   for (int32_t i = 0; i < sizeof(g_Bit2CodePage) / sizeof(FX_BitCodePage);
   1086        i++) {
   1087     if (g_Bit2CodePage[i].wCodePage == wCodePage) {
   1088       return g_Bit2CodePage[i].wBit;
   1089     }
   1090   }
   1091   return (FX_WORD)-1;
   1092 }
   1093 FX_WORD FX_GetUnicodeBit(FX_WCHAR wcUnicode) {
   1094   FGAS_LPCFONTUSB x = FGAS_GetUnicodeBitField(wcUnicode);
   1095   if (NULL == x) {
   1096     return 999;
   1097   }
   1098   return x->wBitField;
   1099 }
   1100 int32_t CFX_FontMgrImp::CalcPenalty(CFX_FontDescriptor* pInstalled,
   1101                                     FX_WORD wCodePage,
   1102                                     FX_DWORD dwFontStyles,
   1103                                     const CFX_WideString& FontName,
   1104                                     FX_WCHAR wcUnicode) {
   1105   int32_t nPenalty = 30000;
   1106   if (0 != FontName.GetLength()) {
   1107     if (FontName != pInstalled->m_wsFaceName) {
   1108       int32_t i;
   1109       for (i = 0; i < pInstalled->m_wsFamilyNames.GetSize(); i++) {
   1110         if (pInstalled->m_wsFamilyNames[i] == FontName) {
   1111           break;
   1112         }
   1113       }
   1114       if (i == pInstalled->m_wsFamilyNames.GetSize()) {
   1115         nPenalty += 0xFFFF;
   1116       } else {
   1117         nPenalty -= 28000;
   1118       }
   1119     } else {
   1120       nPenalty -= 30000;
   1121     }
   1122     if (30000 == nPenalty &&
   1123         0 == IsPartName(pInstalled->m_wsFaceName, FontName)) {
   1124       int32_t i;
   1125       for (i = 0; i < pInstalled->m_wsFamilyNames.GetSize(); i++) {
   1126         if (0 != IsPartName(pInstalled->m_wsFamilyNames[i], FontName)) {
   1127           break;
   1128         }
   1129       }
   1130       if (i == pInstalled->m_wsFamilyNames.GetSize()) {
   1131         nPenalty += 0xFFFF;
   1132       } else {
   1133         nPenalty -= 26000;
   1134       }
   1135     } else {
   1136       nPenalty -= 27000;
   1137     }
   1138   }
   1139   FX_DWORD dwStyleMask = pInstalled->m_dwFontStyles ^ dwFontStyles;
   1140   if (dwStyleMask & FX_FONTSTYLE_Bold) {
   1141     nPenalty += 4500;
   1142   }
   1143   if (dwStyleMask & FX_FONTSTYLE_FixedPitch) {
   1144     nPenalty += 10000;
   1145   }
   1146   if (dwStyleMask & FX_FONTSTYLE_Italic) {
   1147     nPenalty += 10000;
   1148   }
   1149   if (dwStyleMask & FX_FONTSTYLE_Serif) {
   1150     nPenalty += 500;
   1151   }
   1152   if (dwStyleMask & FX_FONTSTYLE_Symbolic) {
   1153     nPenalty += 0xFFFF;
   1154   }
   1155   if (nPenalty >= 0xFFFF) {
   1156     return 0xFFFF;
   1157   }
   1158   FX_WORD wBit =
   1159       ((0 == wCodePage || 0xFFFF == wCodePage) ? (FX_WORD)-1
   1160                                                : FX_GetCodePageBit(wCodePage));
   1161   if (wBit != (FX_WORD)-1) {
   1162     FXSYS_assert(wBit < 64);
   1163     if (0 == (pInstalled->m_dwCsb[wBit / 32] & (1 << (wBit % 32)))) {
   1164       nPenalty += 0xFFFF;
   1165     } else {
   1166       nPenalty -= 60000;
   1167     }
   1168   }
   1169   wBit =
   1170       ((0 == wcUnicode || 0xFFFE == wcUnicode) ? (FX_WORD)999
   1171                                                : FX_GetUnicodeBit(wcUnicode));
   1172   if (wBit != (FX_WORD)999) {
   1173     FXSYS_assert(wBit < 128);
   1174     if (0 == (pInstalled->m_dwUsb[wBit / 32] & (1 << (wBit % 32)))) {
   1175       nPenalty += 0xFFFF;
   1176     } else {
   1177       nPenalty -= 60000;
   1178     }
   1179   }
   1180   return nPenalty;
   1181 }
   1182 void CFX_FontMgrImp::ClearFontCache() {
   1183   FX_POSITION pos = m_Hash2CandidateList.GetStartPosition();
   1184   while (pos) {
   1185     FX_DWORD dwHash;
   1186     CFX_FontDescriptorInfos* pDescs;
   1187     m_Hash2CandidateList.GetNextAssoc(pos, dwHash, pDescs);
   1188     if (NULL != pDescs) {
   1189       delete pDescs;
   1190     }
   1191   }
   1192   pos = m_FileAccess2IFXFont.GetStartPosition();
   1193   while (pos) {
   1194     FX_DWORD dwHash;
   1195     IFX_Font* pFont;
   1196     m_FileAccess2IFXFont.GetNextAssoc(pos, dwHash, pFont);
   1197     if (NULL != pFont) {
   1198       pFont->Release();
   1199     }
   1200   }
   1201   pos = m_IFXFont2FileRead.GetStartPosition();
   1202   while (pos) {
   1203     IFX_Font* pFont;
   1204     IFX_FileRead* pFileRead;
   1205     m_IFXFont2FileRead.GetNextAssoc(pos, pFont, pFileRead);
   1206     pFileRead->Release();
   1207   }
   1208 }
   1209 void CFX_FontMgrImp::RemoveFont(IFX_Font* pEFont) {
   1210   if (NULL == pEFont) {
   1211     return;
   1212   }
   1213   IFX_FileRead* pFileRead;
   1214   if (m_IFXFont2FileRead.Lookup(pEFont, pFileRead)) {
   1215     pFileRead->Release();
   1216     m_IFXFont2FileRead.RemoveKey(pEFont);
   1217   }
   1218   FX_POSITION pos;
   1219   pos = m_FileAccess2IFXFont.GetStartPosition();
   1220   while (pos) {
   1221     FX_DWORD dwHash;
   1222     IFX_Font* pCFont;
   1223     m_FileAccess2IFXFont.GetNextAssoc(pos, dwHash, pCFont);
   1224     if (pCFont == pEFont) {
   1225       m_FileAccess2IFXFont.RemoveKey(dwHash);
   1226       break;
   1227     }
   1228   }
   1229   pos = m_Hash2Fonts.GetStartPosition();
   1230   while (pos) {
   1231     FX_DWORD dwHash;
   1232     CFX_ArrayTemplate<IFX_Font*>* pFonts;
   1233     m_Hash2Fonts.GetNextAssoc(pos, dwHash, pFonts);
   1234     if (NULL != pFonts) {
   1235       for (int32_t i = 0; i < pFonts->GetSize(); i++) {
   1236         if (pFonts->GetAt(i) == pEFont) {
   1237           pFonts->SetAt(i, NULL);
   1238         }
   1239       }
   1240     } else {
   1241       m_Hash2Fonts.RemoveKey(dwHash);
   1242     }
   1243   }
   1244 }
   1245 void CFX_FontMgrImp::ReportFace(FXFT_Face pFace,
   1246                                 CFX_FontDescriptors& Fonts,
   1247                                 IFX_FileAccess* pFontAccess) {
   1248   if (0 == (pFace->face_flags & FT_FACE_FLAG_SCALABLE)) {
   1249     return;
   1250   }
   1251   CFX_FontDescriptor* pFont = new CFX_FontDescriptor;
   1252   pFont->m_dwFontStyles |= FXFT_Is_Face_Bold(pFace) ? FX_FONTSTYLE_Bold : 0;
   1253   pFont->m_dwFontStyles |= FXFT_Is_Face_Italic(pFace) ? FX_FONTSTYLE_Italic : 0;
   1254   pFont->m_dwFontStyles |= GetFlags(pFace);
   1255   CFX_WordArray Charsets;
   1256   GetCharsets(pFace, Charsets);
   1257   GetUSBCSB(pFace, pFont->m_dwUsb, pFont->m_dwCsb);
   1258   unsigned long nLength = 0;
   1259   FT_ULong dwTag;
   1260   uint8_t* pTable = NULL;
   1261   FT_ENC_TAG(dwTag, 'n', 'a', 'm', 'e');
   1262   unsigned int error = FXFT_Load_Sfnt_Table(pFace, dwTag, 0, NULL, &nLength);
   1263   if (0 == error && 0 != nLength) {
   1264     pTable = FX_Alloc(uint8_t, nLength);
   1265     error = FXFT_Load_Sfnt_Table(pFace, dwTag, 0, pTable, NULL);
   1266     if (0 != error) {
   1267       FX_Free(pTable);
   1268       pTable = NULL;
   1269     }
   1270   }
   1271   GetNames(pTable, pFont->m_wsFamilyNames);
   1272   if (NULL != pTable) {
   1273     FX_Free(pTable);
   1274   }
   1275   pFont->m_wsFamilyNames.Add(CFX_ByteString(pFace->family_name).UTF8Decode());
   1276   pFont->m_wsFaceName =
   1277       CFX_WideString::FromLocal(FXFT_Get_Postscript_Name(pFace));
   1278   pFont->m_nFaceIndex = pFace->face_index;
   1279   pFont->m_pFileAccess = pFontAccess->Retain();
   1280   NormalizeFontName(pFont->m_wsFaceName);
   1281   for (int32_t i = 0; i < pFont->m_wsFamilyNames.GetSize(); i++) {
   1282     NormalizeFontName(pFont->m_wsFamilyNames[i]);
   1283   }
   1284   Fonts.Add(pFont);
   1285 }
   1286 FX_DWORD CFX_FontMgrImp::GetFlags(FXFT_Face pFace) {
   1287   FX_DWORD flag = 0;
   1288   if (FT_IS_FIXED_WIDTH(pFace)) {
   1289     flag |= FX_FONTSTYLE_FixedPitch;
   1290   }
   1291   TT_OS2* pOS2 = (TT_OS2*)FT_Get_Sfnt_Table(pFace, ft_sfnt_os2);
   1292   if (!pOS2) {
   1293     return flag;
   1294   }
   1295   if (pOS2->ulCodePageRange1 & (1 << 31)) {
   1296     flag |= FX_FONTSTYLE_Symbolic;
   1297   }
   1298   if (pOS2->panose[0] == 2) {
   1299     uint8_t uSerif = pOS2->panose[1];
   1300     if ((uSerif > 1 && uSerif < 10) || uSerif > 13) {
   1301       flag |= FX_FONTSTYLE_Serif;
   1302     }
   1303   }
   1304   return flag;
   1305 }
   1306 #define GetUInt8(p) ((uint8_t)((p)[0]))
   1307 #define GetUInt16(p) ((uint16_t)((p)[0] << 8 | (p)[1]))
   1308 #define GetUInt32(p) \
   1309   ((uint32_t)((p)[0] << 24 | (p)[1] << 16 | (p)[2] << 8 | (p)[3]))
   1310 void CFX_FontMgrImp::GetNames(const uint8_t* name_table,
   1311                               CFX_WideStringArray& Names) {
   1312   if (NULL == name_table) {
   1313     return;
   1314   }
   1315   uint8_t* lpTable = (uint8_t*)name_table;
   1316   CFX_WideString wsFamily;
   1317   uint8_t* sp = lpTable + 2;
   1318   uint8_t* lpNameRecord = lpTable + 6;
   1319   uint16_t nNameCount = GetUInt16(sp);
   1320   uint8_t* lpStr = lpTable + GetUInt16(sp + 2);
   1321   for (uint16_t j = 0; j < nNameCount; j++) {
   1322     uint16_t nNameID = GetUInt16(lpNameRecord + j * 12 + 6);
   1323     if (nNameID != 1) {
   1324       continue;
   1325     }
   1326     uint16_t nPlatformID = GetUInt16(lpNameRecord + j * 12 + 0);
   1327     uint16_t nNameLength = GetUInt16(lpNameRecord + j * 12 + 8);
   1328     uint16_t nNameOffset = GetUInt16(lpNameRecord + j * 12 + 10);
   1329     wsFamily.Empty();
   1330     if (nPlatformID != 1) {
   1331       for (uint16_t k = 0; k < nNameLength / 2; k++) {
   1332         FX_WCHAR wcTemp = GetUInt16(lpStr + nNameOffset + k * 2);
   1333         wsFamily += wcTemp;
   1334       }
   1335       Names.Add(wsFamily);
   1336     } else {
   1337       for (uint16_t k = 0; k < nNameLength; k++) {
   1338         FX_WCHAR wcTemp = GetUInt8(lpStr + nNameOffset + k);
   1339         wsFamily += wcTemp;
   1340       }
   1341       Names.Add(wsFamily);
   1342     }
   1343   }
   1344 }
   1345 #undef GetUInt8
   1346 #undef GetUInt16
   1347 #undef GetUInt32
   1348 struct FX_BIT2CHARSET {
   1349   FX_WORD wBit;
   1350   FX_WORD wCharset;
   1351 };
   1352 FX_BIT2CHARSET g_FX_Bit2Charset1[16] = {
   1353     {1 << 0, FX_CHARSET_ANSI},
   1354     {1 << 1, FX_CHARSET_MSWin_EasterEuropean},
   1355     {1 << 2, FX_CHARSET_MSWin_Cyrillic},
   1356     {1 << 3, FX_CHARSET_MSWin_Greek},
   1357     {1 << 4, FX_CHARSET_MSWin_Turkish},
   1358     {1 << 5, FX_CHARSET_MSWin_Hebrew},
   1359     {1 << 6, FX_CHARSET_MSWin_Arabic},
   1360     {1 << 7, FX_CHARSET_MSWin_Baltic},
   1361     {1 << 8, FX_CHARSET_MSWin_Vietnamese},
   1362     {1 << 9, FX_CHARSET_Default},
   1363     {1 << 10, FX_CHARSET_Default},
   1364     {1 << 11, FX_CHARSET_Default},
   1365     {1 << 12, FX_CHARSET_Default},
   1366     {1 << 13, FX_CHARSET_Default},
   1367     {1 << 14, FX_CHARSET_Default},
   1368     {1 << 15, FX_CHARSET_Default},
   1369 };
   1370 FX_BIT2CHARSET g_FX_Bit2Charset2[16] = {
   1371     {1 << 0, FX_CHARSET_Thai},
   1372     {1 << 1, FX_CHARSET_ShiftJIS},
   1373     {1 << 2, FX_CHARSET_ChineseSimplified},
   1374     {1 << 3, FX_CHARSET_Korean},
   1375     {1 << 4, FX_CHARSET_ChineseTriditional},
   1376     {1 << 5, FX_CHARSET_Johab},
   1377     {1 << 6, FX_CHARSET_Default},
   1378     {1 << 7, FX_CHARSET_Default},
   1379     {1 << 8, FX_CHARSET_Default},
   1380     {1 << 9, FX_CHARSET_Default},
   1381     {1 << 10, FX_CHARSET_Default},
   1382     {1 << 11, FX_CHARSET_Default},
   1383     {1 << 12, FX_CHARSET_Default},
   1384     {1 << 13, FX_CHARSET_Default},
   1385     {1 << 14, FX_CHARSET_OEM},
   1386     {1 << 15, FX_CHARSET_Symbol},
   1387 };
   1388 FX_BIT2CHARSET g_FX_Bit2Charset3[16] = {
   1389     {1 << 0, FX_CHARSET_Default},  {1 << 1, FX_CHARSET_Default},
   1390     {1 << 2, FX_CHARSET_Default},  {1 << 3, FX_CHARSET_Default},
   1391     {1 << 4, FX_CHARSET_Default},  {1 << 5, FX_CHARSET_Default},
   1392     {1 << 6, FX_CHARSET_Default},  {1 << 7, FX_CHARSET_Default},
   1393     {1 << 8, FX_CHARSET_Default},  {1 << 9, FX_CHARSET_Default},
   1394     {1 << 10, FX_CHARSET_Default}, {1 << 11, FX_CHARSET_Default},
   1395     {1 << 12, FX_CHARSET_Default}, {1 << 13, FX_CHARSET_Default},
   1396     {1 << 14, FX_CHARSET_Default}, {1 << 15, FX_CHARSET_Default},
   1397 };
   1398 FX_BIT2CHARSET g_FX_Bit2Charset4[16] = {
   1399     {1 << 0, FX_CHARSET_Default},  {1 << 1, FX_CHARSET_Default},
   1400     {1 << 2, FX_CHARSET_Default},  {1 << 3, FX_CHARSET_Default},
   1401     {1 << 4, FX_CHARSET_Default},  {1 << 5, FX_CHARSET_Default},
   1402     {1 << 6, FX_CHARSET_Default},  {1 << 7, FX_CHARSET_Default},
   1403     {1 << 8, FX_CHARSET_Default},  {1 << 9, FX_CHARSET_Default},
   1404     {1 << 10, FX_CHARSET_Default}, {1 << 11, FX_CHARSET_Default},
   1405     {1 << 12, FX_CHARSET_Default}, {1 << 13, FX_CHARSET_Default},
   1406     {1 << 14, FX_CHARSET_Default}, {1 << 15, FX_CHARSET_US},
   1407 };
   1408 #define CODEPAGERANGE_IMPLEMENT(n)                   \
   1409   for (int32_t i = 0; i < 16; i++) {                 \
   1410     if ((a##n & g_FX_Bit2Charset##n[i].wBit) != 0) { \
   1411       Charsets.Add(g_FX_Bit2Charset##n[i].wCharset); \
   1412     }                                                \
   1413   }
   1414 void CFX_FontMgrImp::GetCharsets(FXFT_Face pFace, CFX_WordArray& Charsets) {
   1415   Charsets.RemoveAll();
   1416   TT_OS2* pOS2 = (TT_OS2*)FT_Get_Sfnt_Table(pFace, ft_sfnt_os2);
   1417   if (NULL != pOS2) {
   1418     FX_WORD a1, a2, a3, a4;
   1419     a1 = pOS2->ulCodePageRange1 & 0x0000ffff;
   1420     CODEPAGERANGE_IMPLEMENT(1);
   1421     a2 = (pOS2->ulCodePageRange1 >> 16) & 0x0000ffff;
   1422     CODEPAGERANGE_IMPLEMENT(2);
   1423     a3 = pOS2->ulCodePageRange2 & 0x0000ffff;
   1424     CODEPAGERANGE_IMPLEMENT(3);
   1425     a4 = (pOS2->ulCodePageRange2 >> 16) & 0x0000ffff;
   1426     CODEPAGERANGE_IMPLEMENT(4);
   1427   } else {
   1428     Charsets.Add(FX_CHARSET_Default);
   1429   }
   1430 }
   1431 #undef CODEPAGERANGE_IMPLEMENT
   1432 void CFX_FontMgrImp::GetUSBCSB(FXFT_Face pFace, FX_DWORD* USB, FX_DWORD* CSB) {
   1433   TT_OS2* pOS2 = (TT_OS2*)FT_Get_Sfnt_Table(pFace, ft_sfnt_os2);
   1434   if (NULL != pOS2) {
   1435     USB[0] = pOS2->ulUnicodeRange1;
   1436     USB[1] = pOS2->ulUnicodeRange2;
   1437     USB[2] = pOS2->ulUnicodeRange3;
   1438     USB[3] = pOS2->ulUnicodeRange4;
   1439     CSB[0] = pOS2->ulCodePageRange1;
   1440     CSB[1] = pOS2->ulCodePageRange2;
   1441   } else {
   1442     USB[0] = 0;
   1443     USB[1] = 0;
   1444     USB[2] = 0;
   1445     USB[3] = 0;
   1446     CSB[0] = 0;
   1447     CSB[1] = 0;
   1448   }
   1449 }
   1450 void CFX_FontMgrImp::NormalizeFontName(CFX_WideString& FontName) {
   1451   FontName.MakeLower();
   1452   FontName.Remove(' ');
   1453   FontName.Remove('-');
   1454 }
   1455 int32_t CFX_FontMgrImp::IsPartName(const CFX_WideString& Name1,
   1456                                    const CFX_WideString& Name2) {
   1457   if (Name1.Find((const FX_WCHAR*)Name2) != -1) {
   1458     return 1;
   1459   }
   1460   return 0;
   1461 }
   1462 #endif
   1463