xref: /aosp_15_r20/external/skia/modules/skparagraph/src/FontCollection.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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