blob: 49744a1f6318b15831e19e072ab42f793480f9b0 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
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.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
reed@google.com0fc17c32013-03-21 13:33:49 +00008#include "SkFontHost_FreeType_common.h"
djsollen@google.com97145162012-05-31 19:55:08 +00009#include "SkFontDescriptor.h"
bungeman@google.comb3d154d2013-11-11 15:53:29 +000010#include "SkFontMgr.h"
bungeman5cf19492015-06-15 15:17:21 -070011#include "SkFontMgr_custom.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000012#include "SkDescriptor.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkOSFile.h"
14#include "SkPaint.h"
humperad5e9a52014-11-19 08:32:19 -080015#include "SkRTConf.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkString.h"
17#include "SkStream.h"
18#include "SkThread.h"
19#include "SkTSearch.h"
bungeman@google.comb3d154d2013-11-11 15:53:29 +000020#include "SkTypefaceCache.h"
21#include "SkTArray.h"
22
23#include <limits>
reed@android.com8a1c16f2008-12-17 15:59:43 +000024
bungeman@google.comb3d154d2013-11-11 15:53:29 +000025/** The base SkTypeface implementation for the custom font manager. */
26class SkTypeface_Custom : public SkTypeface_FreeType {
reed@android.com8a1c16f2008-12-17 15:59:43 +000027public:
bungemana4c4a2d2014-10-20 13:33:19 -070028 SkTypeface_Custom(const SkFontStyle& style, bool isFixedPitch,
bungemand71b7572014-09-18 10:55:32 -070029 bool sysFont, const SkString familyName, int index)
bungeman@google.comb3d154d2013-11-11 15:53:29 +000030 : INHERITED(style, SkTypefaceCache::NewFontID(), isFixedPitch)
bungemand71b7572014-09-18 10:55:32 -070031 , fIsSysFont(sysFont), fFamilyName(familyName), fIndex(index)
bungeman@google.comb3d154d2013-11-11 15:53:29 +000032 { }
chudy@google.comada44802012-07-30 12:59:12 +000033
reed@android.com8a1c16f2008-12-17 15:59:43 +000034 bool isSysFont() const { return fIsSysFont; }
reed@google.com292b1d42013-03-22 17:21:59 +000035
reed@google.com5526ede2013-03-25 13:03:37 +000036protected:
mtklein36352bf2015-03-25 18:17:31 -070037 void onGetFamilyName(SkString* familyName) const override {
bungemanb374d6a2014-09-17 07:48:59 -070038 *familyName = fFamilyName;
39 }
40
mtklein36352bf2015-03-25 18:17:31 -070041 void onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const override {
bungeman@google.comb3d154d2013-11-11 15:53:29 +000042 desc->setFamilyName(fFamilyName.c_str());
bungeman@google.comb3d154d2013-11-11 15:53:29 +000043 *isLocal = !this->isSysFont();
44 }
reed@google.com5526ede2013-03-25 13:03:37 +000045
bungemand71b7572014-09-18 10:55:32 -070046 int getIndex() const { return fIndex; }
47
reed@android.com8a1c16f2008-12-17 15:59:43 +000048private:
bungemand71b7572014-09-18 10:55:32 -070049 const bool fIsSysFont;
50 const SkString fFamilyName;
51 const int fIndex;
chudy@google.comada44802012-07-30 12:59:12 +000052
reed@google.com032fbb82013-03-21 13:38:18 +000053 typedef SkTypeface_FreeType INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +000054};
55
bungeman@google.comb3d154d2013-11-11 15:53:29 +000056/** The empty SkTypeface implementation for the custom font manager.
57 * Used as the last resort fallback typeface.
reed@android.comf244f1b2010-04-16 12:40:08 +000058 */
bungeman@google.comb3d154d2013-11-11 15:53:29 +000059class SkTypeface_Empty : public SkTypeface_Custom {
reed@android.comf244f1b2010-04-16 12:40:08 +000060public:
bungemana4c4a2d2014-10-20 13:33:19 -070061 SkTypeface_Empty() : INHERITED(SkFontStyle(), false, true, SkString(), 0) {}
chudy@google.comada44802012-07-30 12:59:12 +000062
reed@google.com292b1d42013-03-22 17:21:59 +000063protected:
mtklein36352bf2015-03-25 18:17:31 -070064 SkStreamAsset* onOpenStream(int*) const override { return NULL; }
reed@google.com292b1d42013-03-22 17:21:59 +000065
reed@android.comf244f1b2010-04-16 12:40:08 +000066private:
bungeman@google.comb3d154d2013-11-11 15:53:29 +000067 typedef SkTypeface_Custom INHERITED;
reed@android.comf244f1b2010-04-16 12:40:08 +000068};
69
bungeman@google.comb3d154d2013-11-11 15:53:29 +000070/** The stream SkTypeface implementation for the custom font manager. */
71class SkTypeface_Stream : public SkTypeface_Custom {
reed@android.com8a1c16f2008-12-17 15:59:43 +000072public:
bungemana4c4a2d2014-10-20 13:33:19 -070073 SkTypeface_Stream(const SkFontStyle& style, bool isFixedPitch, bool sysFont,
bungeman5f213d92015-01-27 05:39:10 -080074 const SkString familyName, SkStreamAsset* stream, int index)
bungemana4c4a2d2014-10-20 13:33:19 -070075 : INHERITED(style, isFixedPitch, sysFont, familyName, index)
scroggoe58898e2015-01-21 12:23:20 -080076 , fStream(stream)
bungeman@google.comb3d154d2013-11-11 15:53:29 +000077 { }
chudy@google.comada44802012-07-30 12:59:12 +000078
reed@google.com292b1d42013-03-22 17:21:59 +000079protected:
mtklein36352bf2015-03-25 18:17:31 -070080 SkStreamAsset* onOpenStream(int* ttcIndex) const override {
bungemand71b7572014-09-18 10:55:32 -070081 *ttcIndex = this->getIndex();
commit-bot@chromium.orga2b44dc2014-03-24 21:42:01 +000082 return fStream->duplicate();
reed@google.com292b1d42013-03-22 17:21:59 +000083 }
84
reed@android.com8a1c16f2008-12-17 15:59:43 +000085private:
bungeman5f213d92015-01-27 05:39:10 -080086 const SkAutoTDelete<const SkStreamAsset> fStream;
chudy@google.comada44802012-07-30 12:59:12 +000087
bungeman@google.comb3d154d2013-11-11 15:53:29 +000088 typedef SkTypeface_Custom INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +000089};
90
bungeman@google.comb3d154d2013-11-11 15:53:29 +000091/** The file SkTypeface implementation for the custom font manager. */
92class SkTypeface_File : public SkTypeface_Custom {
reed@android.com8a1c16f2008-12-17 15:59:43 +000093public:
bungemana4c4a2d2014-10-20 13:33:19 -070094 SkTypeface_File(const SkFontStyle& style, bool isFixedPitch, bool sysFont,
95 const SkString familyName, const char path[], int index)
bungemand71b7572014-09-18 10:55:32 -070096 : INHERITED(style, isFixedPitch, sysFont, familyName, index)
bungeman@google.comb3d154d2013-11-11 15:53:29 +000097 , fPath(path)
98 { }
chudy@google.comada44802012-07-30 12:59:12 +000099
reed@google.com292b1d42013-03-22 17:21:59 +0000100protected:
mtklein36352bf2015-03-25 18:17:31 -0700101 SkStreamAsset* onOpenStream(int* ttcIndex) const override {
bungemand71b7572014-09-18 10:55:32 -0700102 *ttcIndex = this->getIndex();
bungeman5cf19492015-06-15 15:17:21 -0700103 return SkStream::NewFromFile(fPath.c_str());
reed@google.com292b1d42013-03-22 17:21:59 +0000104 }
105
reed@android.com8a1c16f2008-12-17 15:59:43 +0000106private:
107 SkString fPath;
chudy@google.comada44802012-07-30 12:59:12 +0000108
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000109 typedef SkTypeface_Custom INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000110};
111
112///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000113
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000114/**
115 * SkFontStyleSet_Custom
116 *
117 * This class is used by SkFontMgr_Custom to hold SkTypeface_Custom families.
118 */
119class SkFontStyleSet_Custom : public SkFontStyleSet {
120public:
121 explicit SkFontStyleSet_Custom(const SkString familyName) : fFamilyName(familyName) { }
122
bungeman5c9fa282015-03-30 12:53:48 -0700123 /** Should only be called during the inital build phase. */
124 void appendTypeface(SkTypeface_Custom* typeface) {
125 fStyles.push_back().reset(typeface);
126 }
127
mtklein36352bf2015-03-25 18:17:31 -0700128 int count() override {
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000129 return fStyles.count();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000130 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000131
mtklein36352bf2015-03-25 18:17:31 -0700132 void getStyle(int index, SkFontStyle* style, SkString* name) override {
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000133 SkASSERT(index < fStyles.count());
134 bool bold = fStyles[index]->isBold();
135 bool italic = fStyles[index]->isItalic();
136 *style = SkFontStyle(bold ? SkFontStyle::kBold_Weight : SkFontStyle::kNormal_Weight,
137 SkFontStyle::kNormal_Width,
138 italic ? SkFontStyle::kItalic_Slant : SkFontStyle::kUpright_Slant);
139 name->reset();
140 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000141
mtklein36352bf2015-03-25 18:17:31 -0700142 SkTypeface* createTypeface(int index) override {
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000143 SkASSERT(index < fStyles.count());
144 return SkRef(fStyles[index].get());
145 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000147 static int match_score(const SkFontStyle& pattern, const SkFontStyle& candidate) {
148 int score = 0;
149 score += (pattern.width() - candidate.width()) * 100;
150 score += (pattern.isItalic() == candidate.isItalic()) ? 0 : 1000;
151 score += pattern.weight() - candidate.weight();
152 return score;
153 }
154
mtklein36352bf2015-03-25 18:17:31 -0700155 SkTypeface* matchStyle(const SkFontStyle& pattern) override {
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000156 if (0 == fStyles.count()) {
157 return NULL;
158 }
159
160 SkTypeface_Custom* closest = fStyles[0];
161 int minScore = std::numeric_limits<int>::max();
162 for (int i = 0; i < fStyles.count(); ++i) {
163 bool bold = fStyles[i]->isBold();
164 bool italic = fStyles[i]->isItalic();
165 SkFontStyle style = SkFontStyle(bold ? SkFontStyle::kBold_Weight
166 : SkFontStyle::kNormal_Weight,
167 SkFontStyle::kNormal_Width,
168 italic ? SkFontStyle::kItalic_Slant
169 : SkFontStyle::kUpright_Slant);
170
171 int score = match_score(pattern, style);
172 if (score < minScore) {
173 closest = fStyles[i];
174 minScore = score;
175 }
176 }
177 return SkRef(closest);
178 }
179
bungeman5c9fa282015-03-30 12:53:48 -0700180 SkString getFamilyName() { return fFamilyName; }
181
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000182private:
183 SkTArray<SkAutoTUnref<SkTypeface_Custom>, true> fStyles;
184 SkString fFamilyName;
185
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000186 friend class SkFontMgr_Custom;
187};
188
189/**
190 * SkFontMgr_Custom
191 *
192 * This class is essentially a collection of SkFontStyleSet_Custom,
193 * one SkFontStyleSet_Custom for each family. This class may be modified
194 * to load fonts from any source by changing the initialization.
195 */
196class SkFontMgr_Custom : public SkFontMgr {
197public:
bungeman5c9fa282015-03-30 12:53:48 -0700198 typedef SkTArray<SkAutoTUnref<SkFontStyleSet_Custom>, true> Families;
199 class SystemFontLoader {
200 public:
201 virtual ~SystemFontLoader() { }
202 virtual void loadSystemFonts(const SkTypeface_FreeType::Scanner&, Families*) const = 0;
203 };
bungeman5cf19492015-06-15 15:17:21 -0700204 explicit SkFontMgr_Custom(const SystemFontLoader& loader) : fDefaultFamily(NULL) {
bungeman5c9fa282015-03-30 12:53:48 -0700205 loader.loadSystemFonts(fScanner, &fFamilies);
206
207 // Try to pick a default font.
208 static const char* defaultNames[] = {
209 "Arial", "Verdana", "Times New Roman", "Droid Sans", NULL
210 };
211 for (size_t i = 0; i < SK_ARRAY_COUNT(defaultNames); ++i) {
212 SkFontStyleSet_Custom* set = this->onMatchFamily(defaultNames[i]);
213 if (NULL == set) {
214 continue;
215 }
216
217 SkTypeface* tf = set->matchStyle(SkFontStyle(SkFontStyle::kNormal_Weight,
218 SkFontStyle::kNormal_Width,
219 SkFontStyle::kUpright_Slant));
220 if (NULL == tf) {
221 continue;
222 }
223
224 fDefaultFamily = set;
225 break;
226 }
227 if (NULL == fDefaultFamily) {
228 fDefaultFamily = fFamilies[0];
229 }
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000230 }
231
232protected:
mtklein36352bf2015-03-25 18:17:31 -0700233 int onCountFamilies() const override {
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000234 return fFamilies.count();
235 }
236
mtklein36352bf2015-03-25 18:17:31 -0700237 void onGetFamilyName(int index, SkString* familyName) const override {
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000238 SkASSERT(index < fFamilies.count());
bungeman5c9fa282015-03-30 12:53:48 -0700239 familyName->set(fFamilies[index]->getFamilyName());
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000240 }
241
mtklein36352bf2015-03-25 18:17:31 -0700242 SkFontStyleSet_Custom* onCreateStyleSet(int index) const override {
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000243 SkASSERT(index < fFamilies.count());
244 return SkRef(fFamilies[index].get());
245 }
246
mtklein36352bf2015-03-25 18:17:31 -0700247 SkFontStyleSet_Custom* onMatchFamily(const char familyName[]) const override {
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000248 for (int i = 0; i < fFamilies.count(); ++i) {
bungeman5c9fa282015-03-30 12:53:48 -0700249 if (fFamilies[i]->getFamilyName().equals(familyName)) {
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000250 return SkRef(fFamilies[i].get());
251 }
252 }
253 return NULL;
254 }
255
bungeman5c9fa282015-03-30 12:53:48 -0700256 SkTypeface* onMatchFamilyStyle(const char familyName[],
257 const SkFontStyle& fontStyle) const override
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000258 {
259 SkAutoTUnref<SkFontStyleSet> sset(this->matchFamily(familyName));
260 return sset->matchStyle(fontStyle);
261 }
262
bungeman5c9fa282015-03-30 12:53:48 -0700263 SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&,
264 const char* bcp47[], int bcp47Count,
265 SkUnichar character) const override
djsollen33068c12014-11-14 10:52:53 -0800266 {
267 return NULL;
268 }
269
bungeman5c9fa282015-03-30 12:53:48 -0700270 SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember,
271 const SkFontStyle& fontStyle) const override
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000272 {
273 for (int i = 0; i < fFamilies.count(); ++i) {
274 for (int j = 0; j < fFamilies[i]->fStyles.count(); ++j) {
275 if (fFamilies[i]->fStyles[j] == familyMember) {
276 return fFamilies[i]->matchStyle(fontStyle);
277 }
278 }
279 }
280 return NULL;
281 }
282
mtklein36352bf2015-03-25 18:17:31 -0700283 SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const override {
scroggoa1193e42015-01-21 12:09:53 -0800284 return this->createFromStream(new SkMemoryStream(data), ttcIndex);
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000285 }
286
mtklein36352bf2015-03-25 18:17:31 -0700287 SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) const override {
bungeman5f213d92015-01-27 05:39:10 -0800288 SkAutoTDelete<SkStreamAsset> stream(bareStream);
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000289 if (NULL == stream || stream->getLength() <= 0) {
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000290 return NULL;
291 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292
bungeman@google.comfe747652013-03-25 19:36:11 +0000293 bool isFixedPitch;
bungemana4c4a2d2014-10-20 13:33:19 -0700294 SkFontStyle style;
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000295 SkString name;
bungeman41868fe2015-05-20 09:21:04 -0700296 if (fScanner.scanFont(stream, ttcIndex, &name, &style, &isFixedPitch, NULL)) {
bungeman3a21d612014-07-11 08:52:26 -0700297 return SkNEW_ARGS(SkTypeface_Stream, (style, isFixedPitch, false, name,
bungeman5f213d92015-01-27 05:39:10 -0800298 stream.detach(), ttcIndex));
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000299 } else {
300 return NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000301 }
reed@android.comf244f1b2010-04-16 12:40:08 +0000302 }
303
mtklein36352bf2015-03-25 18:17:31 -0700304 SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override {
bungeman5f213d92015-01-27 05:39:10 -0800305 SkAutoTDelete<SkStreamAsset> stream(SkStream::NewFromFile(path));
scroggoa1193e42015-01-21 12:09:53 -0800306 return stream.get() ? this->createFromStream(stream.detach(), ttcIndex) : NULL;
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000307 }
308
bungeman5c9fa282015-03-30 12:53:48 -0700309 SkTypeface* onLegacyCreateTypeface(const char familyName[], unsigned styleBits) const override {
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000310 SkTypeface::Style oldStyle = (SkTypeface::Style)styleBits;
311 SkFontStyle style = SkFontStyle(oldStyle & SkTypeface::kBold
312 ? SkFontStyle::kBold_Weight
313 : SkFontStyle::kNormal_Weight,
314 SkFontStyle::kNormal_Width,
315 oldStyle & SkTypeface::kItalic
316 ? SkFontStyle::kItalic_Slant
317 : SkFontStyle::kUpright_Slant);
318 SkTypeface* tf = NULL;
319
bsalomon49f085d2014-09-05 13:34:00 -0700320 if (familyName) {
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000321 tf = this->onMatchFamilyStyle(familyName, style);
bungeman@google.com2cf84ec2012-09-26 19:16:54 +0000322 }
bungeman@google.com2cf84ec2012-09-26 19:16:54 +0000323
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000324 if (NULL == tf) {
bungeman5c9fa282015-03-30 12:53:48 -0700325 tf = fDefaultFamily->matchStyle(style);
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000326 }
327
328 return SkSafeRef(tf);
bungeman@google.com2cf84ec2012-09-26 19:16:54 +0000329 }
330
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000331private:
bungeman5c9fa282015-03-30 12:53:48 -0700332 Families fFamilies;
333 SkFontStyleSet_Custom* fDefaultFamily;
334 SkTypeface_FreeType::Scanner fScanner;
335};
bungeman@google.com2cf84ec2012-09-26 19:16:54 +0000336
bungeman5c9fa282015-03-30 12:53:48 -0700337///////////////////////////////////////////////////////////////////////////////
338
339class DirectorySystemFontLoader : public SkFontMgr_Custom::SystemFontLoader {
340public:
341 DirectorySystemFontLoader(const char* dir) : fBaseDirectory(dir) { }
342
343 void loadSystemFonts(const SkTypeface_FreeType::Scanner& scanner,
344 SkFontMgr_Custom::Families* families) const override
345 {
346 load_directory_fonts(scanner, fBaseDirectory, ".ttf", families);
347 load_directory_fonts(scanner, fBaseDirectory, ".ttc", families);
348 load_directory_fonts(scanner, fBaseDirectory, ".otf", families);
349 load_directory_fonts(scanner, fBaseDirectory, ".pfb", families);
350
351 if (families->empty()) {
352 SkFontStyleSet_Custom* family = new SkFontStyleSet_Custom(SkString());
353 families->push_back().reset(family);
354 family->appendTypeface(SkNEW(SkTypeface_Empty));
355 }
356 }
357
358private:
359 static SkFontStyleSet_Custom* find_family(SkFontMgr_Custom::Families& families,
360 const char familyName[])
361 {
362 for (int i = 0; i < families.count(); ++i) {
363 if (families[i]->getFamilyName().equals(familyName)) {
364 return families[i].get();
365 }
366 }
367 return NULL;
368 }
369
370 static void load_directory_fonts(const SkTypeface_FreeType::Scanner& scanner,
371 const SkString& directory, const char* suffix,
372 SkFontMgr_Custom::Families* families)
373 {
bungeman14df8332014-10-28 15:07:23 -0700374 SkOSFile::Iter iter(directory.c_str(), suffix);
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000375 SkString name;
376
377 while (iter.next(&name, false)) {
bungeman14df8332014-10-28 15:07:23 -0700378 SkString filename(SkOSPath::Join(directory.c_str(), name.c_str()));
scroggoa1193e42015-01-21 12:09:53 -0800379 SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(filename.c_str()));
bungeman14df8332014-10-28 15:07:23 -0700380 if (!stream.get()) {
381 SkDebugf("---- failed to open <%s>\n", filename.c_str());
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000382 continue;
383 }
384
bungeman14df8332014-10-28 15:07:23 -0700385 int numFaces;
bungeman5c9fa282015-03-30 12:53:48 -0700386 if (!scanner.recognizedFont(stream, &numFaces)) {
bungeman14df8332014-10-28 15:07:23 -0700387 SkDebugf("---- failed to open <%s> as a font\n", filename.c_str());
388 continue;
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000389 }
bungeman14df8332014-10-28 15:07:23 -0700390
391 for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) {
392 bool isFixedPitch;
393 SkString realname;
394 SkFontStyle style = SkFontStyle(); // avoid uninitialized warning
bungeman41868fe2015-05-20 09:21:04 -0700395 if (!scanner.scanFont(stream, faceIndex, &realname, &style, &isFixedPitch, NULL)) {
bungeman14df8332014-10-28 15:07:23 -0700396 SkDebugf("---- failed to open <%s> <%d> as a font\n",
397 filename.c_str(), faceIndex);
398 continue;
399 }
400
401 SkTypeface_Custom* tf = SkNEW_ARGS(SkTypeface_File, (
402 style,
403 isFixedPitch,
404 true, // system-font (cannot delete)
405 realname,
bungeman5c9fa282015-03-30 12:53:48 -0700406 filename.c_str(),
407 faceIndex));
bungeman14df8332014-10-28 15:07:23 -0700408
bungeman5c9fa282015-03-30 12:53:48 -0700409 SkFontStyleSet_Custom* addTo = find_family(*families, realname.c_str());
bungeman14df8332014-10-28 15:07:23 -0700410 if (NULL == addTo) {
411 addTo = new SkFontStyleSet_Custom(realname);
bungeman5c9fa282015-03-30 12:53:48 -0700412 families->push_back().reset(addTo);
bungeman14df8332014-10-28 15:07:23 -0700413 }
414 addTo->appendTypeface(tf);
415 }
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000416 }
417
418 SkOSFile::Iter dirIter(directory.c_str());
419 while (dirIter.next(&name, true)) {
420 if (name.startsWith(".")) {
421 continue;
422 }
tfarinaa8e2e152014-07-28 19:26:58 -0700423 SkString dirname(SkOSPath::Join(directory.c_str(), name.c_str()));
bungeman5c9fa282015-03-30 12:53:48 -0700424 load_directory_fonts(scanner, dirname, suffix, families);
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000425 }
426 }
427
bungeman5c9fa282015-03-30 12:53:48 -0700428 SkString fBaseDirectory;
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000429};
reed@google.com070da5e2013-03-27 20:01:49 +0000430
bungeman5cf19492015-06-15 15:17:21 -0700431SK_API SkFontMgr* SkFontMgr_New_Custom_Directory(const char* dir) {
432 return new SkFontMgr_Custom(DirectorySystemFontLoader(dir));
433}
434
435///////////////////////////////////////////////////////////////////////////////
436
bungeman5c9fa282015-03-30 12:53:48 -0700437struct SkEmbeddedResource { const uint8_t* data; size_t size; };
438struct SkEmbeddedResourceHeader { const SkEmbeddedResource* entries; int count; };
439
440class EmbeddedSystemFontLoader : public SkFontMgr_Custom::SystemFontLoader {
441public:
442 EmbeddedSystemFontLoader(const SkEmbeddedResourceHeader* header) : fHeader(header) { }
443
444 void loadSystemFonts(const SkTypeface_FreeType::Scanner& scanner,
445 SkFontMgr_Custom::Families* families) const override
446 {
447 for (int i = 0; i < fHeader->count; ++i) {
448 const SkEmbeddedResource& fontEntry = fHeader->entries[i];
449 load_embedded_font(scanner, fontEntry.data, fontEntry.size, i, families);
450 }
451
452 if (families->empty()) {
453 SkFontStyleSet_Custom* family = new SkFontStyleSet_Custom(SkString());
454 families->push_back().reset(family);
455 family->appendTypeface(SkNEW(SkTypeface_Empty));
456 }
457 }
458
459private:
460 static SkFontStyleSet_Custom* find_family(SkFontMgr_Custom::Families& families,
461 const char familyName[])
462 {
463 for (int i = 0; i < families.count(); ++i) {
464 if (families[i]->getFamilyName().equals(familyName)) {
465 return families[i].get();
466 }
467 }
468 return NULL;
469 }
470
471 static void load_embedded_font(const SkTypeface_FreeType::Scanner& scanner,
472 const uint8_t* data, size_t size, int index,
473 SkFontMgr_Custom::Families* families)
474 {
475 SkAutoTDelete<SkMemoryStream> stream(new SkMemoryStream(data, size, false));
476
477 int numFaces;
478 if (!scanner.recognizedFont(stream, &numFaces)) {
479 SkDebugf("---- failed to open <%d> as a font\n", index);
480 return;
481 }
482
483 for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) {
484 bool isFixedPitch;
485 SkString realname;
486 SkFontStyle style = SkFontStyle(); // avoid uninitialized warning
bungeman41868fe2015-05-20 09:21:04 -0700487 if (!scanner.scanFont(stream, faceIndex, &realname, &style, &isFixedPitch, NULL)) {
bungeman5c9fa282015-03-30 12:53:48 -0700488 SkDebugf("---- failed to open <%d> <%d> as a font\n", index, faceIndex);
489 return;
490 }
491
492 SkTypeface_Custom* tf = SkNEW_ARGS(SkTypeface_Stream, (
493 style,
494 isFixedPitch,
495 true, // system-font (cannot delete)
496 realname,
497 stream.detach(),
498 faceIndex));
499
500 SkFontStyleSet_Custom* addTo = find_family(*families, realname.c_str());
501 if (NULL == addTo) {
502 addTo = new SkFontStyleSet_Custom(realname);
503 families->push_back().reset(addTo);
504 }
505 addTo->appendTypeface(tf);
506 }
507 }
508
509 const SkEmbeddedResourceHeader* fHeader;
510};
511
bungeman5cf19492015-06-15 15:17:21 -0700512SkFontMgr* SkFontMgr_New_Custom_Embedded(const SkEmbeddedResourceHeader* header) {
513 return new SkFontMgr_Custom(EmbeddedSystemFontLoader(header));
reed@google.com070da5e2013-03-27 20:01:49 +0000514}