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