1 /*
2 * Copyright 2017 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 "include/core/SkFontScanner.h"
9 #include "include/core/SkRefCnt.h"
10 #include "include/core/SkStream.h"
11 #include "include/ports/SkFontMgr_directory.h"
12 #include "src/core/SkOSFile.h"
13 #include "src/ports/SkFontMgr_custom.h"
14 #include "src/ports/SkTypeface_FreeType.h"
15 #include "src/utils/SkOSPath.h"
16
17 class DirectorySystemFontLoader : public SkFontMgr_Custom::SystemFontLoader {
18 public:
DirectorySystemFontLoader(const char * dir)19 DirectorySystemFontLoader(const char* dir) : fBaseDirectory(dir) { }
20
loadSystemFonts(const SkFontScanner * scanner,SkFontMgr_Custom::Families * families) const21 void loadSystemFonts(const SkFontScanner* scanner,
22 SkFontMgr_Custom::Families* families) const override
23 {
24 load_directory_fonts(scanner, fBaseDirectory, ".ttf", families);
25 load_directory_fonts(scanner, fBaseDirectory, ".ttc", families);
26 load_directory_fonts(scanner, fBaseDirectory, ".otf", families);
27 load_directory_fonts(scanner, fBaseDirectory, ".pfb", families);
28
29 if (families->empty()) {
30 SkFontStyleSet_Custom* family = new SkFontStyleSet_Custom(SkString());
31 families->push_back().reset(family);
32 family->appendTypeface(sk_make_sp<SkTypeface_Empty>());
33 }
34 }
35
36 private:
find_family(SkFontMgr_Custom::Families & families,const char familyName[])37 static SkFontStyleSet_Custom* find_family(SkFontMgr_Custom::Families& families,
38 const char familyName[])
39 {
40 for (int i = 0; i < families.size(); ++i) {
41 if (families[i]->getFamilyName().equals(familyName)) {
42 return families[i].get();
43 }
44 }
45 return nullptr;
46 }
47
load_directory_fonts(const SkFontScanner * scanner,const SkString & directory,const char * suffix,SkFontMgr_Custom::Families * families)48 static void load_directory_fonts(const SkFontScanner* scanner,
49 const SkString& directory, const char* suffix,
50 SkFontMgr_Custom::Families* families)
51 {
52 SkOSFile::Iter iter(directory.c_str(), suffix);
53 SkString name;
54
55 while (iter.next(&name, false)) {
56 SkString filename(SkOSPath::Join(directory.c_str(), name.c_str()));
57 std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(filename.c_str());
58 if (!stream) {
59 // SkDebugf("---- failed to open <%s>\n", filename.c_str());
60 continue;
61 }
62
63 int numFaces;
64 if (!scanner->scanFile(stream.get(), &numFaces)) {
65 // SkDebugf("---- failed to open <%s> as a font\n", filename.c_str());
66 continue;
67 }
68
69 for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) {
70 int numInstances;
71 if (!scanner->scanFace(stream.get(), faceIndex, &numInstances)) {
72 // SkDebugf("---- failed to open <%s> as a font\n", filename.c_str());
73 continue;
74 }
75 for (int instanceIndex = 0; instanceIndex <= numInstances; ++instanceIndex) {
76 bool isFixedPitch;
77 SkString realname;
78 SkFontStyle style = SkFontStyle(); // avoid uninitialized warning
79 if (!scanner->scanInstance(stream.get(),
80 faceIndex,
81 instanceIndex,
82 &realname,
83 &style,
84 &isFixedPitch,
85 nullptr)) {
86 // SkDebugf("---- failed to open <%s> <%d> as a font\n",
87 // filename.c_str(), faceIndex);
88 continue;
89 }
90
91 SkFontStyleSet_Custom* addTo = find_family(*families, realname.c_str());
92 if (nullptr == addTo) {
93 addTo = new SkFontStyleSet_Custom(realname);
94 families->push_back().reset(addTo);
95 }
96 addTo->appendTypeface(sk_make_sp<SkTypeface_File>(
97 style, isFixedPitch, true, realname, filename.c_str(),
98 (instanceIndex << 16) + faceIndex));
99 }
100 }
101 }
102
103 SkOSFile::Iter dirIter(directory.c_str());
104 while (dirIter.next(&name, true)) {
105 if (name.startsWith(".")) {
106 continue;
107 }
108 SkString dirname(SkOSPath::Join(directory.c_str(), name.c_str()));
109 load_directory_fonts(scanner, dirname, suffix, families);
110 }
111 }
112
113 SkString fBaseDirectory;
114 };
115
SkFontMgr_New_Custom_Directory(const char * dir)116 sk_sp<SkFontMgr> SkFontMgr_New_Custom_Directory(const char* dir) {
117 return sk_make_sp<SkFontMgr_Custom>(DirectorySystemFontLoader(dir));
118 }
119