• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
25 class SkData;
26 
27 /** The base SkTypeface implementation for the custom font manager. */
28 class SkTypeface_Custom : public SkTypeface_FreeType {
29 public:
SkTypeface_Custom(const SkFontStyle & style,bool isFixedPitch,bool sysFont,const SkString familyName,int index)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 
isSysFont() const36     bool isSysFont() const { return fIsSysFont; }
37 
38 protected:
onGetFamilyName(SkString * familyName) const39     void onGetFamilyName(SkString* familyName) const override {
40         *familyName = fFamilyName;
41     }
42 
onGetFontDescriptor(SkFontDescriptor * desc,bool * isLocal) const43     void onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const override {
44         desc->setFamilyName(fFamilyName.c_str());
45         *isLocal = !this->isSysFont();
46     }
47 
getIndex() const48     int getIndex() const { return fIndex; }
49 
50 private:
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  */
61 class SkTypeface_Empty : public SkTypeface_Custom {
62 public:
SkTypeface_Empty()63     SkTypeface_Empty() : INHERITED(SkFontStyle(), false, true, SkString(), 0) {}
64 
65 protected:
onOpenStream(int *) const66     SkStreamAsset* onOpenStream(int*) const override { return nullptr; }
67 
68 private:
69     typedef SkTypeface_Custom INHERITED;
70 };
71 
72 /** The stream SkTypeface implementation for the custom font manager. */
73 class SkTypeface_Stream : public SkTypeface_Custom {
74 public:
SkTypeface_Stream(const SkFontStyle & style,bool isFixedPitch,bool sysFont,const SkString familyName,SkStreamAsset * stream,int index)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 
81 protected:
onOpenStream(int * ttcIndex) const82     SkStreamAsset* onOpenStream(int* ttcIndex) const override {
83         *ttcIndex = this->getIndex();
84         return fStream->duplicate();
85     }
86 
87 private:
88     const SkAutoTDelete<const SkStreamAsset> fStream;
89 
90     typedef SkTypeface_Custom INHERITED;
91 };
92 
93 /** The file SkTypeface implementation for the custom font manager. */
94 class SkTypeface_File : public SkTypeface_Custom {
95 public:
SkTypeface_File(const SkFontStyle & style,bool isFixedPitch,bool sysFont,const SkString familyName,const char path[],int index)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 
102 protected:
onOpenStream(int * ttcIndex) const103     SkStreamAsset* onOpenStream(int* ttcIndex) const override {
104         *ttcIndex = this->getIndex();
105         return SkStream::NewFromFile(fPath.c_str());
106     }
107 
108 private:
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  */
121 class SkFontStyleSet_Custom : public SkFontStyleSet {
122 public:
SkFontStyleSet_Custom(const SkString familyName)123     explicit SkFontStyleSet_Custom(const SkString familyName) : fFamilyName(familyName) { }
124 
125     /** Should only be called during the inital build phase. */
appendTypeface(SkTypeface_Custom * typeface)126     void appendTypeface(SkTypeface_Custom* typeface) {
127         fStyles.push_back().reset(typeface);
128     }
129 
count()130     int count() override {
131         return fStyles.count();
132     }
133 
getStyle(int index,SkFontStyle * style,SkString * name)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 
createTypeface(int index)144     SkTypeface* createTypeface(int index) override {
145         SkASSERT(index < fStyles.count());
146         return SkRef(fStyles[index].get());
147     }
148 
match_score(const SkFontStyle & pattern,const SkFontStyle & candidate)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 
matchStyle(const SkFontStyle & pattern)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 
getFamilyName()182     SkString getFamilyName() { return fFamilyName; }
183 
184 private:
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  */
198 class SkFontMgr_Custom : public SkFontMgr {
199 public:
200     typedef SkTArray<SkAutoTUnref<SkFontStyleSet_Custom>, true> Families;
201     class SystemFontLoader {
202     public:
~SystemFontLoader()203         virtual ~SystemFontLoader() { }
204         virtual void loadSystemFonts(const SkTypeface_FreeType::Scanner&, Families*) const = 0;
205     };
SkFontMgr_Custom(const SystemFontLoader & loader)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 
234 protected:
onCountFamilies() const235     int onCountFamilies() const override {
236         return fFamilies.count();
237     }
238 
onGetFamilyName(int index,SkString * familyName) const239     void onGetFamilyName(int index, SkString* familyName) const override {
240         SkASSERT(index < fFamilies.count());
241         familyName->set(fFamilies[index]->getFamilyName());
242     }
243 
onCreateStyleSet(int index) const244     SkFontStyleSet_Custom* onCreateStyleSet(int index) const override {
245         SkASSERT(index < fFamilies.count());
246         return SkRef(fFamilies[index].get());
247     }
248 
onMatchFamily(const char familyName[]) const249     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 
onMatchFamilyStyle(const char familyName[],const SkFontStyle & fontStyle) const258     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 
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle &,const char * bcp47[],int bcp47Count,SkUnichar character) const265     SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&,
266                                             const char* bcp47[], int bcp47Count,
267                                             SkUnichar character) const override
268     {
269         return nullptr;
270     }
271 
onMatchFaceStyle(const SkTypeface * familyMember,const SkFontStyle & fontStyle) const272     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 
onCreateFromData(SkData * data,int ttcIndex) const285     SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const override {
286         return this->createFromStream(new SkMemoryStream(data), ttcIndex);
287     }
288 
onCreateFromStream(SkStreamAsset * bareStream,int ttcIndex) const289     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 
onCreateFromFile(const char path[],int ttcIndex) const306     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 
onLegacyCreateTypeface(const char familyName[],unsigned styleBits) const311     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 
333 private:
334     Families fFamilies;
335     SkFontStyleSet_Custom* fDefaultFamily;
336     SkTypeface_FreeType::Scanner fScanner;
337 };
338 
339 ///////////////////////////////////////////////////////////////////////////////
340 
341 class DirectorySystemFontLoader : public SkFontMgr_Custom::SystemFontLoader {
342 public:
DirectorySystemFontLoader(const char * dir)343     DirectorySystemFontLoader(const char* dir) : fBaseDirectory(dir) { }
344 
loadSystemFonts(const SkTypeface_FreeType::Scanner & scanner,SkFontMgr_Custom::Families * families) const345     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 
360 private:
find_family(SkFontMgr_Custom::Families & families,const char familyName[])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 
load_directory_fonts(const SkTypeface_FreeType::Scanner & scanner,const SkString & directory,const char * suffix,SkFontMgr_Custom::Families * families)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 
SkFontMgr_New_Custom_Directory(const char * dir)429 SK_API SkFontMgr* SkFontMgr_New_Custom_Directory(const char* dir) {
430     return new SkFontMgr_Custom(DirectorySystemFontLoader(dir));
431 }
432 
433 ///////////////////////////////////////////////////////////////////////////////
434 
435 struct SkEmbeddedResource { const uint8_t* data; size_t size; };
436 struct SkEmbeddedResourceHeader { const SkEmbeddedResource* entries; int count; };
437 
438 class EmbeddedSystemFontLoader : public SkFontMgr_Custom::SystemFontLoader {
439 public:
EmbeddedSystemFontLoader(const SkEmbeddedResourceHeader * header)440     EmbeddedSystemFontLoader(const SkEmbeddedResourceHeader* header) : fHeader(header) { }
441 
loadSystemFonts(const SkTypeface_FreeType::Scanner & scanner,SkFontMgr_Custom::Families * families) const442     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 
457 private:
find_family(SkFontMgr_Custom::Families & families,const char familyName[])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 
load_embedded_font(const SkTypeface_FreeType::Scanner & scanner,const uint8_t * data,size_t size,int index,SkFontMgr_Custom::Families * families)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 
SkFontMgr_New_Custom_Embedded(const SkEmbeddedResourceHeader * header)506 SkFontMgr* SkFontMgr_New_Custom_Embedded(const SkEmbeddedResourceHeader* header) {
507     return new SkFontMgr_Custom(EmbeddedSystemFontLoader(header));
508 }
509