• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The PDFium Authors
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 <array>
11 #include <iterator>
12 #include <utility>
13 
14 #include "core/fxcrt/compiler_specific.h"
15 #include "core/fxcrt/containers/adapters.h"
16 #include "core/fxcrt/fx_codepage.h"
17 #include "core/fxcrt/fx_extension.h"
18 #include "core/fxcrt/fx_folder.h"
19 #include "core/fxcrt/fx_system.h"
20 #include "core/fxcrt/stl_util.h"
21 #include "core/fxge/android/cfpf_skiafont.h"
22 #include "core/fxge/android/cfpf_skiapathfont.h"
23 #include "core/fxge/freetype/fx_freetype.h"
24 #include "core/fxge/fx_font.h"
25 
26 namespace {
27 
28 constexpr int kSkiaMatchNameWeight = 62;
29 constexpr int kSkiaMatchSystemNameWeight = 60;
30 constexpr int kSkiaMatchSerifStyleWeight = 16;
31 constexpr int kSkiaMatchScriptStyleWeight = 8;
32 
33 struct SkiaFontMap {
34   uint32_t family;
35   uint32_t subst;
36 };
37 
38 const SkiaFontMap kSkiaFontmap[] = {
39     {0x58c5083, 0xc8d2e345},  {0x5dfade2, 0xe1633081},
40     {0x684317d, 0xe1633081},  {0x14ee2d13, 0xc8d2e345},
41     {0x3918fe2d, 0xbbeeec72}, {0x3b98b31c, 0xe1633081},
42     {0x3d49f40e, 0xe1633081}, {0x432c41c5, 0xe1633081},
43     {0x491b6ad0, 0xe1633081}, {0x5612cab1, 0x59b9f8f1},
44     {0x779ce19d, 0xc8d2e345}, {0x7cc9510b, 0x59b9f8f1},
45     {0x83746053, 0xbbeeec72}, {0xaaa60c03, 0xbbeeec72},
46     {0xbf85ff26, 0xe1633081}, {0xc04fe601, 0xbbeeec72},
47     {0xca3812d5, 0x59b9f8f1}, {0xca383e15, 0x59b9f8f1},
48     {0xcad5eaf6, 0x59b9f8f1}, {0xcb7a04c8, 0xc8d2e345},
49     {0xfb4ce0de, 0xe1633081},
50 };
51 
52 const SkiaFontMap kSkiaSansFontMap[] = {
53     {0x58c5083, 0xd5b8d10f},  {0x14ee2d13, 0xd5b8d10f},
54     {0x779ce19d, 0xd5b8d10f}, {0xcb7a04c8, 0xd5b8d10f},
55     {0xfb4ce0de, 0xd5b8d10f},
56 };
57 
SkiaGetSubstFont(uint32_t hash,pdfium::span<const SkiaFontMap> font_map)58 uint32_t SkiaGetSubstFont(uint32_t hash,
59                           pdfium::span<const SkiaFontMap> font_map) {
60   const SkiaFontMap* it =
61       std::lower_bound(font_map.begin(), font_map.end(), hash,
62                        [](const SkiaFontMap& item, uint32_t hash) {
63                          return item.family < hash;
64                        });
65   if (it != font_map.end() && it->family == hash) {
66     return it->subst;
67   }
68   return 0;
69 }
70 
71 enum SKIACHARSET {
72   SKIACHARSET_Ansi = 1 << 0,
73   SKIACHARSET_Default = 1 << 1,
74   SKIACHARSET_Symbol = 1 << 2,
75   SKIACHARSET_ShiftJIS = 1 << 3,
76   SKIACHARSET_Korean = 1 << 4,
77   SKIACHARSET_Johab = 1 << 5,
78   SKIACHARSET_GB2312 = 1 << 6,
79   SKIACHARSET_BIG5 = 1 << 7,
80   SKIACHARSET_Greek = 1 << 8,
81   SKIACHARSET_Turkish = 1 << 9,
82   SKIACHARSET_Vietnamese = 1 << 10,
83   SKIACHARSET_Hebrew = 1 << 11,
84   SKIACHARSET_Arabic = 1 << 12,
85   SKIACHARSET_Baltic = 1 << 13,
86   SKIACHARSET_Cyrillic = 1 << 14,
87   SKIACHARSET_Thai = 1 << 15,
88   SKIACHARSET_EeasternEuropean = 1 << 16,
89   SKIACHARSET_PC = 1 << 17,
90   SKIACHARSET_OEM = 1 << 18,
91 };
92 
SkiaGetCharset(FX_Charset charset)93 uint32_t SkiaGetCharset(FX_Charset charset) {
94   switch (charset) {
95     case FX_Charset::kANSI:
96       return SKIACHARSET_Ansi;
97     case FX_Charset::kDefault:
98       return SKIACHARSET_Default;
99     case FX_Charset::kSymbol:
100       return SKIACHARSET_Symbol;
101     case FX_Charset::kShiftJIS:
102       return SKIACHARSET_ShiftJIS;
103     case FX_Charset::kHangul:
104       return SKIACHARSET_Korean;
105     case FX_Charset::kChineseSimplified:
106       return SKIACHARSET_GB2312;
107     case FX_Charset::kChineseTraditional:
108       return SKIACHARSET_BIG5;
109     case FX_Charset::kMSWin_Greek:
110       return SKIACHARSET_Greek;
111     case FX_Charset::kMSWin_Turkish:
112       return SKIACHARSET_Turkish;
113     case FX_Charset::kMSWin_Hebrew:
114       return SKIACHARSET_Hebrew;
115     case FX_Charset::kMSWin_Arabic:
116       return SKIACHARSET_Arabic;
117     case FX_Charset::kMSWin_Baltic:
118       return SKIACHARSET_Baltic;
119     case FX_Charset::kMSWin_Cyrillic:
120       return SKIACHARSET_Cyrillic;
121     case FX_Charset::kThai:
122       return SKIACHARSET_Thai;
123     case FX_Charset::kMSWin_EasternEuropean:
124       return SKIACHARSET_EeasternEuropean;
125     default:
126       return SKIACHARSET_Default;
127   }
128 }
129 
SkiaNormalizeFontName(ByteStringView family)130 uint32_t SkiaNormalizeFontName(ByteStringView family) {
131   uint32_t hash_code = 0;
132   for (unsigned char ch : family) {
133     if (ch == ' ' || ch == '-' || ch == ',')
134       continue;
135     hash_code = 31 * hash_code + tolower(ch);
136   }
137   return hash_code;
138 }
139 
GetFamilyHash(ByteStringView family,uint32_t style,FX_Charset charset)140 uint32_t GetFamilyHash(ByteStringView family,
141                        uint32_t style,
142                        FX_Charset charset) {
143   ByteString font(family);
144   if (FontStyleIsForceBold(style)) {
145     font += "Bold";
146   }
147   if (FontStyleIsItalic(style)) {
148     font += "Italic";
149   }
150   if (FontStyleIsSerif(style)) {
151     font += "Serif";
152   }
153   font += static_cast<uint8_t>(charset);
154   return FX_HashCode_GetA(font.AsStringView());
155 }
156 
SkiaIsCJK(FX_Charset charset)157 bool SkiaIsCJK(FX_Charset charset) {
158   return FX_CharSetIsCJK(charset);
159 }
160 
SkiaMaybeSymbol(ByteStringView facename)161 bool SkiaMaybeSymbol(ByteStringView facename) {
162   ByteString name(facename);
163   name.MakeLower();
164   return name.Contains("symbol");
165 }
166 
SkiaMaybeArabic(ByteStringView facename)167 bool SkiaMaybeArabic(ByteStringView facename) {
168   ByteString name(facename);
169   name.MakeLower();
170   return name.Contains("arabic");
171 }
172 
173 constexpr auto kFPFSkiaFontCharsets = fxcrt::ToArray<const uint32_t>({
174     SKIACHARSET_Ansi,
175     SKIACHARSET_EeasternEuropean,
176     SKIACHARSET_Cyrillic,
177     SKIACHARSET_Greek,
178     SKIACHARSET_Turkish,
179     SKIACHARSET_Hebrew,
180     SKIACHARSET_Arabic,
181     SKIACHARSET_Baltic,
182     0,
183     0,
184     0,
185     0,
186     0,
187     0,
188     0,
189     0,
190     SKIACHARSET_Thai,
191     SKIACHARSET_ShiftJIS,
192     SKIACHARSET_GB2312,
193     SKIACHARSET_Korean,
194     SKIACHARSET_BIG5,
195     SKIACHARSET_Johab,
196     0,
197     0,
198     0,
199     0,
200     0,
201     0,
202     0,
203     0,
204     SKIACHARSET_OEM,
205     SKIACHARSET_Symbol,
206 });
207 
SkiaGetFaceCharset(uint32_t code_range)208 uint32_t SkiaGetFaceCharset(uint32_t code_range) {
209   uint32_t charset = 0;
210   for (int32_t i = 0; i < 32; i++) {
211     if (code_range & (1 << i)) {
212       charset |= kFPFSkiaFontCharsets[i];
213     }
214   }
215   return charset;
216 }
217 
218 }  // namespace
219 
220 CFPF_SkiaFontMgr::CFPF_SkiaFontMgr() = default;
221 
222 CFPF_SkiaFontMgr::~CFPF_SkiaFontMgr() = default;
223 
InitFTLibrary()224 bool CFPF_SkiaFontMgr::InitFTLibrary() {
225   if (ft_library_) {
226     return true;
227   }
228 
229   FXFT_LibraryRec* library = nullptr;
230   FT_Init_FreeType(&library);
231   if (!library) {
232     return false;
233   }
234 
235   ft_library_.reset(library);
236   return true;
237 }
238 
LoadFonts(const char ** user_paths)239 void CFPF_SkiaFontMgr::LoadFonts(const char** user_paths) {
240   if (loaded_fonts_) {
241     return;
242   }
243 
244   ScanPath("/system/fonts");
245 
246   if (user_paths) {
247     // SAFETY: nullptr-terminated array required from caller.
248     UNSAFE_BUFFERS({
249       for (const char** path = user_paths; *path; ++path) {
250         ScanPath(*path);
251       }
252     });
253   }
254 
255   loaded_fonts_ = true;
256 }
257 
CreateFont(ByteStringView family_name,FX_Charset charset,uint32_t style)258 CFPF_SkiaFont* CFPF_SkiaFontMgr::CreateFont(ByteStringView family_name,
259                                             FX_Charset charset,
260                                             uint32_t style) {
261   const uint32_t hash = GetFamilyHash(family_name, style, charset);
262   auto family_iter = family_font_map_.find(hash);
263   if (family_iter != family_font_map_.end()) {
264     return family_iter->second.get();
265   }
266 
267   const uint32_t face_name_hash = SkiaNormalizeFontName(family_name);
268   const uint32_t subst_hash = SkiaGetSubstFont(face_name_hash, kSkiaFontmap);
269   const uint32_t subst_sans_hash =
270       SkiaGetSubstFont(face_name_hash, kSkiaSansFontMap);
271   const bool maybe_symbol = SkiaMaybeSymbol(family_name);
272   if (charset != FX_Charset::kMSWin_Arabic && SkiaMaybeArabic(family_name)) {
273     charset = FX_Charset::kMSWin_Arabic;
274   } else if (charset == FX_Charset::kANSI) {
275     charset = FX_Charset::kDefault;
276   }
277   int32_t expected_score = kSkiaMatchNameWeight +
278                            kSkiaMatchSerifStyleWeight * 3 +
279                            kSkiaMatchScriptStyleWeight * 2;
280   const CFPF_SkiaPathFont* best_font = nullptr;
281   int32_t best_score = -1;
282   int32_t best_glyph_num = 0;
283   for (const std::unique_ptr<CFPF_SkiaPathFont>& font :
284        pdfium::Reversed(font_faces_)) {
285     if (!(font->charsets() & SkiaGetCharset(charset))) {
286       continue;
287     }
288     int32_t score = 0;
289     const uint32_t sys_font_name_hash = SkiaNormalizeFontName(font->family());
290     if (face_name_hash == sys_font_name_hash) {
291       score += kSkiaMatchNameWeight;
292     }
293     bool matches_name = (score == kSkiaMatchNameWeight);
294     if (FontStyleIsForceBold(style) == FontStyleIsForceBold(font->style())) {
295       score += kSkiaMatchSerifStyleWeight;
296     }
297     if (FontStyleIsItalic(style) == FontStyleIsItalic(font->style())) {
298       score += kSkiaMatchSerifStyleWeight;
299     }
300     if (FontStyleIsFixedPitch(style) == FontStyleIsFixedPitch(font->style())) {
301       score += kSkiaMatchScriptStyleWeight;
302     }
303     if (FontStyleIsSerif(style) == FontStyleIsSerif(font->style())) {
304       score += kSkiaMatchSerifStyleWeight;
305     }
306     if (FontStyleIsScript(style) == FontStyleIsScript(font->style())) {
307       score += kSkiaMatchScriptStyleWeight;
308     }
309     if (subst_hash == sys_font_name_hash ||
310         subst_sans_hash == sys_font_name_hash) {
311       score += kSkiaMatchSystemNameWeight;
312       matches_name = true;
313     }
314     if (charset == FX_Charset::kDefault || maybe_symbol) {
315       if (score > best_score && matches_name) {
316         best_score = score;
317         best_font = font.get();
318       }
319     } else if (SkiaIsCJK(charset)) {
320       if (matches_name || font->glyph_num() > best_glyph_num) {
321         best_font = font.get();
322         best_glyph_num = font->glyph_num();
323       }
324     } else if (score > best_score) {
325       best_score = score;
326       best_font = font.get();
327     }
328     if (score >= expected_score) {
329       best_font = font.get();
330       break;
331     }
332   }
333   if (!best_font) {
334     return nullptr;
335   }
336 
337   auto font = std::make_unique<CFPF_SkiaFont>(this, best_font, charset);
338   if (!font->IsValid())
339     return nullptr;
340 
341   CFPF_SkiaFont* ret = font.get();
342   family_font_map_[hash] = std::move(font);
343   return ret;
344 }
345 
GetFontFace(ByteStringView path,int32_t face_index)346 RetainPtr<CFX_Face> CFPF_SkiaFontMgr::GetFontFace(ByteStringView path,
347                                                   int32_t face_index) {
348   if (path.IsEmpty()) {
349     return nullptr;
350   }
351 
352   if (face_index < 0) {
353     return nullptr;
354   }
355 
356   FT_Open_Args args;
357   args.flags = FT_OPEN_PATHNAME;
358   args.pathname = const_cast<FT_String*>(path.unterminated_c_str());
359   RetainPtr<CFX_Face> face =
360       CFX_Face::Open(ft_library_.get(), &args, face_index);
361   if (!face)
362     return nullptr;
363 
364   face->SetPixelSize(0, 64);
365   return face;
366 }
367 
ScanPath(const ByteString & path)368 void CFPF_SkiaFontMgr::ScanPath(const ByteString& path) {
369   std::unique_ptr<FX_Folder> handle = FX_Folder::OpenFolder(path);
370   if (!handle)
371     return;
372 
373   ByteString filename;
374   bool is_folder = false;
375   while (handle->GetNextFile(&filename, &is_folder)) {
376     if (is_folder) {
377       if (filename == "." || filename == "..")
378         continue;
379     } else {
380       ByteString ext = filename.Last(4);
381       ext.MakeLower();
382       if (ext != ".ttf" && ext != ".ttc" && ext != ".otf")
383         continue;
384     }
385     ByteString fullpath(path);
386     fullpath += "/";
387     fullpath += filename;
388     if (is_folder) {
389       ScanPath(fullpath);
390     } else {
391       ScanFile(fullpath);
392     }
393   }
394 }
395 
ScanFile(const ByteString & file)396 void CFPF_SkiaFontMgr::ScanFile(const ByteString& file) {
397   RetainPtr<CFX_Face> face = GetFontFace(file.AsStringView(), 0);
398   if (!face)
399     return;
400 
401   font_faces_.push_back(ReportFace(face, file));
402 }
403 
ReportFace(RetainPtr<CFX_Face> face,const ByteString & file)404 std::unique_ptr<CFPF_SkiaPathFont> CFPF_SkiaFontMgr::ReportFace(
405     RetainPtr<CFX_Face> face,
406     const ByteString& file) {
407   uint32_t style = 0;
408   if (face->IsBold()) {
409     style |= FXFONT_FORCE_BOLD;
410   }
411   if (face->IsItalic()) {
412     style |= FXFONT_ITALIC;
413   }
414   if (face->IsFixedWidth()) {
415     style |= FXFONT_FIXED_PITCH;
416   }
417 
418   uint32_t charset = SKIACHARSET_Default;
419   std::optional<std::array<uint32_t, 2>> code_page_range =
420       face->GetOs2CodePageRange();
421   if (code_page_range.has_value()) {
422     if (code_page_range.value()[0] & (1 << 31)) {
423       style |= FXFONT_SYMBOLIC;
424     }
425     charset |= SkiaGetFaceCharset(code_page_range.value()[0]);
426   }
427 
428   std::optional<std::array<uint8_t, 2>> panose = face->GetOs2Panose();
429   if (panose.has_value() && panose.value()[0] == 2) {
430     uint8_t serif = panose.value()[1];
431     if ((serif > 1 && serif < 10) || serif > 13) {
432       style |= FXFONT_SERIF;
433     }
434   }
435 
436   return std::make_unique<CFPF_SkiaPathFont>(file, face->GetFamilyName(), style,
437                                              face->GetRec()->face_index,
438                                              charset, face->GetGlyphCount());
439 }
440