• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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