• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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