• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2024 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/SkFontMgr.h"
9 #include "include/core/SkStream.h"
10 #include "include/core/SkTypeface.h"
11 #include "include/core/SkTypes.h"
12 #include "include/ports/SkFontMgr_android_ndk.h"
13 #include "include/ports/SkFontScanner_FreeType.h"
14 #include "include/private/base/SkTArray.h"
15 #include "include/private/base/SkTemplates.h"
16 #include "src/base/SkTSearch.h"
17 #include "src/base/SkUTF.h"
18 #include "src/core/SkFontDescriptor.h"
19 #include "src/core/SkOSFile.h"
20 #include "src/ports/SkTypeface_proxy.h"
21 
22 #include <android/api-level.h>
23 
24 using namespace skia_private;
25 
26 /**
27  * Technically, the AFont API was introduced in Android 10 (Q, API 29). However...
28  *
29  * The AFontMatcher API implementation is broken from its introduction until at least API 33. What
30  * is desired is to find a font for the given locale which contains the given character. However,
31  * the implementation actually attempts to shape the string passed to it with the default font and
32  * then returns the font chosen for the first run. However, this produces undesireable results, as
33  * it will always prefer the default font over the locale, so any code points covered by the default
34  * font will always come from the default font regardless of the requested locale. In addition, this
35  * will claim coverage for code points "made up" by the shaper through normalization,
36  * denormalization, whitespace synthesis, no-draw synthesis, etc, for the default font, when there
37  * may be better choices later in fallback.
38  *
39  * On Android 10 (Q, API 29) AFont_getLocale always returns nullptr (if there is a locale set) or
40  * whatever std::unique_ptr<std::string>()->c_str() returns, which happens to be 0x1. As a result,
41  * AFont_getLocale cannot be used until Android 11 (R, API 30). This is b/139201432 and fixed with
42  * "Make AFont_getLocale work" [0]. This change is in Android 11 (API 30) but does not appear to
43  * have been cherry-picked into Android 10 (Q, API 29).
44  * [0]  https://cs.android.com/android/_/android/platform/frameworks/base/+/01709c7469b59e451f064c266bbe442e9bef0ab4
45  *
46  * As a result, there is no correct way to use locale information from the Android 10 NDK. So this
47  * font manager only works with Android 11 (R, API 30) and above.
48  */
49 #define SK_FONTMGR_ANDROID_NDK_API_LEVEL __ANDROID_API_R__
50 
51 #if __ANDROID_API__ >= SK_FONTMGR_ANDROID_NDK_API_LEVEL
52 #include <android/font.h>
53 #include <android/font_matcher.h>
54 #include <android/system_fonts.h>
55 #endif
56 
57 #include <cinttypes>
58 #include <memory>
59 
60 #include <dlfcn.h>
61 
62 struct ASystemFontIterator;
63 struct AFont;
64 
65 namespace {
66 
67 [[maybe_unused]] static inline const constexpr bool kSkFontMgrVerbose = false;
68 
69 struct AndroidFontAPI {
70     ASystemFontIterator* (*ASystemFontIterator_open)();
71     void (*ASystemFontIterator_close)(ASystemFontIterator*);
72     AFont* (*ASystemFontIterator_next)(ASystemFontIterator*);
73 
74     void (*AFont_close)(AFont*);
75     const char* (*AFont_getFontFilePath)(const AFont*);
76     uint16_t (*AFont_getWeight)(const AFont*);
77     bool (*AFont_isItalic)(const AFont*);
78     const char* (*AFont_getLocale)(const AFont*);
79     size_t (*AFont_getCollectionIndex)(const AFont*);
80     size_t (*AFont_getAxisCount)(const AFont*);
81     uint32_t (*AFont_getAxisTag)(const AFont*, uint32_t axisIndex);
82     float (*AFont_getAxisValue)(const AFont*, uint32_t axisIndex);
83 };
84 
85 #if __ANDROID_API__ >= SK_FONTMGR_ANDROID_NDK_API_LEVEL
86 
GetAndroidFontAPI()87 static const AndroidFontAPI* GetAndroidFontAPI() {
88     static AndroidFontAPI androidFontAPI {
89         ASystemFontIterator_open,
90         ASystemFontIterator_close,
91         ASystemFontIterator_next,
92 
93         AFont_close,
94         AFont_getFontFilePath,
95         AFont_getWeight,
96         AFont_isItalic,
97         AFont_getLocale,
98         AFont_getCollectionIndex,
99         AFont_getAxisCount,
100         AFont_getAxisTag,
101         AFont_getAxisValue,
102     };
103     if constexpr (kSkFontMgrVerbose) { SkDebugf("SKIA: GetAndroidFontAPI direct\n"); }
104     return &androidFontAPI;
105 }
106 
107 #else
108 
GetAndroidFontAPI()109 static const AndroidFontAPI* GetAndroidFontAPI() {
110     struct OptionalAndroidFontAPI : AndroidFontAPI {
111         bool valid = false;
112     };
113     static OptionalAndroidFontAPI androidFontAPI = [](){
114         using DLHandle = std::unique_ptr<void, SkFunctionObject<dlclose>>;
115         OptionalAndroidFontAPI api;
116 
117         if (android_get_device_api_level() < SK_FONTMGR_ANDROID_NDK_API_LEVEL) {
118             return api;
119         }
120 
121         DLHandle self(dlopen("libandroid.so", RTLD_LAZY | RTLD_LOCAL));
122         if (!self) {
123             return api;
124         }
125 
126 #define SK_DLSYM_ANDROID_FONT_API(NAME)                           \
127         do {                                                      \
128             *(void**)(&api.NAME) = dlsym(self.get(), #NAME);      \
129             if (!api.NAME) {                                      \
130                 if constexpr (kSkFontMgrVerbose) {                \
131                     SkDebugf("SKIA: Failed to load: " #NAME "\n");\
132                 }                                                 \
133                 return api;                                       \
134             }                                                     \
135         } while (0)
136 
137         SK_DLSYM_ANDROID_FONT_API(ASystemFontIterator_open);
138         SK_DLSYM_ANDROID_FONT_API(ASystemFontIterator_close);
139         SK_DLSYM_ANDROID_FONT_API(ASystemFontIterator_next);
140 
141         SK_DLSYM_ANDROID_FONT_API(AFont_close);
142         SK_DLSYM_ANDROID_FONT_API(AFont_getFontFilePath);
143         SK_DLSYM_ANDROID_FONT_API(AFont_getWeight);
144         SK_DLSYM_ANDROID_FONT_API(AFont_isItalic);
145         SK_DLSYM_ANDROID_FONT_API(AFont_getLocale);
146         SK_DLSYM_ANDROID_FONT_API(AFont_getCollectionIndex);
147         SK_DLSYM_ANDROID_FONT_API(AFont_getAxisCount);
148         SK_DLSYM_ANDROID_FONT_API(AFont_getAxisTag);
149         SK_DLSYM_ANDROID_FONT_API(AFont_getAxisValue);
150 
151 #undef SK_DLSYM_ANDROID_FONT_API
152 
153         api.valid = true;
154         return api;
155     }();
156     if constexpr (kSkFontMgrVerbose) { SkDebugf("SKIA: GetAndroidFontAPI dlsym\n"); }
157     return androidFontAPI.valid ? &androidFontAPI : nullptr;
158 };
159 
160 #endif
161 
162 struct SkAFont {
SkAFont__anonabc623540111::SkAFont163     SkAFont(const AndroidFontAPI& api, AFont* font) : fAPI(api), fFont(font) {}
SkAFont__anonabc623540111::SkAFont164     SkAFont(SkAFont&& that) : fAPI(that.fAPI), fFont(that.fFont) {
165         that.fFont = nullptr;
166     }
~SkAFont__anonabc623540111::SkAFont167     ~SkAFont() {
168         if (fFont) {
169             if constexpr (kSkFontMgrVerbose) { SkDebugf("SKIA: AFont_close\n"); }
170             fAPI.AFont_close(fFont);
171         }
172     }
operator bool__anonabc623540111::SkAFont173     explicit operator bool() { return fFont; }
174 
getFontFilePath__anonabc623540111::SkAFont175     const char* getFontFilePath() const { return fAPI.AFont_getFontFilePath(fFont); }
getWeight__anonabc623540111::SkAFont176     uint16_t getWeight() const { return fAPI.AFont_getWeight(fFont); }
isItalic__anonabc623540111::SkAFont177     bool isItalic() const { return fAPI.AFont_isItalic(fFont); }
getLocale__anonabc623540111::SkAFont178     const char* getLocale() const { return fAPI.AFont_getLocale(fFont); }
getCollectionIndex__anonabc623540111::SkAFont179     size_t getCollectionIndex() const { return fAPI.AFont_getCollectionIndex(fFont); }
getAxisCount__anonabc623540111::SkAFont180     size_t getAxisCount() const { return fAPI.AFont_getAxisCount(fFont); }
getAxisTag__anonabc623540111::SkAFont181     uint32_t getAxisTag(uint32_t index) const { return fAPI.AFont_getAxisTag(fFont, index); }
getAxisValue__anonabc623540111::SkAFont182     float getAxisValue(uint32_t index) const { return fAPI.AFont_getAxisValue(fFont, index); }
183 
184 private:
185     const AndroidFontAPI& fAPI;
186     AFont* fFont;
187 };
188 
189 struct SkASystemFontIterator {
SkASystemFontIterator__anonabc623540111::SkASystemFontIterator190     SkASystemFontIterator(const AndroidFontAPI& api)
191         : fAPI(api)
192         , fIterator(fAPI.ASystemFontIterator_open())
193     {
194         if constexpr (kSkFontMgrVerbose) { SkDebugf("SKIA: ASystemFontIterator_open\n"); }
195     }
196     SkASystemFontIterator(SkASystemFontIterator&&) = default;
~SkASystemFontIterator__anonabc623540111::SkASystemFontIterator197     ~SkASystemFontIterator() {
198         if constexpr (kSkFontMgrVerbose) { SkDebugf("SKIA: ASystemFontIterator_close\n"); }
199         fAPI.ASystemFontIterator_close(fIterator);
200     }
operator bool__anonabc623540111::SkASystemFontIterator201     explicit operator bool() { return fIterator; }
202 
next__anonabc623540111::SkASystemFontIterator203     SkAFont next() { return SkAFont(fAPI, fAPI.ASystemFontIterator_next(fIterator)); }
204 
205 private:
206     const AndroidFontAPI& fAPI;
207     ASystemFontIterator* const fIterator;
208 };
209 
210 class SkLanguage {
211 public:
SkLanguage()212     SkLanguage() { }
SkLanguage(const SkString & tag)213     SkLanguage(const SkString& tag) : fTag(tag) { }
SkLanguage(const char * tag)214     SkLanguage(const char* tag) : fTag(tag) { }
SkLanguage(const char * tag,size_t len)215     SkLanguage(const char* tag, size_t len) : fTag(tag, len) { }
216     SkLanguage(const SkLanguage&) = default;
217     SkLanguage& operator=(const SkLanguage& b) = default;
218 
219     /** Gets a BCP 47 language identifier for this SkLanguage.
220         @return a BCP 47 language identifier representing this language
221     */
getTag() const222     const SkString& getTag() const { return fTag; }
223 
224     /** Performs BCP 47 fallback to return an SkLanguage one step more general.
225         @return an SkLanguage one step more general
226     */
getParent() const227     SkLanguage getParent() const {
228         SkASSERT(!fTag.isEmpty());
229         const char* tag = fTag.c_str();
230 
231         // strip off the rightmost "-.*"
232         const char* parentTagEnd = strrchr(tag, '-');
233         if (parentTagEnd == nullptr) {
234             return SkLanguage();
235         }
236         size_t parentTagLen = parentTagEnd - tag;
237         return SkLanguage(tag, parentTagLen);
238     }
239 
operator ==(const SkLanguage & b) const240     bool operator==(const SkLanguage& b) const {
241         return fTag == b.fTag;
242     }
operator !=(const SkLanguage & b) const243     bool operator!=(const SkLanguage& b) const {
244         return fTag != b.fTag;
245     }
246 
247     using sk_is_trivially_relocatable = std::true_type;
248 private:
249     //! BCP 47 language identifier
250     SkString fTag;
251     static_assert(::sk_is_trivially_relocatable<decltype(fTag)>::value);
252 };
253 
254 class SkTypeface_AndroidNDK : public SkTypeface_proxy {
255 public:
SkTypeface_AndroidNDK(sk_sp<SkTypeface> proxy,const SkString & pathName,const bool cacheFontFiles,int index,const SkFontStyle & style,bool isFixedPitch,const SkString & familyName,TArray<SkLanguage> && lang)256     SkTypeface_AndroidNDK(sk_sp<SkTypeface> proxy,
257                           const SkString& pathName,
258                           const bool cacheFontFiles,
259                           int index,
260                           const SkFontStyle& style,
261                           bool isFixedPitch,
262                           const SkString& familyName,
263                           TArray<SkLanguage>&& lang)
264         : SkTypeface_proxy(style, isFixedPitch)
265         , fFamilyName(familyName)
266         , fPathName(pathName)
267         , fIndex(index)
268         , fLang(std::move(lang))
269         , fFile(cacheFontFiles ? SkStream::MakeFromFile(fPathName.c_str()) : nullptr)
270         , fCacheFontFiles(cacheFontFiles)
271     {
272         if (cacheFontFiles) {
273             SkASSERT(fFile);
274         }
275         SkTypeface_proxy::setProxy(proxy);
276     }
277 
Make(sk_sp<SkTypeface> proxy,const SkString & pathName,const bool cacheFontFiles,int index,const SkFontStyle & style,bool isFixedPitch,const SkString & familyName,TArray<SkLanguage> && lang)278     static sk_sp<SkTypeface_AndroidNDK> Make(sk_sp<SkTypeface> proxy,
279                                              const SkString& pathName,
280                                              const bool cacheFontFiles,
281                                              int index,
282                                              const SkFontStyle& style,
283                                              bool isFixedPitch,
284                                              const SkString& familyName,
285                                              TArray<SkLanguage>&& lang) {
286         return sk_sp<SkTypeface_AndroidNDK>(new SkTypeface_AndroidNDK(std::move(proxy),
287                                                                       pathName,
288                                                                       cacheFontFiles,
289                                                                       index,
290                                                                       style,
291                                                                       isFixedPitch,
292                                                                       familyName,
293                                                                       std::move(lang)));
294     }
295 
makeStream() const296     std::unique_ptr<SkStreamAsset> makeStream() const {
297         if (fFile) {
298             return fFile->duplicate();
299         }
300         return SkStream::MakeFromFile(fPathName.c_str());
301     }
302 
onGetFamilyName(SkString * familyName) const303     void onGetFamilyName(SkString* familyName) const override {
304         *familyName = fFamilyName;
305     }
306 
onGetFontDescriptor(SkFontDescriptor * desc,bool * serialize) const307     void onGetFontDescriptor(SkFontDescriptor* desc, bool* serialize) const override {
308         SkASSERT(desc);
309         SkASSERT(serialize);
310         SkTypeface_proxy::onGetFontDescriptor(desc, serialize);
311         desc->setFamilyName(fFamilyName.c_str());
312         desc->setStyle(this->fontStyle());
313         *serialize = false;
314     }
315 
onOpenStream(int * ttcIndex) const316     std::unique_ptr<SkStreamAsset> onOpenStream(int* ttcIndex) const override {
317         *ttcIndex = fIndex;
318         return this->makeStream();
319     }
320 
onMakeClone(const SkFontArguments & args) const321     sk_sp<SkTypeface> onMakeClone(const SkFontArguments& args) const override {
322         auto proxy = SkTypeface_proxy::onMakeClone(args);
323         if (proxy == nullptr) {
324             return nullptr;
325         }
326         return SkTypeface_AndroidNDK::Make(
327                 std::move(proxy),
328                 fPathName,
329                 fCacheFontFiles,
330                 fIndex,
331                 this->fontStyle(),
332                 this->isFixedPitch(),
333                 fFamilyName,
334                 TArray<SkLanguage>());
335     }
336 
onGetFontStyle() const337     SkFontStyle onGetFontStyle() const override {
338         return SkTypeface::onGetFontStyle();
339     }
340 
onGetFixedPitch() const341     bool onGetFixedPitch() const override {
342         return SkTypeface::onGetFixedPitch();
343     }
344 
345     const SkString fFamilyName;
346     const SkString fPathName;
347     int fIndex;
348     const STArray<4, SkFixed> fAxes;
349     const STArray<4, SkLanguage> fLang;
350     std::unique_ptr<SkStreamAsset> fFile;
351     bool fCacheFontFiles;
352 };
353 
354 class SkFontStyleSet_AndroidNDK : public SkFontStyleSet {
355 public:
SkFontStyleSet_AndroidNDK()356     explicit SkFontStyleSet_AndroidNDK() { }
357 
count()358     int count() override {
359         return fStyles.size();
360     }
getStyle(int index,SkFontStyle * style,SkString * name)361     void getStyle(int index, SkFontStyle* style, SkString* name) override {
362         if (index < 0 || fStyles.size() <= index) {
363             return;
364         }
365         if (style) {
366             *style = fStyles[index]->fontStyle();
367         }
368         if (name) {
369             name->reset();
370         }
371     }
createTypeface(int index)372     sk_sp<SkTypeface> createTypeface(int index) override {
373         if (index < 0 || fStyles.size() <= index) {
374             return nullptr;
375         }
376         return fStyles[index];
377     }
378 
matchStyle(const SkFontStyle & pattern)379     sk_sp<SkTypeface> matchStyle(const SkFontStyle& pattern) override {
380         sk_sp<SkTypeface> match = this->matchStyleCSS3(pattern);
381         if constexpr (kSkFontMgrVerbose) {
382             SkTypeface_AndroidNDK* amatch = static_cast<SkTypeface_AndroidNDK*>(match.get());
383             SkString name;
384             amatch->getFamilyName(&name);
385             SkFontStyle fontStyle = amatch->fontStyle();
386             SkString axes;
387             for (auto&& axis : amatch->fAxes) {
388                 axes.appendScalar(SkFixedToScalar(axis));
389                 axes.append(", ");
390             }
391             SkDebugf("SKIA: Search for [%d, %d, %d] matched %s [%d, %d, %d] %s#%d [%s]\n",
392                      pattern.weight(), pattern.width(), pattern.slant(),
393                      name.c_str(), fontStyle.weight(), fontStyle.width(), fontStyle.slant(),
394                      amatch->fPathName.c_str(), amatch->fIndex, axes.c_str());
395         }
396         return match;
397     }
398 
399 private:
400     TArray<sk_sp<SkTypeface_AndroidNDK>> fStyles;
401     friend class SkFontMgr_AndroidNDK;
402 };
403 
404 struct NameToFamily {
405     SkString name;
406     SkString normalizedName;
407     SkFontStyleSet_AndroidNDK* styleSet;
408 
409     using sk_is_trivially_relocatable = std::true_type;
410     static_assert(::sk_is_trivially_relocatable<decltype(name)>::value);
411     static_assert(::sk_is_trivially_relocatable<decltype(normalizedName)>::value);
412     static_assert(::sk_is_trivially_relocatable<decltype(styleSet)>::value);
413 };
414 
415 class SkFontMgr_AndroidNDK : public SkFontMgr {
addSystemTypeface(sk_sp<SkTypeface_AndroidNDK> typeface,const SkString & name)416     void addSystemTypeface(sk_sp<SkTypeface_AndroidNDK> typeface, const SkString& name) {
417         NameToFamily* nameToFamily = nullptr;
418         for (NameToFamily& current : fNameToFamilyMap) {
419             if (current.name == name) {
420                 nameToFamily = &current;
421                 break;
422             }
423         }
424         if (!nameToFamily) {
425             sk_sp<SkFontStyleSet_AndroidNDK> newSet(new SkFontStyleSet_AndroidNDK());
426             SkAutoAsciiToLC tolc(name.c_str());
427             nameToFamily = &fNameToFamilyMap.emplace_back(
428                 NameToFamily{name, SkString(tolc.lc(), tolc.length()), newSet.get()});
429             fStyleSets.push_back(std::move(newSet));
430         }
431         if constexpr (kSkFontMgrVerbose) { SkDebugf("SKIA: Adding member to %s\n", name.c_str()); }
432         nameToFamily->styleSet->fStyles.push_back(typeface);
433     }
434 
435 public:
SkFontMgr_AndroidNDK(const AndroidFontAPI & androidFontAPI,bool const cacheFontFiles,std::unique_ptr<SkFontScanner> scanner)436     SkFontMgr_AndroidNDK(const AndroidFontAPI& androidFontAPI, bool const cacheFontFiles,
437                           std::unique_ptr<SkFontScanner> scanner)
438         : fAPI(androidFontAPI)
439         , fScanner(std::move(scanner))
440     {
441         SkASystemFontIterator fontIter(fAPI);
442         if (!fontIter) {
443             if constexpr (kSkFontMgrVerbose) { SkDebugf("SKIA: No ASystemFontIterator"); }
444             return;
445         }
446 
447         if constexpr (kSkFontMgrVerbose) { SkDebugf("SKIA: Iterating over AFonts\n"); }
448         while (SkAFont font = fontIter.next()) {
449             sk_sp<SkTypeface_AndroidNDK> typeface = this->make(std::move(font), cacheFontFiles);
450             if (!typeface) {
451                 continue;
452             }
453 
454             SkString name;
455             typeface->getFamilyName(&name);
456             this->addSystemTypeface(typeface, name);
457 
458             // A font may have many localized family names.
459             sk_sp<SkTypeface::LocalizedStrings> names(typeface->createFamilyNameIterator());
460             SkTypeface::LocalizedString localeName;
461             while (names->next(&localeName)) {
462                 if (localeName.fString != name) {
463                     this->addSystemTypeface(typeface, localeName.fString);
464                 }
465             }
466 
467             // There nothing in the NDK to indicate how to handle generic font names like 'serif',
468             // 'sans-serif`, 'monospace', etc.
469         }
470 
471         if (fStyleSets.empty()) {
472             if constexpr (kSkFontMgrVerbose) { SkDebugf("SKIA: No fonts!"); }
473         } else {
474             this->findDefaultStyleSet();
475         }
476     }
477 
478 protected:
479     /** Returns not how many families we have, but how many unique names
480      *  exist among the families.
481      */
onCountFamilies() const482     int onCountFamilies() const override {
483         return fNameToFamilyMap.size();
484     }
485 
onGetFamilyName(int index,SkString * familyName) const486     void onGetFamilyName(int index, SkString* familyName) const override {
487         if (index < 0 || fNameToFamilyMap.size() <= index) {
488             familyName->reset();
489             return;
490         }
491         familyName->set(fNameToFamilyMap[index].name);
492     }
493 
onCreateStyleSet(int index) const494     sk_sp<SkFontStyleSet> onCreateStyleSet(int index) const override {
495         if (index < 0 || fNameToFamilyMap.size() <= index) {
496             return nullptr;
497         }
498         return sk_ref_sp(fNameToFamilyMap[index].styleSet);
499     }
500 
onMatchFamily(const char familyName[]) const501     sk_sp<SkFontStyleSet> onMatchFamily(const char familyName[]) const override {
502         if (!familyName) {
503             return nullptr;
504         }
505         SkAutoAsciiToLC tolc(familyName);
506         for (int i = 0; i < fNameToFamilyMap.size(); ++i) {
507             if (fNameToFamilyMap[i].normalizedName.equals(tolc.lc())) {
508                 return sk_ref_sp(fNameToFamilyMap[i].styleSet);
509             }
510         }
511         return nullptr;
512     }
513 
onMatchFamilyStyle(const char familyName[],const SkFontStyle & style) const514     sk_sp<SkTypeface> onMatchFamilyStyle(const char familyName[],
515                                          const SkFontStyle& style) const override
516     {
517         sk_sp<SkFontStyleSet> sset(this->onMatchFamily(familyName));
518         if (!sset) {
519             return nullptr;
520         }
521         return sset->matchStyle(style);
522     }
523 
make(SkAFont font,bool cacheFontFiles) const524     sk_sp<SkTypeface_AndroidNDK> make(SkAFont font, bool cacheFontFiles) const {
525         const char* filePath = font.getFontFilePath();
526 
527         std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(filePath);
528         if (!stream) {
529             if constexpr (kSkFontMgrVerbose) {
530                 SkDebugf("SKIA: Font file %s does not exist or cannot be opened.\n", filePath);
531             }
532             return nullptr;
533         }
534 
535         size_t collectionIndex = font.getCollectionIndex();
536         if constexpr (kSkFontMgrVerbose) {
537             SkDebugf("SKIA: Making font from %s#%zu\n", filePath, collectionIndex);
538         }
539         if (!SkTFitsIn<int>(collectionIndex)) {
540             if constexpr (kSkFontMgrVerbose) { SkDebugf("SKIA: Collection index invalid!"); }
541             return nullptr;
542         }
543 
544         constexpr SkFourByteTag wdth = SkSetFourByteTag('w','d','t','h');
545         size_t requestAxisCount = font.getAxisCount();
546         if (!SkTFitsIn<int>(requestAxisCount)) {
547             if constexpr (kSkFontMgrVerbose) { SkDebugf("SKIA: Axis count unreasonable!"); }
548             return nullptr;
549         }
550         using Coordinate = SkFontArguments::VariationPosition::Coordinate;
551         AutoSTMalloc<4, Coordinate> requestAxisValues(requestAxisCount);
552         std::optional<int> requestedWidth;
553         for (size_t i = 0; i < requestAxisCount; ++i) {
554             uint32_t tag = font.getAxisTag(i);
555             float value = font.getAxisValue(i);
556             requestAxisValues[i] = { tag, value };
557             if (tag == wdth) {
558                 // Set the width based on the requested `wdth` axis value.
559                 requestedWidth = SkFontDescriptor::SkFontStyleWidthForWidthAxisValue(value);
560             }
561         }
562         SkFontArguments::VariationPosition requestedPosition = {
563                 requestAxisValues.get(), SkTo<int>(requestAxisCount)
564         };
565         auto proxy = fScanner->MakeFromStream(
566                 std::move(stream),
567                 SkFontArguments()
568                         .setCollectionIndex(collectionIndex)
569                         .setVariationDesignPosition(requestedPosition));
570         if (!proxy) {
571             if constexpr (kSkFontMgrVerbose) {
572                 SkDebugf("SKIA: Font file %s exists, but is not a valid font.\n", filePath);
573             }
574             return nullptr;
575         }
576         SkFontStyle style = proxy->fontStyle();
577         int weight = SkTo<int>(font.getWeight());
578         SkFontStyle::Slant slant = style.slant();
579         if (font.isItalic()) {
580             slant = SkFontStyle::kItalic_Slant;
581         }
582         int width = requestedWidth.value_or(style.width());
583         style = SkFontStyle(weight, width, slant);
584 
585         // The family name(s) are not reported.
586         // This would be very helpful for aliases, like "sans-serif", "Arial", etc.
587         SkString familyName;
588         proxy->getFamilyName(&familyName);
589 
590         STArray<4, SkLanguage> skLangs;
591         const char* aLangs = font.getLocale();
592         if (aLangs) {
593             if constexpr (kSkFontMgrVerbose) {
594                 SkDebugf("SKIA: %s ALangs %s\n", familyName.c_str(), aLangs);
595             }
596             // Format: ',' or '\0' are terminators, '\0' is the final terminator.
597             const char* begin = aLangs;
598             const char* end = aLangs;
599             while (true) {
600                 while (*end != '\0' && *end != ',') {
601                     ++end;
602                 }
603                 const size_t size = end - begin;
604                 if (size) {
605                     skLangs.emplace_back(begin, size);
606                 }
607                 if (*end == '\0') {
608                     break;
609                 }
610                 ++end;
611                 begin = end;
612             }
613         }
614         if constexpr (kSkFontMgrVerbose) {
615             for (auto&& lang : skLangs) {
616                 SkDebugf("SKIA: %s Lang %s\n", familyName.c_str(), lang.getTag().c_str());
617             }
618         }
619 
620         if constexpr (kSkFontMgrVerbose) {
621             SkDebugf("SKIA: New typeface %s [%d %d %d]\n", familyName.c_str(), style.weight(),
622                      style.width(), style.slant());
623         }
624 
625         return SkTypeface_AndroidNDK::Make(
626                 proxy, SkString(filePath), cacheFontFiles, SkTo<int>(collectionIndex),
627                 style, proxy->isFixedPitch(), familyName, std::move(skLangs));
628     }
629 
630 
has_locale_and_character(SkTypeface_AndroidNDK * face,const SkString & langTag,SkUnichar character,const char * scope,size_t * step)631     static bool has_locale_and_character(SkTypeface_AndroidNDK* face,
632                                          const SkString& langTag,
633                                          SkUnichar character,
634                                          const char* scope, size_t* step) {
635         ++*step;
636         if (!langTag.isEmpty() &&
637             std::none_of(face->fLang.begin(), face->fLang.end(), [&](SkLanguage lang) {
638                 return lang.getTag().startsWith(langTag.c_str());
639             }))
640         {
641             return false;
642         }
643 
644         if (face->unicharToGlyph(character) == 0) {
645             return false;
646         }
647 
648         if constexpr (kSkFontMgrVerbose) {
649             SkString foundName;
650             face->getFamilyName(&foundName);
651             SkDebugf("SKIA: Found U+%" PRIx32 " in \"%s\" lang \"%s\" scope %s step %zu.\n",
652                      character, foundName.c_str(), langTag.c_str(), scope, *step);
653         }
654         return true;
655     }
656 
findByCharacterLocaleFamily(SkTypeface_AndroidNDK * familyFace,const SkFontStyle & style,const SkString & langTag,SkUnichar character) const657     sk_sp<SkTypeface> findByCharacterLocaleFamily(
658         SkTypeface_AndroidNDK* familyFace,
659         const SkFontStyle& style,
660         const SkString& langTag,
661         SkUnichar character) const
662     {
663         size_t step = 0;
664         // First look at the familyFace
665         if (familyFace && has_locale_and_character(familyFace, langTag, character, "face", &step)) {
666             return sk_ref_sp(familyFace);
667         }
668 
669         // Look through the styles that match in each family.
670         for (int i = 0; i < fNameToFamilyMap.size(); ++i) {
671             SkFontStyleSet_AndroidNDK* family = fNameToFamilyMap[i].styleSet;
672             sk_sp<SkTypeface> face(family->matchStyle(style));
673             auto aface = static_cast<SkTypeface_AndroidNDK*>(face.get());
674             if (has_locale_and_character(aface, langTag, character, "style", &step)) {
675                 return face;
676             }
677         }
678 
679         // Look through everything.
680 
681         // Android by default has a setup like
682         // /system/fonts/NotoSansSymbols-Regular-Subsetted.ttf#0
683         // /system/fonts/NotoSansSymbols-Regular-Subsetted2.ttf#0
684         // Which are both "Noto Sans Symbols" so end up in a "family" together. However, these
685         // are not in the same family, these are two different fonts in different families and
686         // should have been given different names. Internally this works because these are
687         // in separate <family> tags, but the NDK API doesn't provide that information.
688         // While Android internally depends on all fonts in a family having the same characters
689         // mapped, this cannot be relied upon when guessing at the families by name.
690 
691         for (int i = 0; i < fNameToFamilyMap.size(); ++i) {
692             SkFontStyleSet_AndroidNDK* family = fNameToFamilyMap[i].styleSet;
693             for (int j = 0; j < family->count(); ++j) {
694                 sk_sp<SkTypeface> face(family->createTypeface(j));
695                 auto aface = static_cast<SkTypeface_AndroidNDK*>(face.get());
696                 if (has_locale_and_character(aface, langTag, character, "anything", &step)) {
697                     return face;
698                 }
699             }
700         }
701 
702         return nullptr;
703     }
704 
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character) const705     sk_sp<SkTypeface> onMatchFamilyStyleCharacter(const char familyName[],
706                                                   const SkFontStyle& style,
707                                                   const char* bcp47[],
708                                                   int bcp47Count,
709                                                   SkUnichar character) const override {
710         // If at some point AFontMatcher becomes usable, the code for using it is at
711         // https://skia-review.googlesource.com/c/skia/+/585970/13/src/ports/SkFontMgr_android_ndk.cpp#766
712 
713         sk_sp<SkTypeface> familyFace;
714         SkTypeface_AndroidNDK* afamilyFace = nullptr;
715         if (familyName) {
716             familyFace = this->onMatchFamilyStyle(familyName, style);
717             afamilyFace = static_cast<SkTypeface_AndroidNDK*>(familyFace.get());
718         }
719 
720         for (int bcp47Index = bcp47Count; bcp47Index --> 0;) {
721             SkLanguage lang(bcp47[bcp47Index]);
722             while (!lang.getTag().isEmpty()) {
723                 sk_sp<SkTypeface> typeface =
724                     findByCharacterLocaleFamily(afamilyFace, style, lang.getTag(), character);
725                 if (typeface) {
726                     return typeface;
727                 }
728                 lang = lang.getParent();
729             }
730         }
731 
732         sk_sp<SkTypeface> typeface =
733             findByCharacterLocaleFamily(afamilyFace, style, SkString(), character);
734         if (typeface) {
735             return typeface;
736         }
737 
738         if constexpr (kSkFontMgrVerbose) {
739             SkDebugf("SKIA: No font had U+%" PRIx32 "\n", character);
740         }
741         return nullptr;
742     }
743 
onMakeFromData(sk_sp<SkData> data,int ttcIndex) const744     sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData> data, int ttcIndex) const override {
745         return this->makeFromStream(
746             std::unique_ptr<SkStreamAsset>(new SkMemoryStream(std::move(data))), ttcIndex);
747     }
748 
onMakeFromFile(const char path[],int ttcIndex) const749     sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override {
750         std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(path);
751         return stream ? this->makeFromStream(std::move(stream), ttcIndex) : nullptr;
752     }
753 
onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,int ttcIndex) const754     sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,
755                                             int ttcIndex) const override {
756         return this->makeFromStream(std::move(stream),
757                                     SkFontArguments().setCollectionIndex(ttcIndex));
758     }
759 
onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,const SkFontArguments & args) const760     sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,
761                                            const SkFontArguments& args) const override {
762         return fScanner->MakeFromStream(std::move(stream), args);
763     }
764 
onLegacyMakeTypeface(const char name[],SkFontStyle style) const765     sk_sp<SkTypeface> onLegacyMakeTypeface(const char name[], SkFontStyle style) const override {
766         if (name) {
767             // On Android, we must return nullptr when we can't find the requested
768             // named typeface so that the system/app can provide their own recovery
769             // mechanism. On other platforms we'd provide a typeface from the
770             // default family instead.
771             return sk_sp<SkTypeface>(this->onMatchFamilyStyle(name, style));
772         }
773         if (fDefaultStyleSet) {
774             return sk_sp<SkTypeface>(fDefaultStyleSet->matchStyle(style));
775         }
776         return nullptr;
777     }
778 
779 
780 private:
781     const AndroidFontAPI& fAPI;
782     std::unique_ptr<SkFontScanner> fScanner;
783 
784     TArray<sk_sp<SkFontStyleSet_AndroidNDK>> fStyleSets;
785     sk_sp<SkFontStyleSet> fDefaultStyleSet;
786 
787     TArray<NameToFamily> fNameToFamilyMap;
788 
findDefaultStyleSet()789     void findDefaultStyleSet() {
790         SkASSERT(!fStyleSets.empty());
791 
792         static constexpr const char* kDefaultNames[] = { "sans-serif", "Roboto" };
793         for (const char* defaultName : kDefaultNames) {
794             fDefaultStyleSet = this->onMatchFamily(defaultName);
795             if (fDefaultStyleSet) {
796                 break;
797             }
798         }
799         if (nullptr == fDefaultStyleSet) {
800             fDefaultStyleSet = fStyleSets[0];
801         }
802         SkASSERT(fDefaultStyleSet);
803     }
804 };
805 
806 }  // namespace
807 
SkFontMgr_New_AndroidNDK(bool cacheFontFiles)808 sk_sp<SkFontMgr> SkFontMgr_New_AndroidNDK(bool cacheFontFiles) {
809     return SkFontMgr_New_AndroidNDK(cacheFontFiles, SkFontScanner_Make_FreeType());
810 }
811 
SkFontMgr_New_AndroidNDK(bool cacheFontFiles,std::unique_ptr<SkFontScanner> scanner)812 sk_sp<SkFontMgr> SkFontMgr_New_AndroidNDK(bool cacheFontFiles,
813                                            std::unique_ptr<SkFontScanner> scanner)
814 {
815     AndroidFontAPI const * const androidFontAPI = GetAndroidFontAPI();
816     if (!androidFontAPI) {
817         return nullptr;
818     }
819     return sk_sp(new SkFontMgr_AndroidNDK(*androidFontAPI, cacheFontFiles, std::move(scanner)));
820 }
821