1 // Copyright 2019 Google LLC.
2 #include "modules/skparagraph/include/FontCollection.h"
3
4 #include "include/core/SkTypeface.h"
5 #include "modules/skparagraph/include/Paragraph.h"
6 #include "modules/skparagraph/src/ParagraphImpl.h"
7 #include "modules/skshaper/include/SkShaper_harfbuzz.h"
8
9 namespace {
10 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
11 const char* kColorEmojiFontMac = "Apple Color Emoji";
12 #else
13 const char* kColorEmojiLocale = "und-Zsye";
14 #endif
15 }
16 namespace skia {
17 namespace textlayout {
18
operator ==(const FontCollection::FamilyKey & other) const19 bool FontCollection::FamilyKey::operator==(const FontCollection::FamilyKey& other) const {
20 return fFamilyNames == other.fFamilyNames &&
21 fFontStyle == other.fFontStyle &&
22 fFontArguments == other.fFontArguments;
23 }
24
operator ()(const FontCollection::FamilyKey & key) const25 size_t FontCollection::FamilyKey::Hasher::operator()(const FontCollection::FamilyKey& key) const {
26 size_t hash = 0;
27 for (const SkString& family : key.fFamilyNames) {
28 hash ^= std::hash<std::string>()(family.c_str());
29 }
30 return hash ^
31 std::hash<uint32_t>()(key.fFontStyle.weight()) ^
32 std::hash<uint32_t>()(key.fFontStyle.slant()) ^
33 std::hash<std::optional<FontArguments>>()(key.fFontArguments);
34 }
35
FontCollection()36 FontCollection::FontCollection()
37 : fEnableFontFallback(true)
38 , fDefaultFamilyNames({SkString(DEFAULT_FONT_FAMILY)}) { }
39
getFontManagersCount() const40 size_t FontCollection::getFontManagersCount() const { return this->getFontManagerOrder().size(); }
41
setAssetFontManager(sk_sp<SkFontMgr> font_manager)42 void FontCollection::setAssetFontManager(sk_sp<SkFontMgr> font_manager) {
43 fAssetFontManager = std::move(font_manager);
44 }
45
setDynamicFontManager(sk_sp<SkFontMgr> font_manager)46 void FontCollection::setDynamicFontManager(sk_sp<SkFontMgr> font_manager) {
47 fDynamicFontManager = std::move(font_manager);
48 }
49
setTestFontManager(sk_sp<SkFontMgr> font_manager)50 void FontCollection::setTestFontManager(sk_sp<SkFontMgr> font_manager) {
51 fTestFontManager = std::move(font_manager);
52 }
53
setDefaultFontManager(sk_sp<SkFontMgr> fontManager,const char defaultFamilyName[])54 void FontCollection::setDefaultFontManager(sk_sp<SkFontMgr> fontManager,
55 const char defaultFamilyName[]) {
56 fDefaultFontManager = std::move(fontManager);
57 fDefaultFamilyNames.emplace_back(defaultFamilyName);
58 }
59
setDefaultFontManager(sk_sp<SkFontMgr> fontManager,const std::vector<SkString> & defaultFamilyNames)60 void FontCollection::setDefaultFontManager(sk_sp<SkFontMgr> fontManager,
61 const std::vector<SkString>& defaultFamilyNames) {
62 fDefaultFontManager = std::move(fontManager);
63 fDefaultFamilyNames = defaultFamilyNames;
64 }
65
setDefaultFontManager(sk_sp<SkFontMgr> fontManager)66 void FontCollection::setDefaultFontManager(sk_sp<SkFontMgr> fontManager) {
67 fDefaultFontManager = std::move(fontManager);
68 }
69
70 // Return the available font managers in the order they should be queried.
getFontManagerOrder() const71 std::vector<sk_sp<SkFontMgr>> FontCollection::getFontManagerOrder() const {
72 std::vector<sk_sp<SkFontMgr>> order;
73 if (fDynamicFontManager) {
74 order.push_back(fDynamicFontManager);
75 }
76 if (fAssetFontManager) {
77 order.push_back(fAssetFontManager);
78 }
79 if (fTestFontManager) {
80 order.push_back(fTestFontManager);
81 }
82 if (fDefaultFontManager && fEnableFontFallback) {
83 order.push_back(fDefaultFontManager);
84 }
85 return order;
86 }
87
findTypefaces(const std::vector<SkString> & familyNames,SkFontStyle fontStyle)88 std::vector<sk_sp<SkTypeface>> FontCollection::findTypefaces(const std::vector<SkString>& familyNames, SkFontStyle fontStyle) {
89 return findTypefaces(familyNames, fontStyle, std::nullopt);
90 }
91
findTypefaces(const std::vector<SkString> & familyNames,SkFontStyle fontStyle,const std::optional<FontArguments> & fontArgs)92 std::vector<sk_sp<SkTypeface>> FontCollection::findTypefaces(const std::vector<SkString>& familyNames, SkFontStyle fontStyle, const std::optional<FontArguments>& fontArgs) {
93 // Look inside the font collections cache first
94 FamilyKey familyKey(familyNames, fontStyle, fontArgs);
95 auto found = fTypefaces.find(familyKey);
96 if (found) {
97 return *found;
98 }
99
100 std::vector<sk_sp<SkTypeface>> typefaces;
101 for (const SkString& familyName : familyNames) {
102 sk_sp<SkTypeface> match = matchTypeface(familyName, fontStyle);
103 if (match && fontArgs) {
104 match = fontArgs->CloneTypeface(match);
105 }
106 if (match) {
107 typefaces.emplace_back(std::move(match));
108 }
109 }
110
111 if (typefaces.empty()) {
112 sk_sp<SkTypeface> match;
113 for (const SkString& familyName : fDefaultFamilyNames) {
114 match = matchTypeface(familyName, fontStyle);
115 if (match) {
116 break;
117 }
118 }
119 if (!match) {
120 for (const auto& manager : this->getFontManagerOrder()) {
121 match = manager->legacyMakeTypeface(nullptr, fontStyle);
122 if (match) {
123 break;
124 }
125 }
126 }
127 if (match) {
128 typefaces.emplace_back(std::move(match));
129 }
130 }
131
132 fTypefaces.set(familyKey, typefaces);
133 return typefaces;
134 }
135
matchTypeface(const SkString & familyName,SkFontStyle fontStyle)136 sk_sp<SkTypeface> FontCollection::matchTypeface(const SkString& familyName, SkFontStyle fontStyle) {
137 for (const auto& manager : this->getFontManagerOrder()) {
138 sk_sp<SkFontStyleSet> set(manager->matchFamily(familyName.c_str()));
139 if (!set || set->count() == 0) {
140 continue;
141 }
142
143 sk_sp<SkTypeface> match(set->matchStyle(fontStyle));
144 if (match) {
145 return match;
146 }
147 }
148
149 return nullptr;
150 }
151
152 // Find ANY font in available font managers that resolves the unicode codepoint
defaultFallback(SkUnichar unicode,SkFontStyle fontStyle,const SkString & locale)153 sk_sp<SkTypeface> FontCollection::defaultFallback(SkUnichar unicode,
154 SkFontStyle fontStyle,
155 const SkString& locale) {
156
157 for (const auto& manager : this->getFontManagerOrder()) {
158 std::vector<const char*> bcp47;
159 if (!locale.isEmpty()) {
160 bcp47.push_back(locale.c_str());
161 }
162 sk_sp<SkTypeface> typeface(manager->matchFamilyStyleCharacter(
163 nullptr, fontStyle, bcp47.data(), bcp47.size(), unicode));
164
165 if (typeface != nullptr) {
166 return typeface;
167 }
168 }
169 return nullptr;
170 }
171
172 // Find ANY font in available font managers that resolves this emojiStart
defaultEmojiFallback(SkUnichar emojiStart,SkFontStyle fontStyle,const SkString & locale)173 sk_sp<SkTypeface> FontCollection::defaultEmojiFallback(SkUnichar emojiStart,
174 SkFontStyle fontStyle,
175 const SkString& locale) {
176
177 for (const auto& manager : this->getFontManagerOrder()) {
178 std::vector<const char*> bcp47;
179 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
180 sk_sp<SkTypeface> emojiTypeface =
181 fDefaultFontManager->matchFamilyStyle(kColorEmojiFontMac, SkFontStyle());
182 if (emojiTypeface != nullptr) {
183 return emojiTypeface;
184 }
185 #else
186 bcp47.push_back(kColorEmojiLocale);
187 #endif
188 if (!locale.isEmpty()) {
189 bcp47.push_back(locale.c_str());
190 }
191
192 // Not really ideal since the first codepoint may not be the best one
193 // but we start from a good colored emoji at least
194 sk_sp<SkTypeface> typeface(manager->matchFamilyStyleCharacter(
195 nullptr, fontStyle, bcp47.data(), bcp47.size(), emojiStart));
196 if (typeface != nullptr) {
197 // ... and stop as soon as we find something in hope it will work for all of them
198 return typeface;
199 }
200 }
201 return nullptr;
202 }
203
defaultFallback()204 sk_sp<SkTypeface> FontCollection::defaultFallback() {
205 if (fDefaultFontManager == nullptr) {
206 return nullptr;
207 }
208 for (const SkString& familyName : fDefaultFamilyNames) {
209 sk_sp<SkTypeface> match = fDefaultFontManager->matchFamilyStyle(familyName.c_str(),
210 SkFontStyle());
211 if (match) {
212 return match;
213 }
214 }
215 return nullptr;
216 }
217
disableFontFallback()218 void FontCollection::disableFontFallback() { fEnableFontFallback = false; }
enableFontFallback()219 void FontCollection::enableFontFallback() { fEnableFontFallback = true; }
220
clearCaches()221 void FontCollection::clearCaches() {
222 fParagraphCache.reset();
223 fTypefaces.reset();
224 SkShapers::HB::PurgeCaches();
225 }
226
227 } // namespace textlayout
228 } // namespace skia
229