xref: /aosp_15_r20/external/skia/src/ports/SkFontMgr_android.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2014 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/core/SkTypes.h"
9 
10 #include "include/core/SkData.h"
11 #include "include/core/SkFontMgr.h"
12 #include "include/core/SkFontStyle.h"
13 #include "include/core/SkPaint.h"
14 #include "include/core/SkRefCnt.h"
15 #include "include/core/SkStream.h"
16 #include "include/core/SkString.h"
17 #include "include/ports/SkFontMgr_android.h"
18 #include "include/ports/SkFontScanner_FreeType.h"
19 #include "include/private/base/SkFixed.h"
20 #include "include/private/base/SkTArray.h"
21 #include "include/private/base/SkTDArray.h"
22 #include "include/private/base/SkTemplates.h"
23 #include "src/base/SkTSearch.h"
24 #include "src/core/SkAdvancedTypefaceMetrics.h"
25 #include "src/core/SkFontDescriptor.h"
26 #include "src/core/SkOSFile.h"
27 #include "src/core/SkTypefaceCache.h"
28 #include "src/ports/SkFontMgr_android_parser.h"
29 #include "src/ports/SkTypeface_proxy.h"
30 
31 #include <algorithm>
32 #include <limits>
33 
34 using namespace skia_private;
35 
36 class SkData;
37 
38 namespace {
39 class SkTypeface_AndroidSystem : public SkTypeface_proxy {
40 public:
SkTypeface_AndroidSystem(sk_sp<SkTypeface> proxy,const SkString & pathName,const bool cacheFontFiles,int index,const SkFontStyle & style,bool isFixedPitch,const SkString & familyName,const TArray<SkLanguage,true> & lang,FontVariant variantStyle)41     SkTypeface_AndroidSystem(sk_sp<SkTypeface> proxy,
42                              const SkString& pathName,
43                              const bool cacheFontFiles,
44                              int index,
45                              const SkFontStyle& style,
46                              bool isFixedPitch,
47                              const SkString& familyName,
48                              const TArray<SkLanguage, true>& lang,
49                              FontVariant variantStyle)
50             : SkTypeface_proxy(style, isFixedPitch)
51             , fPathName(pathName)
52             , fFamilyName(familyName)
53             , fIndex(index)
54             , fLang(lang)
55             , fVariantStyle(variantStyle)
56             , fFile(cacheFontFiles ? sk_fopen(fPathName.c_str(), kRead_SkFILE_Flag) : nullptr) {
57         SkTypeface_proxy::setProxy(proxy);
58     }
Make(sk_sp<SkTypeface> proxy,const SkString & pathName,const bool cacheFontFiles,int index,const SkFontStyle & style,bool isFixedPitch,const SkString & familyName,const TArray<SkLanguage,true> & lang,FontVariant variantStyle)59     static sk_sp<SkTypeface_AndroidSystem> Make(sk_sp<SkTypeface> proxy,
60                                                 const SkString& pathName,
61                                                 const bool cacheFontFiles,
62                                                 int index,
63                                                 const SkFontStyle& style,
64                                                 bool isFixedPitch,
65                                                 const SkString& familyName,
66                                                 const TArray<SkLanguage, true>& lang,
67                                                 FontVariant variantStyle) {
68         return sk_sp<SkTypeface_AndroidSystem>(new SkTypeface_AndroidSystem(std::move(proxy),
69                                                                             pathName,
70                                                                             cacheFontFiles,
71                                                                             index,
72                                                                             style,
73                                                                             isFixedPitch,
74                                                                             familyName,
75                                                                             lang,
76                                                                             variantStyle));
77     }
78 
makeStream() const79     std::unique_ptr<SkStreamAsset> makeStream() const {
80         if (fFile) {
81             sk_sp<SkData> data(SkData::MakeFromFILE(fFile));
82             return data ? std::make_unique<SkMemoryStream>(std::move(data)) : nullptr;
83         }
84         return SkStream::MakeFromFile(fPathName.c_str());
85     }
86 
87     const SkString fPathName;
88     const SkString fFamilyName;
89     int fIndex;
90     const STArray<4, SkFixed, true> fAxes;
91     const STArray<4, SkLanguage, true> fLang;
92     const FontVariant fVariantStyle;
93     SkAutoTCallVProc<FILE, sk_fclose> fFile;
94 
95 protected:
onGetFamilyName(SkString * familyName) const96     void onGetFamilyName(SkString* familyName) const override {
97         *familyName = fFamilyName;
98     }
99 
onMakeClone(const SkFontArguments & args) const100     sk_sp<SkTypeface> onMakeClone(const SkFontArguments& args) const override {
101         return SkTypeface_AndroidSystem::Make(
102                 SkTypeface_proxy::onMakeClone(args),
103                 fPathName,
104                 fFile,
105                 fIndex,
106                 this->fontStyle(),
107                 this->isFixedPitch(),
108                 fFamilyName,
109                 fLang,
110                 fVariantStyle);
111     }
112 
onGetFontDescriptor(SkFontDescriptor * desc,bool * serialize) const113     void onGetFontDescriptor(SkFontDescriptor* desc, bool* serialize) const override {
114         SkTypeface_proxy::onGetFontDescriptor(desc, serialize);
115 
116         SkASSERT(desc);
117         SkASSERT(serialize);
118         desc->setFamilyName(fFamilyName.c_str());
119         desc->setStyle(this->fontStyle());
120         *serialize = false;
121     }
122 
onOpenStream(int * ttcIndex) const123     std::unique_ptr<SkStreamAsset> onOpenStream(int* ttcIndex) const override {
124         *ttcIndex = fIndex;
125         return this->makeStream();
126     }
127 
onGetFontStyle() const128     SkFontStyle onGetFontStyle() const override {
129         return SkTypeface::onGetFontStyle();
130     }
131 
onGetFixedPitch() const132     bool onGetFixedPitch() const override {
133         return SkTypeface::onGetFixedPitch();
134     }
135 };
136 
sk_sp_static_cast(sk_sp<S> && s)137 template <typename D, typename S> sk_sp<D> sk_sp_static_cast(sk_sp<S>&& s) {
138     return sk_sp<D>(static_cast<D*>(s.release()));
139 }
140 
141 class SkFontStyleSet_Android : public SkFontStyleSet {
142 public:
SkFontStyleSet_Android(const FontFamily & family,const SkFontScanner * scanner,const bool cacheFontFiles)143     explicit SkFontStyleSet_Android(const FontFamily& family, const SkFontScanner* scanner,
144                                     const bool cacheFontFiles) {
145         const SkString* cannonicalFamilyName = nullptr;
146         if (!family.fNames.empty()) {
147             cannonicalFamilyName = &family.fNames[0];
148         }
149         fFallbackFor = family.fFallbackFor;
150 
151         // TODO? make this lazy
152         for (int i = 0; i < family.fFonts.size(); ++i) {
153             const FontFileInfo& fontFile = family.fFonts[i];
154 
155             SkString pathName(family.fBasePath);
156             pathName.append(fontFile.fFileName);
157 
158             std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(pathName.c_str());
159             if (!stream) {
160                 SkDEBUGF("Requested font file %s does not exist or cannot be opened.\n",
161                          pathName.c_str());
162                 continue;
163             }
164 
165             SkFontArguments::VariationPosition position = {
166                     fontFile.fVariationDesignPosition.begin(),
167                     fontFile.fVariationDesignPosition.size()
168             };
169             auto proxy = scanner->MakeFromStream(
170                 std::move(stream),
171                 SkFontArguments().setCollectionIndex(fontFile.fIndex)
172                                  .setVariationDesignPosition(position));
173             if (!proxy) {
174                 SkDEBUGF("Requested font file %s does not have valid font data.\n",
175                          pathName.c_str());
176                 continue;
177             }
178 
179             uint32_t variant = family.fVariant;
180             if (kDefault_FontVariant == variant) {
181                 variant = kCompact_FontVariant | kElegant_FontVariant;
182             }
183 
184             // The first specified family name overrides the family name found in the font.
185             // TODO: SkTypeface_AndroidSystem::onCreateFamilyNameIterator should return
186             // all of the specified family names in addition to the names found in the font.
187             SkString familyName;
188             proxy->getFamilyName(&familyName);
189             if (cannonicalFamilyName != nullptr) {
190                 familyName = *cannonicalFamilyName;
191             }
192 
193             SkFontStyle fontStyle = proxy->fontStyle();
194             int weight = fontFile.fWeight != 0 ? fontFile.fWeight : fontStyle.weight();
195             SkFontStyle::Slant slant = fontStyle.slant();
196             switch (fontFile.fStyle) {
197                 case FontFileInfo::Style::kAuto: slant = fontStyle.slant(); break;
198                 case FontFileInfo::Style::kNormal: slant = SkFontStyle::kUpright_Slant; break;
199                 case FontFileInfo::Style::kItalic: slant = SkFontStyle::kItalic_Slant; break;
200                 default: SkASSERT(false); break;
201             }
202             fontStyle = SkFontStyle(weight, fontStyle.width(), slant);
203 
204             fStyles.push_back().reset(
205                 new SkTypeface_AndroidSystem(proxy,
206                                              pathName,
207                                              cacheFontFiles,
208                                              fontFile.fIndex,
209                                              fontStyle,
210                                              proxy->isFixedPitch(),
211                                              familyName,
212                                              family.fLanguages,
213                                              variant));
214         }
215     }
216 
count()217     int count() override {
218         return fStyles.size();
219     }
getStyle(int index,SkFontStyle * style,SkString * name)220     void getStyle(int index, SkFontStyle* style, SkString* name) override {
221         if (index < 0 || fStyles.size() <= index) {
222             return;
223         }
224         if (style) {
225             *style = fStyles[index]->fontStyle();
226         }
227         if (name) {
228             name->reset();
229         }
230     }
createTypeface(int index)231     sk_sp<SkTypeface> createTypeface(int index) override {
232         if (index < 0 || fStyles.size() <= index) {
233             return nullptr;
234         }
235         return fStyles[index];
236     }
237 
matchAStyle(const SkFontStyle & pattern)238     sk_sp<SkTypeface_AndroidSystem> matchAStyle(const SkFontStyle& pattern) {
239         return sk_sp_static_cast<SkTypeface_AndroidSystem>(this->matchStyleCSS3(pattern));
240     }
matchStyle(const SkFontStyle & pattern)241     sk_sp<SkTypeface> matchStyle(const SkFontStyle& pattern) override {
242         return this->matchAStyle(pattern);
243     }
244 
245 private:
246     TArray<sk_sp<SkTypeface_AndroidSystem>> fStyles;
247     SkString fFallbackFor;
248 
249     friend struct NameToFamily;
250     friend class SkFontMgr_Android;
251 
252     using INHERITED = SkFontStyleSet;
253 };
254 
255 /** On Android a single family can have many names, but our API assumes unique names.
256  *  Map names to the back end so that all names for a given family refer to the same
257  *  (non-replicated) set of typefaces.
258  *  SkTDict<> doesn't let us do index-based lookup, so we write our own mapping.
259  */
260 struct NameToFamily {
261     SkString name;
262     SkFontStyleSet_Android* styleSet;
263 };
264 
265 class SkFontMgr_Android : public SkFontMgr {
266 public:
SkFontMgr_Android(const SkFontMgr_Android_CustomFonts * custom,std::unique_ptr<SkFontScanner> scanner)267     SkFontMgr_Android(const SkFontMgr_Android_CustomFonts* custom,
268                       std::unique_ptr<SkFontScanner> scanner)
269         : fScanner(std::move(scanner)) {
270         SkTDArray<FontFamily*> families;
271         if (custom && SkFontMgr_Android_CustomFonts::kPreferSystem != custom->fSystemFontUse) {
272             SkString base(custom->fBasePath);
273             SkFontMgr_Android_Parser::GetCustomFontFamilies(
274                 families, base, custom->fFontsXml, custom->fFallbackFontsXml);
275         }
276         if (!custom ||
277             (custom && SkFontMgr_Android_CustomFonts::kOnlyCustom != custom->fSystemFontUse))
278         {
279             SkFontMgr_Android_Parser::GetSystemFontFamilies(families);
280         }
281         if (custom && SkFontMgr_Android_CustomFonts::kPreferSystem == custom->fSystemFontUse) {
282             SkString base(custom->fBasePath);
283             SkFontMgr_Android_Parser::GetCustomFontFamilies(
284                 families, base, custom->fFontsXml, custom->fFallbackFontsXml);
285         }
286         this->buildNameToFamilyMap(families, custom ? custom->fIsolated : false);
287         this->findDefaultStyleSet();
288         for (FontFamily* p : families) {
289             delete p;
290         }
291         families.reset();
292     }
293 
294 protected:
295     /** Returns not how many families we have, but how many unique names
296      *  exist among the families.
297      */
onCountFamilies() const298     int onCountFamilies() const override {
299         return fNameToFamilyMap.size();
300     }
301 
onGetFamilyName(int index,SkString * familyName) const302     void onGetFamilyName(int index, SkString* familyName) const override {
303         if (index < 0 || fNameToFamilyMap.size() <= index) {
304             familyName->reset();
305             return;
306         }
307         familyName->set(fNameToFamilyMap[index].name);
308     }
309 
onCreateStyleSet(int index) const310     sk_sp<SkFontStyleSet> onCreateStyleSet(int index) const override {
311         if (index < 0 || fNameToFamilyMap.size() <= index) {
312             return nullptr;
313         }
314         return sk_ref_sp(fNameToFamilyMap[index].styleSet);
315     }
316 
onMatchFamily(const char familyName[]) const317     sk_sp<SkFontStyleSet> onMatchFamily(const char familyName[]) const override {
318         if (!familyName) {
319             return nullptr;
320         }
321         SkAutoAsciiToLC tolc(familyName);
322         for (int i = 0; i < fNameToFamilyMap.size(); ++i) {
323             if (fNameToFamilyMap[i].name.equals(tolc.lc())) {
324                 return sk_ref_sp(fNameToFamilyMap[i].styleSet);
325             }
326         }
327         // TODO: eventually we should not need to name fallback families.
328         for (int i = 0; i < fFallbackNameToFamilyMap.size(); ++i) {
329             if (fFallbackNameToFamilyMap[i].name.equals(tolc.lc())) {
330                 return sk_ref_sp(fFallbackNameToFamilyMap[i].styleSet);
331             }
332         }
333         return nullptr;
334     }
335 
onMatchFamilyStyle(const char familyName[],const SkFontStyle & style) const336     sk_sp<SkTypeface> onMatchFamilyStyle(const char familyName[],
337                                          const SkFontStyle& style) const override {
338         sk_sp<SkFontStyleSet> sset(this->matchFamily(familyName));
339         return sset->matchStyle(style);
340     }
341 
find_family_style_character(const SkString & familyName,const TArray<NameToFamily,true> & fallbackNameToFamilyMap,const SkFontStyle & style,bool elegant,const SkString & langTag,SkUnichar character)342     static sk_sp<SkTypeface_AndroidSystem> find_family_style_character(
343             const SkString& familyName,
344             const TArray<NameToFamily, true>& fallbackNameToFamilyMap,
345             const SkFontStyle& style, bool elegant,
346             const SkString& langTag, SkUnichar character)
347     {
348         for (int i = 0; i < fallbackNameToFamilyMap.size(); ++i) {
349             SkFontStyleSet_Android* family = fallbackNameToFamilyMap[i].styleSet;
350             if (familyName != family->fFallbackFor) {
351                 continue;
352             }
353             sk_sp<SkTypeface_AndroidSystem> face(family->matchAStyle(style));
354 
355             if (!langTag.isEmpty() &&
356                 std::none_of(face->fLang.begin(), face->fLang.end(), [&](const SkLanguage& lang){
357                     return lang.getTag().startsWith(langTag.c_str());
358                 }))
359             {
360                 continue;
361             }
362 
363             if (SkToBool(face->fVariantStyle & kElegant_FontVariant) != elegant) {
364                 continue;
365             }
366 
367             if (face->unicharToGlyph(character) != 0) {
368                 return face;
369             }
370         }
371         return nullptr;
372     }
373 
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character) const374     sk_sp<SkTypeface> onMatchFamilyStyleCharacter(const char familyName[],
375                                                   const SkFontStyle& style,
376                                                   const char* bcp47[],
377                                                   int bcp47Count,
378                                                   SkUnichar character) const override {
379         // The variant 'elegant' is 'not squashed', 'compact' is 'stays in ascent/descent'.
380         // The variant 'default' means 'compact and elegant'.
381         // As a result, it is not possible to know the variant context from the font alone.
382         // TODO: add 'is_elegant' and 'is_compact' bits to 'style' request.
383 
384         SkString familyNameString(familyName);
385         for (const SkString& currentFamilyName : { familyNameString, SkString() }) {
386             // The first time match anything elegant, second time anything not elegant.
387             for (int elegant = 2; elegant --> 0;) {
388                 for (int bcp47Index = bcp47Count; bcp47Index --> 0;) {
389                     SkLanguage lang(bcp47[bcp47Index]);
390                     while (!lang.getTag().isEmpty()) {
391                         sk_sp<SkTypeface_AndroidSystem> matchingTypeface =
392                             find_family_style_character(currentFamilyName, fFallbackNameToFamilyMap,
393                                                         style, SkToBool(elegant),
394                                                         lang.getTag(), character);
395                         if (matchingTypeface) {
396                             return matchingTypeface;
397                         }
398 
399                         lang = lang.getParent();
400                     }
401                 }
402                 sk_sp<SkTypeface_AndroidSystem> matchingTypeface =
403                     find_family_style_character(currentFamilyName, fFallbackNameToFamilyMap,
404                                                 style, SkToBool(elegant),
405                                                 SkString(), character);
406                 if (matchingTypeface) {
407                     return matchingTypeface;
408                 }
409             }
410         }
411         return nullptr;
412     }
413 
onMakeFromData(sk_sp<SkData> data,int ttcIndex) const414     sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData> data, int ttcIndex) const override {
415         return this->makeFromStream(std::unique_ptr<SkStreamAsset>(new SkMemoryStream(std::move(data))),
416                                     ttcIndex);
417     }
418 
onMakeFromFile(const char path[],int ttcIndex) const419     sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override {
420         std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(path);
421         return stream ? this->makeFromStream(std::move(stream), ttcIndex) : nullptr;
422     }
423 
onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,int ttcIndex) const424     sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,
425                                             int ttcIndex) const override {
426         return this->makeFromStream(std::move(stream),
427                                     SkFontArguments().setCollectionIndex(ttcIndex));
428     }
429 
onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,const SkFontArguments & args) const430     sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,
431                                            const SkFontArguments& args) const override {
432         return fScanner->MakeFromStream(std::move(stream), args);
433     }
434 
onLegacyMakeTypeface(const char familyName[],SkFontStyle style) const435     sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[], SkFontStyle style) const override {
436         if (familyName) {
437             // On Android, we must return nullptr when we can't find the requested
438             // named typeface so that the system/app can provide their own recovery
439             // mechanism. On other platforms we'd provide a typeface from the
440             // default family instead.
441             return sk_sp<SkTypeface>(this->onMatchFamilyStyle(familyName, style));
442         }
443         if (fDefaultStyleSet) {
444             return sk_sp<SkTypeface>(fDefaultStyleSet->matchStyle(style));
445         }
446         return SkTypeface::MakeEmpty();
447     }
448 
449 
450 private:
451 
452     std::unique_ptr<SkFontScanner> fScanner;
453 
454     TArray<sk_sp<SkFontStyleSet_Android>> fStyleSets;
455     sk_sp<SkFontStyleSet> fDefaultStyleSet;
456 
457     TArray<NameToFamily, true> fNameToFamilyMap;
458     TArray<NameToFamily, true> fFallbackNameToFamilyMap;
459 
addFamily(FontFamily & family,const bool isolated,int familyIndex)460     void addFamily(FontFamily& family, const bool isolated, int familyIndex) {
461         TArray<NameToFamily, true>* nameToFamily = &fNameToFamilyMap;
462         if (family.fIsFallbackFont) {
463             nameToFamily = &fFallbackNameToFamilyMap;
464 
465             if (family.fNames.empty()) {
466                 SkString& fallbackName = family.fNames.push_back();
467                 fallbackName.printf("%.2x##fallback", (uint32_t)familyIndex);
468             }
469         }
470 
471         sk_sp<SkFontStyleSet_Android> newSet =
472             sk_make_sp<SkFontStyleSet_Android>(family, fScanner.get(), isolated);
473         if (0 == newSet->count()) {
474             return;
475         }
476 
477         for (const SkString& name : family.fNames) {
478             nameToFamily->emplace_back(NameToFamily{name, newSet.get()});
479         }
480         fStyleSets.emplace_back(std::move(newSet));
481     }
buildNameToFamilyMap(const SkTDArray<FontFamily * > & families,const bool isolated)482     void buildNameToFamilyMap(const SkTDArray<FontFamily*>& families, const bool isolated) {
483         int familyIndex = 0;
484         for (FontFamily* family : families) {
485             addFamily(*family, isolated, familyIndex++);
486             for (const auto& [unused, fallbackFamily] : family->fallbackFamilies) {
487                 addFamily(*fallbackFamily, isolated, familyIndex++);
488             }
489         }
490     }
491 
findDefaultStyleSet()492     void findDefaultStyleSet() {
493         static const char* defaultNames[] = { "sans-serif" };
494         for (const char* defaultName : defaultNames) {
495             fDefaultStyleSet = this->onMatchFamily(defaultName);
496             if (fDefaultStyleSet) {
497                 break;
498             }
499         }
500         if (!fDefaultStyleSet && !fStyleSets.empty()) {
501             fDefaultStyleSet = fStyleSets[0];
502         }
503     }
504 
505     using INHERITED = SkFontMgr;
506 };
507 
508 #ifdef SK_DEBUG
509 static char const * const gSystemFontUseStrings[] = {
510     "OnlyCustom", "PreferCustom", "PreferSystem"
511 };
512 #endif
513 
514 }  // namespace
515 
SkFontMgr_New_Android(const SkFontMgr_Android_CustomFonts * custom)516 sk_sp<SkFontMgr> SkFontMgr_New_Android(const SkFontMgr_Android_CustomFonts* custom) {
517     return SkFontMgr_New_Android(custom, SkFontScanner_Make_FreeType());
518 }
519 
SkFontMgr_New_Android(const SkFontMgr_Android_CustomFonts * custom,std::unique_ptr<SkFontScanner> scanner)520 sk_sp<SkFontMgr> SkFontMgr_New_Android(const SkFontMgr_Android_CustomFonts* custom, std::unique_ptr<SkFontScanner> scanner) {
521     if (custom) {
522         SkASSERT(0 <= custom->fSystemFontUse);
523         SkASSERT(custom->fSystemFontUse < std::size(gSystemFontUseStrings));
524         SkDEBUGF("SystemFontUse: %s BasePath: %s Fonts: %s FallbackFonts: %s\n",
525                  gSystemFontUseStrings[custom->fSystemFontUse],
526                  custom->fBasePath,
527                  custom->fFontsXml,
528                  custom->fFallbackFontsXml);
529     }
530     return sk_make_sp<SkFontMgr_Android>(custom, std::move(scanner));
531 }
532