blob: 782b93fb252fd243065f4573872b3980c62d3ba6 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkFontHost.h"
11#include "SkDescriptor.h"
12#include "SkMMapStream.h"
13#include "SkOSFile.h"
14#include "SkPaint.h"
15#include "SkString.h"
16#include "SkStream.h"
17#include "SkThread.h"
18#include "SkTSearch.h"
19#include <stdio.h>
20
21#define FONT_CACHE_MEMORY_BUDGET (1 * 1024 * 1024)
22
23#ifndef SK_FONT_FILE_PREFIX
24 #define SK_FONT_FILE_PREFIX "/usr/share/fonts/truetype/msttcorefonts/"
25#endif
26
reed@google.com36812762011-02-23 14:49:33 +000027SkTypeface::Style find_name_and_attributes(SkStream* stream, SkString* name,
28 bool* isFixedWidth);
reed@android.com8a1c16f2008-12-17 15:59:43 +000029
30static void GetFullPathForSysFonts(SkString* full, const char name[])
31{
32 full->append(SK_FONT_FILE_PREFIX);
33 full->append(name);
34}
35
36///////////////////////////////////////////////////////////////////////////////
37
38struct FamilyRec;
39
40/* This guy holds a mapping of a name -> family, used for looking up fonts.
41 Since it is stored in a stretchy array that doesn't preserve object
42 semantics, we don't use constructor/destructors, but just have explicit
43 helpers to manage our internal bookkeeping.
44 */
45struct NameFamilyPair {
46 const char* fName; // we own this
47 FamilyRec* fFamily; // we don't own this, we just reference it
48
49 void construct(const char name[], FamilyRec* family)
50 {
51 fName = strdup(name);
52 fFamily = family; // we don't own this, so just record the referene
53 }
54 void destruct()
55 {
56 free((char*)fName);
57 // we don't own family, so just ignore our reference
58 }
59};
60
61// we use atomic_inc to grow this for each typeface we create
62static int32_t gUniqueFontID;
63
64// this is the mutex that protects these globals
65static SkMutex gFamilyMutex;
66static FamilyRec* gFamilyHead;
67static SkTDArray<NameFamilyPair> gNameList;
68
69struct FamilyRec {
70 FamilyRec* fNext;
71 SkTypeface* fFaces[4];
72
73 FamilyRec()
74 {
75 fNext = gFamilyHead;
76 memset(fFaces, 0, sizeof(fFaces));
77 gFamilyHead = this;
78 }
79};
80
81static SkTypeface* find_best_face(const FamilyRec* family,
reed@android.com1bfd0ca2009-02-20 14:22:36 +000082 SkTypeface::Style style) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000083 SkTypeface* const* faces = family->fFaces;
84
85 if (faces[style] != NULL) { // exact match
86 return faces[style];
87 }
88 // look for a matching bold
89 style = (SkTypeface::Style)(style ^ SkTypeface::kItalic);
90 if (faces[style] != NULL) {
91 return faces[style];
92 }
93 // look for the plain
94 if (faces[SkTypeface::kNormal] != NULL) {
95 return faces[SkTypeface::kNormal];
96 }
97 // look for anything
98 for (int i = 0; i < 4; i++) {
99 if (faces[i] != NULL) {
100 return faces[i];
101 }
102 }
103 // should never get here, since the faces list should not be empty
104 SkASSERT(!"faces list is empty");
105 return NULL;
106}
107
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000108static FamilyRec* find_family(const SkTypeface* member) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000109 FamilyRec* curr = gFamilyHead;
110 while (curr != NULL) {
111 for (int i = 0; i < 4; i++) {
112 if (curr->fFaces[i] == member) {
113 return curr;
114 }
115 }
116 curr = curr->fNext;
117 }
118 return NULL;
119}
120
reed@android.comf2afb672009-09-28 16:12:48 +0000121static SkTypeface* find_from_uniqueID(uint32_t uniqueID) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000122 FamilyRec* curr = gFamilyHead;
123 while (curr != NULL) {
124 for (int i = 0; i < 4; i++) {
125 SkTypeface* face = curr->fFaces[i];
126 if (face != NULL && face->uniqueID() == uniqueID) {
reed@android.comf2afb672009-09-28 16:12:48 +0000127 return face;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000128 }
129 }
130 curr = curr->fNext;
131 }
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000132 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000133}
134
reed@android.comf2afb672009-09-28 16:12:48 +0000135static bool valid_uniqueID(uint32_t uniqueID) {
136 return find_from_uniqueID(uniqueID) != NULL;
137}
138
reed@android.com8a1c16f2008-12-17 15:59:43 +0000139/* Remove reference to this face from its family. If the resulting family
140 is empty (has no faces), return that family, otherwise return NULL
141 */
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000142static FamilyRec* remove_from_family(const SkTypeface* face) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000143 FamilyRec* family = find_family(face);
144 SkASSERT(family->fFaces[face->style()] == face);
145 family->fFaces[face->style()] = NULL;
146
147 for (int i = 0; i < 4; i++) {
148 if (family->fFaces[i] != NULL) { // family is non-empty
149 return NULL;
150 }
151 }
152 return family; // return the empty family
153}
154
155// maybe we should make FamilyRec be doubly-linked
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000156static void detach_and_delete_family(FamilyRec* family) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000157 FamilyRec* curr = gFamilyHead;
158 FamilyRec* prev = NULL;
159
160 while (curr != NULL) {
161 FamilyRec* next = curr->fNext;
162 if (curr == family) {
163 if (prev == NULL) {
164 gFamilyHead = next;
165 } else {
166 prev->fNext = next;
167 }
168 SkDELETE(family);
169 return;
170 }
171 prev = curr;
172 curr = next;
173 }
174 SkASSERT(!"Yikes, couldn't find family in our list to remove/delete");
175}
176
177static FamilyRec* find_familyrec(const char name[]) {
178 const NameFamilyPair* list = gNameList.begin();
179 int index = SkStrLCSearch(&list[0].fName, gNameList.count(), name,
180 sizeof(list[0]));
181 return index >= 0 ? list[index].fFamily : NULL;
182}
183
184static SkTypeface* find_typeface(const char name[], SkTypeface::Style style) {
185 FamilyRec* rec = find_familyrec(name);
186 return rec ? find_best_face(rec, style) : NULL;
187}
188
189static SkTypeface* find_typeface(const SkTypeface* familyMember,
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000190 SkTypeface::Style style) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191 const FamilyRec* family = find_family(familyMember);
192 return family ? find_best_face(family, style) : NULL;
193}
194
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000195static void add_name(const char name[], FamilyRec* family) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000196 SkAutoAsciiToLC tolc(name);
197 name = tolc.lc();
198
199 NameFamilyPair* list = gNameList.begin();
200 int count = gNameList.count();
201
202 int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
203
204 if (index < 0) {
205 list = gNameList.insert(~index);
206 list->construct(name, family);
207 }
208}
209
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000210static void remove_from_names(FamilyRec* emptyFamily) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000211#ifdef SK_DEBUG
212 for (int i = 0; i < 4; i++) {
213 SkASSERT(emptyFamily->fFaces[i] == NULL);
214 }
215#endif
216
217 SkTDArray<NameFamilyPair>& list = gNameList;
218
219 // must go backwards when removing
220 for (int i = list.count() - 1; i >= 0; --i) {
221 NameFamilyPair* pair = &list[i];
222 if (pair->fFamily == emptyFamily) {
223 pair->destruct();
224 list.remove(i);
225 }
226 }
227}
228
229///////////////////////////////////////////////////////////////////////////////
230
231class FamilyTypeface : public SkTypeface {
232public:
reed@google.com36812762011-02-23 14:49:33 +0000233 FamilyTypeface(Style style, bool sysFont, FamilyRec* family, bool isFixedWidth)
234 : SkTypeface(style, sk_atomic_inc(&gUniqueFontID) + 1, isFixedWidth) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000235 fIsSysFont = sysFont;
236
237 SkAutoMutexAcquire ac(gFamilyMutex);
238
239 if (NULL == family) {
240 family = SkNEW(FamilyRec);
241 }
242 family->fFaces[style] = this;
243 fFamilyRec = family; // just record it so we can return it if asked
244 }
245
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000246 virtual ~FamilyTypeface() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000247 SkAutoMutexAcquire ac(gFamilyMutex);
248
249 // remove us from our family. If the family is now empty, we return
250 // that and then remove that family from the name list
251 FamilyRec* family = remove_from_family(this);
252 if (NULL != family) {
253 remove_from_names(family);
254 detach_and_delete_family(family);
255 }
256 }
257
258 bool isSysFont() const { return fIsSysFont; }
259 FamilyRec* getFamily() const { return fFamilyRec; }
reed@android.com22dbaaf2009-05-18 00:43:58 +0000260 // openStream returns a SkStream that has been ref-ed
reed@android.com8a1c16f2008-12-17 15:59:43 +0000261 virtual SkStream* openStream() = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000262 virtual const char* getUniqueString() const = 0;
263
264private:
265 FamilyRec* fFamilyRec; // we don't own this, just point to it
266 bool fIsSysFont;
267
268 typedef SkTypeface INHERITED;
269};
270
271///////////////////////////////////////////////////////////////////////////////
272
reed@android.comf244f1b2010-04-16 12:40:08 +0000273/* This subclass is just a place holder for when we have no fonts available.
274 It exists so that our globals (e.g. gFamilyHead) that expect *something*
275 will not be null.
276 */
277class EmptyTypeface : public FamilyTypeface {
278public:
reed@google.com36812762011-02-23 14:49:33 +0000279 EmptyTypeface() : INHERITED(SkTypeface::kNormal, true, NULL, false) {}
reed@android.comf244f1b2010-04-16 12:40:08 +0000280
281 // overrides
282 virtual SkStream* openStream() { return NULL; }
reed@android.comf244f1b2010-04-16 12:40:08 +0000283 virtual const char* getUniqueString() const { return NULL; }
284
285private:
286 typedef FamilyTypeface INHERITED;
287};
288
reed@android.com8a1c16f2008-12-17 15:59:43 +0000289class StreamTypeface : public FamilyTypeface {
290public:
291 StreamTypeface(Style style, bool sysFont, FamilyRec* family,
reed@google.com36812762011-02-23 14:49:33 +0000292 SkStream* stream, bool isFixedWidth)
293 : INHERITED(style, sysFont, family, isFixedWidth) {
reed@android.com1c0c5a02010-04-12 20:16:49 +0000294 stream->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000295 fStream = stream;
296 }
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000297 virtual ~StreamTypeface() {
reed@android.com1c0c5a02010-04-12 20:16:49 +0000298 fStream->unref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000299 }
300
301 // overrides
reed@android.com22dbaaf2009-05-18 00:43:58 +0000302 virtual SkStream* openStream()
303 {
304 // openStream returns a refed stream.
305 fStream->ref();
306 return fStream;
307 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000308 virtual const char* getUniqueString() const { return NULL; }
309
310private:
311 SkStream* fStream;
312
313 typedef FamilyTypeface INHERITED;
314};
315
316class FileTypeface : public FamilyTypeface {
317public:
318 FileTypeface(Style style, bool sysFont, FamilyRec* family,
reed@google.com36812762011-02-23 14:49:33 +0000319 const char path[], bool isFixedWidth)
320 : INHERITED(style, sysFont, family, isFixedWidth) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000321 fPath.set(path);
322 }
323
324 // overrides
325 virtual SkStream* openStream()
326 {
327 SkStream* stream = SkNEW_ARGS(SkMMAPStream, (fPath.c_str()));
328
329 // check for failure
330 if (stream->getLength() <= 0) {
331 SkDELETE(stream);
332 // maybe MMAP isn't supported. try FILE
333 stream = SkNEW_ARGS(SkFILEStream, (fPath.c_str()));
334 if (stream->getLength() <= 0) {
335 SkDELETE(stream);
336 stream = NULL;
337 }
338 }
339 return stream;
340 }
reed@android.com51709c72010-04-16 12:51:29 +0000341
reed@android.com8a1c16f2008-12-17 15:59:43 +0000342 virtual const char* getUniqueString() const {
343 const char* str = strrchr(fPath.c_str(), '/');
344 if (str) {
345 str += 1; // skip the '/'
346 }
347 return str;
348 }
349
350private:
351 SkString fPath;
352
353 typedef FamilyTypeface INHERITED;
354};
355
356///////////////////////////////////////////////////////////////////////////////
357///////////////////////////////////////////////////////////////////////////////
358
359static bool get_name_and_style(const char path[], SkString* name,
reed@google.com36812762011-02-23 14:49:33 +0000360 SkTypeface::Style* style, bool* isFixedWidth) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000361 SkMMAPStream stream(path);
362 if (stream.getLength() > 0) {
reed@google.com36812762011-02-23 14:49:33 +0000363 *style = find_name_and_attributes(&stream, name, isFixedWidth);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000364 return true;
365 }
366 else {
367 SkFILEStream stream(path);
368 if (stream.getLength() > 0) {
reed@google.com36812762011-02-23 14:49:33 +0000369 *style = find_name_and_attributes(&stream, name, isFixedWidth);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000370 return true;
371 }
372 }
373
374 SkDebugf("---- failed to open <%s> as a font\n", path);
375 return false;
376}
377
378// these globals are assigned (once) by load_system_fonts()
379static SkTypeface* gFallBackTypeface;
380static FamilyRec* gDefaultFamily;
381static SkTypeface* gDefaultNormal;
382
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000383static void load_system_fonts() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000384 // check if we've already be called
385 if (NULL != gDefaultNormal) {
reed@google.com6fb8f772011-05-17 15:47:04 +0000386// printf("---- default font %p\n", gDefaultNormal);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000387 return;
388 }
reed@android.comf2afb672009-09-28 16:12:48 +0000389
reed@android.comf244f1b2010-04-16 12:40:08 +0000390 SkOSFile::Iter iter(SK_FONT_FILE_PREFIX, ".ttf");
391 SkString name;
392 int count = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000393
394 while (iter.next(&name, false)) {
395 SkString filename;
396 GetFullPathForSysFonts(&filename, name.c_str());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000397
reed@google.com36812762011-02-23 14:49:33 +0000398 bool isFixedWidth;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000399 SkString realname;
reed@google.com6963af22011-01-04 12:52:02 +0000400 SkTypeface::Style style = SkTypeface::kNormal; // avoid uninitialized warning
reed@android.com8a1c16f2008-12-17 15:59:43 +0000401
reed@google.com36812762011-02-23 14:49:33 +0000402 if (!get_name_and_style(filename.c_str(), &realname, &style, &isFixedWidth)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000403 SkDebugf("------ can't load <%s> as a font\n", filename.c_str());
404 continue;
405 }
reed@android.comf2afb672009-09-28 16:12:48 +0000406
reed@android.com8a1c16f2008-12-17 15:59:43 +0000407// SkDebugf("font: <%s> %d <%s>\n", realname.c_str(), style, filename.c_str());
reed@android.comf2afb672009-09-28 16:12:48 +0000408
reed@android.com8a1c16f2008-12-17 15:59:43 +0000409 FamilyRec* family = find_familyrec(realname.c_str());
reed@android.com887e4f32010-04-15 14:04:52 +0000410 if (family && family->fFaces[style]) {
411// SkDebugf("---- skipping duplicate typeface %s style %d\n",
412// realname.c_str(), style);
413 continue;
414 }
415
reed@android.com8a1c16f2008-12-17 15:59:43 +0000416 // this constructor puts us into the global gFamilyHead llist
417 FamilyTypeface* tf = SkNEW_ARGS(FileTypeface,
418 (style,
419 true, // system-font (cannot delete)
420 family, // what family to join
reed@google.com36812762011-02-23 14:49:33 +0000421 filename.c_str(),
422 isFixedWidth) // filename
reed@android.com8a1c16f2008-12-17 15:59:43 +0000423 );
424
425 if (NULL == family) {
426 add_name(realname.c_str(), tf->getFamily());
427 }
reed@android.comf244f1b2010-04-16 12:40:08 +0000428 count += 1;
429 }
430
431 if (0 == count) {
432 SkNEW(EmptyTypeface);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000433 }
reed@android.comf2afb672009-09-28 16:12:48 +0000434
reed@android.com8a1c16f2008-12-17 15:59:43 +0000435 // do this after all fonts are loaded. This is our default font, and it
436 // acts as a sentinel so we only execute load_system_fonts() once
437 static const char* gDefaultNames[] = {
438 "Arial", "Verdana", "Times New Roman", NULL
439 };
440 const char** names = gDefaultNames;
441 while (*names) {
442 SkTypeface* tf = find_typeface(*names++, SkTypeface::kNormal);
443 if (tf) {
444 gDefaultNormal = tf;
445 break;
446 }
447 }
448 // check if we found *something*
449 if (NULL == gDefaultNormal) {
450 if (NULL == gFamilyHead) {
451 sk_throw();
452 }
453 for (int i = 0; i < 4; i++) {
454 if ((gDefaultNormal = gFamilyHead->fFaces[i]) != NULL) {
455 break;
456 }
457 }
458 }
459 if (NULL == gDefaultNormal) {
460 sk_throw();
461 }
462 gFallBackTypeface = gDefaultNormal;
463 gDefaultFamily = find_family(gDefaultNormal);
464
465// SkDebugf("---- default %p head %p family %p\n", gDefaultNormal, gFamilyHead, gDefaultFamily);
466}
467
468///////////////////////////////////////////////////////////////////////////////
469
470void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
471#if 0
472 const char* name = ((FamilyTypeface*)face)->getUniqueString();
473
474 stream->write8((uint8_t)face->getStyle());
475
476 if (NULL == name || 0 == *name) {
477 stream->writePackedUInt(0);
478 // SkDebugf("--- fonthost serialize null\n");
479 } else {
480 uint32_t len = strlen(name);
481 stream->writePackedUInt(len);
482 stream->write(name, len);
483 // SkDebugf("--- fonthost serialize <%s> %d\n", name, face->getStyle());
484 }
485#endif
486 sk_throw();
487}
488
489SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
490#if 0
491 load_system_fonts();
492
493 int style = stream->readU8();
494
495 int len = stream->readPackedUInt();
496 if (len > 0) {
497 SkString str;
498 str.resize(len);
499 stream->read(str.writable_str(), len);
500
501 const FontInitRec* rec = gSystemFonts;
502 for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
503 if (strcmp(rec[i].fFileName, str.c_str()) == 0) {
504 // backup until we hit the fNames
505 for (int j = i; j >= 0; --j) {
506 if (rec[j].fNames != NULL) {
agl@chromium.org5f6a0762010-04-20 22:06:40 +0000507 return SkFontHost::CreateTypeface(NULL, rec[j].fNames[0], NULL, 0,
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000508 (SkTypeface::Style)style);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000509 }
510 }
511 }
512 }
513 }
agl@chromium.org5f6a0762010-04-20 22:06:40 +0000514 return SkFontHost::CreateTypeface(NULL, NULL, NULL, 0, (SkTypeface::Style)style);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000515#endif
516 sk_throw();
reed@android.com6f252972009-01-14 16:46:16 +0000517 return NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000518}
519
520///////////////////////////////////////////////////////////////////////////////
521
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000522SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
523 const char familyName[],
agl@chromium.org5f6a0762010-04-20 22:06:40 +0000524 const void* data, size_t bytelength,
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000525 SkTypeface::Style style) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000526 load_system_fonts();
527
528 SkAutoMutexAcquire ac(gFamilyMutex);
529
530 // clip to legal style bits
531 style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
532
533 SkTypeface* tf = NULL;
534
535 if (NULL != familyFace) {
536 tf = find_typeface(familyFace, style);
537 } else if (NULL != familyName) {
538 // SkDebugf("======= familyName <%s>\n", familyName);
539 tf = find_typeface(familyName, style);
540 }
541
542 if (NULL == tf) {
543 tf = find_best_face(gDefaultFamily, style);
544 }
reed@android.com887e4f32010-04-15 14:04:52 +0000545
546 SkSafeRef(tf);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000547 return tf;
548}
549
reed@android.comf2afb672009-09-28 16:12:48 +0000550bool SkFontHost::ValidFontID(uint32_t fontID) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000551 SkAutoMutexAcquire ac(gFamilyMutex);
552
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000553 return valid_uniqueID(fontID);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000554}
555
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000556SkStream* SkFontHost::OpenStream(uint32_t fontID) {
reed@android.comf2afb672009-09-28 16:12:48 +0000557 FamilyTypeface* tf = (FamilyTypeface*)find_from_uniqueID(fontID);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000558 SkStream* stream = tf ? tf->openStream() : NULL;
559
reed@android.com1c0c5a02010-04-12 20:16:49 +0000560 if (stream && stream->getLength() == 0) {
561 stream->unref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000562 stream = NULL;
563 }
564 return stream;
565}
566
reed@android.comac981542009-07-31 16:17:01 +0000567size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
568 int32_t* index) {
569 SkDebugf("SkFontHost::GetFileName unimplemented\n");
570 return 0;
571}
572
reed@google.com7d26c592011-06-13 13:01:10 +0000573SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
reed@android.comf2afb672009-09-28 16:12:48 +0000574 return 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000575}
576
577///////////////////////////////////////////////////////////////////////////////
578
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000579SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000580 if (NULL == stream || stream->getLength() <= 0) {
581 SkDELETE(stream);
582 return NULL;
583 }
reed@google.com36812762011-02-23 14:49:33 +0000584
585 bool isFixedWidth;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000586 SkString name;
reed@google.com36812762011-02-23 14:49:33 +0000587 SkTypeface::Style style = find_name_and_attributes(stream, &name, &isFixedWidth);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000588
reed@google.com36812762011-02-23 14:49:33 +0000589 return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream, isFixedWidth));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000590}
591
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000592SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
593 SkTypeface* face = NULL;
594 SkFILEStream* stream = SkNEW_ARGS(SkFILEStream, (path));
595
596 if (stream->isValid()) {
reed@android.comf2afb672009-09-28 16:12:48 +0000597 face = CreateTypefaceFromStream(stream);
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000598 }
599 stream->unref();
reed@android.comf2afb672009-09-28 16:12:48 +0000600 return face;
reed@android.com0becfc5b2009-01-13 13:26:44 +0000601}
602
reed@android.com8a1c16f2008-12-17 15:59:43 +0000603///////////////////////////////////////////////////////////////////////////////
604
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000605size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000606 if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET)
607 return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET;
608 else
609 return 0; // nothing to do
610}
611