1/*
2 * Copyright 2006 The Android Open Source Project
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 "SkFontHost_FreeType_common.h"
9#include "SkFontDescriptor.h"
10#include "SkFontMgr.h"
11#include "SkDescriptor.h"
12#include "SkOSFile.h"
13#include "SkPaint.h"
14#include "SkRTConf.h"
15#include "SkString.h"
16#include "SkStream.h"
17#include "SkThread.h"
18#include "SkTSearch.h"
19#include "SkTypefaceCache.h"
20#include "SkTArray.h"
21
22#include <limits>
23
24/** The base SkTypeface implementation for the custom font manager. */
25class SkTypeface_Custom : public SkTypeface_FreeType {
26public:
27    SkTypeface_Custom(const SkFontStyle& style, bool isFixedPitch,
28                      bool sysFont, const SkString familyName, int index)
29        : INHERITED(style, SkTypefaceCache::NewFontID(), isFixedPitch)
30        , fIsSysFont(sysFont), fFamilyName(familyName), fIndex(index)
31    { }
32
33    bool isSysFont() const { return fIsSysFont; }
34
35protected:
36    void onGetFamilyName(SkString* familyName) const override {
37        *familyName = fFamilyName;
38    }
39
40    void onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const override {
41        desc->setFamilyName(fFamilyName.c_str());
42        desc->setFontIndex(fIndex);
43        *isLocal = !this->isSysFont();
44    }
45
46    int getIndex() const { return fIndex; }
47
48private:
49    const bool fIsSysFont;
50    const SkString fFamilyName;
51    const int fIndex;
52
53    typedef SkTypeface_FreeType INHERITED;
54};
55
56/** The empty SkTypeface implementation for the custom font manager.
57 *  Used as the last resort fallback typeface.
58 */
59class SkTypeface_Empty : public SkTypeface_Custom {
60public:
61    SkTypeface_Empty() : INHERITED(SkFontStyle(), false, true, SkString(), 0) {}
62
63protected:
64    SkStreamAsset* onOpenStream(int*) const override { return NULL; }
65
66private:
67    typedef SkTypeface_Custom INHERITED;
68};
69
70/** The stream SkTypeface implementation for the custom font manager. */
71class SkTypeface_Stream : public SkTypeface_Custom {
72public:
73    SkTypeface_Stream(const SkFontStyle& style, bool isFixedPitch, bool sysFont,
74                      const SkString familyName, SkStreamAsset* stream, int index)
75        : INHERITED(style, isFixedPitch, sysFont, familyName, index)
76        , fStream(stream)
77    { }
78
79protected:
80    SkStreamAsset* onOpenStream(int* ttcIndex) const override {
81        *ttcIndex = this->getIndex();
82        return fStream->duplicate();
83    }
84
85private:
86    const SkAutoTDelete<const SkStreamAsset> fStream;
87
88    typedef SkTypeface_Custom INHERITED;
89};
90
91// This configuration option is useful if we need to open and hold handles to
92// all found system font data (e.g., for skfiddle, where the application can't
93// access the filesystem to read fonts on demand)
94
95SK_CONF_DECLARE(bool, c_CustomTypefaceRetain, "fonts.customFont.retainAllData", false,
96                "Retain the open stream for each found font on the system.");
97
98/** The file SkTypeface implementation for the custom font manager. */
99class SkTypeface_File : public SkTypeface_Custom {
100public:
101    SkTypeface_File(const SkFontStyle& style, bool isFixedPitch, bool sysFont,
102                    const SkString familyName, const char path[], int index)
103        : INHERITED(style, isFixedPitch, sysFont, familyName, index)
104        , fPath(path)
105        , fStream(c_CustomTypefaceRetain ? SkStream::NewFromFile(fPath.c_str()) : NULL)
106    { }
107
108protected:
109    SkStreamAsset* onOpenStream(int* ttcIndex) const override {
110        *ttcIndex = this->getIndex();
111        if (fStream.get()) {
112            return fStream->duplicate();
113        } else {
114            return SkStream::NewFromFile(fPath.c_str());
115        }
116    }
117
118private:
119    SkString fPath;
120    const SkAutoTDelete<SkStreamAsset> fStream;
121
122    typedef SkTypeface_Custom INHERITED;
123};
124
125///////////////////////////////////////////////////////////////////////////////
126
127/**
128 *  SkFontStyleSet_Custom
129 *
130 *  This class is used by SkFontMgr_Custom to hold SkTypeface_Custom families.
131 */
132class SkFontStyleSet_Custom : public SkFontStyleSet {
133public:
134    explicit SkFontStyleSet_Custom(const SkString familyName) : fFamilyName(familyName) { }
135
136    /** Should only be called during the inital build phase. */
137    void appendTypeface(SkTypeface_Custom* typeface) {
138        fStyles.push_back().reset(typeface);
139    }
140
141    int count() override {
142        return fStyles.count();
143    }
144
145    void getStyle(int index, SkFontStyle* style, SkString* name) override {
146        SkASSERT(index < fStyles.count());
147        bool bold = fStyles[index]->isBold();
148        bool italic = fStyles[index]->isItalic();
149        *style = SkFontStyle(bold ? SkFontStyle::kBold_Weight : SkFontStyle::kNormal_Weight,
150                             SkFontStyle::kNormal_Width,
151                             italic ? SkFontStyle::kItalic_Slant : SkFontStyle::kUpright_Slant);
152        name->reset();
153    }
154
155    SkTypeface* createTypeface(int index) override {
156        SkASSERT(index < fStyles.count());
157        return SkRef(fStyles[index].get());
158    }
159
160    static int match_score(const SkFontStyle& pattern, const SkFontStyle& candidate) {
161        int score = 0;
162        score += (pattern.width() - candidate.width()) * 100;
163        score += (pattern.isItalic() == candidate.isItalic()) ? 0 : 1000;
164        score += pattern.weight() - candidate.weight();
165        return score;
166    }
167
168    SkTypeface* matchStyle(const SkFontStyle& pattern) override {
169        if (0 == fStyles.count()) {
170            return NULL;
171        }
172
173        SkTypeface_Custom* closest = fStyles[0];
174        int minScore = std::numeric_limits<int>::max();
175        for (int i = 0; i < fStyles.count(); ++i) {
176            bool bold = fStyles[i]->isBold();
177            bool italic = fStyles[i]->isItalic();
178            SkFontStyle style = SkFontStyle(bold ? SkFontStyle::kBold_Weight
179                                                 : SkFontStyle::kNormal_Weight,
180                                            SkFontStyle::kNormal_Width,
181                                            italic ? SkFontStyle::kItalic_Slant
182                                                   : SkFontStyle::kUpright_Slant);
183
184            int score = match_score(pattern, style);
185            if (score < minScore) {
186                closest = fStyles[i];
187                minScore = score;
188            }
189        }
190        return SkRef(closest);
191    }
192
193    SkString getFamilyName() { return fFamilyName; }
194
195private:
196    SkTArray<SkAutoTUnref<SkTypeface_Custom>, true> fStyles;
197    SkString fFamilyName;
198
199    friend class SkFontMgr_Custom;
200};
201
202/**
203 *  SkFontMgr_Custom
204 *
205 *  This class is essentially a collection of SkFontStyleSet_Custom,
206 *  one SkFontStyleSet_Custom for each family. This class may be modified
207 *  to load fonts from any source by changing the initialization.
208 */
209class SkFontMgr_Custom : public SkFontMgr {
210public:
211    typedef SkTArray<SkAutoTUnref<SkFontStyleSet_Custom>, true> Families;
212    class SystemFontLoader {
213    public:
214        virtual ~SystemFontLoader() { }
215        virtual void loadSystemFonts(const SkTypeface_FreeType::Scanner&, Families*) const = 0;
216    };
217    explicit SkFontMgr_Custom(const SystemFontLoader& loader) {
218        loader.loadSystemFonts(fScanner, &fFamilies);
219
220        // Try to pick a default font.
221        static const char* defaultNames[] = {
222            "Arial", "Verdana", "Times New Roman", "Droid Sans", NULL
223        };
224        for (size_t i = 0; i < SK_ARRAY_COUNT(defaultNames); ++i) {
225            SkFontStyleSet_Custom* set = this->onMatchFamily(defaultNames[i]);
226            if (NULL == set) {
227                continue;
228            }
229
230            SkTypeface* tf = set->matchStyle(SkFontStyle(SkFontStyle::kNormal_Weight,
231                                                         SkFontStyle::kNormal_Width,
232                                                         SkFontStyle::kUpright_Slant));
233            if (NULL == tf) {
234                continue;
235            }
236
237            fDefaultFamily = set;
238            break;
239        }
240        if (NULL == fDefaultFamily) {
241            fDefaultFamily = fFamilies[0];
242        }
243    }
244
245protected:
246    int onCountFamilies() const override {
247        return fFamilies.count();
248    }
249
250    void onGetFamilyName(int index, SkString* familyName) const override {
251        SkASSERT(index < fFamilies.count());
252        familyName->set(fFamilies[index]->getFamilyName());
253    }
254
255    SkFontStyleSet_Custom* onCreateStyleSet(int index) const override {
256        SkASSERT(index < fFamilies.count());
257        return SkRef(fFamilies[index].get());
258    }
259
260    SkFontStyleSet_Custom* onMatchFamily(const char familyName[]) const override {
261        for (int i = 0; i < fFamilies.count(); ++i) {
262            if (fFamilies[i]->getFamilyName().equals(familyName)) {
263                return SkRef(fFamilies[i].get());
264            }
265        }
266        return NULL;
267    }
268
269    SkTypeface* onMatchFamilyStyle(const char familyName[],
270                                   const SkFontStyle& fontStyle) const override
271    {
272        SkAutoTUnref<SkFontStyleSet> sset(this->matchFamily(familyName));
273        return sset->matchStyle(fontStyle);
274    }
275
276    SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&,
277                                            const char* bcp47[], int bcp47Count,
278                                            SkUnichar character) const override
279    {
280        return NULL;
281    }
282
283    SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember,
284                                 const SkFontStyle& fontStyle) const override
285    {
286        for (int i = 0; i < fFamilies.count(); ++i) {
287            for (int j = 0; j < fFamilies[i]->fStyles.count(); ++j) {
288                if (fFamilies[i]->fStyles[j] == familyMember) {
289                    return fFamilies[i]->matchStyle(fontStyle);
290                }
291            }
292        }
293        return NULL;
294    }
295
296    SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const override {
297        return this->createFromStream(new SkMemoryStream(data), ttcIndex);
298    }
299
300    SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) const override {
301        SkAutoTDelete<SkStreamAsset> stream(bareStream);
302        if (NULL == stream || stream->getLength() <= 0) {
303            return NULL;
304        }
305
306        bool isFixedPitch;
307        SkFontStyle style;
308        SkString name;
309        if (fScanner.scanFont(stream, ttcIndex, &name, &style, &isFixedPitch)) {
310            return SkNEW_ARGS(SkTypeface_Stream, (style, isFixedPitch, false, name,
311                                                  stream.detach(), ttcIndex));
312        } else {
313            return NULL;
314        }
315    }
316
317    SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override {
318        SkAutoTDelete<SkStreamAsset> stream(SkStream::NewFromFile(path));
319        return stream.get() ? this->createFromStream(stream.detach(), ttcIndex) : NULL;
320    }
321
322    SkTypeface* onLegacyCreateTypeface(const char familyName[], unsigned styleBits) const override {
323        SkTypeface::Style oldStyle = (SkTypeface::Style)styleBits;
324        SkFontStyle style = SkFontStyle(oldStyle & SkTypeface::kBold
325                                                 ? SkFontStyle::kBold_Weight
326                                                 : SkFontStyle::kNormal_Weight,
327                                        SkFontStyle::kNormal_Width,
328                                        oldStyle & SkTypeface::kItalic
329                                                 ? SkFontStyle::kItalic_Slant
330                                                 : SkFontStyle::kUpright_Slant);
331        SkTypeface* tf = NULL;
332
333        if (familyName) {
334            tf = this->onMatchFamilyStyle(familyName, style);
335        }
336
337        if (NULL == tf) {
338            tf = fDefaultFamily->matchStyle(style);
339        }
340
341        return SkSafeRef(tf);
342    }
343
344private:
345    Families fFamilies;
346    SkFontStyleSet_Custom* fDefaultFamily;
347    SkTypeface_FreeType::Scanner fScanner;
348};
349
350///////////////////////////////////////////////////////////////////////////////
351
352class DirectorySystemFontLoader : public SkFontMgr_Custom::SystemFontLoader {
353public:
354    DirectorySystemFontLoader(const char* dir) : fBaseDirectory(dir) { }
355
356    void loadSystemFonts(const SkTypeface_FreeType::Scanner& scanner,
357                         SkFontMgr_Custom::Families* families) const override
358    {
359        load_directory_fonts(scanner, fBaseDirectory, ".ttf", families);
360        load_directory_fonts(scanner, fBaseDirectory, ".ttc", families);
361        load_directory_fonts(scanner, fBaseDirectory, ".otf", families);
362        load_directory_fonts(scanner, fBaseDirectory, ".pfb", families);
363
364        if (families->empty()) {
365            SkFontStyleSet_Custom* family = new SkFontStyleSet_Custom(SkString());
366            families->push_back().reset(family);
367            family->appendTypeface(SkNEW(SkTypeface_Empty));
368        }
369    }
370
371private:
372    static SkFontStyleSet_Custom* find_family(SkFontMgr_Custom::Families& families,
373                                              const char familyName[])
374    {
375       for (int i = 0; i < families.count(); ++i) {
376            if (families[i]->getFamilyName().equals(familyName)) {
377                return families[i].get();
378            }
379        }
380        return NULL;
381    }
382
383    static void load_directory_fonts(const SkTypeface_FreeType::Scanner& scanner,
384                                     const SkString& directory, const char* suffix,
385                                     SkFontMgr_Custom::Families* families)
386    {
387        SkOSFile::Iter iter(directory.c_str(), suffix);
388        SkString name;
389
390        while (iter.next(&name, false)) {
391            SkString filename(SkOSPath::Join(directory.c_str(), name.c_str()));
392            SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(filename.c_str()));
393            if (!stream.get()) {
394                SkDebugf("---- failed to open <%s>\n", filename.c_str());
395                continue;
396            }
397
398            int numFaces;
399            if (!scanner.recognizedFont(stream, &numFaces)) {
400                SkDebugf("---- failed to open <%s> as a font\n", filename.c_str());
401                continue;
402            }
403
404            for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) {
405                bool isFixedPitch;
406                SkString realname;
407                SkFontStyle style = SkFontStyle(); // avoid uninitialized warning
408                if (!scanner.scanFont(stream, faceIndex, &realname, &style, &isFixedPitch)) {
409                    SkDebugf("---- failed to open <%s> <%d> as a font\n",
410                             filename.c_str(), faceIndex);
411                    continue;
412                }
413
414                SkTypeface_Custom* tf = SkNEW_ARGS(SkTypeface_File, (
415                                                    style,
416                                                    isFixedPitch,
417                                                    true,  // system-font (cannot delete)
418                                                    realname,
419                                                    filename.c_str(),
420                                                    faceIndex));
421
422                SkFontStyleSet_Custom* addTo = find_family(*families, realname.c_str());
423                if (NULL == addTo) {
424                    addTo = new SkFontStyleSet_Custom(realname);
425                    families->push_back().reset(addTo);
426                }
427                addTo->appendTypeface(tf);
428            }
429        }
430
431        SkOSFile::Iter dirIter(directory.c_str());
432        while (dirIter.next(&name, true)) {
433            if (name.startsWith(".")) {
434                continue;
435            }
436            SkString dirname(SkOSPath::Join(directory.c_str(), name.c_str()));
437            load_directory_fonts(scanner, dirname, suffix, families);
438        }
439    }
440
441    SkString fBaseDirectory;
442};
443
444struct SkEmbeddedResource { const uint8_t* data; size_t size; };
445struct SkEmbeddedResourceHeader { const SkEmbeddedResource* entries; int count; };
446
447class EmbeddedSystemFontLoader : public SkFontMgr_Custom::SystemFontLoader {
448public:
449    EmbeddedSystemFontLoader(const SkEmbeddedResourceHeader* header) : fHeader(header) { }
450
451    void loadSystemFonts(const SkTypeface_FreeType::Scanner& scanner,
452                         SkFontMgr_Custom::Families* families) const override
453    {
454        for (int i = 0; i < fHeader->count; ++i) {
455            const SkEmbeddedResource& fontEntry = fHeader->entries[i];
456            load_embedded_font(scanner, fontEntry.data, fontEntry.size, i, families);
457        }
458
459        if (families->empty()) {
460            SkFontStyleSet_Custom* family = new SkFontStyleSet_Custom(SkString());
461            families->push_back().reset(family);
462            family->appendTypeface(SkNEW(SkTypeface_Empty));
463        }
464    }
465
466private:
467    static SkFontStyleSet_Custom* find_family(SkFontMgr_Custom::Families& families,
468                                              const char familyName[])
469    {
470       for (int i = 0; i < families.count(); ++i) {
471            if (families[i]->getFamilyName().equals(familyName)) {
472                return families[i].get();
473            }
474        }
475        return NULL;
476    }
477
478    static void load_embedded_font(const SkTypeface_FreeType::Scanner& scanner,
479                                   const uint8_t* data, size_t size, int index,
480                                   SkFontMgr_Custom::Families* families)
481    {
482        SkAutoTDelete<SkMemoryStream> stream(new SkMemoryStream(data, size, false));
483
484        int numFaces;
485        if (!scanner.recognizedFont(stream, &numFaces)) {
486            SkDebugf("---- failed to open <%d> as a font\n", index);
487            return;
488        }
489
490        for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) {
491            bool isFixedPitch;
492            SkString realname;
493            SkFontStyle style = SkFontStyle(); // avoid uninitialized warning
494            if (!scanner.scanFont(stream, faceIndex, &realname, &style, &isFixedPitch)) {
495                SkDebugf("---- failed to open <%d> <%d> as a font\n", index, faceIndex);
496                return;
497            }
498
499            SkTypeface_Custom* tf = SkNEW_ARGS(SkTypeface_Stream, (
500                                                style,
501                                                isFixedPitch,
502                                                true,  // system-font (cannot delete)
503                                                realname,
504                                                stream.detach(),
505                                                faceIndex));
506
507            SkFontStyleSet_Custom* addTo = find_family(*families, realname.c_str());
508            if (NULL == addTo) {
509                addTo = new SkFontStyleSet_Custom(realname);
510                families->push_back().reset(addTo);
511            }
512            addTo->appendTypeface(tf);
513        }
514    }
515
516    const SkEmbeddedResourceHeader* fHeader;
517};
518
519#ifdef SK_EMBEDDED_FONTS
520
521extern "C" const SkEmbeddedResourceHeader SK_EMBEDDED_FONTS;
522SkFontMgr* SkFontMgr::Factory() {
523    return new SkFontMgr_Custom(EmbeddedSystemFontLoader(&SK_EMBEDDED_FONTS));
524}
525
526#else
527
528#ifndef SK_FONT_FILE_PREFIX
529#    define SK_FONT_FILE_PREFIX "/usr/share/fonts/"
530#endif
531SkFontMgr* SkFontMgr::Factory() {
532    return new SkFontMgr_Custom(DirectorySystemFontLoader(SK_FONT_FILE_PREFIX));
533}
534
535#endif
536