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