SkFontMgr_android.cpp revision ee0c2e4fd429424beaa35f29e7f656997ba3f115
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 "SkFontConfigParser_android.h"
9#include "SkFontDescriptor.h"
10#include "SkFontHost_FreeType_common.h"
11#include "SkFontMgr.h"
12#include "SkFontStyle.h"
13#include "SkStream.h"
14#include "SkTDArray.h"
15#include "SkTSearch.h"
16#include "SkTypeface.h"
17#include "SkTypeface_android.h"
18#include "SkTypefaceCache.h"
19
20#include <limits>
21#include <stdlib.h>
22
23#ifndef SK_FONT_FILE_PREFIX
24#    define SK_FONT_FILE_PREFIX "/fonts/"
25#endif
26
27#ifndef SK_DEBUG_FONTS
28    #define SK_DEBUG_FONTS 0
29#endif
30
31#if SK_DEBUG_FONTS
32#    define DEBUG_FONT(args) SkDebugf args
33#else
34#    define DEBUG_FONT(args)
35#endif
36
37// For test only.
38static const char* gTestMainConfigFile = NULL;
39static const char* gTestFallbackConfigFile = NULL;
40static const char* gTestFontFilePrefix = NULL;
41
42class SkTypeface_Android : public SkTypeface_FreeType {
43public:
44    SkTypeface_Android(int index,
45                       const SkFontStyle& style,
46                       bool isFixedPitch,
47                       const SkString familyName)
48        : INHERITED(style, SkTypefaceCache::NewFontID(), isFixedPitch)
49        , fIndex(index)
50        , fFamilyName(familyName) { }
51
52protected:
53    virtual void onGetFamilyName(SkString* familyName) const SK_OVERRIDE {
54        *familyName = fFamilyName;
55    }
56
57    int fIndex;
58    SkString fFamilyName;
59
60private:
61    typedef SkTypeface_FreeType INHERITED;
62};
63
64class SkTypeface_AndroidSystem : public SkTypeface_Android {
65public:
66    SkTypeface_AndroidSystem(const SkString pathName,
67                             int index,
68                             const SkFontStyle& style,
69                             bool isFixedPitch,
70                             const SkString familyName,
71                             const SkLanguage& lang,
72                             FontVariant variantStyle)
73        : INHERITED(index, style, isFixedPitch, familyName)
74        , fPathName(pathName)
75        , fLang(lang)
76        , fVariantStyle(variantStyle) { }
77
78    virtual void onGetFontDescriptor(SkFontDescriptor* desc,
79                                     bool* serialize) const SK_OVERRIDE {
80        SkASSERT(desc);
81        SkASSERT(serialize);
82        desc->setFamilyName(fFamilyName.c_str());
83        desc->setFontFileName(fPathName.c_str());
84        desc->setFontIndex(fIndex);
85        *serialize = false;
86    }
87    virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE {
88        *ttcIndex = fIndex;
89        return SkStream::NewFromFile(fPathName.c_str());
90    }
91
92    const SkString fPathName;
93    const SkLanguage fLang;
94    const FontVariant fVariantStyle;
95
96    typedef SkTypeface_Android INHERITED;
97};
98
99class SkTypeface_AndroidStream : public SkTypeface_Android {
100public:
101    SkTypeface_AndroidStream(SkStream* stream,
102                             int index,
103                             const SkFontStyle& style,
104                             bool isFixedPitch,
105                             const SkString familyName)
106        : INHERITED(index, style, isFixedPitch, familyName)
107        , fStream(SkRef(stream)) { }
108
109    virtual void onGetFontDescriptor(SkFontDescriptor* desc,
110                                     bool* serialize) const SK_OVERRIDE {
111        SkASSERT(desc);
112        SkASSERT(serialize);
113        desc->setFamilyName(fFamilyName.c_str());
114        desc->setFontFileName(NULL);
115        *serialize = true;
116    }
117
118    virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE {
119        *ttcIndex = fIndex;
120        return fStream->duplicate();
121    }
122
123private:
124    SkAutoTUnref<SkStream> fStream;
125
126    typedef SkTypeface_Android INHERITED;
127};
128
129void get_path_for_sys_fonts(const char* basePath, const SkString& name, SkString* full) {
130    if (basePath) {
131        full->set(basePath);
132    } else {
133        full->set(getenv("ANDROID_ROOT"));
134        full->append(SK_FONT_FILE_PREFIX);
135    }
136    full->append(name);
137}
138
139class SkFontStyleSet_Android : public SkFontStyleSet {
140public:
141    explicit SkFontStyleSet_Android(const FontFamily& family, const char* basePath,
142                                    const SkTypeface_FreeType::Scanner& scanner)
143    {
144        const SkString* cannonicalFamilyName = NULL;
145        if (family.fNames.count() > 0) {
146            cannonicalFamilyName = &family.fNames[0];
147        }
148        // TODO? make this lazy
149        for (int i = 0; i < family.fFonts.count(); ++i) {
150            const FontFileInfo& fontFile = family.fFonts[i];
151
152            SkString pathName;
153            get_path_for_sys_fonts(basePath, fontFile.fFileName, &pathName);
154
155            SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(pathName.c_str()));
156            if (!stream.get()) {
157                DEBUG_FONT(("---- SystemFonts[%d] file=%s (NOT EXIST)", i, pathName.c_str()));
158                continue;
159            }
160
161            const int ttcIndex = fontFile.fIndex;
162            SkString familyName;
163            SkFontStyle style;
164            bool isFixedWidth;
165            if (!scanner.scanFont(stream.get(), ttcIndex, &familyName, &style, &isFixedWidth)) {
166                DEBUG_FONT(("---- SystemFonts[%d] file=%s (INVALID)", i, pathName.c_str()));
167                continue;
168            }
169
170            const SkLanguage& lang = family.fLanguage;
171            uint32_t variant = family.fVariant;
172            if (kDefault_FontVariant == variant) {
173                variant = kCompact_FontVariant | kElegant_FontVariant;
174            }
175
176            // The first specified family name overrides the family name found in the font.
177            // TODO: SkTypeface_AndroidSystem::onCreateFamilyNameIterator should return
178            // all of the specified family names in addition to the names found in the font.
179            if (cannonicalFamilyName != NULL) {
180                familyName = *cannonicalFamilyName;
181            }
182
183            fStyles.push_back().reset(SkNEW_ARGS(SkTypeface_AndroidSystem,
184                                                 (pathName, ttcIndex,
185                                                  style, isFixedWidth, familyName,
186                                                  lang, variant)));
187        }
188    }
189
190    virtual int count() SK_OVERRIDE {
191        return fStyles.count();
192    }
193    virtual void getStyle(int index, SkFontStyle* style, SkString* name) SK_OVERRIDE {
194        if (index < 0 || fStyles.count() <= index) {
195            return;
196        }
197        if (style) {
198            *style = this->style(index);
199        }
200        if (name) {
201            name->reset();
202        }
203    }
204    virtual SkTypeface_AndroidSystem* createTypeface(int index) SK_OVERRIDE {
205        if (index < 0 || fStyles.count() <= index) {
206            return NULL;
207        }
208        return SkRef(fStyles[index].get());
209    }
210
211    /** Find the typeface in this style set that most closely matches the given pattern.
212     *  TODO: consider replacing with SkStyleSet_Indirect::matchStyle();
213     *  this simpler version using match_score() passes all our tests.
214     */
215    virtual SkTypeface_AndroidSystem* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE {
216        if (0 == fStyles.count()) {
217            return NULL;
218        }
219        SkTypeface_AndroidSystem* closest = fStyles[0];
220        int minScore = std::numeric_limits<int>::max();
221        for (int i = 0; i < fStyles.count(); ++i) {
222            SkFontStyle style = this->style(i);
223            int score = match_score(pattern, style);
224            if (score < minScore) {
225                closest = fStyles[i];
226                minScore = score;
227            }
228        }
229        return SkRef(closest);
230    }
231
232private:
233    SkFontStyle style(int index) {
234        return SkFontStyle(this->weight(index), SkFontStyle::kNormal_Width,
235                           this->slant(index));
236    }
237    SkFontStyle::Weight weight(int index) {
238        if (fStyles[index]->isBold()) return SkFontStyle::kBold_Weight;
239        return SkFontStyle::kNormal_Weight;
240    }
241    SkFontStyle::Slant slant(int index) {
242        if (fStyles[index]->isItalic()) return SkFontStyle::kItalic_Slant;
243        return SkFontStyle::kUpright_Slant;
244    }
245    static int match_score(const SkFontStyle& pattern, const SkFontStyle& candidate) {
246        int score = 0;
247        score += abs((pattern.width() - candidate.width()) * 100);
248        score += abs((pattern.isItalic() == candidate.isItalic()) ? 0 : 1000);
249        score += abs(pattern.weight() - candidate.weight());
250        return score;
251    }
252
253    SkTArray<SkAutoTUnref<SkTypeface_AndroidSystem>, true> fStyles;
254
255    friend struct NameToFamily;
256    friend class SkFontMgr_Android;
257
258    typedef SkFontStyleSet INHERITED;
259};
260
261/** On Android a single family can have many names, but our API assumes unique names.
262 *  Map names to the back end so that all names for a given family refer to the same
263 *  (non-replicated) set of typefaces.
264 *  SkTDict<> doesn't let us do index-based lookup, so we write our own mapping.
265 */
266struct NameToFamily {
267    SkString name;
268    SkFontStyleSet_Android* styleSet;
269};
270
271class SkFontMgr_Android : public SkFontMgr {
272public:
273    SkFontMgr_Android() {
274        SkTDArray<FontFamily*> fontFamilies;
275        SkFontConfigParser::GetFontFamilies(fontFamilies);
276        this->buildNameToFamilyMap(fontFamilies, NULL);
277        this->findDefaultFont();
278    }
279    SkFontMgr_Android(const char* mainConfigFile, const char* fallbackConfigFile,
280                      const char* basePath)
281    {
282        SkTDArray<FontFamily*> fontFamilies;
283        SkFontConfigParser::GetTestFontFamilies(fontFamilies, mainConfigFile, fallbackConfigFile);
284        this->buildNameToFamilyMap(fontFamilies, basePath);
285        this->findDefaultFont();
286    }
287
288protected:
289    /** Returns not how many families we have, but how many unique names
290     *  exist among the families.
291     */
292    virtual int onCountFamilies() const SK_OVERRIDE {
293        return fNameToFamilyMap.count();
294    }
295
296    virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERRIDE {
297        if (index < 0 || fNameToFamilyMap.count() <= index) {
298            familyName->reset();
299            return;
300        }
301        familyName->set(fNameToFamilyMap[index].name);
302    }
303
304    virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE {
305        if (index < 0 || fNameToFamilyMap.count() <= index) {
306            return NULL;
307        }
308        return SkRef(fNameToFamilyMap[index].styleSet);
309    }
310
311    virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVERRIDE {
312        if (!familyName) {
313            return NULL;
314        }
315        SkAutoAsciiToLC tolc(familyName);
316        for (int i = 0; i < fNameToFamilyMap.count(); ++i) {
317            if (fNameToFamilyMap[i].name.equals(tolc.lc())) {
318                return SkRef(fNameToFamilyMap[i].styleSet);
319            }
320        }
321        // TODO: eventually we should not need to name fallback families.
322        for (int i = 0; i < fFallbackNameToFamilyMap.count(); ++i) {
323            if (fFallbackNameToFamilyMap[i].name.equals(tolc.lc())) {
324                return SkRef(fFallbackNameToFamilyMap[i].styleSet);
325            }
326        }
327        return NULL;
328    }
329
330    virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
331                                           const SkFontStyle& style) const SK_OVERRIDE {
332        SkAutoTUnref<SkFontStyleSet> sset(this->matchFamily(familyName));
333        return sset->matchStyle(style);
334    }
335
336    virtual SkTypeface* onMatchFaceStyle(const SkTypeface* typeface,
337                                         const SkFontStyle& style) const SK_OVERRIDE {
338        for (int i = 0; i < fFontStyleSets.count(); ++i) {
339            for (int j = 0; j < fFontStyleSets[i]->fStyles.count(); ++j) {
340                if (fFontStyleSets[i]->fStyles[j] == typeface) {
341                    return fFontStyleSets[i]->matchStyle(style);
342                }
343            }
344        }
345        return NULL;
346    }
347
348static SkTypeface_AndroidSystem* find_family_style_character(
349        const SkTDArray<NameToFamily>& fallbackNameToFamilyMap,
350        const SkFontStyle& style, bool elegant,
351        const SkString& langTag, SkUnichar character)
352{
353    for (int i = 0; i < fallbackNameToFamilyMap.count(); ++i) {
354        SkFontStyleSet_Android* family = fallbackNameToFamilyMap[i].styleSet;
355        SkAutoTUnref<SkTypeface_AndroidSystem> face(family->matchStyle(style));
356
357        if (!langTag.isEmpty() && !face->fLang.getTag().startsWith(langTag.c_str())) {
358            continue;
359        }
360
361        if (SkToBool(face->fVariantStyle & kElegant_FontVariant) != elegant) {
362            continue;
363        }
364
365        SkPaint paint;
366        paint.setTypeface(face);
367        paint.setTextEncoding(SkPaint::kUTF32_TextEncoding);
368
369        uint16_t glyphID;
370        paint.textToGlyphs(&character, sizeof(character), &glyphID);
371        if (glyphID != 0) {
372            return face.detach();
373        }
374    }
375    return NULL;
376}
377#ifdef SK_FM_NEW_MATCH_FAMILY_STYLE_CHARACTER
378    virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[],
379                                                    const SkFontStyle& style,
380                                                    const char* bcp47[],
381                                                    int bcp47Count,
382                                                    SkUnichar character) const SK_OVERRIDE
383    {
384#else
385    virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[],
386                                                    const SkFontStyle& style,
387                                                    const char bcp47_val[],
388                                                    SkUnichar character) const SK_OVERRIDE
389    {
390        const char** bcp47 = &bcp47_val;
391        int bcp47Count = bcp47_val ? 1 : 0;
392#endif
393        // The variant 'elegant' is 'not squashed', 'compact' is 'stays in ascent/descent'.
394        // The variant 'default' means 'compact and elegant'.
395        // As a result, it is not possible to know the variant context from the font alone.
396        // TODO: add 'is_elegant' and 'is_compact' bits to 'style' request.
397
398        // The first time match anything elegant, second time anything not elegant.
399        for (int elegant = 2; elegant --> 0;) {
400            for (int bcp47Index = bcp47Count; bcp47Index --> 0;) {
401                SkLanguage lang(bcp47[bcp47Index]);
402                while (!lang.getTag().isEmpty()) {
403                    SkTypeface_AndroidSystem* matchingTypeface =
404                        find_family_style_character(fFallbackNameToFamilyMap,
405                                                    style, SkToBool(elegant),
406                                                    lang.getTag(), character);
407                    if (matchingTypeface) {
408                        return matchingTypeface;
409                    }
410
411                    lang = lang.getParent();
412                }
413            }
414            SkTypeface_AndroidSystem* matchingTypeface =
415                find_family_style_character(fFallbackNameToFamilyMap,
416                                            style, SkToBool(elegant),
417                                            SkString(), character);
418            if (matchingTypeface) {
419                return matchingTypeface;
420            }
421        }
422        return NULL;
423    }
424
425    virtual SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const SK_OVERRIDE {
426        SkAutoTUnref<SkStream> stream(new SkMemoryStream(data));
427        return this->createFromStream(stream, ttcIndex);
428    }
429
430    virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const SK_OVERRIDE {
431        SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path));
432        return stream.get() ? this->createFromStream(stream, ttcIndex) : NULL;
433    }
434
435    virtual SkTypeface* onCreateFromStream(SkStream* stream, int ttcIndex) const SK_OVERRIDE {
436        bool isFixedPitch;
437        SkFontStyle style;
438        SkString name;
439        if (!fScanner.scanFont(stream, ttcIndex, &name, &style, &isFixedPitch)) {
440            return NULL;
441        }
442        return SkNEW_ARGS(SkTypeface_AndroidStream, (stream, ttcIndex,
443                                                     style, isFixedPitch, name));
444    }
445
446
447    virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
448                                               unsigned styleBits) const SK_OVERRIDE {
449        SkFontStyle style = SkFontStyle(styleBits);
450
451        if (familyName) {
452            // On Android, we must return NULL 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 this->onMatchFamilyStyle(familyName, style);
457        }
458        return fDefaultFamily->matchStyle(style);
459    }
460
461
462private:
463
464    SkTypeface_FreeType::Scanner fScanner;
465
466    SkTArray<SkAutoTUnref<SkFontStyleSet_Android>, true> fFontStyleSets;
467    SkFontStyleSet* fDefaultFamily;
468    SkTypeface* fDefaultTypeface;
469
470    SkTDArray<NameToFamily> fNameToFamilyMap;
471    SkTDArray<NameToFamily> fFallbackNameToFamilyMap;
472
473    void buildNameToFamilyMap(SkTDArray<FontFamily*> families, const char* basePath) {
474        for (int i = 0; i < families.count(); i++) {
475            FontFamily& family = *families[i];
476
477            SkTDArray<NameToFamily>* nameToFamily = &fNameToFamilyMap;
478            if (family.fIsFallbackFont) {
479                nameToFamily = &fFallbackNameToFamilyMap;
480
481                if (0 == family.fNames.count()) {
482                    SkString& fallbackName = family.fNames.push_back();
483                    fallbackName.printf("%.2x##fallback", i);
484                }
485            }
486
487            SkFontStyleSet_Android* newSet =
488                SkNEW_ARGS(SkFontStyleSet_Android, (family, basePath, fScanner));
489            if (0 == newSet->count()) {
490                SkDELETE(newSet);
491                continue;
492            }
493            fFontStyleSets.push_back().reset(newSet);
494
495            for (int j = 0; j < family.fNames.count(); j++) {
496                NameToFamily* nextEntry = nameToFamily->append();
497                SkNEW_PLACEMENT_ARGS(&nextEntry->name, SkString, (family.fNames[j]));
498                nextEntry->styleSet = newSet;
499            }
500        }
501    }
502
503    void findDefaultFont() {
504        SkASSERT(!fFontStyleSets.empty());
505
506        static const char* gDefaultNames[] = { "sans-serif" };
507        for (size_t i = 0; i < SK_ARRAY_COUNT(gDefaultNames); ++i) {
508            SkFontStyleSet* set = this->onMatchFamily(gDefaultNames[i]);
509            if (NULL == set) {
510                continue;
511            }
512            SkTypeface* tf = set->matchStyle(SkFontStyle());
513            if (NULL == tf) {
514                continue;
515            }
516            fDefaultFamily = set;
517            fDefaultTypeface = tf;
518            break;
519        }
520        if (NULL == fDefaultTypeface) {
521            fDefaultFamily = fFontStyleSets[0];
522            fDefaultTypeface = fDefaultFamily->createTypeface(0);
523        }
524        SkASSERT(fDefaultFamily);
525        SkASSERT(fDefaultTypeface);
526    }
527
528    typedef SkFontMgr INHERITED;
529};
530
531///////////////////////////////////////////////////////////////////////////////
532
533SkFontMgr* SkFontMgr::Factory() {
534    // The call to SkGetTestFontConfiguration is so that Chromium can override the environment.
535    // TODO: these globals need to be removed, in favor of a constructor / separate Factory
536    // which can be used instead.
537    const char* mainConfigFile;
538    const char* fallbackConfigFile;
539    const char* basePath;
540    SkGetTestFontConfiguration(&mainConfigFile, &fallbackConfigFile, &basePath);
541    if (mainConfigFile) {
542        return SkNEW_ARGS(SkFontMgr_Android, (mainConfigFile, fallbackConfigFile, basePath));
543    }
544
545    return SkNEW(SkFontMgr_Android);
546}
547
548void SkUseTestFontConfigFile(const char* mainconf, const char* fallbackconf,
549                             const char* fontsdir) {
550    gTestMainConfigFile = mainconf;
551    gTestFallbackConfigFile = fallbackconf;
552    gTestFontFilePrefix = fontsdir;
553    SkASSERT(gTestMainConfigFile);
554    SkASSERT(gTestFallbackConfigFile);
555    SkASSERT(gTestFontFilePrefix);
556    SkDEBUGF(("Use Test Config File Main %s, Fallback %s, Font Dir %s",
557              gTestMainConfigFile, gTestFallbackConfigFile, gTestFontFilePrefix));
558}
559
560void SkGetTestFontConfiguration(const char** mainconf, const char** fallbackconf,
561                                const char** fontsdir) {
562    *mainconf = gTestMainConfigFile;
563    *fallbackconf = gTestFallbackConfigFile;
564    *fontsdir = gTestFontFilePrefix;
565}
566