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