SkFontMgr_android.cpp revision 802ad83dca2efd57fde6c7ba666555ea78b5324c
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                       Style 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                             Style 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                             Style 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 SkString* cannonicalFamilyName = NULL;
143        if (family.fNames.count() > 0) {
144            cannonicalFamilyName = &family.fNames[0];
145        }
146        // TODO? make this lazy
147        for (int i = 0; i < family.fFonts.count(); ++i) {
148            const FontFileInfo& fontFile = family.fFonts[i];
149
150            SkString pathName;
151            get_path_for_sys_fonts(basePath, fontFile.fFileName, &pathName);
152
153            SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(pathName.c_str()));
154            if (!stream.get()) {
155                DEBUG_FONT(("---- SystemFonts[%d] file=%s (NOT EXIST)", i, pathName.c_str()));
156                continue;
157            }
158
159            const int ttcIndex = fontFile.fIndex;
160            SkString familyName;
161            SkTypeface::Style style;
162            bool isFixedWidth;
163            if (!SkTypeface_FreeType::ScanFont(stream.get(), ttcIndex,
164                                               &familyName, &style, &isFixedWidth)) {
165                DEBUG_FONT(("---- SystemFonts[%d] file=%s (INVALID)", i, pathName.c_str()));
166                continue;
167            }
168
169            const SkLanguage& lang = family.fLanguage;
170            uint32_t variant = family.fVariant;
171            if (kDefault_FontVariant == variant) {
172                variant = kCompact_FontVariant | kElegant_FontVariant;
173            }
174
175            // The first specified family name overrides the family name found in the font.
176            // TODO: SkTypeface_AndroidSystem::onCreateFamilyNameIterator should return
177            // all of the specified family names in addition to the names found in the font.
178            if (cannonicalFamilyName != NULL) {
179                familyName = *cannonicalFamilyName;
180            }
181
182            fStyles.push_back().reset(SkNEW_ARGS(SkTypeface_AndroidSystem,
183                                                 (pathName, ttcIndex,
184                                                  style, isFixedWidth, familyName,
185                                                  lang, variant)));
186        }
187    }
188
189    virtual int count() SK_OVERRIDE {
190        return fStyles.count();
191    }
192    virtual void getStyle(int index, SkFontStyle* style, SkString* name) SK_OVERRIDE {
193        if (index < 0 || fStyles.count() <= index) {
194            return;
195        }
196        if (style) {
197            *style = this->style(index);
198        }
199        if (name) {
200            name->reset();
201        }
202    }
203    virtual SkTypeface_AndroidSystem* createTypeface(int index) SK_OVERRIDE {
204        if (index < 0 || fStyles.count() <= index) {
205            return NULL;
206        }
207        return SkRef(fStyles[index].get());
208    }
209
210    /** Find the typeface in this style set that most closely matches the given pattern.
211     *  TODO: consider replacing with SkStyleSet_Indirect::matchStyle();
212     *  this simpler version using match_score() passes all our tests.
213     */
214    virtual SkTypeface_AndroidSystem* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE {
215        if (0 == fStyles.count()) {
216            return NULL;
217        }
218        SkTypeface_AndroidSystem* closest = fStyles[0];
219        int minScore = std::numeric_limits<int>::max();
220        for (int i = 0; i < fStyles.count(); ++i) {
221            SkFontStyle style = this->style(i);
222            int score = match_score(pattern, style);
223            if (score < minScore) {
224                closest = fStyles[i];
225                minScore = score;
226            }
227        }
228        return SkRef(closest);
229    }
230
231private:
232    SkFontStyle style(int index) {
233        return SkFontStyle(this->weight(index), SkFontStyle::kNormal_Width,
234                           this->slant(index));
235    }
236    SkFontStyle::Weight weight(int index) {
237        if (fStyles[index]->isBold()) return SkFontStyle::kBold_Weight;
238        return SkFontStyle::kNormal_Weight;
239    }
240    SkFontStyle::Slant slant(int index) {
241        if (fStyles[index]->isItalic()) return SkFontStyle::kItalic_Slant;
242        return SkFontStyle::kUpright_Slant;
243    }
244    static int match_score(const SkFontStyle& pattern, const SkFontStyle& candidate) {
245        int score = 0;
246        score += abs((pattern.width() - candidate.width()) * 100);
247        score += abs((pattern.isItalic() == candidate.isItalic()) ? 0 : 1000);
248        score += abs(pattern.weight() - candidate.weight());
249        return score;
250    }
251
252    SkTArray<SkAutoTUnref<SkTypeface_AndroidSystem>, true> fStyles;
253
254    friend struct NameToFamily;
255    friend class SkFontMgr_Android;
256
257    typedef SkFontStyleSet INHERITED;
258};
259
260/** On Android a single family can have many names, but our API assumes unique names.
261 *  Map names to the back end so that all names for a given family refer to the same
262 *  (non-replicated) set of typefaces.
263 *  SkTDict<> doesn't let us do index-based lookup, so we write our own mapping.
264 */
265struct NameToFamily {
266    SkString name;
267    SkFontStyleSet_Android* styleSet;
268};
269
270class SkFontMgr_Android : public SkFontMgr {
271public:
272    SkFontMgr_Android() {
273        SkTDArray<FontFamily*> fontFamilies;
274        SkFontConfigParser::GetFontFamilies(fontFamilies);
275        this->buildNameToFamilyMap(fontFamilies, NULL);
276        this->findDefaultFont();
277    }
278    SkFontMgr_Android(const char* mainConfigFile, const char* fallbackConfigFile,
279                      const char* basePath)
280    {
281        SkTDArray<FontFamily*> fontFamilies;
282        SkFontConfigParser::GetTestFontFamilies(fontFamilies, mainConfigFile, fallbackConfigFile);
283        this->buildNameToFamilyMap(fontFamilies, basePath);
284        this->findDefaultFont();
285    }
286
287protected:
288    /** Returns not how many families we have, but how many unique names
289     *  exist among the families.
290     */
291    virtual int onCountFamilies() const SK_OVERRIDE {
292        return fNameToFamilyMap.count();
293    }
294
295    virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERRIDE {
296        if (index < 0 || fNameToFamilyMap.count() <= index) {
297            familyName->reset();
298            return;
299        }
300        familyName->set(fNameToFamilyMap[index].name);
301    }
302
303    virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE {
304        if (index < 0 || fNameToFamilyMap.count() <= index) {
305            return NULL;
306        }
307        return SkRef(fNameToFamilyMap[index].styleSet);
308    }
309
310    virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVERRIDE {
311        if (!familyName) {
312            return NULL;
313        }
314        SkAutoAsciiToLC tolc(familyName);
315        for (int i = 0; i < fNameToFamilyMap.count(); ++i) {
316            if (fNameToFamilyMap[i].name.equals(tolc.lc())) {
317                return SkRef(fNameToFamilyMap[i].styleSet);
318            }
319        }
320        // TODO: eventually we should not need to name fallback families.
321        for (int i = 0; i < fFallbackNameToFamilyMap.count(); ++i) {
322            if (fFallbackNameToFamilyMap[i].name.equals(tolc.lc())) {
323                return SkRef(fFallbackNameToFamilyMap[i].styleSet);
324            }
325        }
326        return NULL;
327    }
328
329    virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
330                                           const SkFontStyle& style) const SK_OVERRIDE {
331        SkAutoTUnref<SkFontStyleSet> sset(this->matchFamily(familyName));
332        return sset->matchStyle(style);
333    }
334
335    virtual SkTypeface* onMatchFaceStyle(const SkTypeface* typeface,
336                                         const SkFontStyle& style) const SK_OVERRIDE {
337        for (int i = 0; i < fFontStyleSets.count(); ++i) {
338            for (int j = 0; j < fFontStyleSets[i]->fStyles.count(); ++j) {
339                if (fFontStyleSets[i]->fStyles[j] == typeface) {
340                    return fFontStyleSets[i]->matchStyle(style);
341                }
342            }
343        }
344        return NULL;
345    }
346
347    virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[],
348                                                    const SkFontStyle& style,
349                                                    const char bpc47[],
350                                                    uint32_t character) const SK_OVERRIDE
351    {
352        // The variant 'elegant' is 'not squashed', 'compact' is 'stays in ascent/descent'.
353        // The variant 'default' means 'compact and elegant'.
354        // As a result, it is not possible to know the variant context from the font alone.
355        // TODO: add 'is_elegant' and 'is_compact' bits to 'style' request.
356
357        // For compatibility, try 'elegant' fonts first in fallback.
358        uint32_t variantMask = kElegant_FontVariant;
359
360        // The first time match anything in the mask, second time anything not in the mask.
361        for (bool maskMatches = true; maskMatches != false; maskMatches = false) {
362            SkLanguage lang(bpc47);
363            // Match against the language, removing a segment each time.
364            // The last time through the loop, the language will be empty.
365            // The empty language is special, and matches all languages.
366            do {
367                const SkString& langTag = lang.getTag();
368                for (int i = 0; i < fFallbackNameToFamilyMap.count(); ++i) {
369                    SkFontStyleSet_Android* family = fFallbackNameToFamilyMap[i].styleSet;
370                    SkAutoTUnref<SkTypeface_AndroidSystem> face(family->matchStyle(style));
371
372                    if (!langTag.isEmpty() && langTag != face->fLang.getTag()) {
373                        continue;
374                    }
375
376                    if (SkToBool(face->fVariantStyle & variantMask) != maskMatches) {
377                        continue;
378                    }
379
380                    SkPaint paint;
381                    paint.setTypeface(face);
382                    paint.setTextEncoding(SkPaint::kUTF32_TextEncoding);
383
384                    uint16_t glyphID;
385                    paint.textToGlyphs(&character, sizeof(character), &glyphID);
386                    if (glyphID != 0) {
387                        return face.detach();
388                    }
389                }
390            } while (!lang.getTag().isEmpty() && (lang = lang.getParent(), true));
391        }
392        return NULL;
393    }
394
395    virtual SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const SK_OVERRIDE {
396        SkAutoTUnref<SkStream> stream(new SkMemoryStream(data));
397        return this->createFromStream(stream, ttcIndex);
398    }
399
400    virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const SK_OVERRIDE {
401        SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path));
402        return stream.get() ? this->createFromStream(stream, ttcIndex) : NULL;
403    }
404
405    virtual SkTypeface* onCreateFromStream(SkStream* stream, int ttcIndex) const SK_OVERRIDE {
406        bool isFixedPitch;
407        SkTypeface::Style style;
408        SkString name;
409        if (!SkTypeface_FreeType::ScanFont(stream, ttcIndex, &name, &style, &isFixedPitch)) {
410            return NULL;
411        }
412        return SkNEW_ARGS(SkTypeface_AndroidStream, (stream, ttcIndex,
413                                                     style, isFixedPitch, name));
414    }
415
416
417    virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
418                                               unsigned styleBits) const SK_OVERRIDE {
419        SkTypeface::Style oldStyle = (SkTypeface::Style)styleBits;
420        SkFontStyle style = SkFontStyle(oldStyle & SkTypeface::kBold
421                                                 ? SkFontStyle::kBold_Weight
422                                                 : SkFontStyle::kNormal_Weight,
423                                        SkFontStyle::kNormal_Width,
424                                        oldStyle & SkTypeface::kItalic
425                                                 ? SkFontStyle::kItalic_Slant
426                                                 : SkFontStyle::kUpright_Slant);
427
428        if (familyName) {
429            // On Android, we must return NULL when we can't find the requested
430            // named typeface so that the system/app can provide their own recovery
431            // mechanism. On other platforms we'd provide a typeface from the
432            // default family instead.
433            return this->onMatchFamilyStyle(familyName, style);
434        }
435        return fDefaultFamily->matchStyle(style);
436    }
437
438
439private:
440
441    SkTArray<SkAutoTUnref<SkFontStyleSet_Android>, true> fFontStyleSets;
442    SkFontStyleSet* fDefaultFamily;
443    SkTypeface* fDefaultTypeface;
444
445    SkTDArray<NameToFamily> fNameToFamilyMap;
446    SkTDArray<NameToFamily> fFallbackNameToFamilyMap;
447
448    void buildNameToFamilyMap(SkTDArray<FontFamily*> families, const char* basePath) {
449        for (int i = 0; i < families.count(); i++) {
450            FontFamily& family = *families[i];
451
452            SkTDArray<NameToFamily>* nameToFamily = &fNameToFamilyMap;
453            if (family.fIsFallbackFont) {
454                nameToFamily = &fFallbackNameToFamilyMap;
455
456                if (0 == family.fNames.count()) {
457                    SkString& fallbackName = family.fNames.push_back();
458                    fallbackName.printf("%.2x##fallback", i);
459                }
460            }
461
462            SkFontStyleSet_Android* newSet = SkNEW_ARGS(SkFontStyleSet_Android, (family, basePath));
463            if (0 == newSet->count()) {
464                SkDELETE(newSet);
465                continue;
466            }
467            fFontStyleSets.push_back().reset(newSet);
468
469            for (int j = 0; j < family.fNames.count(); j++) {
470                NameToFamily* nextEntry = nameToFamily->append();
471                SkNEW_PLACEMENT_ARGS(&nextEntry->name, SkString, (family.fNames[j]));
472                nextEntry->styleSet = newSet;
473            }
474        }
475    }
476
477    void findDefaultFont() {
478        SkASSERT(!fFontStyleSets.empty());
479
480        static const char* gDefaultNames[] = { "sans-serif" };
481        for (size_t i = 0; i < SK_ARRAY_COUNT(gDefaultNames); ++i) {
482            SkFontStyleSet* set = this->onMatchFamily(gDefaultNames[i]);
483            if (NULL == set) {
484                continue;
485            }
486            SkTypeface* tf = set->matchStyle(SkFontStyle());
487            if (NULL == tf) {
488                continue;
489            }
490            fDefaultFamily = set;
491            fDefaultTypeface = tf;
492            break;
493        }
494        if (NULL == fDefaultTypeface) {
495            fDefaultFamily = fFontStyleSets[0];
496            fDefaultTypeface = fDefaultFamily->createTypeface(0);
497        }
498        SkASSERT(fDefaultFamily);
499        SkASSERT(fDefaultTypeface);
500    }
501
502    typedef SkFontMgr INHERITED;
503};
504
505///////////////////////////////////////////////////////////////////////////////
506
507SkFontMgr* SkFontMgr::Factory() {
508    // The call to SkGetTestFontConfiguration is so that Chromium can override the environment.
509    // TODO: these globals need to be removed, in favor of a constructor / separate Factory
510    // which can be used instead.
511    const char* mainConfigFile;
512    const char* fallbackConfigFile;
513    const char* basePath;
514    SkGetTestFontConfiguration(&mainConfigFile, &fallbackConfigFile, &basePath);
515    if (mainConfigFile) {
516        return SkNEW_ARGS(SkFontMgr_Android, (mainConfigFile, fallbackConfigFile, basePath));
517    }
518
519    return SkNEW(SkFontMgr_Android);
520}
521
522void SkUseTestFontConfigFile(const char* mainconf, const char* fallbackconf,
523                             const char* fontsdir) {
524    gTestMainConfigFile = mainconf;
525    gTestFallbackConfigFile = fallbackconf;
526    gTestFontFilePrefix = fontsdir;
527    SkASSERT(gTestMainConfigFile);
528    SkASSERT(gTestFallbackConfigFile);
529    SkASSERT(gTestFontFilePrefix);
530    SkDEBUGF(("Use Test Config File Main %s, Fallback %s, Font Dir %s",
531              gTestMainConfigFile, gTestFallbackConfigFile, gTestFontFilePrefix));
532}
533
534void SkGetTestFontConfiguration(const char** mainconf, const char** fallbackconf,
535                                const char** fontsdir) {
536    *mainconf = gTestMainConfigFile;
537    *fallbackconf = gTestFallbackConfigFile;
538    *fontsdir = gTestFontFilePrefix;
539}
540