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