blob: 6749ced350fd10d311e71b3c29b71c31207a2aea [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
djsollen@google.com97145162012-05-31 19:55:08 +00008#include "SkFontDescriptor.h"
bungemanf20488b2015-07-29 11:49:40 -07009#include "SkFontHost_FreeType_common.h"
bungeman@google.comb3d154d2013-11-11 15:53:29 +000010#include "SkFontMgr.h"
bungeman5cf19492015-06-15 15:17:21 -070011#include "SkFontMgr_custom.h"
bungemanf20488b2015-07-29 11:49:40 -070012#include "SkFontStyle.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkOSFile.h"
bungemanf20488b2015-07-29 11:49:40 -070014#include "SkRefCnt.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015#include "SkStream.h"
bungemanf20488b2015-07-29 11:49:40 -070016#include "SkString.h"
bungeman@google.comb3d154d2013-11-11 15:53:29 +000017#include "SkTArray.h"
bungemanf20488b2015-07-29 11:49:40 -070018#include "SkTemplates.h"
19#include "SkTypeface.h"
20#include "SkTypefaceCache.h"
21#include "SkTypes.h"
bungeman@google.comb3d154d2013-11-11 15:53:29 +000022
23#include <limits>
reed@android.com8a1c16f2008-12-17 15:59:43 +000024
bungemanf20488b2015-07-29 11:49:40 -070025class SkData;
26
bungeman@google.comb3d154d2013-11-11 15:53:29 +000027/** The base SkTypeface implementation for the custom font manager. */
28class SkTypeface_Custom : public SkTypeface_FreeType {
reed@android.com8a1c16f2008-12-17 15:59:43 +000029public:
bungemana4c4a2d2014-10-20 13:33:19 -070030 SkTypeface_Custom(const SkFontStyle& style, bool isFixedPitch,
bungemand71b7572014-09-18 10:55:32 -070031 bool sysFont, const SkString familyName, int index)
bungeman@google.comb3d154d2013-11-11 15:53:29 +000032 : INHERITED(style, SkTypefaceCache::NewFontID(), isFixedPitch)
bungemand71b7572014-09-18 10:55:32 -070033 , fIsSysFont(sysFont), fFamilyName(familyName), fIndex(index)
bungeman@google.comb3d154d2013-11-11 15:53:29 +000034 { }
chudy@google.comada44802012-07-30 12:59:12 +000035
reed@android.com8a1c16f2008-12-17 15:59:43 +000036 bool isSysFont() const { return fIsSysFont; }
reed@google.com292b1d42013-03-22 17:21:59 +000037
reed@google.com5526ede2013-03-25 13:03:37 +000038protected:
mtklein36352bf2015-03-25 18:17:31 -070039 void onGetFamilyName(SkString* familyName) const override {
bungemanb374d6a2014-09-17 07:48:59 -070040 *familyName = fFamilyName;
41 }
42
mtklein36352bf2015-03-25 18:17:31 -070043 void onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const override {
bungeman@google.comb3d154d2013-11-11 15:53:29 +000044 desc->setFamilyName(fFamilyName.c_str());
bungeman@google.comb3d154d2013-11-11 15:53:29 +000045 *isLocal = !this->isSysFont();
46 }
reed@google.com5526ede2013-03-25 13:03:37 +000047
bungemand71b7572014-09-18 10:55:32 -070048 int getIndex() const { return fIndex; }
49
reed@android.com8a1c16f2008-12-17 15:59:43 +000050private:
bungemand71b7572014-09-18 10:55:32 -070051 const bool fIsSysFont;
52 const SkString fFamilyName;
53 const int fIndex;
chudy@google.comada44802012-07-30 12:59:12 +000054
reed@google.com032fbb82013-03-21 13:38:18 +000055 typedef SkTypeface_FreeType INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +000056};
57
bungeman@google.comb3d154d2013-11-11 15:53:29 +000058/** The empty SkTypeface implementation for the custom font manager.
59 * Used as the last resort fallback typeface.
reed@android.comf244f1b2010-04-16 12:40:08 +000060 */
bungeman@google.comb3d154d2013-11-11 15:53:29 +000061class SkTypeface_Empty : public SkTypeface_Custom {
reed@android.comf244f1b2010-04-16 12:40:08 +000062public:
bungemana4c4a2d2014-10-20 13:33:19 -070063 SkTypeface_Empty() : INHERITED(SkFontStyle(), false, true, SkString(), 0) {}
chudy@google.comada44802012-07-30 12:59:12 +000064
reed@google.com292b1d42013-03-22 17:21:59 +000065protected:
halcanary96fcdcc2015-08-27 07:41:13 -070066 SkStreamAsset* onOpenStream(int*) const override { return nullptr; }
reed@google.com292b1d42013-03-22 17:21:59 +000067
reed@android.comf244f1b2010-04-16 12:40:08 +000068private:
bungeman@google.comb3d154d2013-11-11 15:53:29 +000069 typedef SkTypeface_Custom INHERITED;
reed@android.comf244f1b2010-04-16 12:40:08 +000070};
71
bungeman@google.comb3d154d2013-11-11 15:53:29 +000072/** The stream SkTypeface implementation for the custom font manager. */
73class SkTypeface_Stream : public SkTypeface_Custom {
reed@android.com8a1c16f2008-12-17 15:59:43 +000074public:
bungemana4c4a2d2014-10-20 13:33:19 -070075 SkTypeface_Stream(const SkFontStyle& style, bool isFixedPitch, bool sysFont,
bungeman5f213d92015-01-27 05:39:10 -080076 const SkString familyName, SkStreamAsset* stream, int index)
bungemana4c4a2d2014-10-20 13:33:19 -070077 : INHERITED(style, isFixedPitch, sysFont, familyName, index)
scroggoe58898e2015-01-21 12:23:20 -080078 , fStream(stream)
bungeman@google.comb3d154d2013-11-11 15:53:29 +000079 { }
chudy@google.comada44802012-07-30 12:59:12 +000080
reed@google.com292b1d42013-03-22 17:21:59 +000081protected:
mtklein36352bf2015-03-25 18:17:31 -070082 SkStreamAsset* onOpenStream(int* ttcIndex) const override {
bungemand71b7572014-09-18 10:55:32 -070083 *ttcIndex = this->getIndex();
commit-bot@chromium.orga2b44dc2014-03-24 21:42:01 +000084 return fStream->duplicate();
reed@google.com292b1d42013-03-22 17:21:59 +000085 }
86
reed@android.com8a1c16f2008-12-17 15:59:43 +000087private:
bungeman5f213d92015-01-27 05:39:10 -080088 const SkAutoTDelete<const SkStreamAsset> fStream;
chudy@google.comada44802012-07-30 12:59:12 +000089
bungeman@google.comb3d154d2013-11-11 15:53:29 +000090 typedef SkTypeface_Custom INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +000091};
92
bungeman@google.comb3d154d2013-11-11 15:53:29 +000093/** The file SkTypeface implementation for the custom font manager. */
94class SkTypeface_File : public SkTypeface_Custom {
reed@android.com8a1c16f2008-12-17 15:59:43 +000095public:
bungemana4c4a2d2014-10-20 13:33:19 -070096 SkTypeface_File(const SkFontStyle& style, bool isFixedPitch, bool sysFont,
97 const SkString familyName, const char path[], int index)
bungemand71b7572014-09-18 10:55:32 -070098 : INHERITED(style, isFixedPitch, sysFont, familyName, index)
bungeman@google.comb3d154d2013-11-11 15:53:29 +000099 , fPath(path)
100 { }
chudy@google.comada44802012-07-30 12:59:12 +0000101
reed@google.com292b1d42013-03-22 17:21:59 +0000102protected:
mtklein36352bf2015-03-25 18:17:31 -0700103 SkStreamAsset* onOpenStream(int* ttcIndex) const override {
bungemand71b7572014-09-18 10:55:32 -0700104 *ttcIndex = this->getIndex();
bungeman5cf19492015-06-15 15:17:21 -0700105 return SkStream::NewFromFile(fPath.c_str());
reed@google.com292b1d42013-03-22 17:21:59 +0000106 }
107
reed@android.com8a1c16f2008-12-17 15:59:43 +0000108private:
109 SkString fPath;
chudy@google.comada44802012-07-30 12:59:12 +0000110
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000111 typedef SkTypeface_Custom INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000112};
113
114///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000115
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000116/**
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
bungeman5c9fa282015-03-30 12:53:48 -0700125 /** Should only be called during the inital build phase. */
126 void appendTypeface(SkTypeface_Custom* typeface) {
127 fStyles.push_back().reset(typeface);
128 }
129
mtklein36352bf2015-03-25 18:17:31 -0700130 int count() override {
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000131 return fStyles.count();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000132 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000133
mtklein36352bf2015-03-25 18:17:31 -0700134 void getStyle(int index, SkFontStyle* style, SkString* name) override {
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000135 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 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000143
mtklein36352bf2015-03-25 18:17:31 -0700144 SkTypeface* createTypeface(int index) override {
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000145 SkASSERT(index < fStyles.count());
146 return SkRef(fStyles[index].get());
147 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000148
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000149 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
mtklein36352bf2015-03-25 18:17:31 -0700157 SkTypeface* matchStyle(const SkFontStyle& pattern) override {
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000158 if (0 == fStyles.count()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700159 return nullptr;
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000160 }
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
bungeman5c9fa282015-03-30 12:53:48 -0700182 SkString getFamilyName() { return fFamilyName; }
183
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000184private:
185 SkTArray<SkAutoTUnref<SkTypeface_Custom>, true> fStyles;
186 SkString fFamilyName;
187
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000188 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:
bungeman5c9fa282015-03-30 12:53:48 -0700200 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 };
halcanary96fcdcc2015-08-27 07:41:13 -0700206 explicit SkFontMgr_Custom(const SystemFontLoader& loader) : fDefaultFamily(nullptr) {
bungeman5c9fa282015-03-30 12:53:48 -0700207 loader.loadSystemFonts(fScanner, &fFamilies);
208
209 // Try to pick a default font.
210 static const char* defaultNames[] = {
halcanary96fcdcc2015-08-27 07:41:13 -0700211 "Arial", "Verdana", "Times New Roman", "Droid Sans", nullptr
bungeman5c9fa282015-03-30 12:53:48 -0700212 };
213 for (size_t i = 0; i < SK_ARRAY_COUNT(defaultNames); ++i) {
214 SkFontStyleSet_Custom* set = this->onMatchFamily(defaultNames[i]);
halcanary96fcdcc2015-08-27 07:41:13 -0700215 if (nullptr == set) {
bungeman5c9fa282015-03-30 12:53:48 -0700216 continue;
217 }
218
219 SkTypeface* tf = set->matchStyle(SkFontStyle(SkFontStyle::kNormal_Weight,
220 SkFontStyle::kNormal_Width,
221 SkFontStyle::kUpright_Slant));
halcanary96fcdcc2015-08-27 07:41:13 -0700222 if (nullptr == tf) {
bungeman5c9fa282015-03-30 12:53:48 -0700223 continue;
224 }
225
226 fDefaultFamily = set;
227 break;
228 }
halcanary96fcdcc2015-08-27 07:41:13 -0700229 if (nullptr == fDefaultFamily) {
bungeman5c9fa282015-03-30 12:53:48 -0700230 fDefaultFamily = fFamilies[0];
231 }
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000232 }
233
234protected:
mtklein36352bf2015-03-25 18:17:31 -0700235 int onCountFamilies() const override {
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000236 return fFamilies.count();
237 }
238
mtklein36352bf2015-03-25 18:17:31 -0700239 void onGetFamilyName(int index, SkString* familyName) const override {
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000240 SkASSERT(index < fFamilies.count());
bungeman5c9fa282015-03-30 12:53:48 -0700241 familyName->set(fFamilies[index]->getFamilyName());
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000242 }
243
mtklein36352bf2015-03-25 18:17:31 -0700244 SkFontStyleSet_Custom* onCreateStyleSet(int index) const override {
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000245 SkASSERT(index < fFamilies.count());
246 return SkRef(fFamilies[index].get());
247 }
248
mtklein36352bf2015-03-25 18:17:31 -0700249 SkFontStyleSet_Custom* onMatchFamily(const char familyName[]) const override {
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000250 for (int i = 0; i < fFamilies.count(); ++i) {
bungeman5c9fa282015-03-30 12:53:48 -0700251 if (fFamilies[i]->getFamilyName().equals(familyName)) {
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000252 return SkRef(fFamilies[i].get());
253 }
254 }
halcanary96fcdcc2015-08-27 07:41:13 -0700255 return nullptr;
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000256 }
257
bungeman5c9fa282015-03-30 12:53:48 -0700258 SkTypeface* onMatchFamilyStyle(const char familyName[],
259 const SkFontStyle& fontStyle) const override
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000260 {
261 SkAutoTUnref<SkFontStyleSet> sset(this->matchFamily(familyName));
262 return sset->matchStyle(fontStyle);
263 }
264
bungeman5c9fa282015-03-30 12:53:48 -0700265 SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&,
266 const char* bcp47[], int bcp47Count,
267 SkUnichar character) const override
djsollen33068c12014-11-14 10:52:53 -0800268 {
halcanary96fcdcc2015-08-27 07:41:13 -0700269 return nullptr;
djsollen33068c12014-11-14 10:52:53 -0800270 }
271
bungeman5c9fa282015-03-30 12:53:48 -0700272 SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember,
273 const SkFontStyle& fontStyle) const override
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000274 {
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 }
halcanary96fcdcc2015-08-27 07:41:13 -0700282 return nullptr;
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000283 }
284
mtklein36352bf2015-03-25 18:17:31 -0700285 SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const override {
scroggoa1193e42015-01-21 12:09:53 -0800286 return this->createFromStream(new SkMemoryStream(data), ttcIndex);
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000287 }
288
mtklein36352bf2015-03-25 18:17:31 -0700289 SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) const override {
bungeman5f213d92015-01-27 05:39:10 -0800290 SkAutoTDelete<SkStreamAsset> stream(bareStream);
halcanary96fcdcc2015-08-27 07:41:13 -0700291 if (nullptr == stream || stream->getLength() <= 0) {
292 return nullptr;
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000293 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000294
bungeman@google.comfe747652013-03-25 19:36:11 +0000295 bool isFixedPitch;
bungemana4c4a2d2014-10-20 13:33:19 -0700296 SkFontStyle style;
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000297 SkString name;
halcanary96fcdcc2015-08-27 07:41:13 -0700298 if (fScanner.scanFont(stream, ttcIndex, &name, &style, &isFixedPitch, nullptr)) {
mtklein18300a32016-03-16 13:53:35 -0700299 return new SkTypeface_Stream(style, isFixedPitch, false, name, stream.release(),
halcanary385fe4d2015-08-26 13:07:48 -0700300 ttcIndex);
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000301 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700302 return nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000303 }
reed@android.comf244f1b2010-04-16 12:40:08 +0000304 }
305
mtklein36352bf2015-03-25 18:17:31 -0700306 SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override {
bungeman5f213d92015-01-27 05:39:10 -0800307 SkAutoTDelete<SkStreamAsset> stream(SkStream::NewFromFile(path));
mtklein18300a32016-03-16 13:53:35 -0700308 return stream.get() ? this->createFromStream(stream.release(), ttcIndex) : nullptr;
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000309 }
310
bungeman11a77c62016-04-12 13:45:06 -0700311#ifdef SK_VERY_LEGACY_CREATE_TYPEFACE
bungeman5c9fa282015-03-30 12:53:48 -0700312 SkTypeface* onLegacyCreateTypeface(const char familyName[], unsigned styleBits) const override {
bungeman11a77c62016-04-12 13:45:06 -0700313 SkFontStyle style = SkFontStyle::FromOldStyle(styleBits);
314#else
315 SkTypeface* onLegacyCreateTypeface(const char familyName[], SkFontStyle style) const override {
316#endif
halcanary96fcdcc2015-08-27 07:41:13 -0700317 SkTypeface* tf = nullptr;
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000318
bsalomon49f085d2014-09-05 13:34:00 -0700319 if (familyName) {
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000320 tf = this->onMatchFamilyStyle(familyName, style);
bungeman@google.com2cf84ec2012-09-26 19:16:54 +0000321 }
bungeman@google.com2cf84ec2012-09-26 19:16:54 +0000322
halcanary96fcdcc2015-08-27 07:41:13 -0700323 if (nullptr == tf) {
bungeman5c9fa282015-03-30 12:53:48 -0700324 tf = fDefaultFamily->matchStyle(style);
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000325 }
326
327 return SkSafeRef(tf);
bungeman@google.com2cf84ec2012-09-26 19:16:54 +0000328 }
329
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000330private:
bungeman5c9fa282015-03-30 12:53:48 -0700331 Families fFamilies;
332 SkFontStyleSet_Custom* fDefaultFamily;
333 SkTypeface_FreeType::Scanner fScanner;
334};
bungeman@google.com2cf84ec2012-09-26 19:16:54 +0000335
bungeman5c9fa282015-03-30 12:53:48 -0700336///////////////////////////////////////////////////////////////////////////////
337
338class DirectorySystemFontLoader : public SkFontMgr_Custom::SystemFontLoader {
339public:
340 DirectorySystemFontLoader(const char* dir) : fBaseDirectory(dir) { }
341
342 void loadSystemFonts(const SkTypeface_FreeType::Scanner& scanner,
343 SkFontMgr_Custom::Families* families) const override
344 {
345 load_directory_fonts(scanner, fBaseDirectory, ".ttf", families);
346 load_directory_fonts(scanner, fBaseDirectory, ".ttc", families);
347 load_directory_fonts(scanner, fBaseDirectory, ".otf", families);
348 load_directory_fonts(scanner, fBaseDirectory, ".pfb", families);
349
350 if (families->empty()) {
351 SkFontStyleSet_Custom* family = new SkFontStyleSet_Custom(SkString());
352 families->push_back().reset(family);
halcanary385fe4d2015-08-26 13:07:48 -0700353 family->appendTypeface(new SkTypeface_Empty);
bungeman5c9fa282015-03-30 12:53:48 -0700354 }
355 }
356
357private:
358 static SkFontStyleSet_Custom* find_family(SkFontMgr_Custom::Families& families,
359 const char familyName[])
360 {
361 for (int i = 0; i < families.count(); ++i) {
362 if (families[i]->getFamilyName().equals(familyName)) {
363 return families[i].get();
364 }
365 }
halcanary96fcdcc2015-08-27 07:41:13 -0700366 return nullptr;
bungeman5c9fa282015-03-30 12:53:48 -0700367 }
368
369 static void load_directory_fonts(const SkTypeface_FreeType::Scanner& scanner,
370 const SkString& directory, const char* suffix,
371 SkFontMgr_Custom::Families* families)
372 {
bungeman14df8332014-10-28 15:07:23 -0700373 SkOSFile::Iter iter(directory.c_str(), suffix);
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000374 SkString name;
375
376 while (iter.next(&name, false)) {
bungeman14df8332014-10-28 15:07:23 -0700377 SkString filename(SkOSPath::Join(directory.c_str(), name.c_str()));
scroggoa1193e42015-01-21 12:09:53 -0800378 SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(filename.c_str()));
bungeman14df8332014-10-28 15:07:23 -0700379 if (!stream.get()) {
380 SkDebugf("---- failed to open <%s>\n", filename.c_str());
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000381 continue;
382 }
383
bungeman14df8332014-10-28 15:07:23 -0700384 int numFaces;
bungeman5c9fa282015-03-30 12:53:48 -0700385 if (!scanner.recognizedFont(stream, &numFaces)) {
bungeman14df8332014-10-28 15:07:23 -0700386 SkDebugf("---- failed to open <%s> as a font\n", filename.c_str());
387 continue;
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000388 }
bungeman14df8332014-10-28 15:07:23 -0700389
390 for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) {
391 bool isFixedPitch;
392 SkString realname;
393 SkFontStyle style = SkFontStyle(); // avoid uninitialized warning
halcanary96fcdcc2015-08-27 07:41:13 -0700394 if (!scanner.scanFont(stream, faceIndex, &realname, &style, &isFixedPitch, nullptr)) {
bungeman14df8332014-10-28 15:07:23 -0700395 SkDebugf("---- failed to open <%s> <%d> as a font\n",
396 filename.c_str(), faceIndex);
397 continue;
398 }
399
halcanary385fe4d2015-08-26 13:07:48 -0700400 SkTypeface_Custom* tf = new SkTypeface_File(style, isFixedPitch,
401 true, // system-font (cannot delete)
402 realname, filename.c_str(), faceIndex);
bungeman14df8332014-10-28 15:07:23 -0700403
bungeman5c9fa282015-03-30 12:53:48 -0700404 SkFontStyleSet_Custom* addTo = find_family(*families, realname.c_str());
halcanary96fcdcc2015-08-27 07:41:13 -0700405 if (nullptr == addTo) {
bungeman14df8332014-10-28 15:07:23 -0700406 addTo = new SkFontStyleSet_Custom(realname);
bungeman5c9fa282015-03-30 12:53:48 -0700407 families->push_back().reset(addTo);
bungeman14df8332014-10-28 15:07:23 -0700408 }
409 addTo->appendTypeface(tf);
410 }
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000411 }
412
413 SkOSFile::Iter dirIter(directory.c_str());
414 while (dirIter.next(&name, true)) {
415 if (name.startsWith(".")) {
416 continue;
417 }
tfarinaa8e2e152014-07-28 19:26:58 -0700418 SkString dirname(SkOSPath::Join(directory.c_str(), name.c_str()));
bungeman5c9fa282015-03-30 12:53:48 -0700419 load_directory_fonts(scanner, dirname, suffix, families);
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000420 }
421 }
422
bungeman5c9fa282015-03-30 12:53:48 -0700423 SkString fBaseDirectory;
bungeman@google.comb3d154d2013-11-11 15:53:29 +0000424};
reed@google.com070da5e2013-03-27 20:01:49 +0000425
bungeman5cf19492015-06-15 15:17:21 -0700426SK_API SkFontMgr* SkFontMgr_New_Custom_Directory(const char* dir) {
427 return new SkFontMgr_Custom(DirectorySystemFontLoader(dir));
428}
429
430///////////////////////////////////////////////////////////////////////////////
431
bungeman5c9fa282015-03-30 12:53:48 -0700432struct SkEmbeddedResource { const uint8_t* data; size_t size; };
433struct SkEmbeddedResourceHeader { const SkEmbeddedResource* entries; int count; };
434
435class EmbeddedSystemFontLoader : public SkFontMgr_Custom::SystemFontLoader {
436public:
437 EmbeddedSystemFontLoader(const SkEmbeddedResourceHeader* header) : fHeader(header) { }
438
439 void loadSystemFonts(const SkTypeface_FreeType::Scanner& scanner,
440 SkFontMgr_Custom::Families* families) const override
441 {
442 for (int i = 0; i < fHeader->count; ++i) {
443 const SkEmbeddedResource& fontEntry = fHeader->entries[i];
444 load_embedded_font(scanner, fontEntry.data, fontEntry.size, i, families);
445 }
446
447 if (families->empty()) {
448 SkFontStyleSet_Custom* family = new SkFontStyleSet_Custom(SkString());
449 families->push_back().reset(family);
halcanary385fe4d2015-08-26 13:07:48 -0700450 family->appendTypeface(new SkTypeface_Empty);
bungeman5c9fa282015-03-30 12:53:48 -0700451 }
452 }
453
454private:
455 static SkFontStyleSet_Custom* find_family(SkFontMgr_Custom::Families& families,
456 const char familyName[])
457 {
458 for (int i = 0; i < families.count(); ++i) {
459 if (families[i]->getFamilyName().equals(familyName)) {
460 return families[i].get();
461 }
462 }
halcanary96fcdcc2015-08-27 07:41:13 -0700463 return nullptr;
bungeman5c9fa282015-03-30 12:53:48 -0700464 }
465
466 static void load_embedded_font(const SkTypeface_FreeType::Scanner& scanner,
467 const uint8_t* data, size_t size, int index,
468 SkFontMgr_Custom::Families* families)
469 {
470 SkAutoTDelete<SkMemoryStream> stream(new SkMemoryStream(data, size, false));
471
472 int numFaces;
473 if (!scanner.recognizedFont(stream, &numFaces)) {
474 SkDebugf("---- failed to open <%d> as a font\n", index);
475 return;
476 }
477
478 for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) {
479 bool isFixedPitch;
480 SkString realname;
481 SkFontStyle style = SkFontStyle(); // avoid uninitialized warning
halcanary96fcdcc2015-08-27 07:41:13 -0700482 if (!scanner.scanFont(stream, faceIndex, &realname, &style, &isFixedPitch, nullptr)) {
bungeman5c9fa282015-03-30 12:53:48 -0700483 SkDebugf("---- failed to open <%d> <%d> as a font\n", index, faceIndex);
484 return;
485 }
486
halcanary385fe4d2015-08-26 13:07:48 -0700487 SkTypeface_Custom* tf =
488 new SkTypeface_Stream(style, isFixedPitch, true, // system-font (cannot delete)
mtklein18300a32016-03-16 13:53:35 -0700489 realname, stream.release(), faceIndex);
bungeman5c9fa282015-03-30 12:53:48 -0700490
491 SkFontStyleSet_Custom* addTo = find_family(*families, realname.c_str());
halcanary96fcdcc2015-08-27 07:41:13 -0700492 if (nullptr == addTo) {
bungeman5c9fa282015-03-30 12:53:48 -0700493 addTo = new SkFontStyleSet_Custom(realname);
494 families->push_back().reset(addTo);
495 }
496 addTo->appendTypeface(tf);
497 }
498 }
499
500 const SkEmbeddedResourceHeader* fHeader;
501};
502
bungeman5cf19492015-06-15 15:17:21 -0700503SkFontMgr* SkFontMgr_New_Custom_Embedded(const SkEmbeddedResourceHeader* header) {
504 return new SkFontMgr_Custom(EmbeddedSystemFontLoader(header));
reed@google.com070da5e2013-03-27 20:01:49 +0000505}
caryclarkfe7ada72016-03-21 06:55:52 -0700506
507///////////////////////////////////////////////////////////////////////////////
508
509class EmptyFontLoader : public SkFontMgr_Custom::SystemFontLoader {
510public:
511 EmptyFontLoader() { }
512
513 void loadSystemFonts(const SkTypeface_FreeType::Scanner& scanner,
514 SkFontMgr_Custom::Families* families) const override
515 {
516 SkFontStyleSet_Custom* family = new SkFontStyleSet_Custom(SkString());
517 families->push_back().reset(family);
518 family->appendTypeface(new SkTypeface_Empty);
519 }
520
521};
522
523SK_API SkFontMgr* SkFontMgr_New_Custom_Empty() {
524 return new SkFontMgr_Custom(EmptyFontLoader());
525}