1 // Copyright 2016 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/fxge/android/cfpf_skiafontmgr.h"
8 
9 #include <algorithm>
10 #include <utility>
11 
12 #include "core/fxcrt/fx_codepage.h"
13 #include "core/fxcrt/fx_extension.h"
14 #include "core/fxcrt/fx_memory.h"
15 #include "core/fxcrt/fx_stream.h"
16 #include "core/fxcrt/fx_system.h"
17 #include "core/fxge/android/cfpf_skiafont.h"
18 #include "core/fxge/android/cfpf_skiapathfont.h"
19 #include "core/fxge/fx_font.h"
20 #include "core/fxge/fx_freetype.h"
21 #include "third_party/base/ptr_util.h"
22 
23 namespace {
24 
25 constexpr int FPF_SKIAMATCHWEIGHT_NAME1 = 62;
26 constexpr int FPF_SKIAMATCHWEIGHT_NAME2 = 60;
27 constexpr int FPF_SKIAMATCHWEIGHT_1 = 16;
28 constexpr int FPF_SKIAMATCHWEIGHT_2 = 8;
29 
30 struct FPF_SKIAFONTMAP {
31   uint32_t dwFamily;
32   uint32_t dwSubSt;
33 };
34 
35 const FPF_SKIAFONTMAP g_SkiaFontmap[] = {
36     {0x58c5083, 0xc8d2e345},  {0x5dfade2, 0xe1633081},
37     {0x684317d, 0xe1633081},  {0x14ee2d13, 0xc8d2e345},
38     {0x3918fe2d, 0xbbeeec72}, {0x3b98b31c, 0xe1633081},
39     {0x3d49f40e, 0xe1633081}, {0x432c41c5, 0xe1633081},
40     {0x491b6ad0, 0xe1633081}, {0x5612cab1, 0x59b9f8f1},
41     {0x779ce19d, 0xc8d2e345}, {0x7cc9510b, 0x59b9f8f1},
42     {0x83746053, 0xbbeeec72}, {0xaaa60c03, 0xbbeeec72},
43     {0xbf85ff26, 0xe1633081}, {0xc04fe601, 0xbbeeec72},
44     {0xca3812d5, 0x59b9f8f1}, {0xca383e15, 0x59b9f8f1},
45     {0xcad5eaf6, 0x59b9f8f1}, {0xcb7a04c8, 0xc8d2e345},
46     {0xfb4ce0de, 0xe1633081},
47 };
48 
49 const FPF_SKIAFONTMAP g_SkiaSansFontMap[] = {
50     {0x58c5083, 0xd5b8d10f},  {0x14ee2d13, 0xd5b8d10f},
51     {0x779ce19d, 0xd5b8d10f}, {0xcb7a04c8, 0xd5b8d10f},
52     {0xfb4ce0de, 0xd5b8d10f},
53 };
54 
FPF_SkiaGetSubstFont(uint32_t dwHash,const FPF_SKIAFONTMAP * skFontMap,size_t length)55 uint32_t FPF_SkiaGetSubstFont(uint32_t dwHash,
56                               const FPF_SKIAFONTMAP* skFontMap,
57                               size_t length) {
58   const FPF_SKIAFONTMAP* pEnd = skFontMap + length;
59   const FPF_SKIAFONTMAP* pFontMap = std::lower_bound(
60       skFontMap, pEnd, dwHash, [](const FPF_SKIAFONTMAP& item, uint32_t hash) {
61         return item.dwFamily < hash;
62       });
63   if (pFontMap < pEnd && pFontMap->dwFamily == dwHash)
64     return pFontMap->dwSubSt;
65   return 0;
66 }
67 
FPF_GetHashCode_StringA(const char * pStr,int32_t iLength)68 uint32_t FPF_GetHashCode_StringA(const char* pStr, int32_t iLength) {
69   if (!pStr)
70     return 0;
71   if (iLength < 0)
72     iLength = strlen(pStr);
73   const char* pStrEnd = pStr + iLength;
74   uint32_t uHashCode = 0;
75   while (pStr < pStrEnd)
76     uHashCode = 31 * uHashCode + tolower(*pStr++);
77   return uHashCode;
78 }
79 
80 enum FPF_SKIACHARSET {
81   FPF_SKIACHARSET_Ansi = 1 << 0,
82   FPF_SKIACHARSET_Default = 1 << 1,
83   FPF_SKIACHARSET_Symbol = 1 << 2,
84   FPF_SKIACHARSET_ShiftJIS = 1 << 3,
85   FPF_SKIACHARSET_Korean = 1 << 4,
86   FPF_SKIACHARSET_Johab = 1 << 5,
87   FPF_SKIACHARSET_GB2312 = 1 << 6,
88   FPF_SKIACHARSET_BIG5 = 1 << 7,
89   FPF_SKIACHARSET_Greek = 1 << 8,
90   FPF_SKIACHARSET_Turkish = 1 << 9,
91   FPF_SKIACHARSET_Vietnamese = 1 << 10,
92   FPF_SKIACHARSET_Hebrew = 1 << 11,
93   FPF_SKIACHARSET_Arabic = 1 << 12,
94   FPF_SKIACHARSET_Baltic = 1 << 13,
95   FPF_SKIACHARSET_Cyrillic = 1 << 14,
96   FPF_SKIACHARSET_Thai = 1 << 15,
97   FPF_SKIACHARSET_EeasternEuropean = 1 << 16,
98   FPF_SKIACHARSET_PC = 1 << 17,
99   FPF_SKIACHARSET_OEM = 1 << 18,
100 };
101 
FPF_SkiaGetCharset(uint8_t uCharset)102 uint32_t FPF_SkiaGetCharset(uint8_t uCharset) {
103   switch (uCharset) {
104     case FX_CHARSET_ANSI:
105       return FPF_SKIACHARSET_Ansi;
106     case FX_CHARSET_Default:
107       return FPF_SKIACHARSET_Default;
108     case FX_CHARSET_Symbol:
109       return FPF_SKIACHARSET_Symbol;
110     case FX_CHARSET_ShiftJIS:
111       return FPF_SKIACHARSET_ShiftJIS;
112     case FX_CHARSET_Hangul:
113       return FPF_SKIACHARSET_Korean;
114     case FX_CHARSET_ChineseSimplified:
115       return FPF_SKIACHARSET_GB2312;
116     case FX_CHARSET_ChineseTraditional:
117       return FPF_SKIACHARSET_BIG5;
118     case FX_CHARSET_MSWin_Greek:
119       return FPF_SKIACHARSET_Greek;
120     case FX_CHARSET_MSWin_Turkish:
121       return FPF_SKIACHARSET_Turkish;
122     case FX_CHARSET_MSWin_Hebrew:
123       return FPF_SKIACHARSET_Hebrew;
124     case FX_CHARSET_MSWin_Arabic:
125       return FPF_SKIACHARSET_Arabic;
126     case FX_CHARSET_MSWin_Baltic:
127       return FPF_SKIACHARSET_Baltic;
128     case FX_CHARSET_MSWin_Cyrillic:
129       return FPF_SKIACHARSET_Cyrillic;
130     case FX_CHARSET_Thai:
131       return FPF_SKIACHARSET_Thai;
132     case FX_CHARSET_MSWin_EasternEuropean:
133       return FPF_SKIACHARSET_EeasternEuropean;
134   }
135   return FPF_SKIACHARSET_Default;
136 }
137 
FPF_SKIANormalizeFontName(ByteStringView bsfamily)138 uint32_t FPF_SKIANormalizeFontName(ByteStringView bsfamily) {
139   uint32_t dwHash = 0;
140   int32_t iLength = bsfamily.GetLength();
141   const char* pBuffer = bsfamily.unterminated_c_str();
142   for (int32_t i = 0; i < iLength; i++) {
143     char ch = pBuffer[i];
144     if (ch == ' ' || ch == '-' || ch == ',')
145       continue;
146     dwHash = 31 * dwHash + tolower(ch);
147   }
148   return dwHash;
149 }
150 
FPF_SKIAGetFamilyHash(ByteStringView bsFamily,uint32_t dwStyle,uint8_t uCharset)151 uint32_t FPF_SKIAGetFamilyHash(ByteStringView bsFamily,
152                                uint32_t dwStyle,
153                                uint8_t uCharset) {
154   ByteString bsFont(bsFamily);
155   if (FontStyleIsForceBold(dwStyle))
156     bsFont += "Bold";
157   if (FontStyleIsItalic(dwStyle))
158     bsFont += "Italic";
159   if (FontStyleIsSerif(dwStyle))
160     bsFont += "Serif";
161   bsFont += uCharset;
162   return FPF_GetHashCode_StringA(bsFont.c_str(), bsFont.GetLength());
163 }
164 
FPF_SkiaIsCJK(uint8_t uCharset)165 bool FPF_SkiaIsCJK(uint8_t uCharset) {
166   return FX_CharSetIsCJK(uCharset);
167 }
168 
FPF_SkiaMaybeSymbol(ByteStringView bsFacename)169 bool FPF_SkiaMaybeSymbol(ByteStringView bsFacename) {
170   ByteString bsName(bsFacename);
171   bsName.MakeLower();
172   return bsName.Contains("symbol");
173 }
174 
FPF_SkiaMaybeArabic(ByteStringView bsFacename)175 bool FPF_SkiaMaybeArabic(ByteStringView bsFacename) {
176   ByteString bsName(bsFacename);
177   bsName.MakeLower();
178   return bsName.Contains("arabic");
179 }
180 
181 const uint32_t g_FPFSkiaFontCharsets[] = {
182     FPF_SKIACHARSET_Ansi,
183     FPF_SKIACHARSET_EeasternEuropean,
184     FPF_SKIACHARSET_Cyrillic,
185     FPF_SKIACHARSET_Greek,
186     FPF_SKIACHARSET_Turkish,
187     FPF_SKIACHARSET_Hebrew,
188     FPF_SKIACHARSET_Arabic,
189     FPF_SKIACHARSET_Baltic,
190     0,
191     0,
192     0,
193     0,
194     0,
195     0,
196     0,
197     0,
198     FPF_SKIACHARSET_Thai,
199     FPF_SKIACHARSET_ShiftJIS,
200     FPF_SKIACHARSET_GB2312,
201     FPF_SKIACHARSET_Korean,
202     FPF_SKIACHARSET_BIG5,
203     FPF_SKIACHARSET_Johab,
204     0,
205     0,
206     0,
207     0,
208     0,
209     0,
210     0,
211     0,
212     FPF_SKIACHARSET_OEM,
213     FPF_SKIACHARSET_Symbol,
214 };
215 
FPF_SkiaGetFaceCharset(TT_OS2 * pOS2)216 uint32_t FPF_SkiaGetFaceCharset(TT_OS2* pOS2) {
217   uint32_t dwCharset = 0;
218   if (pOS2) {
219     for (int32_t i = 0; i < 32; i++) {
220       if (pOS2->ulCodePageRange1 & (1 << i))
221         dwCharset |= g_FPFSkiaFontCharsets[i];
222     }
223   }
224   dwCharset |= FPF_SKIACHARSET_Default;
225   return dwCharset;
226 }
227 
228 }  // namespace
229 
230 CFPF_SkiaFontMgr::CFPF_SkiaFontMgr() = default;
231 
~CFPF_SkiaFontMgr()232 CFPF_SkiaFontMgr::~CFPF_SkiaFontMgr() {
233   m_FamilyFonts.clear();
234   m_FontFaces.clear();
235 }
236 
InitFTLibrary()237 bool CFPF_SkiaFontMgr::InitFTLibrary() {
238   if (m_FTLibrary)
239     return true;
240 
241   FXFT_LibraryRec* pLibrary = nullptr;
242   FT_Init_FreeType(&pLibrary);
243   if (!pLibrary)
244     return false;
245 
246   m_FTLibrary.reset(pLibrary);
247   return true;
248 }
249 
LoadSystemFonts()250 void CFPF_SkiaFontMgr::LoadSystemFonts() {
251   if (m_bLoaded)
252     return;
253   ScanPath("/system/fonts");
254   m_bLoaded = true;
255 }
256 
CreateFont(ByteStringView bsFamilyname,uint8_t uCharset,uint32_t dwStyle)257 CFPF_SkiaFont* CFPF_SkiaFontMgr::CreateFont(ByteStringView bsFamilyname,
258                                             uint8_t uCharset,
259                                             uint32_t dwStyle) {
260   uint32_t dwHash = FPF_SKIAGetFamilyHash(bsFamilyname, dwStyle, uCharset);
261   auto family_iter = m_FamilyFonts.find(dwHash);
262   if (family_iter != m_FamilyFonts.end())
263     return family_iter->second.get();
264 
265   uint32_t dwFaceName = FPF_SKIANormalizeFontName(bsFamilyname);
266   uint32_t dwSubst = FPF_SkiaGetSubstFont(dwFaceName, g_SkiaFontmap,
267                                           FX_ArraySize(g_SkiaFontmap));
268   uint32_t dwSubstSans = FPF_SkiaGetSubstFont(dwFaceName, g_SkiaSansFontMap,
269                                               FX_ArraySize(g_SkiaSansFontMap));
270   bool bMaybeSymbol = FPF_SkiaMaybeSymbol(bsFamilyname);
271   if (uCharset != FX_CHARSET_MSWin_Arabic &&
272       FPF_SkiaMaybeArabic(bsFamilyname)) {
273     uCharset = FX_CHARSET_MSWin_Arabic;
274   } else if (uCharset == FX_CHARSET_ANSI) {
275     uCharset = FX_CHARSET_Default;
276   }
277   int32_t nExpectVal = FPF_SKIAMATCHWEIGHT_NAME1 + FPF_SKIAMATCHWEIGHT_1 * 3 +
278                        FPF_SKIAMATCHWEIGHT_2 * 2;
279   const CFPF_SkiaPathFont* pBestFont = nullptr;
280   int32_t nMax = -1;
281   int32_t nGlyphNum = 0;
282   for (auto face_iter = m_FontFaces.rbegin(); face_iter != m_FontFaces.rend();
283        ++face_iter) {
284     const CFPF_SkiaPathFont* pFont = face_iter->get();
285     if (!(pFont->charsets() & FPF_SkiaGetCharset(uCharset)))
286       continue;
287     int32_t nFind = 0;
288     uint32_t dwSysFontName = FPF_SKIANormalizeFontName(pFont->family());
289     if (dwFaceName == dwSysFontName)
290       nFind += FPF_SKIAMATCHWEIGHT_NAME1;
291     bool bMatchedName = (nFind == FPF_SKIAMATCHWEIGHT_NAME1);
292     if (FontStyleIsForceBold(dwStyle) == FontStyleIsForceBold(pFont->style()))
293       nFind += FPF_SKIAMATCHWEIGHT_1;
294     if (FontStyleIsItalic(dwStyle) == FontStyleIsItalic(pFont->style()))
295       nFind += FPF_SKIAMATCHWEIGHT_1;
296     if (FontStyleIsFixedPitch(dwStyle) ==
297         FontStyleIsFixedPitch(pFont->style())) {
298       nFind += FPF_SKIAMATCHWEIGHT_2;
299     }
300     if (FontStyleIsSerif(dwStyle) == FontStyleIsSerif(pFont->style()))
301       nFind += FPF_SKIAMATCHWEIGHT_1;
302     if (FontStyleIsScript(dwStyle) == FontStyleIsScript(pFont->style()))
303       nFind += FPF_SKIAMATCHWEIGHT_2;
304     if (dwSubst == dwSysFontName || dwSubstSans == dwSysFontName) {
305       nFind += FPF_SKIAMATCHWEIGHT_NAME2;
306       bMatchedName = true;
307     }
308     if (uCharset == FX_CHARSET_Default || bMaybeSymbol) {
309       if (nFind > nMax && bMatchedName) {
310         nMax = nFind;
311         pBestFont = face_iter->get();
312       }
313     } else if (FPF_SkiaIsCJK(uCharset)) {
314       if (bMatchedName || pFont->glyph_num() > nGlyphNum) {
315         pBestFont = face_iter->get();
316         nGlyphNum = pFont->glyph_num();
317       }
318     } else if (nFind > nMax) {
319       nMax = nFind;
320       pBestFont = face_iter->get();
321     }
322     if (nExpectVal <= nFind) {
323       pBestFont = face_iter->get();
324       break;
325     }
326   }
327   if (!pBestFont)
328     return nullptr;
329 
330   auto pFont =
331       pdfium::MakeUnique<CFPF_SkiaFont>(this, pBestFont, dwStyle, uCharset);
332   if (!pFont->IsValid())
333     return nullptr;
334 
335   CFPF_SkiaFont* pRet = pFont.get();
336   m_FamilyFonts[dwHash] = std::move(pFont);
337   return pRet;
338 }
339 
GetFontFace(ByteStringView bsFile,int32_t iFaceIndex)340 RetainPtr<CFX_Face> CFPF_SkiaFontMgr::GetFontFace(ByteStringView bsFile,
341                                                   int32_t iFaceIndex) {
342   if (bsFile.IsEmpty())
343     return nullptr;
344 
345   if (iFaceIndex < 0)
346     return nullptr;
347 
348   FT_Open_Args args;
349   args.flags = FT_OPEN_PATHNAME;
350   args.pathname = const_cast<FT_String*>(bsFile.unterminated_c_str());
351   RetainPtr<CFX_Face> face =
352       CFX_Face::Open(m_FTLibrary.get(), &args, iFaceIndex);
353   if (!face)
354     return nullptr;
355 
356   FT_Set_Pixel_Sizes(face->GetRec(), 0, 64);
357   return face;
358 }
359 
ScanPath(const ByteString & path)360 void CFPF_SkiaFontMgr::ScanPath(const ByteString& path) {
361   std::unique_ptr<FX_FolderHandle, FxFolderHandleCloser> handle(
362       FX_OpenFolder(path.c_str()));
363   if (!handle)
364     return;
365 
366   ByteString filename;
367   bool bFolder = false;
368   while (FX_GetNextFile(handle.get(), &filename, &bFolder)) {
369     if (bFolder) {
370       if (filename == "." || filename == "..")
371         continue;
372     } else {
373       ByteString ext = filename.Last(4);
374       ext.MakeLower();
375       if (ext != ".ttf" && ext != ".ttc" && ext != ".otf")
376         continue;
377     }
378     ByteString fullpath(path);
379     fullpath += "/";
380     fullpath += filename;
381     if (bFolder)
382       ScanPath(fullpath);
383     else
384       ScanFile(fullpath);
385   }
386 }
387 
ScanFile(const ByteString & file)388 void CFPF_SkiaFontMgr::ScanFile(const ByteString& file) {
389   RetainPtr<CFX_Face> face = GetFontFace(file.AsStringView(), 0);
390   if (!face)
391     return;
392 
393   m_FontFaces.push_back(ReportFace(face, file));
394 }
395 
ReportFace(RetainPtr<CFX_Face> face,const ByteString & file)396 std::unique_ptr<CFPF_SkiaPathFont> CFPF_SkiaFontMgr::ReportFace(
397     RetainPtr<CFX_Face> face,
398     const ByteString& file) {
399   uint32_t dwStyle = 0;
400   if (FXFT_Is_Face_Bold(face->GetRec()))
401     dwStyle |= FXFONT_FORCE_BOLD;
402   if (FXFT_Is_Face_Italic(face->GetRec()))
403     dwStyle |= FXFONT_ITALIC;
404   if (FT_IS_FIXED_WIDTH(face->GetRec()))
405     dwStyle |= FXFONT_FIXED_PITCH;
406   TT_OS2* pOS2 =
407       static_cast<TT_OS2*>(FT_Get_Sfnt_Table(face->GetRec(), ft_sfnt_os2));
408   if (pOS2) {
409     if (pOS2->ulCodePageRange1 & (1 << 31))
410       dwStyle |= FXFONT_SYMBOLIC;
411     if (pOS2->panose[0] == 2) {
412       uint8_t uSerif = pOS2->panose[1];
413       if ((uSerif > 1 && uSerif < 10) || uSerif > 13)
414         dwStyle |= FXFONT_SERIF;
415     }
416   }
417   if (pOS2 && (pOS2->ulCodePageRange1 & (1 << 31)))
418     dwStyle |= FXFONT_SYMBOLIC;
419 
420   return pdfium::MakeUnique<CFPF_SkiaPathFont>(
421       file, FXFT_Get_Face_Family_Name(face->GetRec()), dwStyle,
422       face->GetRec()->face_index, FPF_SkiaGetFaceCharset(pOS2),
423       face->GetRec()->num_glyphs);
424 }
425