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