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