Flutter Engine
The Flutter Engine
SkFontMgr_android.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
9
10#include "include/core/SkData.h"
22#include "src/base/SkTSearch.h"
25#include "src/core/SkOSFile.h"
29
30#include <algorithm>
31#include <limits>
32
33using namespace skia_private;
34
35class SkData;
36
37namespace {
38
39class SkTypeface_Android : public SkTypeface_FreeType {
40public:
41 SkTypeface_Android(const SkFontStyle& style,
42 bool isFixedPitch,
43 const SkString& familyName)
44 : INHERITED(style, isFixedPitch)
45 , fFamilyName(familyName)
46 { }
47
48protected:
49 void onGetFamilyName(SkString* familyName) const override {
50 *familyName = fFamilyName;
51 }
52
53 SkString fFamilyName;
54
55private:
57};
58
59class SkTypeface_AndroidSystem : public SkTypeface_Android {
60public:
61 SkTypeface_AndroidSystem(const SkString& pathName,
62 const bool cacheFontFiles,
63 int index,
64 const SkFixed* axes, int axesCount,
65 const SkFontStyle& style,
66 bool isFixedPitch,
67 const SkString& familyName,
69 FontVariant variantStyle)
70 : INHERITED(style, isFixedPitch, familyName)
71 , fPathName(pathName)
72 , fIndex(index)
73 , fAxes(axes, axesCount)
74 , fLang(lang)
75 , fVariantStyle(variantStyle)
76 , fFile(cacheFontFiles ? sk_fopen(fPathName.c_str(), kRead_SkFILE_Flag) : nullptr) {
77 if (cacheFontFiles) {
78 SkASSERT(fFile);
79 }
80 }
81
82 std::unique_ptr<SkStreamAsset> makeStream() const {
83 if (fFile) {
85 return data ? std::make_unique<SkMemoryStream>(std::move(data)) : nullptr;
86 }
87 return SkStream::MakeFromFile(fPathName.c_str());
88 }
89
90 void onGetFontDescriptor(SkFontDescriptor* desc, bool* serialize) const override {
92 SkASSERT(serialize);
93 desc->setFamilyName(fFamilyName.c_str());
94 desc->setStyle(this->fontStyle());
96 *serialize = false;
97 }
98 std::unique_ptr<SkStreamAsset> onOpenStream(int* ttcIndex) const override {
99 *ttcIndex = fIndex;
100 return this->makeStream();
101 }
102 std::unique_ptr<SkFontData> onMakeFontData() const override {
103 return std::make_unique<SkFontData>(
104 this->makeStream(), fIndex, 0, fAxes.begin(), fAxes.size(), nullptr, 0);
105 }
106 sk_sp<SkTypeface> onMakeClone(const SkFontArguments& args) const override {
107 SkFontStyle style = this->fontStyle();
108 std::unique_ptr<SkFontData> data = this->cloneFontData(args, &style);
109 if (!data) {
110 return nullptr;
111 }
112 return sk_make_sp<SkTypeface_AndroidSystem>(fPathName,
113 fFile,
114 fIndex,
115 data->getAxis(),
116 data->getAxisCount(),
117 style,
118 this->isFixedPitch(),
119 fFamilyName,
120 fLang,
121 fVariantStyle);
122 }
123
124 const SkString fPathName;
125 int fIndex;
126 const STArray<4, SkFixed, true> fAxes;
128 const FontVariant fVariantStyle;
130
131 using INHERITED = SkTypeface_Android;
132};
133
134template <typename D, typename S> sk_sp<D> sk_sp_static_cast(sk_sp<S>&& s) {
135 return sk_sp<D>(static_cast<D*>(s.release()));
136}
137
138class SkFontStyleSet_Android : public SkFontStyleSet {
139public:
140 explicit SkFontStyleSet_Android(const FontFamily& family, const SkFontScanner* scanner,
141 const bool cacheFontFiles) {
142 const SkString* cannonicalFamilyName = nullptr;
143 if (!family.fNames.empty()) {
144 cannonicalFamilyName = &family.fNames[0];
145 }
146 fFallbackFor = family.fFallbackFor;
147
148 // TODO? make this lazy
149 for (int i = 0; i < family.fFonts.size(); ++i) {
150 const FontFileInfo& fontFile = family.fFonts[i];
151
152 SkString pathName(family.fBasePath);
153 pathName.append(fontFile.fFileName);
154
155 std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(pathName.c_str());
156 if (!stream) {
157 SkDEBUGF("Requested font file %s does not exist or cannot be opened.\n",
158 pathName.c_str());
159 continue;
160 }
161
162 const int ttcIndex = fontFile.fIndex;
163 SkString familyName;
164 SkFontStyle style;
165 bool isFixedWidth;
166 SkFontScanner::AxisDefinitions axisDefinitions;
167 if (!scanner->scanInstance(stream.get(), ttcIndex, 0,
168 &familyName, &style, &isFixedWidth, &axisDefinitions))
169 {
170 SkDEBUGF("Requested font file %s exists, but is not a valid font.\n",
171 pathName.c_str());
172 continue;
173 }
174
175 int weight = fontFile.fWeight != 0 ? fontFile.fWeight : style.weight();
176 SkFontStyle::Slant slant = style.slant();
177 switch (fontFile.fStyle) {
178 case FontFileInfo::Style::kAuto: slant = style.slant(); break;
181 default: SkASSERT(false); break;
182 }
183 style = SkFontStyle(weight, style.width(), slant);
184
185 uint32_t variant = family.fVariant;
186 if (kDefault_FontVariant == variant) {
188 }
189
190 // The first specified family name overrides the family name found in the font.
191 // TODO: SkTypeface_AndroidSystem::onCreateFamilyNameIterator should return
192 // all of the specified family names in addition to the names found in the font.
193 if (cannonicalFamilyName != nullptr) {
194 familyName = *cannonicalFamilyName;
195 }
196
197 AutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.size());
201 };
203 axisDefinitions, position, axisValues, familyName, &style);
204
205 fStyles.push_back().reset(new SkTypeface_AndroidSystem(
206 pathName, cacheFontFiles, ttcIndex, axisValues.get(), axisDefinitions.size(),
207 style, isFixedWidth, familyName, family.fLanguages, variant));
208 }
209 }
210
211 int count() override {
212 return fStyles.size();
213 }
214 void getStyle(int index, SkFontStyle* style, SkString* name) override {
215 if (index < 0 || fStyles.size() <= index) {
216 return;
217 }
218 if (style) {
219 *style = fStyles[index]->fontStyle();
220 }
221 if (name) {
222 name->reset();
223 }
224 }
225 sk_sp<SkTypeface> createTypeface(int index) override {
226 if (index < 0 || fStyles.size() <= index) {
227 return nullptr;
228 }
229 return fStyles[index];
230 }
231
232 sk_sp<SkTypeface_AndroidSystem> matchAStyle(const SkFontStyle& pattern) {
233 return sk_sp_static_cast<SkTypeface_AndroidSystem>(this->matchStyleCSS3(pattern));
234 }
235 sk_sp<SkTypeface> matchStyle(const SkFontStyle& pattern) override {
236 return this->matchAStyle(pattern);
237 }
238
239private:
241 SkString fFallbackFor;
242
243 friend struct NameToFamily;
244 friend class SkFontMgr_Android;
245
247};
248
249/** On Android a single family can have many names, but our API assumes unique names.
250 * Map names to the back end so that all names for a given family refer to the same
251 * (non-replicated) set of typefaces.
252 * SkTDict<> doesn't let us do index-based lookup, so we write our own mapping.
253 */
254struct NameToFamily {
256 SkFontStyleSet_Android* styleSet;
257};
258
259class SkFontMgr_Android : public SkFontMgr {
260public:
261 SkFontMgr_Android(const SkFontMgr_Android_CustomFonts* custom,
262 std::unique_ptr<SkFontScanner> scanner)
263 : fScanner(std::move(scanner)) {
264 SkTDArray<FontFamily*> families;
266 SkString base(custom->fBasePath);
268 families, base, custom->fFontsXml, custom->fFallbackFontsXml);
269 }
270 if (!custom ||
272 {
274 }
276 SkString base(custom->fBasePath);
278 families, base, custom->fFontsXml, custom->fFallbackFontsXml);
279 }
280 this->buildNameToFamilyMap(families, custom ? custom->fIsolated : false);
281 this->findDefaultStyleSet();
282 for (FontFamily* p : families) {
283 delete p;
284 }
285 families.reset();
286 }
287
288protected:
289 /** Returns not how many families we have, but how many unique names
290 * exist among the families.
291 */
292 int onCountFamilies() const override {
293 return fNameToFamilyMap.size();
294 }
295
296 void onGetFamilyName(int index, SkString* familyName) const override {
297 if (index < 0 || fNameToFamilyMap.size() <= index) {
298 familyName->reset();
299 return;
300 }
301 familyName->set(fNameToFamilyMap[index].name);
302 }
303
304 sk_sp<SkFontStyleSet> onCreateStyleSet(int index) const override {
305 if (index < 0 || fNameToFamilyMap.size() <= index) {
306 return nullptr;
307 }
308 return sk_ref_sp(fNameToFamilyMap[index].styleSet);
309 }
310
311 sk_sp<SkFontStyleSet> onMatchFamily(const char familyName[]) const override {
312 if (!familyName) {
313 return nullptr;
314 }
315 SkAutoAsciiToLC tolc(familyName);
316 for (int i = 0; i < fNameToFamilyMap.size(); ++i) {
317 if (fNameToFamilyMap[i].name.equals(tolc.lc())) {
318 return sk_ref_sp(fNameToFamilyMap[i].styleSet);
319 }
320 }
321 // TODO: eventually we should not need to name fallback families.
322 for (int i = 0; i < fFallbackNameToFamilyMap.size(); ++i) {
323 if (fFallbackNameToFamilyMap[i].name.equals(tolc.lc())) {
324 return sk_ref_sp(fFallbackNameToFamilyMap[i].styleSet);
325 }
326 }
327 return nullptr;
328 }
329
330 sk_sp<SkTypeface> onMatchFamilyStyle(const char familyName[],
331 const SkFontStyle& style) const override {
332 sk_sp<SkFontStyleSet> sset(this->matchFamily(familyName));
333 return sset->matchStyle(style);
334 }
335
336 static sk_sp<SkTypeface_AndroidSystem> find_family_style_character(
337 const SkString& familyName,
338 const TArray<NameToFamily, true>& fallbackNameToFamilyMap,
339 const SkFontStyle& style, bool elegant,
340 const SkString& langTag, SkUnichar character)
341 {
342 for (int i = 0; i < fallbackNameToFamilyMap.size(); ++i) {
343 SkFontStyleSet_Android* family = fallbackNameToFamilyMap[i].styleSet;
344 if (familyName != family->fFallbackFor) {
345 continue;
346 }
347 sk_sp<SkTypeface_AndroidSystem> face(family->matchAStyle(style));
348
349 if (!langTag.isEmpty() &&
350 std::none_of(face->fLang.begin(), face->fLang.end(), [&](const SkLanguage& lang){
351 return lang.getTag().startsWith(langTag.c_str());
352 }))
353 {
354 continue;
355 }
356
357 if (SkToBool(face->fVariantStyle & kElegant_FontVariant) != elegant) {
358 continue;
359 }
360
361 if (face->unicharToGlyph(character) != 0) {
362 return face;
363 }
364 }
365 return nullptr;
366 }
367
368 sk_sp<SkTypeface> onMatchFamilyStyleCharacter(const char familyName[],
369 const SkFontStyle& style,
370 const char* bcp47[],
371 int bcp47Count,
372 SkUnichar character) const override {
373 // The variant 'elegant' is 'not squashed', 'compact' is 'stays in ascent/descent'.
374 // The variant 'default' means 'compact and elegant'.
375 // As a result, it is not possible to know the variant context from the font alone.
376 // TODO: add 'is_elegant' and 'is_compact' bits to 'style' request.
377
378 SkString familyNameString(familyName);
379 for (const SkString& currentFamilyName : { familyNameString, SkString() }) {
380 // The first time match anything elegant, second time anything not elegant.
381 for (int elegant = 2; elegant --> 0;) {
382 for (int bcp47Index = bcp47Count; bcp47Index --> 0;) {
383 SkLanguage lang(bcp47[bcp47Index]);
384 while (!lang.getTag().isEmpty()) {
385 sk_sp<SkTypeface_AndroidSystem> matchingTypeface =
386 find_family_style_character(currentFamilyName, fFallbackNameToFamilyMap,
387 style, SkToBool(elegant),
388 lang.getTag(), character);
389 if (matchingTypeface) {
390 return matchingTypeface;
391 }
392
393 lang = lang.getParent();
394 }
395 }
396 sk_sp<SkTypeface_AndroidSystem> matchingTypeface =
397 find_family_style_character(currentFamilyName, fFallbackNameToFamilyMap,
398 style, SkToBool(elegant),
400 if (matchingTypeface) {
401 return matchingTypeface;
402 }
403 }
404 }
405 return nullptr;
406 }
407
408 sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData> data, int ttcIndex) const override {
409 return this->makeFromStream(std::unique_ptr<SkStreamAsset>(new SkMemoryStream(std::move(data))),
410 ttcIndex);
411 }
412
413 sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override {
414 std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(path);
415 return stream ? this->makeFromStream(std::move(stream), ttcIndex) : nullptr;
416 }
417
418 sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,
419 int ttcIndex) const override {
420 return this->makeFromStream(std::move(stream),
421 SkFontArguments().setCollectionIndex(ttcIndex));
422 }
423
424 sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,
425 const SkFontArguments& args) const override {
427 }
428
429 sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[], SkFontStyle style) const override {
430 if (familyName) {
431 // On Android, we must return nullptr when we can't find the requested
432 // named typeface so that the system/app can provide their own recovery
433 // mechanism. On other platforms we'd provide a typeface from the
434 // default family instead.
435 return sk_sp<SkTypeface>(this->onMatchFamilyStyle(familyName, style));
436 }
437 return sk_sp<SkTypeface>(fDefaultStyleSet->matchStyle(style));
438 }
439
440
441private:
442
443 std::unique_ptr<SkFontScanner> fScanner;
444
446 sk_sp<SkFontStyleSet> fDefaultStyleSet;
447
448 TArray<NameToFamily, true> fNameToFamilyMap;
449 TArray<NameToFamily, true> fFallbackNameToFamilyMap;
450
451 void addFamily(FontFamily& family, const bool isolated, int familyIndex) {
452 TArray<NameToFamily, true>* nameToFamily = &fNameToFamilyMap;
453 if (family.fIsFallbackFont) {
454 nameToFamily = &fFallbackNameToFamilyMap;
455
456 if (family.fNames.empty()) {
457 SkString& fallbackName = family.fNames.push_back();
458 fallbackName.printf("%.2x##fallback", (uint32_t)familyIndex);
459 }
460 }
461
463 sk_make_sp<SkFontStyleSet_Android>(family, fScanner.get(), isolated);
464 if (0 == newSet->count()) {
465 return;
466 }
467
468 for (const SkString& name : family.fNames) {
469 nameToFamily->emplace_back(NameToFamily{name, newSet.get()});
470 }
471 fStyleSets.emplace_back(std::move(newSet));
472 }
473 void buildNameToFamilyMap(const SkTDArray<FontFamily*>& families, const bool isolated) {
474 int familyIndex = 0;
475 for (FontFamily* family : families) {
476 addFamily(*family, isolated, familyIndex++);
477 for (const auto& [unused, fallbackFamily] : family->fallbackFamilies) {
478 addFamily(*fallbackFamily, isolated, familyIndex++);
479 }
480 }
481 }
482
483 void findDefaultStyleSet() {
484 SkASSERT(!fStyleSets.empty());
485
486 static const char* defaultNames[] = { "sans-serif" };
487 for (const char* defaultName : defaultNames) {
488 fDefaultStyleSet = this->onMatchFamily(defaultName);
489 if (fDefaultStyleSet) {
490 break;
491 }
492 }
493 if (nullptr == fDefaultStyleSet) {
494 fDefaultStyleSet = fStyleSets[0];
495 }
496 SkASSERT(fDefaultStyleSet);
497 }
498
499 using INHERITED = SkFontMgr;
500};
501
502#ifdef SK_DEBUG
503static char const * const gSystemFontUseStrings[] = {
504 "OnlyCustom", "PreferCustom", "PreferSystem"
505};
506#endif
507
508} // namespace
509
511 return SkFontMgr_New_Android(custom, std::make_unique<SkFontScanner_FreeType>());
512}
513
514
515sk_sp<SkFontMgr> SkFontMgr_New_Android(const SkFontMgr_Android_CustomFonts* custom, std::unique_ptr<SkFontScanner> scanner) {
516 if (custom) {
517 SkASSERT(0 <= custom->fSystemFontUse);
518 SkASSERT(custom->fSystemFontUse < std::size(gSystemFontUseStrings));
519 SkDEBUGF("SystemFontUse: %s BasePath: %s Fonts: %s FallbackFonts: %s\n",
520 gSystemFontUseStrings[custom->fSystemFontUse],
521 custom->fBasePath,
522 custom->fFontsXml,
523 custom->fFallbackFontsXml);
524 }
525 return sk_make_sp<SkFontMgr_Android>(custom, std::move(scanner));
526}
static bool unused
int count
Definition: FontMgrTest.cpp:50
#define SkASSERT(cond)
Definition: SkAssert.h:116
#define SkDEBUGF(...)
Definition: SkDebug.h:24
int32_t SkFixed
Definition: SkFixed.h:25
sk_sp< SkFontMgr > SkFontMgr_New_Android(const SkFontMgr_Android_CustomFonts *custom)
uint32_t FontVariant
@ kDefault_FontVariant
@ kCompact_FontVariant
@ kElegant_FontVariant
FILE * sk_fopen(const char path[], SkFILE_Flags)
@ kRead_SkFILE_Flag
Definition: SkOSFile.h:20
#define INHERITED(method,...)
Definition: SkRecorder.cpp:128
sk_sp< T > sk_ref_sp(T *obj)
Definition: SkRefCnt.h:381
static constexpr bool SkToBool(const T &x)
Definition: SkTo.h:35
int32_t SkUnichar
Definition: SkTypes.h:175
Definition: SkData.h:25
const void * data() const
Definition: SkData.h:37
static sk_sp< SkData > MakeFromFILE(FILE *f)
Definition: SkData.cpp:138
static void computeAxisValues(AxisDefinitions axisDefinitions, const SkFontArguments::VariationPosition position, SkFixed *axisValues, const SkString &name, SkFontStyle *style, const SkFontArguments::VariationPosition::Coordinate *currentPosition=nullptr)
virtual bool scanInstance(SkStreamAsset *stream, int faceIndex, int instanceIndex, SkString *name, SkFontStyle *style, bool *isFixedPitch, AxisDefinitions *axes) const =0
Slant slant() const
Definition: SkFontStyle.h:64
int width() const
Definition: SkFontStyle.h:63
int weight() const
Definition: SkFontStyle.h:62
static std::unique_ptr< SkStreamAsset > MakeFromFile(const char path[])
Definition: SkStream.cpp:922
void printf(const char format[],...) SK_PRINTF_LIKE(2
Definition: SkString.cpp:534
void set(const SkString &src)
Definition: SkString.h:186
bool isEmpty() const
Definition: SkString.h:130
void append(const char text[])
Definition: SkString.h:203
void reset()
Definition: SkString.cpp:358
const char * c_str() const
Definition: SkString.h:133
static sk_sp< SkTypeface > MakeFromStream(std::unique_ptr< SkStreamAsset >, const SkFontArguments &)
SkFourByteTag FactoryId
Definition: SkTypeface.h:335
T * get() const
Definition: SkRefCnt.h:303
bool empty() const
Definition: SkTArray.h:199
int size() const
Definition: SkTArray.h:421
T & emplace_back(Args &&... args)
Definition: SkTArray.h:248
struct MyStruct s
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
void GetCustomFontFamilies(SkTDArray< FontFamily * > &fontFamilies, const SkString &basePath, const char *fontsXml, const char *fallbackFontsXml, const char *langFallbackFontsDir=nullptr)
void GetSystemFontFamilies(SkTDArray< FontFamily * > &fontFamilies)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
Definition: ref_ptr.h:256
skia_private::TArray< SkString, true > fNames
const SkString fBasePath
skia_private::THashMap< SkString, std::unique_ptr< FontFamily > > fallbackFamilies
skia_private::TArray< SkLanguage, true > fLanguages
skia_private::TArray< FontFileInfo, true > fFonts
enum FontFileInfo::Style fStyle
skia_private::TArray< SkFontArguments::VariationPosition::Coordinate, true > fVariationDesignPosition