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