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/SkFontScanner_FreeType_priv.h"
21 #include "src/ports/SkTypeface_FreeType.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__anon0cee45840111::SkAFont164 SkAFont(const AndroidFontAPI& api, AFont* font) : fAPI(api), fFont(font) {}
SkAFont__anon0cee45840111::SkAFont165 SkAFont(SkAFont&& that) : fAPI(that.fAPI), fFont(that.fFont) {
166 that.fFont = nullptr;
167 }
~SkAFont__anon0cee45840111::SkAFont168 ~SkAFont() {
169 if (fFont) {
170 if constexpr (kSkFontMgrVerbose) { SkDebugf("SKIA: AFont_close\n"); }
171 fAPI.AFont_close(fFont);
172 }
173 }
operator bool__anon0cee45840111::SkAFont174 explicit operator bool() { return fFont; }
175
getFontFilePath__anon0cee45840111::SkAFont176 const char* getFontFilePath() const { return fAPI.AFont_getFontFilePath(fFont); }
getWeight__anon0cee45840111::SkAFont177 uint16_t getWeight() const { return fAPI.AFont_getWeight(fFont); }
isItalic__anon0cee45840111::SkAFont178 bool isItalic() const { return fAPI.AFont_isItalic(fFont); }
getLocale__anon0cee45840111::SkAFont179 const char* getLocale() const { return fAPI.AFont_getLocale(fFont); }
getCollectionIndex__anon0cee45840111::SkAFont180 size_t getCollectionIndex() const { return fAPI.AFont_getCollectionIndex(fFont); }
getAxisCount__anon0cee45840111::SkAFont181 size_t getAxisCount() const { return fAPI.AFont_getAxisCount(fFont); }
getAxisTag__anon0cee45840111::SkAFont182 uint32_t getAxisTag(uint32_t index) const { return fAPI.AFont_getAxisTag(fFont, index); }
getAxisValue__anon0cee45840111::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__anon0cee45840111::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__anon0cee45840111::SkASystemFontIterator198 ~SkASystemFontIterator() {
199 if constexpr (kSkFontMgrVerbose) { SkDebugf("SKIA: ASystemFontIterator_close\n"); }
200 fAPI.ASystemFontIterator_close(fIterator);
201 }
operator bool__anon0cee45840111::SkASystemFontIterator202 explicit operator bool() { return fIterator; }
203
next__anon0cee45840111::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_FreeType {
256 public:
SkTypeface_AndroidNDK(std::unique_ptr<SkStreamAsset> file,const SkString & pathName,const bool cacheFontFiles,int index,const SkFixed * axes,int axesCount,const SkFontStyle & style,bool isFixedPitch,const SkString & familyName,TArray<SkLanguage> && lang)257 SkTypeface_AndroidNDK(std::unique_ptr<SkStreamAsset> file,
258 const SkString& pathName,
259 const bool cacheFontFiles,
260 int index,
261 const SkFixed* axes, int axesCount,
262 const SkFontStyle& style,
263 bool isFixedPitch,
264 const SkString& familyName,
265 TArray<SkLanguage>&& lang)
266 : SkTypeface_FreeType(style, isFixedPitch)
267 , fFamilyName(familyName)
268 , fPathName(pathName)
269 , fIndex(index)
270 , fAxes(axes, axesCount)
271 , fLang(std::move(lang))
272 , fFile((cacheFontFiles && file) ? std::move(file)
273 :(cacheFontFiles && !file) ? SkStream::MakeFromFile(fPathName.c_str())
274 : nullptr)
275 , fCacheFontFiles(cacheFontFiles)
276 {
277 if (cacheFontFiles) {
278 SkASSERT(fFile);
279 }
280 }
281
onGetFamilyName(SkString * familyName) const282 void onGetFamilyName(SkString* familyName) const override {
283 *familyName = fFamilyName;
284 }
285
makeStream() const286 std::unique_ptr<SkStreamAsset> makeStream() const {
287 if (fFile) {
288 return fFile->duplicate();
289 }
290 return SkStream::MakeFromFile(fPathName.c_str());
291 }
292
onGetFontDescriptor(SkFontDescriptor * desc,bool * serialize) const293 void onGetFontDescriptor(SkFontDescriptor* desc, bool* serialize) const override {
294 SkASSERT(desc);
295 SkASSERT(serialize);
296 desc->setFamilyName(fFamilyName.c_str());
297 desc->setStyle(this->fontStyle());
298 desc->setFactoryId(SkTypeface_FreeType::FactoryId);
299 *serialize = false;
300 }
onOpenStream(int * ttcIndex) const301 std::unique_ptr<SkStreamAsset> onOpenStream(int* ttcIndex) const override {
302 *ttcIndex = fIndex;
303 return this->makeStream();
304 }
onMakeFontData() const305 std::unique_ptr<SkFontData> onMakeFontData() const override {
306 return std::make_unique<SkFontData>(
307 this->makeStream(), fIndex, 0, fAxes.begin(), fAxes.size(), nullptr, 0);
308 }
onMakeClone(const SkFontArguments & args) const309 sk_sp<SkTypeface> onMakeClone(const SkFontArguments& args) const override {
310 SkFontStyle newStyle = this->fontStyle();
311 std::unique_ptr<SkFontData> data = this->cloneFontData(args, &newStyle);
312 if (!data) {
313 return nullptr;
314 }
315 return sk_sp(new SkTypeface_AndroidNDK(fFile ? fFile->duplicate() : nullptr,
316 fPathName,
317 fCacheFontFiles,
318 fIndex,
319 data->getAxis(),
320 data->getAxisCount(),
321 newStyle,
322 this->isFixedPitch(),
323 fFamilyName,
324 TArray<SkLanguage>()));
325 }
326
makeNamedClone(const SkString & name) const327 sk_sp<SkTypeface_AndroidNDK> makeNamedClone(const SkString& name) const {
328 return sk_sp(new SkTypeface_AndroidNDK(fFile ? fFile->duplicate() : nullptr,
329 fPathName,
330 fCacheFontFiles,
331 fIndex,
332 fAxes.data(), fAxes.size(),
333 this->fontStyle(),
334 this->isFixedPitch(),
335 name,
336 STArray<4, SkLanguage>(fLang)));
337 }
338
339 const SkString fFamilyName;
340 const SkString fPathName;
341 int fIndex;
342 const STArray<4, SkFixed> fAxes;
343 const STArray<4, SkLanguage> fLang;
344 std::unique_ptr<SkStreamAsset> fFile;
345 bool fCacheFontFiles;
346 };
347
348 class SkFontStyleSet_AndroidNDK : public SkFontStyleSet {
349 public:
SkFontStyleSet_AndroidNDK()350 explicit SkFontStyleSet_AndroidNDK() { }
351
count()352 int count() override {
353 return fStyles.size();
354 }
getStyle(int index,SkFontStyle * style,SkString * name)355 void getStyle(int index, SkFontStyle* style, SkString* name) override {
356 if (index < 0 || fStyles.size() <= index) {
357 return;
358 }
359 if (style) {
360 *style = fStyles[index]->fontStyle();
361 }
362 if (name) {
363 name->reset();
364 }
365 }
createTypeface(int index)366 sk_sp<SkTypeface> createTypeface(int index) override {
367 if (index < 0 || fStyles.size() <= index) {
368 return nullptr;
369 }
370 return fStyles[index];
371 }
372
matchStyle(const SkFontStyle & pattern)373 sk_sp<SkTypeface> matchStyle(const SkFontStyle& pattern) override {
374 sk_sp<SkTypeface> match = this->matchStyleCSS3(pattern);
375 if constexpr (kSkFontMgrVerbose) {
376 SkTypeface_AndroidNDK* amatch = static_cast<SkTypeface_AndroidNDK*>(match.get());
377 SkString name;
378 amatch->getFamilyName(&name);
379 SkFontStyle fontStyle = amatch->fontStyle();
380 SkString axes;
381 for (auto&& axis : amatch->fAxes) {
382 axes.appendScalar(SkFixedToScalar(axis));
383 axes.append(", ");
384 }
385 SkDebugf("SKIA: Search for [%d, %d, %d] matched %s [%d, %d, %d] %s#%d [%s]\n",
386 pattern.weight(), pattern.width(), pattern.slant(),
387 name.c_str(), fontStyle.weight(), fontStyle.width(), fontStyle.slant(),
388 amatch->fPathName.c_str(), amatch->fIndex, axes.c_str());
389 }
390 return match;
391 }
392
393 private:
394 TArray<sk_sp<SkTypeface_AndroidNDK>> fStyles;
395 friend class SkFontMgr_AndroidNDK;
396 };
397
398 struct NameToFamily {
399 SkString name;
400 SkString normalizedName;
401 SkFontStyleSet_AndroidNDK* styleSet;
402
403 using sk_is_trivially_relocatable = std::true_type;
404 static_assert(::sk_is_trivially_relocatable<decltype(name)>::value);
405 static_assert(::sk_is_trivially_relocatable<decltype(normalizedName)>::value);
406 static_assert(::sk_is_trivially_relocatable<decltype(styleSet)>::value);
407 };
408
409 class SkFontMgr_AndroidNDK : public SkFontMgr {
addSystemTypeface(sk_sp<SkTypeface_AndroidNDK> typeface,const SkString & name)410 void addSystemTypeface(sk_sp<SkTypeface_AndroidNDK> typeface, const SkString& name) {
411 NameToFamily* nameToFamily = nullptr;
412 for (NameToFamily& current : fNameToFamilyMap) {
413 if (current.name == name) {
414 nameToFamily = ¤t;
415 break;
416 }
417 }
418 if (!nameToFamily) {
419 sk_sp<SkFontStyleSet_AndroidNDK> newSet(new SkFontStyleSet_AndroidNDK());
420 SkAutoAsciiToLC tolc(name.c_str());
421 nameToFamily = &fNameToFamilyMap.emplace_back(
422 NameToFamily{name, SkString(tolc.lc(), tolc.length()), newSet.get()});
423 fStyleSets.push_back(std::move(newSet));
424 }
425 if constexpr (kSkFontMgrVerbose) { SkDebugf("SKIA: Adding member to %s\n", name.c_str()); }
426 nameToFamily->styleSet->fStyles.push_back(typeface);
427 }
428
429 public:
SkFontMgr_AndroidNDK(const AndroidFontAPI & androidFontAPI,bool const cacheFontFiles,std::unique_ptr<SkFontScanner> scanner)430 SkFontMgr_AndroidNDK(const AndroidFontAPI& androidFontAPI, bool const cacheFontFiles,
431 std::unique_ptr<SkFontScanner> scanner)
432 : fAPI(androidFontAPI)
433 , fScanner(std::move(scanner))
434 {
435 SkASystemFontIterator fontIter(fAPI);
436 if (!fontIter) {
437 if constexpr (kSkFontMgrVerbose) { SkDebugf("SKIA: No ASystemFontIterator"); }
438 return;
439 }
440
441 if constexpr (kSkFontMgrVerbose) { SkDebugf("SKIA: Iterating over AFonts\n"); }
442 while (SkAFont font = fontIter.next()) {
443 sk_sp<SkTypeface_AndroidNDK> typeface = this->make(std::move(font), cacheFontFiles);
444 if (!typeface) {
445 continue;
446 }
447
448 SkString name;
449 typeface->getFamilyName(&name);
450 this->addSystemTypeface(typeface, name);
451
452 // A font may have many localized family names.
453 sk_sp<SkTypeface::LocalizedStrings> names(typeface->createFamilyNameIterator());
454 SkTypeface::LocalizedString localeName;
455 while (names->next(&localeName)) {
456 if (localeName.fString != name) {
457 this->addSystemTypeface(typeface, localeName.fString);
458 }
459 }
460
461 // There nothing in the NDK to indicate how to handle generic font names like 'serif',
462 // 'sans-serif`, 'monospace', etc.
463 }
464
465 if (fStyleSets.empty()) {
466 if constexpr (kSkFontMgrVerbose) { SkDebugf("SKIA: No fonts!"); }
467 } else {
468 this->findDefaultStyleSet();
469 }
470 }
471
472 protected:
473 /** Returns not how many families we have, but how many unique names
474 * exist among the families.
475 */
onCountFamilies() const476 int onCountFamilies() const override {
477 return fNameToFamilyMap.size();
478 }
479
onGetFamilyName(int index,SkString * familyName) const480 void onGetFamilyName(int index, SkString* familyName) const override {
481 if (index < 0 || fNameToFamilyMap.size() <= index) {
482 familyName->reset();
483 return;
484 }
485 familyName->set(fNameToFamilyMap[index].name);
486 }
487
onCreateStyleSet(int index) const488 sk_sp<SkFontStyleSet> onCreateStyleSet(int index) const override {
489 if (index < 0 || fNameToFamilyMap.size() <= index) {
490 return nullptr;
491 }
492 return sk_ref_sp(fNameToFamilyMap[index].styleSet);
493 }
494
onMatchFamily(const char familyName[]) const495 sk_sp<SkFontStyleSet> onMatchFamily(const char familyName[]) const override {
496 if (!familyName) {
497 return nullptr;
498 }
499 SkAutoAsciiToLC tolc(familyName);
500 for (int i = 0; i < fNameToFamilyMap.size(); ++i) {
501 if (fNameToFamilyMap[i].normalizedName.equals(tolc.lc())) {
502 return sk_ref_sp(fNameToFamilyMap[i].styleSet);
503 }
504 }
505 return nullptr;
506 }
507
onMatchFamilyStyle(const char familyName[],const SkFontStyle & style) const508 sk_sp<SkTypeface> onMatchFamilyStyle(const char familyName[],
509 const SkFontStyle& style) const override
510 {
511 sk_sp<SkFontStyleSet> sset(this->onMatchFamily(familyName));
512 if (!sset) {
513 return nullptr;
514 }
515 return sset->matchStyle(style);
516 }
517
make(SkAFont font,bool cacheFontFiles) const518 sk_sp<SkTypeface_AndroidNDK> make(SkAFont font, bool cacheFontFiles) const {
519 const char* filePath = font.getFontFilePath();
520
521 std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(filePath);
522 if (!stream) {
523 if constexpr (kSkFontMgrVerbose) {
524 SkDebugf("SKIA: Font file %s does not exist or cannot be opened.\n", filePath);
525 }
526 return nullptr;
527 }
528
529 size_t collectionIndex = font.getCollectionIndex();
530 if constexpr (kSkFontMgrVerbose) {
531 SkDebugf("SKIA: Making font from %s#%zu\n", filePath, collectionIndex);
532 }
533 if (!SkTFitsIn<int>(collectionIndex)) {
534 if constexpr (kSkFontMgrVerbose) { SkDebugf("SKIA: Collection index invalid!"); }
535 return nullptr;
536 }
537 const int ttcIndex = SkTo<int>(collectionIndex);
538
539 SkString familyName;
540 SkFontStyle style;
541 bool isFixedWidth;
542 SkFontScanner::AxisDefinitions axisDefinitions;
543 if (!fScanner->scanInstance(stream.get(), ttcIndex, 0,
544 &familyName, &style, &isFixedWidth, &axisDefinitions))
545 {
546 if constexpr (kSkFontMgrVerbose) {
547 SkDebugf("SKIA: Font file %s exists, but is not a valid font.\n", filePath);
548 }
549 return nullptr;
550 }
551
552 int weight = SkTo<int>(font.getWeight());
553 SkFontStyle::Slant slant = style.slant();
554 if (font.isItalic()) {
555 slant = SkFontStyle::kItalic_Slant;
556 }
557 int width = style.width();
558 constexpr SkFourByteTag wdth = SkSetFourByteTag('w','d','t','h');
559
560 // The family name(s) are not reported.
561 // This would be very helpful for aliases, like "sans-serif", "Arial", etc.
562
563 size_t requestAxisCount = font.getAxisCount();
564 if (!SkTFitsIn<int>(requestAxisCount)) {
565 if constexpr (kSkFontMgrVerbose) { SkDebugf("SKIA: Axis count unreasonable!"); }
566 return nullptr;
567 }
568 using Coordinate = SkFontArguments::VariationPosition::Coordinate;
569 AutoSTMalloc<4, Coordinate> requestAxisValues(requestAxisCount);
570 for (size_t i = 0; i < requestAxisCount; ++i) {
571 uint32_t tag = font.getAxisTag(i);
572 float value = font.getAxisValue(i);
573 requestAxisValues[i] = { tag, value };
574 if (tag == wdth) {
575 // Set the width based on the requested `wdth` axis value.
576 width = SkFontDescriptor::SkFontStyleWidthForWidthAxisValue(value);
577 }
578 }
579
580 AutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.size());
581 SkFontArguments::VariationPosition position = {
582 requestAxisValues.get(), SkTo<int>(requestAxisCount)
583 };
584 SkFontScanner_FreeType::computeAxisValues(axisDefinitions, position,
585 axisValues, familyName, nullptr);
586
587 STArray<4, SkLanguage> skLangs;
588 const char* aLangs = font.getLocale();
589 if (aLangs) {
590 if constexpr (kSkFontMgrVerbose) {
591 SkDebugf("SKIA: %s ALangs %s\n", familyName.c_str(), aLangs);
592 }
593 // Format: ',' or '\0' are terminators, '\0' is the final terminator.
594 const char* begin = aLangs;
595 const char* end = aLangs;
596 while (true) {
597 while (*end != '\0' && *end != ',') {
598 ++end;
599 }
600 const size_t size = end - begin;
601 if (size) {
602 skLangs.emplace_back(begin, size);
603 }
604 if (*end == '\0') {
605 break;
606 }
607 ++end;
608 begin = end;
609 }
610 }
611 if constexpr (kSkFontMgrVerbose) {
612 for (auto&& lang : skLangs) {
613 SkDebugf("SKIA: %s Lang %s\n", familyName.c_str(), lang.getTag().c_str());
614 }
615 }
616
617 style = SkFontStyle(weight, width, slant);
618 if constexpr (kSkFontMgrVerbose) {
619 SkDebugf("SKIA: New typeface %s [%d %d %d]\n", familyName.c_str(), weight,width,slant);
620 }
621 return sk_sp<SkTypeface_AndroidNDK>(new SkTypeface_AndroidNDK(
622 std::move(stream), SkString(filePath), cacheFontFiles, ttcIndex,
623 axisValues.get(), axisDefinitions.size(),
624 style, isFixedWidth, familyName, std::move(skLangs)));
625 }
626
627
has_locale_and_character(SkTypeface_AndroidNDK * face,const SkString & langTag,SkUnichar character,const char * scope,size_t * step)628 static bool has_locale_and_character(SkTypeface_AndroidNDK* face,
629 const SkString& langTag,
630 SkUnichar character,
631 const char* scope, size_t* step) {
632 ++*step;
633 if (!langTag.isEmpty() &&
634 std::none_of(face->fLang.begin(), face->fLang.end(), [&](SkLanguage lang) {
635 return lang.getTag().startsWith(langTag.c_str());
636 }))
637 {
638 return false;
639 }
640
641 if (face->unicharToGlyph(character) == 0) {
642 return false;
643 }
644
645 if constexpr (kSkFontMgrVerbose) {
646 SkString foundName;
647 face->getFamilyName(&foundName);
648 SkDebugf("SKIA: Found U+%" PRIx32 " in \"%s\" lang \"%s\" scope %s step %zu.\n",
649 character, foundName.c_str(), langTag.c_str(), scope, *step);
650 }
651 return true;
652 }
653
findByCharacterLocaleFamily(SkTypeface_AndroidNDK * familyFace,const SkFontStyle & style,const SkString & langTag,SkUnichar character) const654 sk_sp<SkTypeface> findByCharacterLocaleFamily(
655 SkTypeface_AndroidNDK* familyFace,
656 const SkFontStyle& style,
657 const SkString& langTag,
658 SkUnichar character) const
659 {
660 size_t step = 0;
661 // First look at the familyFace
662 if (familyFace && has_locale_and_character(familyFace, langTag, character, "face", &step)) {
663 return sk_ref_sp(familyFace);
664 }
665
666 // Look through the styles that match in each family.
667 for (int i = 0; i < fNameToFamilyMap.size(); ++i) {
668 SkFontStyleSet_AndroidNDK* family = fNameToFamilyMap[i].styleSet;
669 sk_sp<SkTypeface> face(family->matchStyle(style));
670 auto aface = static_cast<SkTypeface_AndroidNDK*>(face.get());
671 if (has_locale_and_character(aface, langTag, character, "style", &step)) {
672 return face;
673 }
674 }
675
676 // Look through everything.
677
678 // Android by default has a setup like
679 // /system/fonts/NotoSansSymbols-Regular-Subsetted.ttf#0
680 // /system/fonts/NotoSansSymbols-Regular-Subsetted2.ttf#0
681 // Which are both "Noto Sans Symbols" so end up in a "family" together. However, these
682 // are not in the same family, these are two different fonts in different families and
683 // should have been given different names. Internally this works because these are
684 // in separate <family> tags, but the NDK API doesn't provide that information.
685 // While Android internally depends on all fonts in a family having the same characters
686 // mapped, this cannot be relied upon when guessing at the families by name.
687
688 for (int i = 0; i < fNameToFamilyMap.size(); ++i) {
689 SkFontStyleSet_AndroidNDK* family = fNameToFamilyMap[i].styleSet;
690 for (int j = 0; j < family->count(); ++j) {
691 sk_sp<SkTypeface> face(family->createTypeface(j));
692 auto aface = static_cast<SkTypeface_AndroidNDK*>(face.get());
693 if (has_locale_and_character(aface, langTag, character, "anything", &step)) {
694 return face;
695 }
696 }
697 }
698
699 return nullptr;
700 }
701
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character) const702 sk_sp<SkTypeface> onMatchFamilyStyleCharacter(const char familyName[],
703 const SkFontStyle& style,
704 const char* bcp47[],
705 int bcp47Count,
706 SkUnichar character) const override {
707 // If at some point AFontMatcher becomes usable, the code for using it is at
708 // https://skia-review.googlesource.com/c/skia/+/585970/13/src/ports/SkFontMgr_android_ndk.cpp#766
709
710 sk_sp<SkTypeface> familyFace;
711 SkTypeface_AndroidNDK* afamilyFace = nullptr;
712 if (familyName) {
713 familyFace = this->onMatchFamilyStyle(familyName, style);
714 afamilyFace = static_cast<SkTypeface_AndroidNDK*>(familyFace.get());
715 }
716
717 for (int bcp47Index = bcp47Count; bcp47Index --> 0;) {
718 SkLanguage lang(bcp47[bcp47Index]);
719 while (!lang.getTag().isEmpty()) {
720 sk_sp<SkTypeface> typeface =
721 findByCharacterLocaleFamily(afamilyFace, style, lang.getTag(), character);
722 if (typeface) {
723 return typeface;
724 }
725 lang = lang.getParent();
726 }
727 }
728
729 sk_sp<SkTypeface> typeface =
730 findByCharacterLocaleFamily(afamilyFace, style, SkString(), character);
731 if (typeface) {
732 return typeface;
733 }
734
735 if constexpr (kSkFontMgrVerbose) {
736 SkDebugf("SKIA: No font had U+%" PRIx32 "\n", character);
737 }
738 return nullptr;
739 }
740
onMakeFromData(sk_sp<SkData> data,int ttcIndex) const741 sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData> data, int ttcIndex) const override {
742 return this->makeFromStream(
743 std::unique_ptr<SkStreamAsset>(new SkMemoryStream(std::move(data))), ttcIndex);
744 }
745
onMakeFromFile(const char path[],int ttcIndex) const746 sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override {
747 std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(path);
748 return stream ? this->makeFromStream(std::move(stream), ttcIndex) : nullptr;
749 }
750
onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,int ttcIndex) const751 sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,
752 int ttcIndex) const override {
753 return this->makeFromStream(std::move(stream),
754 SkFontArguments().setCollectionIndex(ttcIndex));
755 }
756
onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,const SkFontArguments & args) const757 sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,
758 const SkFontArguments& args) const override {
759 return SkTypeface_FreeType::MakeFromStream(std::move(stream), args);
760 }
761
onLegacyMakeTypeface(const char name[],SkFontStyle style) const762 sk_sp<SkTypeface> onLegacyMakeTypeface(const char name[], SkFontStyle style) const override {
763 if (name) {
764 // On Android, we must return nullptr when we can't find the requested
765 // named typeface so that the system/app can provide their own recovery
766 // mechanism. On other platforms we'd provide a typeface from the
767 // default family instead.
768 return sk_sp<SkTypeface>(this->onMatchFamilyStyle(name, style));
769 }
770 if (fDefaultStyleSet) {
771 return sk_sp<SkTypeface>(fDefaultStyleSet->matchStyle(style));
772 }
773 return nullptr;
774 }
775
776
777 private:
778 const AndroidFontAPI& fAPI;
779 std::unique_ptr<SkFontScanner> fScanner;
780
781 TArray<sk_sp<SkFontStyleSet_AndroidNDK>> fStyleSets;
782 sk_sp<SkFontStyleSet> fDefaultStyleSet;
783
784 TArray<NameToFamily> fNameToFamilyMap;
785
findDefaultStyleSet()786 void findDefaultStyleSet() {
787 SkASSERT(!fStyleSets.empty());
788
789 static constexpr const char* kDefaultNames[] = { "sans-serif", "Roboto" };
790 for (const char* defaultName : kDefaultNames) {
791 fDefaultStyleSet = this->onMatchFamily(defaultName);
792 if (fDefaultStyleSet) {
793 break;
794 }
795 }
796 if (nullptr == fDefaultStyleSet) {
797 fDefaultStyleSet = fStyleSets[0];
798 }
799 SkASSERT(fDefaultStyleSet);
800 }
801 };
802
803 } // namespace
804
SkFontMgr_New_AndroidNDK(bool cacheFontFiles)805 sk_sp<SkFontMgr> SkFontMgr_New_AndroidNDK(bool cacheFontFiles) {
806 return SkFontMgr_New_AndroidNDK(cacheFontFiles, SkFontScanner_Make_FreeType());
807 }
808
SkFontMgr_New_AndroidNDK(bool cacheFontFiles,std::unique_ptr<SkFontScanner> scanner)809 sk_sp<SkFontMgr> SkFontMgr_New_AndroidNDK(bool cacheFontFiles,
810 std::unique_ptr<SkFontScanner> scanner)
811 {
812 AndroidFontAPI const * const androidFontAPI = GetAndroidFontAPI();
813 if (!androidFontAPI) {
814 return nullptr;
815 }
816 return sk_sp(new SkFontMgr_AndroidNDK(*androidFontAPI, cacheFontFiles, std::move(scanner)));
817 }
818