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
8 #include "include/core/SkTypes.h"
9
10 #include "include/core/SkData.h"
11 #include "include/core/SkFontMgr.h"
12 #include "include/core/SkFontStyle.h"
13 #include "include/core/SkPaint.h"
14 #include "include/core/SkRefCnt.h"
15 #include "include/core/SkStream.h"
16 #include "include/core/SkString.h"
17 #include "include/ports/SkFontMgr_android.h"
18 #include "include/ports/SkFontScanner_FreeType.h"
19 #include "include/private/base/SkFixed.h"
20 #include "include/private/base/SkTArray.h"
21 #include "include/private/base/SkTDArray.h"
22 #include "include/private/base/SkTemplates.h"
23 #include "src/base/SkTSearch.h"
24 #include "src/core/SkAdvancedTypefaceMetrics.h"
25 #include "src/core/SkFontDescriptor.h"
26 #include "src/core/SkOSFile.h"
27 #include "src/core/SkTypefaceCache.h"
28 #include "src/ports/SkFontMgr_android_parser.h"
29 #include "src/ports/SkTypeface_proxy.h"
30
31 #include <algorithm>
32 #include <limits>
33
34 using namespace skia_private;
35
36 class SkData;
37
38 namespace {
39 class SkTypeface_AndroidSystem : public SkTypeface_proxy {
40 public:
SkTypeface_AndroidSystem(sk_sp<SkTypeface> proxy,const SkString & pathName,const bool cacheFontFiles,int index,const SkFontStyle & style,bool isFixedPitch,const SkString & familyName,const TArray<SkLanguage,true> & lang,FontVariant variantStyle)41 SkTypeface_AndroidSystem(sk_sp<SkTypeface> proxy,
42 const SkString& pathName,
43 const bool cacheFontFiles,
44 int index,
45 const SkFontStyle& style,
46 bool isFixedPitch,
47 const SkString& familyName,
48 const TArray<SkLanguage, true>& lang,
49 FontVariant variantStyle)
50 : SkTypeface_proxy(style, isFixedPitch)
51 , fPathName(pathName)
52 , fFamilyName(familyName)
53 , fIndex(index)
54 , fLang(lang)
55 , fVariantStyle(variantStyle)
56 , fFile(cacheFontFiles ? sk_fopen(fPathName.c_str(), kRead_SkFILE_Flag) : nullptr) {
57 SkTypeface_proxy::setProxy(proxy);
58 }
Make(sk_sp<SkTypeface> proxy,const SkString & pathName,const bool cacheFontFiles,int index,const SkFontStyle & style,bool isFixedPitch,const SkString & familyName,const TArray<SkLanguage,true> & lang,FontVariant variantStyle)59 static sk_sp<SkTypeface_AndroidSystem> Make(sk_sp<SkTypeface> proxy,
60 const SkString& pathName,
61 const bool cacheFontFiles,
62 int index,
63 const SkFontStyle& style,
64 bool isFixedPitch,
65 const SkString& familyName,
66 const TArray<SkLanguage, true>& lang,
67 FontVariant variantStyle) {
68 return sk_sp<SkTypeface_AndroidSystem>(new SkTypeface_AndroidSystem(std::move(proxy),
69 pathName,
70 cacheFontFiles,
71 index,
72 style,
73 isFixedPitch,
74 familyName,
75 lang,
76 variantStyle));
77 }
78
makeStream() const79 std::unique_ptr<SkStreamAsset> makeStream() const {
80 if (fFile) {
81 sk_sp<SkData> data(SkData::MakeFromFILE(fFile));
82 return data ? std::make_unique<SkMemoryStream>(std::move(data)) : nullptr;
83 }
84 return SkStream::MakeFromFile(fPathName.c_str());
85 }
86
87 const SkString fPathName;
88 const SkString fFamilyName;
89 int fIndex;
90 const STArray<4, SkFixed, true> fAxes;
91 const STArray<4, SkLanguage, true> fLang;
92 const FontVariant fVariantStyle;
93 SkAutoTCallVProc<FILE, sk_fclose> fFile;
94
95 protected:
onGetFamilyName(SkString * familyName) const96 void onGetFamilyName(SkString* familyName) const override {
97 *familyName = fFamilyName;
98 }
99
onMakeClone(const SkFontArguments & args) const100 sk_sp<SkTypeface> onMakeClone(const SkFontArguments& args) const override {
101 return SkTypeface_AndroidSystem::Make(
102 SkTypeface_proxy::onMakeClone(args),
103 fPathName,
104 fFile,
105 fIndex,
106 this->fontStyle(),
107 this->isFixedPitch(),
108 fFamilyName,
109 fLang,
110 fVariantStyle);
111 }
112
onGetFontDescriptor(SkFontDescriptor * desc,bool * serialize) const113 void onGetFontDescriptor(SkFontDescriptor* desc, bool* serialize) const override {
114 SkTypeface_proxy::onGetFontDescriptor(desc, serialize);
115
116 SkASSERT(desc);
117 SkASSERT(serialize);
118 desc->setFamilyName(fFamilyName.c_str());
119 desc->setStyle(this->fontStyle());
120 *serialize = false;
121 }
122
onOpenStream(int * ttcIndex) const123 std::unique_ptr<SkStreamAsset> onOpenStream(int* ttcIndex) const override {
124 *ttcIndex = fIndex;
125 return this->makeStream();
126 }
127
onGetFontStyle() const128 SkFontStyle onGetFontStyle() const override {
129 return SkTypeface::onGetFontStyle();
130 }
131
onGetFixedPitch() const132 bool onGetFixedPitch() const override {
133 return SkTypeface::onGetFixedPitch();
134 }
135 };
136
sk_sp_static_cast(sk_sp<S> && s)137 template <typename D, typename S> sk_sp<D> sk_sp_static_cast(sk_sp<S>&& s) {
138 return sk_sp<D>(static_cast<D*>(s.release()));
139 }
140
141 class SkFontStyleSet_Android : public SkFontStyleSet {
142 public:
SkFontStyleSet_Android(const FontFamily & family,const SkFontScanner * scanner,const bool cacheFontFiles)143 explicit SkFontStyleSet_Android(const FontFamily& family, const SkFontScanner* scanner,
144 const bool cacheFontFiles) {
145 const SkString* cannonicalFamilyName = nullptr;
146 if (!family.fNames.empty()) {
147 cannonicalFamilyName = &family.fNames[0];
148 }
149 fFallbackFor = family.fFallbackFor;
150
151 // TODO? make this lazy
152 for (int i = 0; i < family.fFonts.size(); ++i) {
153 const FontFileInfo& fontFile = family.fFonts[i];
154
155 SkString pathName(family.fBasePath);
156 pathName.append(fontFile.fFileName);
157
158 std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(pathName.c_str());
159 if (!stream) {
160 SkDEBUGF("Requested font file %s does not exist or cannot be opened.\n",
161 pathName.c_str());
162 continue;
163 }
164
165 SkFontArguments::VariationPosition position = {
166 fontFile.fVariationDesignPosition.begin(),
167 fontFile.fVariationDesignPosition.size()
168 };
169 auto proxy = scanner->MakeFromStream(
170 std::move(stream),
171 SkFontArguments().setCollectionIndex(fontFile.fIndex)
172 .setVariationDesignPosition(position));
173 if (!proxy) {
174 SkDEBUGF("Requested font file %s does not have valid font data.\n",
175 pathName.c_str());
176 continue;
177 }
178
179 uint32_t variant = family.fVariant;
180 if (kDefault_FontVariant == variant) {
181 variant = kCompact_FontVariant | kElegant_FontVariant;
182 }
183
184 // The first specified family name overrides the family name found in the font.
185 // TODO: SkTypeface_AndroidSystem::onCreateFamilyNameIterator should return
186 // all of the specified family names in addition to the names found in the font.
187 SkString familyName;
188 proxy->getFamilyName(&familyName);
189 if (cannonicalFamilyName != nullptr) {
190 familyName = *cannonicalFamilyName;
191 }
192
193 SkFontStyle fontStyle = proxy->fontStyle();
194 int weight = fontFile.fWeight != 0 ? fontFile.fWeight : fontStyle.weight();
195 SkFontStyle::Slant slant = fontStyle.slant();
196 switch (fontFile.fStyle) {
197 case FontFileInfo::Style::kAuto: slant = fontStyle.slant(); break;
198 case FontFileInfo::Style::kNormal: slant = SkFontStyle::kUpright_Slant; break;
199 case FontFileInfo::Style::kItalic: slant = SkFontStyle::kItalic_Slant; break;
200 default: SkASSERT(false); break;
201 }
202 fontStyle = SkFontStyle(weight, fontStyle.width(), slant);
203
204 fStyles.push_back().reset(
205 new SkTypeface_AndroidSystem(proxy,
206 pathName,
207 cacheFontFiles,
208 fontFile.fIndex,
209 fontStyle,
210 proxy->isFixedPitch(),
211 familyName,
212 family.fLanguages,
213 variant));
214 }
215 }
216
count()217 int count() override {
218 return fStyles.size();
219 }
getStyle(int index,SkFontStyle * style,SkString * name)220 void getStyle(int index, SkFontStyle* style, SkString* name) override {
221 if (index < 0 || fStyles.size() <= index) {
222 return;
223 }
224 if (style) {
225 *style = fStyles[index]->fontStyle();
226 }
227 if (name) {
228 name->reset();
229 }
230 }
createTypeface(int index)231 sk_sp<SkTypeface> createTypeface(int index) override {
232 if (index < 0 || fStyles.size() <= index) {
233 return nullptr;
234 }
235 return fStyles[index];
236 }
237
matchAStyle(const SkFontStyle & pattern)238 sk_sp<SkTypeface_AndroidSystem> matchAStyle(const SkFontStyle& pattern) {
239 return sk_sp_static_cast<SkTypeface_AndroidSystem>(this->matchStyleCSS3(pattern));
240 }
matchStyle(const SkFontStyle & pattern)241 sk_sp<SkTypeface> matchStyle(const SkFontStyle& pattern) override {
242 return this->matchAStyle(pattern);
243 }
244
245 private:
246 TArray<sk_sp<SkTypeface_AndroidSystem>> fStyles;
247 SkString fFallbackFor;
248
249 friend struct NameToFamily;
250 friend class SkFontMgr_Android;
251
252 using INHERITED = SkFontStyleSet;
253 };
254
255 /** On Android a single family can have many names, but our API assumes unique names.
256 * Map names to the back end so that all names for a given family refer to the same
257 * (non-replicated) set of typefaces.
258 * SkTDict<> doesn't let us do index-based lookup, so we write our own mapping.
259 */
260 struct NameToFamily {
261 SkString name;
262 SkFontStyleSet_Android* styleSet;
263 };
264
265 class SkFontMgr_Android : public SkFontMgr {
266 public:
SkFontMgr_Android(const SkFontMgr_Android_CustomFonts * custom,std::unique_ptr<SkFontScanner> scanner)267 SkFontMgr_Android(const SkFontMgr_Android_CustomFonts* custom,
268 std::unique_ptr<SkFontScanner> scanner)
269 : fScanner(std::move(scanner)) {
270 SkTDArray<FontFamily*> families;
271 if (custom && SkFontMgr_Android_CustomFonts::kPreferSystem != custom->fSystemFontUse) {
272 SkString base(custom->fBasePath);
273 SkFontMgr_Android_Parser::GetCustomFontFamilies(
274 families, base, custom->fFontsXml, custom->fFallbackFontsXml);
275 }
276 if (!custom ||
277 (custom && SkFontMgr_Android_CustomFonts::kOnlyCustom != custom->fSystemFontUse))
278 {
279 SkFontMgr_Android_Parser::GetSystemFontFamilies(families);
280 }
281 if (custom && SkFontMgr_Android_CustomFonts::kPreferSystem == custom->fSystemFontUse) {
282 SkString base(custom->fBasePath);
283 SkFontMgr_Android_Parser::GetCustomFontFamilies(
284 families, base, custom->fFontsXml, custom->fFallbackFontsXml);
285 }
286 this->buildNameToFamilyMap(families, custom ? custom->fIsolated : false);
287 this->findDefaultStyleSet();
288 for (FontFamily* p : families) {
289 delete p;
290 }
291 families.reset();
292 }
293
294 protected:
295 /** Returns not how many families we have, but how many unique names
296 * exist among the families.
297 */
onCountFamilies() const298 int onCountFamilies() const override {
299 return fNameToFamilyMap.size();
300 }
301
onGetFamilyName(int index,SkString * familyName) const302 void onGetFamilyName(int index, SkString* familyName) const override {
303 if (index < 0 || fNameToFamilyMap.size() <= index) {
304 familyName->reset();
305 return;
306 }
307 familyName->set(fNameToFamilyMap[index].name);
308 }
309
onCreateStyleSet(int index) const310 sk_sp<SkFontStyleSet> onCreateStyleSet(int index) const override {
311 if (index < 0 || fNameToFamilyMap.size() <= index) {
312 return nullptr;
313 }
314 return sk_ref_sp(fNameToFamilyMap[index].styleSet);
315 }
316
onMatchFamily(const char familyName[]) const317 sk_sp<SkFontStyleSet> onMatchFamily(const char familyName[]) const override {
318 if (!familyName) {
319 return nullptr;
320 }
321 SkAutoAsciiToLC tolc(familyName);
322 for (int i = 0; i < fNameToFamilyMap.size(); ++i) {
323 if (fNameToFamilyMap[i].name.equals(tolc.lc())) {
324 return sk_ref_sp(fNameToFamilyMap[i].styleSet);
325 }
326 }
327 // TODO: eventually we should not need to name fallback families.
328 for (int i = 0; i < fFallbackNameToFamilyMap.size(); ++i) {
329 if (fFallbackNameToFamilyMap[i].name.equals(tolc.lc())) {
330 return sk_ref_sp(fFallbackNameToFamilyMap[i].styleSet);
331 }
332 }
333 return nullptr;
334 }
335
onMatchFamilyStyle(const char familyName[],const SkFontStyle & style) const336 sk_sp<SkTypeface> onMatchFamilyStyle(const char familyName[],
337 const SkFontStyle& style) const override {
338 sk_sp<SkFontStyleSet> sset(this->matchFamily(familyName));
339 return sset->matchStyle(style);
340 }
341
find_family_style_character(const SkString & familyName,const TArray<NameToFamily,true> & fallbackNameToFamilyMap,const SkFontStyle & style,bool elegant,const SkString & langTag,SkUnichar character)342 static sk_sp<SkTypeface_AndroidSystem> find_family_style_character(
343 const SkString& familyName,
344 const TArray<NameToFamily, true>& fallbackNameToFamilyMap,
345 const SkFontStyle& style, bool elegant,
346 const SkString& langTag, SkUnichar character)
347 {
348 for (int i = 0; i < fallbackNameToFamilyMap.size(); ++i) {
349 SkFontStyleSet_Android* family = fallbackNameToFamilyMap[i].styleSet;
350 if (familyName != family->fFallbackFor) {
351 continue;
352 }
353 sk_sp<SkTypeface_AndroidSystem> face(family->matchAStyle(style));
354
355 if (!langTag.isEmpty() &&
356 std::none_of(face->fLang.begin(), face->fLang.end(), [&](const SkLanguage& lang){
357 return lang.getTag().startsWith(langTag.c_str());
358 }))
359 {
360 continue;
361 }
362
363 if (SkToBool(face->fVariantStyle & kElegant_FontVariant) != elegant) {
364 continue;
365 }
366
367 if (face->unicharToGlyph(character) != 0) {
368 return face;
369 }
370 }
371 return nullptr;
372 }
373
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character) const374 sk_sp<SkTypeface> onMatchFamilyStyleCharacter(const char familyName[],
375 const SkFontStyle& style,
376 const char* bcp47[],
377 int bcp47Count,
378 SkUnichar character) const override {
379 // The variant 'elegant' is 'not squashed', 'compact' is 'stays in ascent/descent'.
380 // The variant 'default' means 'compact and elegant'.
381 // As a result, it is not possible to know the variant context from the font alone.
382 // TODO: add 'is_elegant' and 'is_compact' bits to 'style' request.
383
384 SkString familyNameString(familyName);
385 for (const SkString& currentFamilyName : { familyNameString, SkString() }) {
386 // The first time match anything elegant, second time anything not elegant.
387 for (int elegant = 2; elegant --> 0;) {
388 for (int bcp47Index = bcp47Count; bcp47Index --> 0;) {
389 SkLanguage lang(bcp47[bcp47Index]);
390 while (!lang.getTag().isEmpty()) {
391 sk_sp<SkTypeface_AndroidSystem> matchingTypeface =
392 find_family_style_character(currentFamilyName, fFallbackNameToFamilyMap,
393 style, SkToBool(elegant),
394 lang.getTag(), character);
395 if (matchingTypeface) {
396 return matchingTypeface;
397 }
398
399 lang = lang.getParent();
400 }
401 }
402 sk_sp<SkTypeface_AndroidSystem> matchingTypeface =
403 find_family_style_character(currentFamilyName, fFallbackNameToFamilyMap,
404 style, SkToBool(elegant),
405 SkString(), character);
406 if (matchingTypeface) {
407 return matchingTypeface;
408 }
409 }
410 }
411 return nullptr;
412 }
413
onMakeFromData(sk_sp<SkData> data,int ttcIndex) const414 sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData> data, int ttcIndex) const override {
415 return this->makeFromStream(std::unique_ptr<SkStreamAsset>(new SkMemoryStream(std::move(data))),
416 ttcIndex);
417 }
418
onMakeFromFile(const char path[],int ttcIndex) const419 sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override {
420 std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(path);
421 return stream ? this->makeFromStream(std::move(stream), ttcIndex) : nullptr;
422 }
423
onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,int ttcIndex) const424 sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,
425 int ttcIndex) const override {
426 return this->makeFromStream(std::move(stream),
427 SkFontArguments().setCollectionIndex(ttcIndex));
428 }
429
onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,const SkFontArguments & args) const430 sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,
431 const SkFontArguments& args) const override {
432 return fScanner->MakeFromStream(std::move(stream), args);
433 }
434
onLegacyMakeTypeface(const char familyName[],SkFontStyle style) const435 sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[], SkFontStyle style) const override {
436 if (familyName) {
437 // On Android, we must return nullptr when we can't find the requested
438 // named typeface so that the system/app can provide their own recovery
439 // mechanism. On other platforms we'd provide a typeface from the
440 // default family instead.
441 return sk_sp<SkTypeface>(this->onMatchFamilyStyle(familyName, style));
442 }
443 if (fDefaultStyleSet) {
444 return sk_sp<SkTypeface>(fDefaultStyleSet->matchStyle(style));
445 }
446 return SkTypeface::MakeEmpty();
447 }
448
449
450 private:
451
452 std::unique_ptr<SkFontScanner> fScanner;
453
454 TArray<sk_sp<SkFontStyleSet_Android>> fStyleSets;
455 sk_sp<SkFontStyleSet> fDefaultStyleSet;
456
457 TArray<NameToFamily, true> fNameToFamilyMap;
458 TArray<NameToFamily, true> fFallbackNameToFamilyMap;
459
addFamily(FontFamily & family,const bool isolated,int familyIndex)460 void addFamily(FontFamily& family, const bool isolated, int familyIndex) {
461 TArray<NameToFamily, true>* nameToFamily = &fNameToFamilyMap;
462 if (family.fIsFallbackFont) {
463 nameToFamily = &fFallbackNameToFamilyMap;
464
465 if (family.fNames.empty()) {
466 SkString& fallbackName = family.fNames.push_back();
467 fallbackName.printf("%.2x##fallback", (uint32_t)familyIndex);
468 }
469 }
470
471 sk_sp<SkFontStyleSet_Android> newSet =
472 sk_make_sp<SkFontStyleSet_Android>(family, fScanner.get(), isolated);
473 if (0 == newSet->count()) {
474 return;
475 }
476
477 for (const SkString& name : family.fNames) {
478 nameToFamily->emplace_back(NameToFamily{name, newSet.get()});
479 }
480 fStyleSets.emplace_back(std::move(newSet));
481 }
buildNameToFamilyMap(const SkTDArray<FontFamily * > & families,const bool isolated)482 void buildNameToFamilyMap(const SkTDArray<FontFamily*>& families, const bool isolated) {
483 int familyIndex = 0;
484 for (FontFamily* family : families) {
485 addFamily(*family, isolated, familyIndex++);
486 for (const auto& [unused, fallbackFamily] : family->fallbackFamilies) {
487 addFamily(*fallbackFamily, isolated, familyIndex++);
488 }
489 }
490 }
491
findDefaultStyleSet()492 void findDefaultStyleSet() {
493 static const char* defaultNames[] = { "sans-serif" };
494 for (const char* defaultName : defaultNames) {
495 fDefaultStyleSet = this->onMatchFamily(defaultName);
496 if (fDefaultStyleSet) {
497 break;
498 }
499 }
500 if (!fDefaultStyleSet && !fStyleSets.empty()) {
501 fDefaultStyleSet = fStyleSets[0];
502 }
503 }
504
505 using INHERITED = SkFontMgr;
506 };
507
508 #ifdef SK_DEBUG
509 static char const * const gSystemFontUseStrings[] = {
510 "OnlyCustom", "PreferCustom", "PreferSystem"
511 };
512 #endif
513
514 } // namespace
515
SkFontMgr_New_Android(const SkFontMgr_Android_CustomFonts * custom)516 sk_sp<SkFontMgr> SkFontMgr_New_Android(const SkFontMgr_Android_CustomFonts* custom) {
517 return SkFontMgr_New_Android(custom, SkFontScanner_Make_FreeType());
518 }
519
SkFontMgr_New_Android(const SkFontMgr_Android_CustomFonts * custom,std::unique_ptr<SkFontScanner> scanner)520 sk_sp<SkFontMgr> SkFontMgr_New_Android(const SkFontMgr_Android_CustomFonts* custom, std::unique_ptr<SkFontScanner> scanner) {
521 if (custom) {
522 SkASSERT(0 <= custom->fSystemFontUse);
523 SkASSERT(custom->fSystemFontUse < std::size(gSystemFontUseStrings));
524 SkDEBUGF("SystemFontUse: %s BasePath: %s Fonts: %s FallbackFonts: %s\n",
525 gSystemFontUseStrings[custom->fSystemFontUse],
526 custom->fBasePath,
527 custom->fFontsXml,
528 custom->fFallbackFontsXml);
529 }
530 return sk_make_sp<SkFontMgr_Android>(custom, std::move(scanner));
531 }
532