Home | History | Annotate | Download | only in android
      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 "core/include/fxcrt/fx_ext.h"
      8 #include "fx_fpf.h"
      9 
     10 #if _FX_OS_ == _FX_ANDROID_
     11 #define FPF_SKIAMATCHWEIGHT_NAME1 62
     12 #define FPF_SKIAMATCHWEIGHT_NAME2 60
     13 #define FPF_SKIAMATCHWEIGHT_1 16
     14 #define FPF_SKIAMATCHWEIGHT_2 8
     15 #include "fpf_skiafontmgr.h"
     16 #include "fpf_skiafont.h"
     17 #ifdef __cplusplus
     18 extern "C" {
     19 #endif
     20 static unsigned long FPF_SkiaStream_Read(FXFT_Stream stream,
     21                                          unsigned long offset,
     22                                          unsigned char* buffer,
     23                                          unsigned long count) {
     24   IFX_FileRead* pFileRead = (IFX_FileRead*)stream->descriptor.pointer;
     25   if (!pFileRead) {
     26     return 0;
     27   }
     28   if (count > 0) {
     29     if (pFileRead->ReadBlock(buffer, (FX_FILESIZE)offset, (size_t)count) !=
     30         count) {
     31       return 0;
     32     }
     33   }
     34   return count;
     35 }
     36 static void FPF_SkiaStream_Close(FXFT_Stream stream) {}
     37 #ifdef __cplusplus
     38 };
     39 #endif
     40 typedef struct _FPF_SKIAFONTMAP {
     41   FX_DWORD dwFamily;
     42   FX_DWORD dwSubSt;
     43 } FPF_SKIAFONTMAP, *FPF_LPSKIAFONTMAP;
     44 typedef FPF_SKIAFONTMAP const* FPF_LPCSKIAFONTMAP;
     45 static const FPF_SKIAFONTMAP g_SkiaFontmap[] = {
     46     {0x58c5083, 0xc8d2e345},  {0x5dfade2, 0xe1633081},
     47     {0x684317d, 0xe1633081},  {0x14ee2d13, 0xc8d2e345},
     48     {0x3918fe2d, 0xbbeeec72}, {0x3b98b31c, 0xe1633081},
     49     {0x3d49f40e, 0xe1633081}, {0x432c41c5, 0xe1633081},
     50     {0x491b6ad0, 0xe1633081}, {0x5612cab1, 0x59b9f8f1},
     51     {0x779ce19d, 0xc8d2e345}, {0x7cc9510b, 0x59b9f8f1},
     52     {0x83746053, 0xbbeeec72}, {0xaaa60c03, 0xbbeeec72},
     53     {0xbf85ff26, 0xe1633081}, {0xc04fe601, 0xbbeeec72},
     54     {0xca3812d5, 0x59b9f8f1}, {0xca383e15, 0x59b9f8f1},
     55     {0xcad5eaf6, 0x59b9f8f1}, {0xcb7a04c8, 0xc8d2e345},
     56     {0xfb4ce0de, 0xe1633081},
     57 };
     58 FX_DWORD FPF_SkiaGetSubstFont(FX_DWORD dwHash) {
     59   int32_t iStart = 0;
     60   int32_t iEnd = sizeof(g_SkiaFontmap) / sizeof(FPF_SKIAFONTMAP);
     61   while (iStart <= iEnd) {
     62     int32_t iMid = (iStart + iEnd) / 2;
     63     FPF_LPCSKIAFONTMAP pItem = &g_SkiaFontmap[iMid];
     64     if (dwHash < pItem->dwFamily) {
     65       iEnd = iMid - 1;
     66     } else if (dwHash > pItem->dwFamily) {
     67       iStart = iMid + 1;
     68     } else {
     69       return pItem->dwSubSt;
     70     }
     71   }
     72   return 0;
     73 }
     74 static const FPF_SKIAFONTMAP g_SkiaSansFontMap[] = {
     75     {0x58c5083, 0xd5b8d10f},  {0x14ee2d13, 0xd5b8d10f},
     76     {0x779ce19d, 0xd5b8d10f}, {0xcb7a04c8, 0xd5b8d10f},
     77     {0xfb4ce0de, 0xd5b8d10f},
     78 };
     79 FX_DWORD FPF_SkiaGetSansFont(FX_DWORD dwHash) {
     80   int32_t iStart = 0;
     81   int32_t iEnd = sizeof(g_SkiaSansFontMap) / sizeof(FPF_SKIAFONTMAP);
     82   while (iStart <= iEnd) {
     83     int32_t iMid = (iStart + iEnd) / 2;
     84     FPF_LPCSKIAFONTMAP pItem = &g_SkiaSansFontMap[iMid];
     85     if (dwHash < pItem->dwFamily) {
     86       iEnd = iMid - 1;
     87     } else if (dwHash > pItem->dwFamily) {
     88       iStart = iMid + 1;
     89     } else {
     90       return pItem->dwSubSt;
     91     }
     92   }
     93   return 0;
     94 }
     95 static uint32_t FPF_GetHashCode_StringA(const FX_CHAR* pStr,
     96                                         int32_t iLength,
     97                                         FX_BOOL bIgnoreCase = FALSE) {
     98   if (!pStr) {
     99     return 0;
    100   }
    101   if (iLength < 0) {
    102     iLength = FXSYS_strlen(pStr);
    103   }
    104   const FX_CHAR* pStrEnd = pStr + iLength;
    105   uint32_t uHashCode = 0;
    106   if (bIgnoreCase) {
    107     while (pStr < pStrEnd) {
    108       uHashCode = 31 * uHashCode + FXSYS_tolower(*pStr++);
    109     }
    110   } else {
    111     while (pStr < pStrEnd) {
    112       uHashCode = 31 * uHashCode + *pStr++;
    113     }
    114   }
    115   return uHashCode;
    116 }
    117 enum FPF_SKIACHARSET {
    118   FPF_SKIACHARSET_Ansi = 1 << 0,
    119   FPF_SKIACHARSET_Default = 1 << 1,
    120   FPF_SKIACHARSET_Symbol = 1 << 2,
    121   FPF_SKIACHARSET_ShiftJIS = 1 << 3,
    122   FPF_SKIACHARSET_Korean = 1 << 4,
    123   FPF_SKIACHARSET_Johab = 1 << 5,
    124   FPF_SKIACHARSET_GB2312 = 1 << 6,
    125   FPF_SKIACHARSET_BIG5 = 1 << 7,
    126   FPF_SKIACHARSET_Greek = 1 << 8,
    127   FPF_SKIACHARSET_Turkish = 1 << 9,
    128   FPF_SKIACHARSET_Vietnamese = 1 << 10,
    129   FPF_SKIACHARSET_Hebrew = 1 << 11,
    130   FPF_SKIACHARSET_Arabic = 1 << 12,
    131   FPF_SKIACHARSET_Baltic = 1 << 13,
    132   FPF_SKIACHARSET_Cyrillic = 1 << 14,
    133   FPF_SKIACHARSET_Thai = 1 << 15,
    134   FPF_SKIACHARSET_EeasternEuropean = 1 << 16,
    135   FPF_SKIACHARSET_PC = 1 << 17,
    136   FPF_SKIACHARSET_OEM = 1 << 18,
    137 };
    138 static FX_DWORD FPF_SkiaGetCharset(uint8_t uCharset) {
    139   switch (uCharset) {
    140     case FXFONT_ANSI_CHARSET:
    141       return FPF_SKIACHARSET_Ansi;
    142     case FXFONT_DEFAULT_CHARSET:
    143       return FPF_SKIACHARSET_Default;
    144     case FXFONT_SYMBOL_CHARSET:
    145       return FPF_SKIACHARSET_Symbol;
    146     case FXFONT_SHIFTJIS_CHARSET:
    147       return FPF_SKIACHARSET_ShiftJIS;
    148     case FXFONT_HANGEUL_CHARSET:
    149       return FPF_SKIACHARSET_Korean;
    150     case FXFONT_GB2312_CHARSET:
    151       return FPF_SKIACHARSET_GB2312;
    152     case FXFONT_CHINESEBIG5_CHARSET:
    153       return FPF_SKIACHARSET_BIG5;
    154     case FXFONT_GREEK_CHARSET:
    155       return FPF_SKIACHARSET_Greek;
    156     case FXFONT_TURKISH_CHARSET:
    157       return FPF_SKIACHARSET_Turkish;
    158     case FXFONT_HEBREW_CHARSET:
    159       return FPF_SKIACHARSET_Hebrew;
    160     case FXFONT_ARABIC_CHARSET:
    161       return FPF_SKIACHARSET_Arabic;
    162     case FXFONT_BALTIC_CHARSET:
    163       return FPF_SKIACHARSET_Baltic;
    164     case FXFONT_RUSSIAN_CHARSET:
    165       return FPF_SKIACHARSET_Cyrillic;
    166     case FXFONT_THAI_CHARSET:
    167       return FPF_SKIACHARSET_Thai;
    168     case FXFONT_EASTEUROPE_CHARSET:
    169       return FPF_SKIACHARSET_EeasternEuropean;
    170   }
    171   return FPF_SKIACHARSET_Default;
    172 }
    173 static FX_DWORD FPF_SKIANormalizeFontName(const CFX_ByteStringC& bsfamily) {
    174   FX_DWORD dwHash = 0;
    175   int32_t iLength = bsfamily.GetLength();
    176   const FX_CHAR* pBuffer = bsfamily.GetCStr();
    177   for (int32_t i = 0; i < iLength; i++) {
    178     FX_CHAR ch = pBuffer[i];
    179     if (ch == ' ' || ch == '-' || ch == ',') {
    180       continue;
    181     }
    182     dwHash = 31 * dwHash + FXSYS_tolower(ch);
    183   }
    184   return dwHash;
    185 }
    186 static FX_DWORD FPF_SKIAGetFamilyHash(const CFX_ByteStringC& bsFamily,
    187                                       FX_DWORD dwStyle,
    188                                       uint8_t uCharset) {
    189   CFX_ByteString bsFont(bsFamily);
    190   if (dwStyle & FXFONT_BOLD) {
    191     bsFont += "Bold";
    192   }
    193   if (dwStyle & FXFONT_ITALIC) {
    194     bsFont += "Italic";
    195   }
    196   if (dwStyle & FXFONT_SERIF) {
    197     bsFont += "Serif";
    198   }
    199   bsFont += uCharset;
    200   return FPF_GetHashCode_StringA(bsFont.c_str(), bsFont.GetLength(), TRUE);
    201 }
    202 static FX_BOOL FPF_SkiaIsCJK(uint8_t uCharset) {
    203   return (uCharset == FXFONT_GB2312_CHARSET) ||
    204          (uCharset == FXFONT_CHINESEBIG5_CHARSET) ||
    205          (uCharset == FXFONT_HANGEUL_CHARSET) ||
    206          (uCharset == FXFONT_SHIFTJIS_CHARSET);
    207 }
    208 static FX_BOOL FPF_SkiaMaybeSymbol(const CFX_ByteStringC& bsFacename) {
    209   CFX_ByteString bsName = bsFacename;
    210   bsName.MakeLower();
    211   return bsName.Find("symbol") > -1;
    212 }
    213 static FX_BOOL FPF_SkiaMaybeArabic(const CFX_ByteStringC& bsFacename) {
    214   CFX_ByteString bsName = bsFacename;
    215   bsName.MakeLower();
    216   return bsName.Find("arabic") > -1;
    217 }
    218 CFPF_SkiaFontMgr::CFPF_SkiaFontMgr() : m_bLoaded(FALSE), m_FTLibrary(NULL) {}
    219 CFPF_SkiaFontMgr::~CFPF_SkiaFontMgr() {
    220   void* pkey = NULL;
    221   CFPF_SkiaFont* pValue = NULL;
    222   FX_POSITION pos = m_FamilyFonts.GetStartPosition();
    223   while (pos) {
    224     m_FamilyFonts.GetNextAssoc(pos, pkey, (void*&)pValue);
    225     if (pValue) {
    226       pValue->Release();
    227     }
    228   }
    229   m_FamilyFonts.RemoveAll();
    230   for (int32_t i = m_FontFaces.GetUpperBound(); i >= 0; i--) {
    231     CFPF_SkiaFontDescriptor* pFont =
    232         (CFPF_SkiaFontDescriptor*)m_FontFaces.ElementAt(i);
    233     delete pFont;
    234   }
    235   m_FontFaces.RemoveAll();
    236   if (m_FTLibrary) {
    237     FXFT_Done_FreeType(m_FTLibrary);
    238   }
    239 }
    240 FX_BOOL CFPF_SkiaFontMgr::InitFTLibrary() {
    241   if (!m_FTLibrary) {
    242     FXFT_Init_FreeType(&m_FTLibrary);
    243   }
    244   return m_FTLibrary != NULL;
    245 }
    246 void CFPF_SkiaFontMgr::LoadSystemFonts() {
    247   if (m_bLoaded) {
    248     return;
    249   }
    250   ScanPath("/system/fonts");
    251   OutputSystemFonts();
    252   m_bLoaded = TRUE;
    253 }
    254 void CFPF_SkiaFontMgr::LoadPrivateFont(IFX_FileRead* pFontFile) {}
    255 void CFPF_SkiaFontMgr::LoadPrivateFont(const CFX_ByteStringC& bsFileName) {}
    256 void CFPF_SkiaFontMgr::LoadPrivateFont(void* pBuffer, size_t szBuffer) {}
    257 IFPF_Font* CFPF_SkiaFontMgr::CreateFont(const CFX_ByteStringC& bsFamilyname,
    258                                         uint8_t uCharset,
    259                                         FX_DWORD dwStyle,
    260                                         FX_DWORD dwMatch) {
    261   FX_DWORD dwHash = FPF_SKIAGetFamilyHash(bsFamilyname, dwStyle, uCharset);
    262   IFPF_Font* pFont = NULL;
    263   if (m_FamilyFonts.Lookup((void*)(uintptr_t)dwHash, (void*&)pFont)) {
    264     if (pFont) {
    265       return pFont->Retain();
    266     }
    267   }
    268   FX_DWORD dwFaceName = FPF_SKIANormalizeFontName(bsFamilyname);
    269   FX_DWORD dwSubst = FPF_SkiaGetSubstFont(dwFaceName);
    270   FX_DWORD dwSubstSans = FPF_SkiaGetSansFont(dwFaceName);
    271   FX_BOOL bMaybeSymbol = FPF_SkiaMaybeSymbol(bsFamilyname);
    272   if (uCharset != FXFONT_ARABIC_CHARSET && FPF_SkiaMaybeArabic(bsFamilyname)) {
    273     uCharset = FXFONT_ARABIC_CHARSET;
    274   } else if (uCharset == FXFONT_ANSI_CHARSET &&
    275              (dwMatch & FPF_MATCHFONT_REPLACEANSI)) {
    276     uCharset = FXFONT_DEFAULT_CHARSET;
    277   }
    278   int32_t nExpectVal = FPF_SKIAMATCHWEIGHT_NAME1 + FPF_SKIAMATCHWEIGHT_1 * 3 +
    279                        FPF_SKIAMATCHWEIGHT_2 * 2;
    280   int32_t nItem = -1;
    281   int32_t nMax = -1;
    282   int32_t nGlyphNum = 0;
    283   for (int32_t i = m_FontFaces.GetUpperBound(); i >= 0; i--) {
    284     CFPF_SkiaPathFont* pFontDes = (CFPF_SkiaPathFont*)m_FontFaces.ElementAt(i);
    285     if (!(pFontDes->m_dwCharsets & FPF_SkiaGetCharset(uCharset))) {
    286       continue;
    287     }
    288     int32_t nFind = 0;
    289     FX_DWORD dwSysFontName = FPF_SKIANormalizeFontName(pFontDes->m_pFamily);
    290     if (dwFaceName == dwSysFontName) {
    291       nFind += FPF_SKIAMATCHWEIGHT_NAME1;
    292     }
    293     FX_BOOL bMatchedName = (nFind == FPF_SKIAMATCHWEIGHT_NAME1);
    294     if ((dwStyle & FXFONT_BOLD) == (pFontDes->m_dwStyle & FXFONT_BOLD)) {
    295       nFind += FPF_SKIAMATCHWEIGHT_1;
    296     }
    297     if ((dwStyle & FXFONT_ITALIC) == (pFontDes->m_dwStyle & FXFONT_ITALIC)) {
    298       nFind += FPF_SKIAMATCHWEIGHT_1;
    299     }
    300     if ((dwStyle & FXFONT_FIXED_PITCH) ==
    301         (pFontDes->m_dwStyle & FXFONT_FIXED_PITCH)) {
    302       nFind += FPF_SKIAMATCHWEIGHT_2;
    303     }
    304     if ((dwStyle & FXFONT_SERIF) == (pFontDes->m_dwStyle & FXFONT_SERIF)) {
    305       nFind += FPF_SKIAMATCHWEIGHT_1;
    306     }
    307     if ((dwStyle & FXFONT_SCRIPT) == (pFontDes->m_dwStyle & FXFONT_SCRIPT)) {
    308       nFind += FPF_SKIAMATCHWEIGHT_2;
    309     }
    310     if (dwSubst == dwSysFontName || dwSubstSans == dwSysFontName) {
    311       nFind += FPF_SKIAMATCHWEIGHT_NAME2;
    312       bMatchedName = TRUE;
    313     }
    314     if (uCharset == FXFONT_DEFAULT_CHARSET || bMaybeSymbol) {
    315       if (nFind > nMax && bMatchedName) {
    316         nMax = nFind;
    317         nItem = i;
    318       }
    319     } else if (FPF_SkiaIsCJK(uCharset)) {
    320       if (bMatchedName || pFontDes->m_iGlyphNum > nGlyphNum) {
    321         nItem = i;
    322         nGlyphNum = pFontDes->m_iGlyphNum;
    323       }
    324     } else if (nFind > nMax) {
    325       nMax = nFind;
    326       nItem = i;
    327     }
    328     if (nExpectVal <= nFind) {
    329       nItem = i;
    330       break;
    331     }
    332   }
    333   if (nItem > -1) {
    334     CFPF_SkiaFontDescriptor* pFontDes =
    335         (CFPF_SkiaFontDescriptor*)m_FontFaces.ElementAt(nItem);
    336     CFPF_SkiaFont* pFont = new CFPF_SkiaFont;
    337     if (pFont->InitFont(this, pFontDes, bsFamilyname, dwStyle, uCharset)) {
    338       m_FamilyFonts.SetAt((void*)(uintptr_t)dwHash, (void*)pFont);
    339       return pFont->Retain();
    340     }
    341     pFont->Release();
    342   }
    343   return NULL;
    344 }
    345 FXFT_Face CFPF_SkiaFontMgr::GetFontFace(IFX_FileRead* pFileRead,
    346                                         int32_t iFaceIndex) {
    347   if (!pFileRead) {
    348     return NULL;
    349   }
    350   if (pFileRead->GetSize() == 0) {
    351     return NULL;
    352   }
    353   if (iFaceIndex < 0) {
    354     return NULL;
    355   }
    356   FXFT_StreamRec streamRec;
    357   FXSYS_memset(&streamRec, 0, sizeof(FXFT_StreamRec));
    358   streamRec.size = pFileRead->GetSize();
    359   streamRec.descriptor.pointer = pFileRead;
    360   streamRec.read = FPF_SkiaStream_Read;
    361   streamRec.close = FPF_SkiaStream_Close;
    362   FXFT_Open_Args args;
    363   args.flags = FT_OPEN_STREAM;
    364   args.stream = &streamRec;
    365   FXFT_Face face;
    366   if (FXFT_Open_Face(m_FTLibrary, &args, iFaceIndex, &face)) {
    367     return NULL;
    368   }
    369   FXFT_Set_Pixel_Sizes(face, 0, 64);
    370   return face;
    371 }
    372 FXFT_Face CFPF_SkiaFontMgr::GetFontFace(const CFX_ByteStringC& bsFile,
    373                                         int32_t iFaceIndex) {
    374   if (bsFile.IsEmpty()) {
    375     return NULL;
    376   }
    377   if (iFaceIndex < 0) {
    378     return NULL;
    379   }
    380   FXFT_Open_Args args;
    381   args.flags = FT_OPEN_PATHNAME;
    382   args.pathname = (FT_String*)bsFile.GetCStr();
    383   FXFT_Face face;
    384   if (FXFT_Open_Face(m_FTLibrary, &args, iFaceIndex, &face)) {
    385     return FALSE;
    386   }
    387   FXFT_Set_Pixel_Sizes(face, 0, 64);
    388   return face;
    389 }
    390 FXFT_Face CFPF_SkiaFontMgr::GetFontFace(const uint8_t* pBuffer,
    391                                         size_t szBuffer,
    392                                         int32_t iFaceIndex) {
    393   if (!pBuffer || szBuffer < 1) {
    394     return NULL;
    395   }
    396   if (iFaceIndex < 0) {
    397     return NULL;
    398   }
    399   FXFT_Open_Args args;
    400   args.flags = FT_OPEN_MEMORY;
    401   args.memory_base = pBuffer;
    402   args.memory_size = szBuffer;
    403   FXFT_Face face;
    404   if (FXFT_Open_Face(m_FTLibrary, &args, iFaceIndex, &face)) {
    405     return FALSE;
    406   }
    407   FXFT_Set_Pixel_Sizes(face, 0, 64);
    408   return face;
    409 }
    410 void CFPF_SkiaFontMgr::ScanPath(const CFX_ByteStringC& path) {
    411   void* handle = FX_OpenFolder(path.GetCStr());
    412   if (!handle) {
    413     return;
    414   }
    415   CFX_ByteString filename;
    416   FX_BOOL bFolder = FALSE;
    417   while (FX_GetNextFile(handle, filename, bFolder)) {
    418     if (bFolder) {
    419       if (filename == "." || filename == "..") {
    420         continue;
    421       }
    422     } else {
    423       CFX_ByteString ext = filename.Right(4);
    424       ext.MakeLower();
    425       if (ext != ".ttf" && ext != ".ttc" && ext != ".otf") {
    426         continue;
    427       }
    428     }
    429     CFX_ByteString fullpath = path;
    430     fullpath += "/";
    431     fullpath += filename;
    432     if (bFolder) {
    433       ScanPath(fullpath);
    434     } else {
    435       ScanFile(fullpath);
    436     }
    437   }
    438   FX_CloseFolder(handle);
    439 }
    440 void CFPF_SkiaFontMgr::ScanFile(const CFX_ByteStringC& file) {
    441   FXFT_Face face = GetFontFace(file);
    442   if (face) {
    443     CFPF_SkiaPathFont* pFontDesc = new CFPF_SkiaPathFont;
    444     pFontDesc->SetPath(file.GetCStr());
    445     ReportFace(face, pFontDesc);
    446     m_FontFaces.Add(pFontDesc);
    447     FXFT_Done_Face(face);
    448   }
    449 }
    450 static const FX_DWORD g_FPFSkiaFontCharsets[] = {
    451     FPF_SKIACHARSET_Ansi,
    452     FPF_SKIACHARSET_EeasternEuropean,
    453     FPF_SKIACHARSET_Cyrillic,
    454     FPF_SKIACHARSET_Greek,
    455     FPF_SKIACHARSET_Turkish,
    456     FPF_SKIACHARSET_Hebrew,
    457     FPF_SKIACHARSET_Arabic,
    458     FPF_SKIACHARSET_Baltic,
    459     0,
    460     0,
    461     0,
    462     0,
    463     0,
    464     0,
    465     0,
    466     0,
    467     FPF_SKIACHARSET_Thai,
    468     FPF_SKIACHARSET_ShiftJIS,
    469     FPF_SKIACHARSET_GB2312,
    470     FPF_SKIACHARSET_Korean,
    471     FPF_SKIACHARSET_BIG5,
    472     FPF_SKIACHARSET_Johab,
    473     0,
    474     0,
    475     0,
    476     0,
    477     0,
    478     0,
    479     0,
    480     0,
    481     FPF_SKIACHARSET_OEM,
    482     FPF_SKIACHARSET_Symbol,
    483 };
    484 static FX_DWORD FPF_SkiaGetFaceCharset(TT_OS2* pOS2) {
    485   FX_DWORD dwCharset = 0;
    486   if (pOS2) {
    487     for (int32_t i = 0; i < 32; i++) {
    488       if (pOS2->ulCodePageRange1 & (1 << i)) {
    489         dwCharset |= g_FPFSkiaFontCharsets[i];
    490       }
    491     }
    492   }
    493   dwCharset |= FPF_SKIACHARSET_Default;
    494   return dwCharset;
    495 }
    496 void CFPF_SkiaFontMgr::ReportFace(FXFT_Face face,
    497                                   CFPF_SkiaFontDescriptor* pFontDesc) {
    498   if (!face || !pFontDesc) {
    499     return;
    500   }
    501   pFontDesc->SetFamily(FXFT_Get_Face_Family_Name(face));
    502   if (FXFT_Is_Face_Bold(face)) {
    503     pFontDesc->m_dwStyle |= FXFONT_BOLD;
    504   }
    505   if (FXFT_Is_Face_Italic(face)) {
    506     pFontDesc->m_dwStyle |= FXFONT_ITALIC;
    507   }
    508   if (FT_IS_FIXED_WIDTH(face)) {
    509     pFontDesc->m_dwStyle |= FXFONT_FIXED_PITCH;
    510   }
    511   TT_OS2* pOS2 = (TT_OS2*)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
    512   if (pOS2) {
    513     if (pOS2->ulCodePageRange1 & (1 << 31)) {
    514       pFontDesc->m_dwStyle |= FXFONT_SYMBOLIC;
    515     }
    516     if (pOS2->panose[0] == 2) {
    517       uint8_t uSerif = pOS2->panose[1];
    518       if ((uSerif > 1 && uSerif < 10) || uSerif > 13) {
    519         pFontDesc->m_dwStyle |= FXFONT_SERIF;
    520       }
    521     }
    522   }
    523   if (pOS2 && (pOS2->ulCodePageRange1 & (1 << 31))) {
    524     pFontDesc->m_dwStyle |= FXFONT_SYMBOLIC;
    525   }
    526   pFontDesc->m_dwCharsets = FPF_SkiaGetFaceCharset(pOS2);
    527   pFontDesc->m_iFaceIndex = face->face_index;
    528   pFontDesc->m_iGlyphNum = face->num_glyphs;
    529 }
    530 void CFPF_SkiaFontMgr::OutputSystemFonts() {}
    531 #endif
    532