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 = ¤t;
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