1 // Copyright 2019 Google LLC.
2 #include "modules/skparagraph/include/FontCollection.h"
3
4 #include "include/core/SkTypeface.h"
5 #include "include/core/SkGraphics.h"
6 #include "modules/skparagraph/include/Paragraph.h"
7 #include "modules/skparagraph/src/ParagraphImpl.h"
8 #include "modules/skshaper/include/SkShaper_harfbuzz.h"
9
10 namespace {
11 #ifndef ENABLE_TEXT_ENHANCE
12 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
13 const char* kColorEmojiFontMac = "Apple Color Emoji";
14 #else
15 const char* kColorEmojiLocale = "und-Zsye";
16 #endif
17 #endif // ENABLE_TEXT_ENHANCE
18
19 #ifdef ENABLE_TEXT_ENHANCE
RSLegacyMakeTypeface(std::shared_ptr<RSFontMgr> fontMgr,const char familyName[],RSFontStyle style)20 std::shared_ptr<RSTypeface> RSLegacyMakeTypeface(
21 std::shared_ptr<RSFontMgr> fontMgr, const char familyName[], RSFontStyle style) {
22 RSTypeface* typeface = fontMgr->MatchFamilyStyle(familyName, style);
23 if (typeface == nullptr && familyName != nullptr) {
24 typeface = fontMgr->MatchFamilyStyle(nullptr, style);
25 }
26
27 if (typeface) {
28 return std::shared_ptr<RSTypeface>(typeface);
29 }
30 return nullptr;
31 }
32
33 constexpr int MAX_VARTYPEFACE_SIZE = 32;
34 std::unordered_map<uint32_t, std::shared_ptr<RSTypeface>> g_faceTypeCache(MAX_VARTYPEFACE_SIZE);
35 #endif
36 }
37 namespace skia {
38 namespace textlayout {
39 #ifdef ENABLE_TEXT_ENHANCE
40 bool FontCollection::fIsAdpaterTextHeightEnabled = false;
41 #endif
operator ==(const FontCollection::FamilyKey & other) const42 bool FontCollection::FamilyKey::operator==(const FontCollection::FamilyKey& other) const {
43 return fFamilyNames == other.fFamilyNames &&
44 fFontStyle == other.fFontStyle &&
45 fFontArguments == other.fFontArguments;
46 }
47
operator ()(const FontCollection::FamilyKey & key) const48 size_t FontCollection::FamilyKey::Hasher::operator()(const FontCollection::FamilyKey& key) const {
49 size_t hash = 0;
50 for (const SkString& family : key.fFamilyNames) {
51 hash ^= std::hash<std::string>()(family.c_str());
52 }
53 #ifdef ENABLE_TEXT_ENHANCE
54 return hash ^
55 std::hash<uint32_t>()(key.fFontStyle.GetWeight()) ^
56 std::hash<uint32_t>()(static_cast<uint32_t>(key.fFontStyle.GetSlant())) ^
57 std::hash<std::optional<FontArguments>>()(key.fFontArguments);
58 #else
59 return hash ^
60 std::hash<uint32_t>()(key.fFontStyle.weight()) ^
61 std::hash<uint32_t>()(key.fFontStyle.slant()) ^
62 std::hash<std::optional<FontArguments>>()(key.fFontArguments);
63 #endif
64 }
65
FontCollection()66 FontCollection::FontCollection()
67 : fEnableFontFallback(true)
68 , fDefaultFamilyNames({SkString(DEFAULT_FONT_FAMILY)}) { }
69
getFontManagersCount() const70 size_t FontCollection::getFontManagersCount() const {
71 #ifdef ENABLE_TEXT_ENHANCE
72 std::shared_lock<std::shared_mutex> readLock(mutex_);
73 #endif
74 return this->getFontManagerOrder().size();
75 }
76
77 #ifdef ENABLE_TEXT_ENHANCE
setAssetFontManager(std::shared_ptr<RSFontMgr> font_manager)78 void FontCollection::setAssetFontManager(std::shared_ptr<RSFontMgr> font_manager) {
79 std::unique_lock<std::shared_mutex> writeLock(mutex_);
80 fAssetFontManager = font_manager;
81 }
82
setDynamicFontManager(std::shared_ptr<RSFontMgr> font_manager)83 void FontCollection::setDynamicFontManager(std::shared_ptr<RSFontMgr> font_manager) {
84 std::unique_lock<std::shared_mutex> writeLock(mutex_);
85 fDynamicFontManager = font_manager;
86 }
87
setTestFontManager(std::shared_ptr<RSFontMgr> font_manager)88 void FontCollection::setTestFontManager(std::shared_ptr<RSFontMgr> font_manager)
89 {
90 std::unique_lock<std::shared_mutex> writeLock(mutex_);
91 fTestFontManager = font_manager;
92 }
93
setDefaultFontManager(std::shared_ptr<RSFontMgr> fontManager,const char defaultFamilyName[])94 void FontCollection::setDefaultFontManager(std::shared_ptr<RSFontMgr> fontManager,
95 const char defaultFamilyName[]) {
96 std::unique_lock<std::shared_mutex> writeLock(mutex_);
97 fDefaultFontManager = std::move(fontManager);
98 fDefaultFamilyNames.emplace_back(defaultFamilyName);
99 }
100
setDefaultFontManager(std::shared_ptr<RSFontMgr> fontManager,const std::vector<SkString> & defaultFamilyNames)101 void FontCollection::setDefaultFontManager(std::shared_ptr<RSFontMgr> fontManager,
102 const std::vector<SkString>& defaultFamilyNames) {
103 std::unique_lock<std::shared_mutex> writeLock(mutex_);
104 fDefaultFontManager = std::move(fontManager);
105 fDefaultFamilyNames = defaultFamilyNames;
106 }
107 #else
setAssetFontManager(sk_sp<SkFontMgr> font_manager)108 void FontCollection::setAssetFontManager(sk_sp<SkFontMgr> font_manager) {
109 fAssetFontManager = std::move(font_manager);
110 }
111
setDynamicFontManager(sk_sp<SkFontMgr> font_manager)112 void FontCollection::setDynamicFontManager(sk_sp<SkFontMgr> font_manager) {
113 fDynamicFontManager = std::move(font_manager);
114 }
115
setTestFontManager(sk_sp<SkFontMgr> font_manager)116 void FontCollection::setTestFontManager(sk_sp<SkFontMgr> font_manager) {
117 fTestFontManager = std::move(font_manager);
118 }
119
setDefaultFontManager(sk_sp<SkFontMgr> fontManager,const char defaultFamilyName[])120 void FontCollection::setDefaultFontManager(sk_sp<SkFontMgr> fontManager,
121 const char defaultFamilyName[]) {
122 fDefaultFontManager = std::move(fontManager);
123 fDefaultFamilyNames.emplace_back(defaultFamilyName);
124 }
125
setDefaultFontManager(sk_sp<SkFontMgr> fontManager,const std::vector<SkString> & defaultFamilyNames)126 void FontCollection::setDefaultFontManager(sk_sp<SkFontMgr> fontManager,
127 const std::vector<SkString>& defaultFamilyNames) {
128 fDefaultFontManager = std::move(fontManager);
129 fDefaultFamilyNames = defaultFamilyNames;
130 }
131
setDefaultFontManager(sk_sp<SkFontMgr> fontManager)132 void FontCollection::setDefaultFontManager(sk_sp<SkFontMgr> fontManager) {
133 fDefaultFontManager = std::move(fontManager);
134 }
135 #endif
136
137 // Return the available font managers in the order they should be queried.
138 #ifdef ENABLE_TEXT_ENHANCE
getFontManagerOrder() const139 std::vector<std::shared_ptr<RSFontMgr>> FontCollection::getFontManagerOrder() const {
140 std::vector<std::shared_ptr<RSFontMgr>> order;
141 #else
142 std::vector<sk_sp<SkFontMgr>> FontCollection::getFontManagerOrder() const {
143 std::vector<sk_sp<SkFontMgr>> order;
144 #endif
145 if (fDynamicFontManager) {
146 order.push_back(fDynamicFontManager);
147 }
148 if (fAssetFontManager) {
149 order.push_back(fAssetFontManager);
150 }
151 if (fTestFontManager) {
152 order.push_back(fTestFontManager);
153 }
154 if (fDefaultFontManager && fEnableFontFallback) {
155 order.push_back(fDefaultFontManager);
156 }
157 return order;
158 }
159
160 #ifdef ENABLE_TEXT_ENHANCE
161 std::vector<std::shared_ptr<RSTypeface>> FontCollection::findTypefaces(
162 const std::vector<SkString>& familyNames, RSFontStyle fontStyle) {
163 #else
164 std::vector<sk_sp<SkTypeface>> FontCollection::findTypefaces(const std::vector<SkString>& familyNames, SkFontStyle fontStyle) {
165 #endif
166 return findTypefaces(familyNames, fontStyle, std::nullopt);
167 }
168
169 #ifdef ENABLE_TEXT_ENHANCE
170 void FontCollection::updateTypefacesMatch(std::vector<std::shared_ptr<RSTypeface>>& typefaces,
171 RSFontStyle fontStyle, const std::optional<FontArguments>& fontArgs) {
172 std::shared_ptr<RSTypeface> match;
173 for (const auto& familyName : fDefaultFamilyNames) {
174 match = matchTypeface(familyName, fontStyle);
175 if (match) {
176 match = CloneTypeface(match, fontArgs);
177 typefaces.emplace_back(std::move(match));
178 }
179 }
180
181 if (!typefaces.empty()) {
182 return;
183 }
184
185 for (const auto& manager : this->getFontManagerOrder()) {
186 match = RSLegacyMakeTypeface(manager, nullptr, fontStyle);
187 if (match) {
188 typefaces.emplace_back(std::move(match));
189 break;
190 }
191 }
192 }
193
194 std::vector<std::shared_ptr<RSTypeface>> FontCollection::findTypefaces(const std::vector<SkString>& familyNames,
195 RSFontStyle fontStyle, const std::optional<FontArguments>& fontArgs) {
196 // Look inside the font collections cache first
197 FamilyKey familyKey(familyNames, fontStyle, fontArgs);
198 {
199 std::shared_lock<std::shared_mutex> readLock(mutex_);
200 auto found = fTypefaces.find(familyKey);
201 if (found != fTypefaces.end()) {
202 return found->second;
203 }
204 }
205
206 std::vector<std::shared_ptr<RSTypeface>> typefaces;
207 for (const auto& familyName : familyNames) {
208 std::shared_ptr<RSTypeface> match = matchTypeface(familyName, fontStyle);
209 if (match) {
210 match = CloneTypeface(match, fontArgs);
211 typefaces.emplace_back(std::move(match));
212 }
213 }
214
215 if (typefaces.empty()) {
216 FontCollection::updateTypefacesMatch(typefaces, fontStyle, fontArgs);
217 }
218
219 std::unique_lock<std::shared_mutex> writeLock(mutex_);
220 fTypefaces.emplace(familyKey, typefaces);
221 return typefaces;
222 }
223 #else
224 std::vector<sk_sp<SkTypeface>> FontCollection::findTypefaces(const std::vector<SkString>& familyNames,
225 SkFontStyle fontStyle, const std::optional<FontArguments>& fontArgs) {
226 // Look inside the font collections cache first
227 FamilyKey familyKey(familyNames, fontStyle, fontArgs);
228 auto found = fTypefaces.find(familyKey);
229 if (found) {
230 return *found;
231 }
232
233 std::vector<sk_sp<SkTypeface>> typefaces;
234 for (const SkString& familyName : familyNames) {
235 sk_sp<SkTypeface> match = matchTypeface(familyName, fontStyle);
236 if (match && fontArgs) {
237 match = fontArgs->CloneTypeface(match);
238 }
239 if (match) {
240 typefaces.emplace_back(std::move(match));
241 }
242 }
243
244 if (typefaces.empty()) {
245 sk_sp<SkTypeface> match;
246 for (const SkString& familyName : fDefaultFamilyNames) {
247 match = matchTypeface(familyName, fontStyle);
248 if (match) {
249 break;
250 }
251 }
252 if (!match) {
253 for (const auto& manager : this->getFontManagerOrder()) {
254 match = manager->legacyMakeTypeface(nullptr, fontStyle);
255 if (match) {
256 break;
257 }
258 }
259 }
260 if (match) {
261 typefaces.emplace_back(std::move(match));
262 }
263 }
264
265 fTypefaces.set(familyKey, typefaces);
266 return typefaces;
267 }
268 #endif
269
270 #ifdef ENABLE_TEXT_ENHANCE
271 std::shared_ptr<RSTypeface> FontCollection::matchTypeface(const SkString& familyName, RSFontStyle fontStyle) {
272 for (const auto& manager : this->getFontManagerOrder()) {
273 std::shared_ptr<RSFontStyleSet> set(manager->MatchFamily(familyName.c_str()));
274 if (!set || set->Count() == 0) {
275 continue;
276 }
277
278 std::shared_ptr<RSTypeface> match(set->MatchStyle(fontStyle));
279 if (match) {
280 return match;
281 }
282 }
283
284 return nullptr;
285 }
286 #else
287 sk_sp<SkTypeface> FontCollection::matchTypeface(const SkString& familyName, SkFontStyle fontStyle) {
288 for (const auto& manager : this->getFontManagerOrder()) {
289 sk_sp<SkFontStyleSet> set(manager->matchFamily(familyName.c_str()));
290 if (!set || set->count() == 0) {
291 continue;
292 }
293
294 sk_sp<SkTypeface> match(set->matchStyle(fontStyle));
295 if (match) {
296 return match;
297 }
298 }
299
300 return nullptr;
301 }
302 #endif
303
304 // Find ANY font in available font managers that resolves the unicode codepoint
305 #ifdef ENABLE_TEXT_ENHANCE
306 std::shared_ptr<RSTypeface> FontCollection::defaultFallback(
307 SkUnichar unicode, RSFontStyle fontStyle, const SkString& locale) {
308 std::shared_lock<std::shared_mutex> readLock(mutex_);
309 for (const auto& manager : this->getFontManagerOrder()) {
310 std::vector<const char*> bcp47;
311 if (!locale.isEmpty()) {
312 bcp47.push_back(locale.c_str());
313 }
314 std::shared_ptr<RSTypeface> typeface(manager->MatchFamilyStyleCharacter(
315 nullptr, fontStyle, bcp47.data(), bcp47.size(), unicode));
316 if (typeface != nullptr) {
317 return typeface;
318 }
319 }
320 return nullptr;
321 }
322 #else
323 sk_sp<SkTypeface> FontCollection::defaultFallback(SkUnichar unicode,
324 SkFontStyle fontStyle,
325 const SkString& locale) {
326
327 for (const auto& manager : this->getFontManagerOrder()) {
328 std::vector<const char*> bcp47;
329 if (!locale.isEmpty()) {
330 bcp47.push_back(locale.c_str());
331 }
332 sk_sp<SkTypeface> typeface(manager->matchFamilyStyleCharacter(
333 nullptr, fontStyle, bcp47.data(), bcp47.size(), unicode));
334
335 if (typeface != nullptr) {
336 return typeface;
337 }
338 }
339 return nullptr;
340 }
341 #endif
342
343
344 #ifndef ENABLE_TEXT_ENHANCE
345 // Find ANY font in available font managers that resolves this emojiStart
346 sk_sp<SkTypeface> FontCollection::defaultEmojiFallback(SkUnichar emojiStart,
347 SkFontStyle fontStyle,
348 const SkString& locale) {
349
350 for (const auto& manager : this->getFontManagerOrder()) {
351 std::vector<const char*> bcp47;
352 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
353 sk_sp<SkTypeface> emojiTypeface =
354 fDefaultFontManager->matchFamilyStyle(kColorEmojiFontMac, SkFontStyle());
355 if (emojiTypeface != nullptr) {
356 return emojiTypeface;
357 }
358 #else
359 bcp47.push_back(kColorEmojiLocale);
360 #endif
361 if (!locale.isEmpty()) {
362 bcp47.push_back(locale.c_str());
363 }
364
365 // Not really ideal since the first codepoint may not be the best one
366 // but we start from a good colored emoji at least
367 sk_sp<SkTypeface> typeface(manager->matchFamilyStyleCharacter(
368 nullptr, fontStyle, bcp47.data(), bcp47.size(), emojiStart));
369 if (typeface != nullptr) {
370 // ... and stop as soon as we find something in hope it will work for all of them
371 return typeface;
372 }
373 }
374 return nullptr;
375 }
376 #endif
377
378 #ifdef ENABLE_TEXT_ENHANCE
379 std::shared_ptr<RSTypeface> FontCollection::defaultFallback() {
380 std::shared_lock<std::shared_mutex> readLock(mutex_);
381 if (fDefaultFontManager == nullptr) {
382 return nullptr;
383 }
384 for (const auto& familyName : fDefaultFamilyNames) {
385 std::shared_ptr<RSTypeface> match = std::shared_ptr<RSTypeface>(
386 fDefaultFontManager->MatchFamilyStyle(familyName.c_str(), RSFontStyle()));
387 if (match) {
388 return match;
389 }
390 }
391 return nullptr;
392 }
393 #else
394 sk_sp<SkTypeface> FontCollection::defaultFallback() {
395 if (fDefaultFontManager == nullptr) {
396 return nullptr;
397 }
398 for (const SkString& familyName : fDefaultFamilyNames) {
399 sk_sp<SkTypeface> match = fDefaultFontManager->matchFamilyStyle(familyName.c_str(),
400 SkFontStyle());
401 if (match) {
402 return match;
403 }
404 }
405 return nullptr;
406 }
407 #endif
408
409 #ifdef ENABLE_TEXT_ENHANCE
410 class SkLRUCacheMgr {
411 public:
412 SkLRUCacheMgr(SkLRUCache<uint32_t, std::shared_ptr<RSTypeface>>& lruCache, SkMutex& mutex)
413 :fLRUCache(lruCache), fMutex(mutex)
414 {
415 fMutex.acquire();
416 }
417 SkLRUCacheMgr(const SkLRUCacheMgr&) = delete;
418 SkLRUCacheMgr(SkLRUCacheMgr&&) = delete;
419 SkLRUCacheMgr& operator=(const SkLRUCacheMgr&) = delete;
420 SkLRUCacheMgr& operator=(SkLRUCacheMgr&&) = delete;
421
422 ~SkLRUCacheMgr() {
423 fMutex.release();
424 }
425
426 std::shared_ptr<RSTypeface> find(uint32_t fontId) {
427 auto face = fLRUCache.find(fontId);
428 return face == nullptr ? nullptr : *face;
429 }
430
431 std::shared_ptr<RSTypeface> insert(uint32_t fontId, std::shared_ptr<RSTypeface> hbFont) {
432 auto face = fLRUCache.insert(fontId, std::move(hbFont));
433 return face == nullptr ? nullptr : *face;
434 }
435
436 void reset() {
437 fLRUCache.reset();
438 }
439
440 private:
441 SkLRUCache<uint32_t, std::shared_ptr<RSTypeface>>& fLRUCache;
442 SkMutex& fMutex;
443 };
444
445 static SkLRUCacheMgr GetLRUCacheInstance() {
446 static SkMutex gFaceCacheMutex;
447 static SkLRUCache<uint32_t, std::shared_ptr<RSTypeface>> gFaceCache(MAX_VARTYPEFACE_SIZE);
448 return SkLRUCacheMgr(gFaceCache, gFaceCacheMutex);
449 }
450
451 std::shared_ptr<RSTypeface> FontCollection::CloneTypeface(std::shared_ptr<RSTypeface> typeface,
452 const std::optional<FontArguments>& fontArgs) {
453 if (!typeface || !fontArgs || typeface->IsCustomTypeface()) {
454 return typeface;
455 }
456
457 size_t hash = 0;
458 hash ^= std::hash<FontArguments>()(fontArgs.value());
459 hash ^= std::hash<uint32_t>()(typeface->GetUniqueID());
460
461 std::unique_lock<std::shared_mutex> writeLock(mutex_);
462 auto cached = GetLRUCacheInstance().find(hash);
463 if (cached) {
464 return cached;
465 } else {
466 auto varTypeface = fontArgs->CloneTypeface(typeface);
467 if (!varTypeface) {
468 return typeface;
469 }
470 GetLRUCacheInstance().insert(hash, varTypeface);
471 return varTypeface;
472 }
473 }
474 #endif
475
476 void FontCollection::disableFontFallback() {
477 #ifdef ENABLE_TEXT_ENHANCE
478 std::unique_lock<std::shared_mutex> writeLock(mutex_);
479 #endif
480 fEnableFontFallback = false;
481 }
482
483 void FontCollection::enableFontFallback() {
484 #ifdef ENABLE_TEXT_ENHANCE
485 std::unique_lock<std::shared_mutex> writeLock(mutex_);
486 #endif
487 fEnableFontFallback = true;
488 }
489
490 void FontCollection::clearCaches() {
491 #ifdef ENABLE_TEXT_ENHANCE
492 std::unique_lock<std::shared_mutex> writeLock(mutex_);
493 fParagraphCache.reset();
494 fTypefaces.clear();
495 SkGraphics::PurgeFontCache();
496 #else
497 fParagraphCache.reset();
498 fTypefaces.reset();
499 #endif
500 SkShapers::HB::PurgeCaches();
501 }
502
503 } // namespace textlayout
504 } // namespace skia
505