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
347static SkTypeface_AndroidSystem* find_family_style_character(
348        const SkTDArray<NameToFamily>& fallbackNameToFamilyMap,
349        const SkFontStyle& style, bool elegant,
350        const SkString& langTag, SkUnichar character)
351{
352    for (int i = 0; i < fallbackNameToFamilyMap.count(); ++i) {
353        SkFontStyleSet_Android* family = fallbackNameToFamilyMap[i].styleSet;
354        SkAutoTUnref<SkTypeface_AndroidSystem> face(family->matchStyle(style));
355
356        if (!langTag.isEmpty() && !face->fLang.getTag().startsWith(langTag.c_str())) {
357            continue;
358        }
359
360        if (SkToBool(face->fVariantStyle & kElegant_FontVariant) != elegant) {
361            continue;
362        }
363
364        SkPaint paint;
365        paint.setTypeface(face);
366        paint.setTextEncoding(SkPaint::kUTF32_TextEncoding);
367
368        uint16_t glyphID;
369        paint.textToGlyphs(&character, sizeof(character), &glyphID);
370        if (glyphID != 0) {
371            return face.detach();
372        }
373    }
374    return NULL;
375}
376#ifdef SK_FM_NEW_MATCH_FAMILY_STYLE_CHARACTER
377    virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[],
378                                                    const SkFontStyle& style,
379                                                    const char* bcp47[],
380                                                    int bcp47Count,
381                                                    SkUnichar character) const SK_OVERRIDE
382    {
383#else
384    virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[],
385                                                    const SkFontStyle& style,
386                                                    const char bcp47_val[],
387                                                    SkUnichar character) const SK_OVERRIDE
388    {
389        const char** bcp47 = &bcp47_val;
390        int bcp47Count = bcp47_val ? 1 : 0;
391#endif
392        // The variant 'elegant' is 'not squashed', 'compact' is 'stays in ascent/descent'.
393        // The variant 'default' means 'compact and elegant'.
394        // As a result, it is not possible to know the variant context from the font alone.
395        // TODO: add 'is_elegant' and 'is_compact' bits to 'style' request.
396
397        // The first time match anything elegant, second time anything not elegant.
398        for (int elegant = 2; elegant --> 0;) {
399            for (int bcp47Index = bcp47Count; bcp47Index --> 0;) {
400                SkLanguage lang(bcp47[bcp47Index]);
401                while (!lang.getTag().isEmpty()) {
402                    SkTypeface_AndroidSystem* matchingTypeface =
403                        find_family_style_character(fFallbackNameToFamilyMap,
404                                                    style, SkToBool(elegant),
405                                                    lang.getTag(), character);
406                    if (matchingTypeface) {
407                        return matchingTypeface;
408                    }
409
410                    lang = lang.getParent();
411                }
412            }
413            SkTypeface_AndroidSystem* matchingTypeface =
414                find_family_style_character(fFallbackNameToFamilyMap,
415                                            style, SkToBool(elegant),
416                                            SkString(), character);
417            if (matchingTypeface) {
418                return matchingTypeface;
419            }
420        }
421        return NULL;
422    }
423
424    virtual SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const SK_OVERRIDE {
425        SkAutoTUnref<SkStream> stream(new SkMemoryStream(data));
426        return this->createFromStream(stream, ttcIndex);
427    }
428
429    virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const SK_OVERRIDE {
430        SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path));
431        return stream.get() ? this->createFromStream(stream, ttcIndex) : NULL;
432    }
433
434    virtual SkTypeface* onCreateFromStream(SkStream* stream, int ttcIndex) const SK_OVERRIDE {
435        bool isFixedPitch;
436        SkTypeface::Style style;
437        SkString name;
438        if (!SkTypeface_FreeType::ScanFont(stream, ttcIndex, &name, &style, &isFixedPitch)) {
439            return NULL;
440        }
441        return SkNEW_ARGS(SkTypeface_AndroidStream, (stream, ttcIndex,
442                                                     style, isFixedPitch, name));
443    }
444
445
446    virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
447                                               unsigned styleBits) const SK_OVERRIDE {
448        SkTypeface::Style oldStyle = (SkTypeface::Style)styleBits;
449        SkFontStyle style = SkFontStyle(oldStyle & SkTypeface::kBold
450                                                 ? SkFontStyle::kBold_Weight
451                                                 : SkFontStyle::kNormal_Weight,
452                                        SkFontStyle::kNormal_Width,
453                                        oldStyle & SkTypeface::kItalic
454                                                 ? SkFontStyle::kItalic_Slant
455                                                 : SkFontStyle::kUpright_Slant);
456
457        if (familyName) {
458            // On Android, we must return NULL when we can't find the requested
459            // named typeface so that the system/app can provide their own recovery
460            // mechanism. On other platforms we'd provide a typeface from the
461            // default family instead.
462            return this->onMatchFamilyStyle(familyName, style);
463        }
464        return fDefaultFamily->matchStyle(style);
465    }
466
467
468private:
469
470    SkTArray<SkAutoTUnref<SkFontStyleSet_Android>, true> fFontStyleSets;
471    SkFontStyleSet* fDefaultFamily;
472    SkTypeface* fDefaultTypeface;
473
474    SkTDArray<NameToFamily> fNameToFamilyMap;
475    SkTDArray<NameToFamily> fFallbackNameToFamilyMap;
476
477    void buildNameToFamilyMap(SkTDArray<FontFamily*> families, const char* basePath) {
478        for (int i = 0; i < families.count(); i++) {
479            FontFamily& family = *families[i];
480
481            SkTDArray<NameToFamily>* nameToFamily = &fNameToFamilyMap;
482            if (family.fIsFallbackFont) {
483                nameToFamily = &fFallbackNameToFamilyMap;
484
485                if (0 == family.fNames.count()) {
486                    SkString& fallbackName = family.fNames.push_back();
487                    fallbackName.printf("%.2x##fallback", i);
488                }
489            }
490
491            SkFontStyleSet_Android* newSet = SkNEW_ARGS(SkFontStyleSet_Android, (family, basePath));
492            if (0 == newSet->count()) {
493                SkDELETE(newSet);
494                continue;
495            }
496            fFontStyleSets.push_back().reset(newSet);
497
498            for (int j = 0; j < family.fNames.count(); j++) {
499                NameToFamily* nextEntry = nameToFamily->append();
500                SkNEW_PLACEMENT_ARGS(&nextEntry->name, SkString, (family.fNames[j]));
501                nextEntry->styleSet = newSet;
502            }
503        }
504    }
505
506    void findDefaultFont() {
507        SkASSERT(!fFontStyleSets.empty());
508
509        static const char* gDefaultNames[] = { "sans-serif" };
510        for (size_t i = 0; i < SK_ARRAY_COUNT(gDefaultNames); ++i) {
511            SkFontStyleSet* set = this->onMatchFamily(gDefaultNames[i]);
512            if (NULL == set) {
513                continue;
514            }
515            SkTypeface* tf = set->matchStyle(SkFontStyle());
516            if (NULL == tf) {
517                continue;
518            }
519            fDefaultFamily = set;
520            fDefaultTypeface = tf;
521            break;
522        }
523        if (NULL == fDefaultTypeface) {
524            fDefaultFamily = fFontStyleSets[0];
525            fDefaultTypeface = fDefaultFamily->createTypeface(0);
526        }
527        SkASSERT(fDefaultFamily);
528        SkASSERT(fDefaultTypeface);
529    }
530
531    typedef SkFontMgr INHERITED;
532};
533
534///////////////////////////////////////////////////////////////////////////////
535
536SkFontMgr* SkFontMgr::Factory() {
537    // The call to SkGetTestFontConfiguration is so that Chromium can override the environment.
538    // TODO: these globals need to be removed, in favor of a constructor / separate Factory
539    // which can be used instead.
540    const char* mainConfigFile;
541    const char* fallbackConfigFile;
542    const char* basePath;
543    SkGetTestFontConfiguration(&mainConfigFile, &fallbackConfigFile, &basePath);
544    if (mainConfigFile) {
545        return SkNEW_ARGS(SkFontMgr_Android, (mainConfigFile, fallbackConfigFile, basePath));
546    }
547
548    return SkNEW(SkFontMgr_Android);
549}
550
551void SkUseTestFontConfigFile(const char* mainconf, const char* fallbackconf,
552                             const char* fontsdir) {
553    gTestMainConfigFile = mainconf;
554    gTestFallbackConfigFile = fallbackconf;
555    gTestFontFilePrefix = fontsdir;
556    SkASSERT(gTestMainConfigFile);
557    SkASSERT(gTestFallbackConfigFile);
558    SkASSERT(gTestFontFilePrefix);
559    SkDEBUGF(("Use Test Config File Main %s, Fallback %s, Font Dir %s",
560              gTestMainConfigFile, gTestFallbackConfigFile, gTestFontFilePrefix));
561}
562
563void SkGetTestFontConfiguration(const char** mainconf, const char** fallbackconf,
564                                const char** fontsdir) {
565    *mainconf = gTestMainConfigFile;
566    *fallbackconf = gTestFallbackConfigFile;
567    *fontsdir = gTestFontFilePrefix;
568}
569