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