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 "SkTypes.h"
9 
10 #include "SkData.h"
11 #include "SkFixed.h"
12 #include "SkFontDescriptor.h"
13 #include "SkFontHost_FreeType_common.h"
14 #include "SkFontMgr.h"
15 #include "SkFontMgr_android.h"
16 #include "SkFontMgr_android_parser.h"
17 #include "SkFontStyle.h"
18 #include "SkOSFile.h"
19 #include "SkPaint.h"
20 #include "SkRefCnt.h"
21 #include "SkString.h"
22 #include "SkStream.h"
23 #include "SkTArray.h"
24 #include "SkTDArray.h"
25 #include "SkTSearch.h"
26 #include "SkTemplates.h"
27 #include "SkTypefaceCache.h"
28 
29 #include <limits>
30 
31 class SkData;
32 
33 class SkTypeface_Android : public SkTypeface_FreeType {
34 public:
SkTypeface_Android(const SkFontStyle & style,bool isFixedPitch,const SkString & familyName)35     SkTypeface_Android(const SkFontStyle& style,
36                        bool isFixedPitch,
37                        const SkString& familyName)
38         : INHERITED(style, SkTypefaceCache::NewFontID(), isFixedPitch)
39         , fFamilyName(familyName)
40         { }
41 
42 protected:
onGetFamilyName(SkString * familyName) const43     void onGetFamilyName(SkString* familyName) const override {
44         *familyName = fFamilyName;
45     }
46 
47     SkString fFamilyName;
48 
49 private:
50     typedef SkTypeface_FreeType INHERITED;
51 };
52 
53 class SkTypeface_AndroidSystem : public SkTypeface_Android {
54 public:
SkTypeface_AndroidSystem(const SkString & pathName,const bool cacheFontFiles,int index,const SkFixed * axes,int axesCount,const SkFontStyle & style,bool isFixedPitch,const SkString & familyName,const SkLanguage & lang,FontVariant variantStyle)55     SkTypeface_AndroidSystem(const SkString& pathName,
56                              const bool cacheFontFiles,
57                              int index,
58                              const SkFixed* axes, int axesCount,
59                              const SkFontStyle& style,
60                              bool isFixedPitch,
61                              const SkString& familyName,
62                              const SkLanguage& lang,
63                              FontVariant variantStyle)
64         : INHERITED(style, isFixedPitch, familyName)
65         , fPathName(pathName)
66         , fIndex(index)
67         , fAxes(axes, axesCount)
68         , fLang(lang)
69         , fVariantStyle(variantStyle)
70         , fFile(cacheFontFiles ? sk_fopen(fPathName.c_str(), kRead_SkFILE_Flag) : nullptr) {
71         if (cacheFontFiles) {
72             SkASSERT(fFile);
73         }
74     }
75 
createStream() const76     SkStreamAsset* createStream() const {
77         if (fFile) {
78             SkData* data = SkData::NewFromFILE(fFile);
79             return data ? new SkMemoryStream(data) : nullptr;
80         }
81         return SkStream::NewFromFile(fPathName.c_str());
82     }
83 
onGetFontDescriptor(SkFontDescriptor * desc,bool * serialize) const84     virtual void onGetFontDescriptor(SkFontDescriptor* desc, bool* serialize) const override {
85         SkASSERT(desc);
86         SkASSERT(serialize);
87         desc->setFamilyName(fFamilyName.c_str());
88         *serialize = false;
89     }
onOpenStream(int * ttcIndex) const90     SkStreamAsset* onOpenStream(int* ttcIndex) const override {
91         *ttcIndex = fIndex;
92         return this->createStream();
93     }
onCreateFontData() const94     SkFontData* onCreateFontData() const override {
95         return new SkFontData(this->createStream(), fIndex, fAxes.begin(), fAxes.count());
96     }
97 
98     const SkString fPathName;
99     int fIndex;
100     const SkSTArray<4, SkFixed, true> fAxes;
101     const SkLanguage fLang;
102     const FontVariant fVariantStyle;
103     SkAutoTCallVProc<FILE, sk_fclose> fFile;
104 
105     typedef SkTypeface_Android INHERITED;
106 };
107 
108 class SkTypeface_AndroidStream : public SkTypeface_Android {
109 public:
SkTypeface_AndroidStream(SkFontData * data,const SkFontStyle & style,bool isFixedPitch,const SkString & familyName)110     SkTypeface_AndroidStream(SkFontData* data,
111                              const SkFontStyle& style,
112                              bool isFixedPitch,
113                              const SkString& familyName)
114         : INHERITED(style, isFixedPitch, familyName)
115         , fData(data)
116     { }
117 
onGetFontDescriptor(SkFontDescriptor * desc,bool * serialize) const118     virtual void onGetFontDescriptor(SkFontDescriptor* desc,
119                                      bool* serialize) const override {
120         SkASSERT(desc);
121         SkASSERT(serialize);
122         desc->setFamilyName(fFamilyName.c_str());
123         *serialize = true;
124     }
125 
onOpenStream(int * ttcIndex) const126     SkStreamAsset* onOpenStream(int* ttcIndex) const override {
127         *ttcIndex = fData->getIndex();
128         return fData->duplicateStream();
129     }
130 
onCreateFontData() const131     SkFontData* onCreateFontData() const override {
132         return new SkFontData(*fData.get());
133     }
134 
135 private:
136     const SkAutoTDelete<const SkFontData> fData;
137     typedef SkTypeface_Android INHERITED;
138 };
139 
140 class SkFontStyleSet_Android : public SkFontStyleSet {
141     typedef SkTypeface_FreeType::Scanner Scanner;
142 
143 public:
SkFontStyleSet_Android(const FontFamily & family,const Scanner & scanner,const bool cacheFontFiles)144     explicit SkFontStyleSet_Android(const FontFamily& family, const Scanner& scanner,
145                                     const bool cacheFontFiles) {
146         const SkString* cannonicalFamilyName = nullptr;
147         if (family.fNames.count() > 0) {
148             cannonicalFamilyName = &family.fNames[0];
149         }
150         // TODO? make this lazy
151         for (int i = 0; i < family.fFonts.count(); ++i) {
152             const FontFileInfo& fontFile = family.fFonts[i];
153 
154             SkString pathName(family.fBasePath);
155             pathName.append(fontFile.fFileName);
156 
157             SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(pathName.c_str()));
158             if (!stream.get()) {
159                 SkDEBUGF(("Requested font file %s does not exist or cannot be opened.\n",
160                           pathName.c_str()));
161                 continue;
162             }
163 
164             const int ttcIndex = fontFile.fIndex;
165             SkString familyName;
166             SkFontStyle style;
167             bool isFixedWidth;
168             Scanner::AxisDefinitions axisDefinitions;
169             if (!scanner.scanFont(stream.get(), ttcIndex,
170                                   &familyName, &style, &isFixedWidth, &axisDefinitions))
171             {
172                 SkDEBUGF(("Requested font file %s exists, but is not a valid font.\n",
173                           pathName.c_str()));
174                 continue;
175             }
176 
177             int weight = fontFile.fWeight != 0 ? fontFile.fWeight : style.weight();
178             SkFontStyle::Slant slant = style.slant();
179             switch (fontFile.fStyle) {
180                 case FontFileInfo::Style::kAuto: slant = style.slant(); break;
181                 case FontFileInfo::Style::kNormal: slant = SkFontStyle::kUpright_Slant; break;
182                 case FontFileInfo::Style::kItalic: slant = SkFontStyle::kItalic_Slant; break;
183                 default: SkASSERT(false); break;
184             }
185             style = SkFontStyle(weight, style.width(), slant);
186 
187             const SkLanguage& lang = family.fLanguage;
188             uint32_t variant = family.fVariant;
189             if (kDefault_FontVariant == variant) {
190                 variant = kCompact_FontVariant | kElegant_FontVariant;
191             }
192 
193             // The first specified family name overrides the family name found in the font.
194             // TODO: SkTypeface_AndroidSystem::onCreateFamilyNameIterator should return
195             // all of the specified family names in addition to the names found in the font.
196             if (cannonicalFamilyName != nullptr) {
197                 familyName = *cannonicalFamilyName;
198             }
199 
200             SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count());
201             Scanner::computeAxisValues(axisDefinitions,
202                                        fontFile.fAxes.begin(), fontFile.fAxes.count(),
203                                        axisValues, familyName);
204 
205             fStyles.push_back().reset(new SkTypeface_AndroidSystem(
206                     pathName, cacheFontFiles, ttcIndex, axisValues.get(), axisDefinitions.count(),
207                     style, isFixedWidth, familyName, lang, variant));
208         }
209     }
210 
count()211     int count() override {
212         return fStyles.count();
213     }
getStyle(int index,SkFontStyle * style,SkString * name)214     void getStyle(int index, SkFontStyle* style, SkString* name) override {
215         if (index < 0 || fStyles.count() <= index) {
216             return;
217         }
218         if (style) {
219             *style = this->style(index);
220         }
221         if (name) {
222             name->reset();
223         }
224     }
createTypeface(int index)225     SkTypeface_AndroidSystem* createTypeface(int index) override {
226         if (index < 0 || fStyles.count() <= index) {
227             return nullptr;
228         }
229         return SkRef(fStyles[index].get());
230     }
231 
232     /** Find the typeface in this style set that most closely matches the given pattern.
233      *  TODO: consider replacing with SkStyleSet_Indirect::matchStyle();
234      *  this simpler version using match_score() passes all our tests.
235      */
matchStyle(const SkFontStyle & pattern)236     SkTypeface_AndroidSystem* matchStyle(const SkFontStyle& pattern) override {
237         if (0 == fStyles.count()) {
238             return nullptr;
239         }
240         SkTypeface_AndroidSystem* closest = fStyles[0];
241         int minScore = std::numeric_limits<int>::max();
242         for (int i = 0; i < fStyles.count(); ++i) {
243             SkFontStyle style = this->style(i);
244             int score = match_score(pattern, style);
245             if (score < minScore) {
246                 closest = fStyles[i];
247                 minScore = score;
248             }
249         }
250         return SkRef(closest);
251     }
252 
253 private:
style(int index)254     SkFontStyle style(int index) {
255         return fStyles[index]->fontStyle();
256     }
match_score(const SkFontStyle & pattern,const SkFontStyle & candidate)257     static int match_score(const SkFontStyle& pattern, const SkFontStyle& candidate) {
258         int score = 0;
259         score += SkTAbs((pattern.width() - candidate.width()) * 100);
260         score += SkTAbs((pattern.isItalic() == candidate.isItalic()) ? 0 : 1000);
261         score += SkTAbs(pattern.weight() - candidate.weight());
262         return score;
263     }
264 
265     SkTArray<SkAutoTUnref<SkTypeface_AndroidSystem>, true> fStyles;
266 
267     friend struct NameToFamily;
268     friend class SkFontMgr_Android;
269 
270     typedef SkFontStyleSet INHERITED;
271 };
272 
273 /** On Android a single family can have many names, but our API assumes unique names.
274  *  Map names to the back end so that all names for a given family refer to the same
275  *  (non-replicated) set of typefaces.
276  *  SkTDict<> doesn't let us do index-based lookup, so we write our own mapping.
277  */
278 struct NameToFamily {
279     SkString name;
280     SkFontStyleSet_Android* styleSet;
281 };
282 
283 class SkFontMgr_Android : public SkFontMgr {
284 public:
SkFontMgr_Android(const SkFontMgr_Android_CustomFonts * custom)285     SkFontMgr_Android(const SkFontMgr_Android_CustomFonts* custom) {
286         SkTDArray<FontFamily*> families;
287         if (custom && SkFontMgr_Android_CustomFonts::kPreferSystem != custom->fSystemFontUse) {
288             SkString base(custom->fBasePath);
289             SkFontMgr_Android_Parser::GetCustomFontFamilies(
290                 families, base, custom->fFontsXml, custom->fFallbackFontsXml);
291         }
292         if (!custom ||
293             (custom && SkFontMgr_Android_CustomFonts::kOnlyCustom != custom->fSystemFontUse))
294         {
295             SkFontMgr_Android_Parser::GetSystemFontFamilies(families);
296         }
297         if (custom && SkFontMgr_Android_CustomFonts::kPreferSystem == custom->fSystemFontUse) {
298             SkString base(custom->fBasePath);
299             SkFontMgr_Android_Parser::GetCustomFontFamilies(
300                 families, base, custom->fFontsXml, custom->fFallbackFontsXml);
301         }
302         this->buildNameToFamilyMap(families, custom ? custom->fIsolated : false);
303         this->findDefaultFont();
304         families.deleteAll();
305     }
306 
307 protected:
308     /** Returns not how many families we have, but how many unique names
309      *  exist among the families.
310      */
onCountFamilies() const311     int onCountFamilies() const override {
312         return fNameToFamilyMap.count();
313     }
314 
onGetFamilyName(int index,SkString * familyName) const315     void onGetFamilyName(int index, SkString* familyName) const override {
316         if (index < 0 || fNameToFamilyMap.count() <= index) {
317             familyName->reset();
318             return;
319         }
320         familyName->set(fNameToFamilyMap[index].name);
321     }
322 
onCreateStyleSet(int index) const323     SkFontStyleSet* onCreateStyleSet(int index) const override {
324         if (index < 0 || fNameToFamilyMap.count() <= index) {
325             return nullptr;
326         }
327         return SkRef(fNameToFamilyMap[index].styleSet);
328     }
329 
onMatchFamily(const char familyName[]) const330     SkFontStyleSet* onMatchFamily(const char familyName[]) const override {
331         if (!familyName) {
332             return nullptr;
333         }
334         SkAutoAsciiToLC tolc(familyName);
335         for (int i = 0; i < fNameToFamilyMap.count(); ++i) {
336             if (fNameToFamilyMap[i].name.equals(tolc.lc())) {
337                 return SkRef(fNameToFamilyMap[i].styleSet);
338             }
339         }
340         // TODO: eventually we should not need to name fallback families.
341         for (int i = 0; i < fFallbackNameToFamilyMap.count(); ++i) {
342             if (fFallbackNameToFamilyMap[i].name.equals(tolc.lc())) {
343                 return SkRef(fFallbackNameToFamilyMap[i].styleSet);
344             }
345         }
346         return nullptr;
347     }
348 
onMatchFamilyStyle(const char familyName[],const SkFontStyle & style) const349     virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
350                                            const SkFontStyle& style) const override {
351         SkAutoTUnref<SkFontStyleSet> sset(this->matchFamily(familyName));
352         return sset->matchStyle(style);
353     }
354 
onMatchFaceStyle(const SkTypeface * typeface,const SkFontStyle & style) const355     virtual SkTypeface* onMatchFaceStyle(const SkTypeface* typeface,
356                                          const SkFontStyle& style) const override {
357         for (int i = 0; i < fFontStyleSets.count(); ++i) {
358             for (int j = 0; j < fFontStyleSets[i]->fStyles.count(); ++j) {
359                 if (fFontStyleSets[i]->fStyles[j] == typeface) {
360                     return fFontStyleSets[i]->matchStyle(style);
361                 }
362             }
363         }
364         return nullptr;
365     }
366 
find_family_style_character(const SkTDArray<NameToFamily> & fallbackNameToFamilyMap,const SkFontStyle & style,bool elegant,const SkString & langTag,SkUnichar character)367     static SkTypeface_AndroidSystem* find_family_style_character(
368             const SkTDArray<NameToFamily>& fallbackNameToFamilyMap,
369             const SkFontStyle& style, bool elegant,
370             const SkString& langTag, SkUnichar character)
371     {
372         for (int i = 0; i < fallbackNameToFamilyMap.count(); ++i) {
373             SkFontStyleSet_Android* family = fallbackNameToFamilyMap[i].styleSet;
374             SkAutoTUnref<SkTypeface_AndroidSystem> face(family->matchStyle(style));
375 
376             if (!langTag.isEmpty() && !face->fLang.getTag().startsWith(langTag.c_str())) {
377                 continue;
378             }
379 
380             if (SkToBool(face->fVariantStyle & kElegant_FontVariant) != elegant) {
381                 continue;
382             }
383 
384             SkPaint paint;
385             paint.setTypeface(face);
386             paint.setTextEncoding(SkPaint::kUTF32_TextEncoding);
387 
388             uint16_t glyphID;
389             paint.textToGlyphs(&character, sizeof(character), &glyphID);
390             if (glyphID != 0) {
391                 return face.detach();
392             }
393         }
394         return nullptr;
395     }
396 
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character) const397     virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[],
398                                                     const SkFontStyle& style,
399                                                     const char* bcp47[],
400                                                     int bcp47Count,
401                                                     SkUnichar character) const override
402     {
403         // The variant 'elegant' is 'not squashed', 'compact' is 'stays in ascent/descent'.
404         // The variant 'default' means 'compact and elegant'.
405         // As a result, it is not possible to know the variant context from the font alone.
406         // TODO: add 'is_elegant' and 'is_compact' bits to 'style' request.
407 
408         // The first time match anything elegant, second time anything not elegant.
409         for (int elegant = 2; elegant --> 0;) {
410             for (int bcp47Index = bcp47Count; bcp47Index --> 0;) {
411                 SkLanguage lang(bcp47[bcp47Index]);
412                 while (!lang.getTag().isEmpty()) {
413                     SkTypeface_AndroidSystem* matchingTypeface =
414                         find_family_style_character(fFallbackNameToFamilyMap,
415                                                     style, SkToBool(elegant),
416                                                     lang.getTag(), character);
417                     if (matchingTypeface) {
418                         return matchingTypeface;
419                     }
420 
421                     lang = lang.getParent();
422                 }
423             }
424             SkTypeface_AndroidSystem* matchingTypeface =
425                 find_family_style_character(fFallbackNameToFamilyMap,
426                                             style, SkToBool(elegant),
427                                             SkString(), character);
428             if (matchingTypeface) {
429                 return matchingTypeface;
430             }
431         }
432         return nullptr;
433     }
434 
onCreateFromData(SkData * data,int ttcIndex) const435     SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const override {
436         return this->createFromStream(new SkMemoryStream(data), ttcIndex);
437     }
438 
onCreateFromFile(const char path[],int ttcIndex) const439     SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override {
440         SkAutoTDelete<SkStreamAsset> stream(SkStream::NewFromFile(path));
441         return stream.get() ? this->createFromStream(stream.detach(), ttcIndex) : nullptr;
442     }
443 
onCreateFromStream(SkStreamAsset * bareStream,int ttcIndex) const444     SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) const override {
445         SkAutoTDelete<SkStreamAsset> stream(bareStream);
446         bool isFixedPitch;
447         SkFontStyle style;
448         SkString name;
449         if (!fScanner.scanFont(stream, ttcIndex, &name, &style, &isFixedPitch, nullptr)) {
450             return nullptr;
451         }
452         SkFontData* data(new SkFontData(stream.detach(), ttcIndex, nullptr, 0));
453         return new SkTypeface_AndroidStream(data, style, isFixedPitch, name);
454     }
455 
onCreateFromStream(SkStreamAsset * s,const FontParameters & params) const456     SkTypeface* onCreateFromStream(SkStreamAsset* s, const FontParameters& params) const override {
457         using Scanner = SkTypeface_FreeType::Scanner;
458         SkAutoTDelete<SkStreamAsset> stream(s);
459         bool isFixedPitch;
460         SkFontStyle style;
461         SkString name;
462         Scanner::AxisDefinitions axisDefinitions;
463         if (!fScanner.scanFont(stream, params.getCollectionIndex(), &name, &style, &isFixedPitch,
464                                &axisDefinitions))
465         {
466             return nullptr;
467         }
468 
469         int paramAxisCount;
470         const FontParameters::Axis* paramAxes = params.getAxes(&paramAxisCount);
471         SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count());
472         Scanner::computeAxisValues(axisDefinitions, paramAxes, paramAxisCount, axisValues, name);
473 
474         SkFontData* data(new SkFontData(stream.detach(), params.getCollectionIndex(),
475                                         axisValues.get(), axisDefinitions.count()));
476         return new SkTypeface_AndroidStream(data, style, isFixedPitch, name);
477     }
478 
onCreateFromFontData(SkFontData * data) const479     SkTypeface* onCreateFromFontData(SkFontData* data) const override {
480         SkStreamAsset* stream(data->getStream());
481         bool isFixedPitch;
482         SkFontStyle style;
483         SkString name;
484         if (!fScanner.scanFont(stream, data->getIndex(), &name, &style, &isFixedPitch, nullptr)) {
485             return nullptr;
486         }
487         return new SkTypeface_AndroidStream(data, style, isFixedPitch, name);
488     }
489 
490 
onLegacyCreateTypeface(const char familyName[],unsigned styleBits) const491     virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
492                                                unsigned styleBits) const override {
493         SkFontStyle style = SkFontStyle(styleBits);
494 
495         if (familyName) {
496             // On Android, we must return nullptr when we can't find the requested
497             // named typeface so that the system/app can provide their own recovery
498             // mechanism. On other platforms we'd provide a typeface from the
499             // default family instead.
500             return this->onMatchFamilyStyle(familyName, style);
501         }
502         return fDefaultFamily->matchStyle(style);
503     }
504 
505 
506 private:
507 
508     SkTypeface_FreeType::Scanner fScanner;
509 
510     SkTArray<SkAutoTUnref<SkFontStyleSet_Android>, true> fFontStyleSets;
511     SkFontStyleSet* fDefaultFamily;
512     SkTypeface* fDefaultTypeface;
513 
514     SkTDArray<NameToFamily> fNameToFamilyMap;
515     SkTDArray<NameToFamily> fFallbackNameToFamilyMap;
516 
buildNameToFamilyMap(SkTDArray<FontFamily * > families,const bool isolated)517     void buildNameToFamilyMap(SkTDArray<FontFamily*> families, const bool isolated) {
518         for (int i = 0; i < families.count(); i++) {
519             FontFamily& family = *families[i];
520 
521             SkTDArray<NameToFamily>* nameToFamily = &fNameToFamilyMap;
522             if (family.fIsFallbackFont) {
523                 nameToFamily = &fFallbackNameToFamilyMap;
524 
525                 if (0 == family.fNames.count()) {
526                     SkString& fallbackName = family.fNames.push_back();
527                     fallbackName.printf("%.2x##fallback", i);
528                 }
529             }
530 
531             SkFontStyleSet_Android* newSet = new SkFontStyleSet_Android(family, fScanner, isolated);
532             if (0 == newSet->count()) {
533                 delete newSet;
534                 continue;
535             }
536             fFontStyleSets.push_back().reset(newSet);
537 
538             for (int j = 0; j < family.fNames.count(); j++) {
539                 NameToFamily* nextEntry = nameToFamily->append();
540                 new (&nextEntry->name) SkString(family.fNames[j]);
541                 nextEntry->styleSet = newSet;
542             }
543         }
544     }
545 
findDefaultFont()546     void findDefaultFont() {
547         SkASSERT(!fFontStyleSets.empty());
548 
549         static const char* gDefaultNames[] = { "sans-serif" };
550         for (size_t i = 0; i < SK_ARRAY_COUNT(gDefaultNames); ++i) {
551             SkFontStyleSet* set = this->onMatchFamily(gDefaultNames[i]);
552             if (nullptr == set) {
553                 continue;
554             }
555             SkTypeface* tf = set->matchStyle(SkFontStyle());
556             if (nullptr == tf) {
557                 continue;
558             }
559             fDefaultFamily = set;
560             fDefaultTypeface = tf;
561             break;
562         }
563         if (nullptr == fDefaultTypeface) {
564             fDefaultFamily = fFontStyleSets[0];
565             fDefaultTypeface = fDefaultFamily->createTypeface(0);
566         }
567         SkASSERT(fDefaultFamily);
568         SkASSERT(fDefaultTypeface);
569     }
570 
571     typedef SkFontMgr INHERITED;
572 };
573 
574 #ifdef SK_DEBUG
575 static char const * const gSystemFontUseStrings[] = {
576     "OnlyCustom", "PreferCustom", "PreferSystem"
577 };
578 #endif
SkFontMgr_New_Android(const SkFontMgr_Android_CustomFonts * custom)579 SkFontMgr* SkFontMgr_New_Android(const SkFontMgr_Android_CustomFonts* custom) {
580     if (custom) {
581         SkASSERT(0 <= custom->fSystemFontUse);
582         SkASSERT(custom->fSystemFontUse < SK_ARRAY_COUNT(gSystemFontUseStrings));
583         SkDEBUGF(("SystemFontUse: %s BasePath: %s Fonts: %s FallbackFonts: %s\n",
584                   gSystemFontUseStrings[custom->fSystemFontUse],
585                   custom->fBasePath,
586                   custom->fFontsXml,
587                   custom->fFallbackFontsXml));
588     }
589 
590     return new SkFontMgr_Android(custom);
591 }
592