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