Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cfpf_skiafontmgr.cpp
Go to the documentation of this file.
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
26namespace {
27
28constexpr int kSkiaMatchNameWeight = 62;
29constexpr int kSkiaMatchSystemNameWeight = 60;
30constexpr int kSkiaMatchSerifStyleWeight = 16;
31constexpr int kSkiaMatchScriptStyleWeight = 8;
32
33struct SkiaFontMap {
34 uint32_t family;
35 uint32_t subst;
36};
37
38const 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
52const SkiaFontMap kSkiaSansFontMap[] = {
53 {0x58c5083, 0xd5b8d10f}, {0x14ee2d13, 0xd5b8d10f},
54 {0x779ce19d, 0xd5b8d10f}, {0xcb7a04c8, 0xd5b8d10f},
55 {0xfb4ce0de, 0xd5b8d10f},
56};
57
58uint32_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
71enum 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
93uint32_t SkiaGetCharset(FX_Charset charset) {
94 switch (charset) {
96 return SKIACHARSET_Ansi;
98 return SKIACHARSET_Default;
100 return SKIACHARSET_Symbol;
102 return SKIACHARSET_ShiftJIS;
104 return SKIACHARSET_Korean;
106 return SKIACHARSET_GB2312;
108 return SKIACHARSET_BIG5;
110 return SKIACHARSET_Greek;
112 return SKIACHARSET_Turkish;
114 return SKIACHARSET_Hebrew;
116 return SKIACHARSET_Arabic;
118 return SKIACHARSET_Baltic;
120 return SKIACHARSET_Cyrillic;
122 return SKIACHARSET_Thai;
124 return SKIACHARSET_EeasternEuropean;
125 default:
126 return SKIACHARSET_Default;
127 }
128}
129
130uint32_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
140uint32_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
157bool SkiaIsCJK(FX_Charset charset) {
158 return FX_CharSetIsCJK(charset);
159}
160
161bool SkiaMaybeSymbol(ByteStringView facename) {
162 ByteString name(facename);
163 name.MakeLower();
164 return name.Contains("symbol");
165}
166
167bool SkiaMaybeArabic(ByteStringView facename) {
168 ByteString name(facename);
169 name.MakeLower();
170 return name.Contains("arabic");
171}
172
173constexpr 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
208uint32_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
221
223
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
239void 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.
249 for (const char** path = user_paths; *path; ++path) {
250 ScanPath(*path);
251 }
252 });
253 }
254
255 loaded_fonts_ = true;
256}
257
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)) {
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
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
368void 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
396void 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
404std::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}
fxcrt::ByteString ByteString
Definition bytestring.h:180
void LoadFonts(const char **user_paths)
RetainPtr< CFX_Face > GetFontFace(ByteStringView path, int32_t face_index)
CFPF_SkiaFont * CreateFont(ByteStringView family_name, FX_Charset charset, uint32_t style)
ByteString & operator+=(const ByteString &str)
ByteString & operator+=(char ch)
bool operator==(const char *ptr) const
ByteString & operator+=(const char *str)
bool operator!=(const char *ptr) const
Definition bytestring.h:65
ByteString(const ByteString &other)=default
#define UNSAFE_BUFFERS(...)
FX_Charset
Definition fx_codepage.h:71
@ kChineseTraditional
Definition fx_codepage.h:91
@ kMSWin_EasternEuropean
@ kChineseSimplified
Definition fx_codepage.h:90
bool FX_CharSetIsCJK(FX_Charset uCharset)
bool FontStyleIsSerif(uint32_t style)
Definition fx_font.h:79
#define FXFONT_SERIF
Definition fx_font.h:31
#define FXFONT_ITALIC
Definition fx_font.h:35
#define FXFONT_SYMBOLIC
Definition fx_font.h:32
bool FontStyleIsItalic(uint32_t style)
Definition fx_font.h:64
#define FXFONT_FORCE_BOLD
Definition fx_font.h:38
bool FontStyleIsForceBold(uint32_t style)
Definition fx_font.h:61
#define FXFONT_FIXED_PITCH
Definition fx_font.h:30
struct FT_LibraryRec_ FXFT_LibraryRec
Definition fx_freetype.h:23
fxcrt::ByteStringView ByteStringView