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