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