7#include "core/fxge/android/cfpf_skiafontmgr.h"
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"
28constexpr int kSkiaMatchNameWeight = 62;
29constexpr int kSkiaMatchSystemNameWeight = 60;
30constexpr int kSkiaMatchSerifStyleWeight = 16;
31constexpr int kSkiaMatchScriptStyleWeight = 8;
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},
52const SkiaFontMap kSkiaSansFontMap[] = {
53 {0x58c5083, 0xd5b8d10f}, {0x14ee2d13, 0xd5b8d10f},
54 {0x779ce19d, 0xd5b8d10f}, {0xcb7a04c8, 0xd5b8d10f},
55 {0xfb4ce0de, 0xd5b8d10f},
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;
65 if (it != font_map.end() && it->family == hash) {
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,
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;
126 return SKIACHARSET_Default;
131 uint32_t hash_code = 0;
132 for (
unsigned char ch : family) {
133 if (ch ==
' ' || ch ==
'-' || ch ==
',')
135 hash_code = 31 * hash_code + tolower(ch);
153 font
+= static_cast<uint8_t>(charset);
154 return FX_HashCode_GetA(font.AsStringView());
164 return name.Contains(
"symbol");
170 return name.Contains(
"arabic");
173constexpr auto kFPFSkiaFontCharsets =
fxcrt::ToArray<
const uint32_t>({
175 SKIACHARSET_EeasternEuropean,
176 SKIACHARSET_Cyrillic,
191 SKIACHARSET_ShiftJIS,
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];
230 FT_Init_FreeType(&library);
235 ft_library_.reset(library);
244 ScanPath(
"/system/fonts");
249 for (
const char** path = user_paths; *path; ++path) {
255 loaded_fonts_ =
true;
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();
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);
277 int32_t expected_score = kSkiaMatchNameWeight +
278 kSkiaMatchSerifStyleWeight * 3 +
279 kSkiaMatchScriptStyleWeight * 2;
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))) {
289 const uint32_t sys_font_name_hash = SkiaNormalizeFontName(font->family());
290 if (face_name_hash == sys_font_name_hash) {
291 score += kSkiaMatchNameWeight;
293 bool matches_name = (score == kSkiaMatchNameWeight);
294 if (FontStyleIsForceBold(style) == FontStyleIsForceBold(font->style())) {
295 score += kSkiaMatchSerifStyleWeight;
297 if (FontStyleIsItalic(style) == FontStyleIsItalic(font->style())) {
298 score += kSkiaMatchSerifStyleWeight;
300 if (FontStyleIsFixedPitch(style) == FontStyleIsFixedPitch(font->style())) {
301 score += kSkiaMatchScriptStyleWeight;
303 if (FontStyleIsSerif(style) == FontStyleIsSerif(font->style())) {
304 score += kSkiaMatchSerifStyleWeight;
306 if (FontStyleIsScript(style) == FontStyleIsScript(font->style())) {
307 score += kSkiaMatchScriptStyleWeight;
309 if (subst_hash == sys_font_name_hash ||
310 subst_sans_hash == sys_font_name_hash) {
311 score += kSkiaMatchSystemNameWeight;
314 if (charset == FX_Charset::kDefault || maybe_symbol) {
315 if (score > best_score && matches_name) {
317 best_font = font.get();
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();
324 }
else if (score > best_score) {
326 best_font = font.get();
328 if (score >= expected_score) {
329 best_font = font.get();
338 if (!font->IsValid())
342 family_font_map_[hash] = std::move(font);
347 int32_t face_index) {
348 if (path.IsEmpty()) {
352 if (face_index < 0) {
357 args.flags = FT_OPEN_PATHNAME;
358 args.pathname =
const_cast<FT_String*>(path.unterminated_c_str());
360 CFX_Face::Open(ft_library_.get(), &args, face_index);
364 face->SetPixelSize(0, 64);
369 std::unique_ptr<FX_Folder> handle = FX_Folder::OpenFolder(path);
374 bool is_folder =
false;
375 while (handle->GetNextFile(&filename, &is_folder)) {
377 if (filename
== "." || filename
== "..")
382 if (ext
!= ".ttf" && ext
!= ".ttc" && ext
!= ".otf")
387 fullpath
+= filename;
397 RetainPtr<CFX_Face> face = GetFontFace(file.AsStringView(), 0);
401 font_faces_.push_back(ReportFace(face, file));
408 if (face->IsBold()) {
411 if (face->IsItalic()) {
414 if (face->IsFixedWidth()) {
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)) {
425 charset |= SkiaGetFaceCharset(code_page_range.value()[0]);
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) {
437 face->GetRec()->face_index,
438 charset, face->GetGlyphCount());
fxcrt::ByteString ByteString
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
ByteString(const ByteString &other)=default
#define UNSAFE_BUFFERS(...)
bool FX_CharSetIsCJK(FX_Charset uCharset)
bool FontStyleIsSerif(uint32_t style)
bool FontStyleIsItalic(uint32_t style)
#define FXFONT_FORCE_BOLD
bool FontStyleIsForceBold(uint32_t style)
#define FXFONT_FIXED_PITCH
struct FT_LibraryRec_ FXFT_LibraryRec
fxcrt::ByteStringView ByteStringView