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