blob: 9aabce7db974bf3d4842f3468023f91de457b4ea [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/* libs/graphics/ports/SkFontHost_android.cpp
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 ** http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17
18#include "SkFontHost.h"
19#include "SkDescriptor.h"
20#include "SkMMapStream.h"
21#include "SkOSFile.h"
22#include "SkPaint.h"
23#include "SkString.h"
24#include "SkStream.h"
25#include "SkThread.h"
26#include "SkTSearch.h"
27#include <stdio.h>
28
29#define FONT_CACHE_MEMORY_BUDGET (1 * 1024 * 1024)
30
31#ifndef SK_FONT_FILE_PREFIX
32 #define SK_FONT_FILE_PREFIX "/usr/share/fonts/truetype/msttcorefonts/"
33#endif
34
reed@google.com36812762011-02-23 14:49:33 +000035SkTypeface::Style find_name_and_attributes(SkStream* stream, SkString* name,
36 bool* isFixedWidth);
reed@android.com8a1c16f2008-12-17 15:59:43 +000037
38static void GetFullPathForSysFonts(SkString* full, const char name[])
39{
40 full->append(SK_FONT_FILE_PREFIX);
41 full->append(name);
42}
43
44///////////////////////////////////////////////////////////////////////////////
45
46struct FamilyRec;
47
48/* This guy holds a mapping of a name -> family, used for looking up fonts.
49 Since it is stored in a stretchy array that doesn't preserve object
50 semantics, we don't use constructor/destructors, but just have explicit
51 helpers to manage our internal bookkeeping.
52 */
53struct NameFamilyPair {
54 const char* fName; // we own this
55 FamilyRec* fFamily; // we don't own this, we just reference it
56
57 void construct(const char name[], FamilyRec* family)
58 {
59 fName = strdup(name);
60 fFamily = family; // we don't own this, so just record the referene
61 }
62 void destruct()
63 {
64 free((char*)fName);
65 // we don't own family, so just ignore our reference
66 }
67};
68
69// we use atomic_inc to grow this for each typeface we create
70static int32_t gUniqueFontID;
71
72// this is the mutex that protects these globals
73static SkMutex gFamilyMutex;
74static FamilyRec* gFamilyHead;
75static SkTDArray<NameFamilyPair> gNameList;
76
77struct FamilyRec {
78 FamilyRec* fNext;
79 SkTypeface* fFaces[4];
80
81 FamilyRec()
82 {
83 fNext = gFamilyHead;
84 memset(fFaces, 0, sizeof(fFaces));
85 gFamilyHead = this;
86 }
87};
88
89static SkTypeface* find_best_face(const FamilyRec* family,
reed@android.com1bfd0ca2009-02-20 14:22:36 +000090 SkTypeface::Style style) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000091 SkTypeface* const* faces = family->fFaces;
92
93 if (faces[style] != NULL) { // exact match
94 return faces[style];
95 }
96 // look for a matching bold
97 style = (SkTypeface::Style)(style ^ SkTypeface::kItalic);
98 if (faces[style] != NULL) {
99 return faces[style];
100 }
101 // look for the plain
102 if (faces[SkTypeface::kNormal] != NULL) {
103 return faces[SkTypeface::kNormal];
104 }
105 // look for anything
106 for (int i = 0; i < 4; i++) {
107 if (faces[i] != NULL) {
108 return faces[i];
109 }
110 }
111 // should never get here, since the faces list should not be empty
112 SkASSERT(!"faces list is empty");
113 return NULL;
114}
115
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000116static FamilyRec* find_family(const SkTypeface* member) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000117 FamilyRec* curr = gFamilyHead;
118 while (curr != NULL) {
119 for (int i = 0; i < 4; i++) {
120 if (curr->fFaces[i] == member) {
121 return curr;
122 }
123 }
124 curr = curr->fNext;
125 }
126 return NULL;
127}
128
reed@android.comf2afb672009-09-28 16:12:48 +0000129static SkTypeface* find_from_uniqueID(uint32_t uniqueID) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000130 FamilyRec* curr = gFamilyHead;
131 while (curr != NULL) {
132 for (int i = 0; i < 4; i++) {
133 SkTypeface* face = curr->fFaces[i];
134 if (face != NULL && face->uniqueID() == uniqueID) {
reed@android.comf2afb672009-09-28 16:12:48 +0000135 return face;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000136 }
137 }
138 curr = curr->fNext;
139 }
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000140 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000141}
142
reed@android.comf2afb672009-09-28 16:12:48 +0000143static bool valid_uniqueID(uint32_t uniqueID) {
144 return find_from_uniqueID(uniqueID) != NULL;
145}
146
reed@android.com8a1c16f2008-12-17 15:59:43 +0000147/* Remove reference to this face from its family. If the resulting family
148 is empty (has no faces), return that family, otherwise return NULL
149 */
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000150static FamilyRec* remove_from_family(const SkTypeface* face) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000151 FamilyRec* family = find_family(face);
152 SkASSERT(family->fFaces[face->style()] == face);
153 family->fFaces[face->style()] = NULL;
154
155 for (int i = 0; i < 4; i++) {
156 if (family->fFaces[i] != NULL) { // family is non-empty
157 return NULL;
158 }
159 }
160 return family; // return the empty family
161}
162
163// maybe we should make FamilyRec be doubly-linked
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000164static void detach_and_delete_family(FamilyRec* family) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000165 FamilyRec* curr = gFamilyHead;
166 FamilyRec* prev = NULL;
167
168 while (curr != NULL) {
169 FamilyRec* next = curr->fNext;
170 if (curr == family) {
171 if (prev == NULL) {
172 gFamilyHead = next;
173 } else {
174 prev->fNext = next;
175 }
176 SkDELETE(family);
177 return;
178 }
179 prev = curr;
180 curr = next;
181 }
182 SkASSERT(!"Yikes, couldn't find family in our list to remove/delete");
183}
184
185static FamilyRec* find_familyrec(const char name[]) {
186 const NameFamilyPair* list = gNameList.begin();
187 int index = SkStrLCSearch(&list[0].fName, gNameList.count(), name,
188 sizeof(list[0]));
189 return index >= 0 ? list[index].fFamily : NULL;
190}
191
192static SkTypeface* find_typeface(const char name[], SkTypeface::Style style) {
193 FamilyRec* rec = find_familyrec(name);
194 return rec ? find_best_face(rec, style) : NULL;
195}
196
197static SkTypeface* find_typeface(const SkTypeface* familyMember,
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000198 SkTypeface::Style style) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000199 const FamilyRec* family = find_family(familyMember);
200 return family ? find_best_face(family, style) : NULL;
201}
202
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000203static void add_name(const char name[], FamilyRec* family) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204 SkAutoAsciiToLC tolc(name);
205 name = tolc.lc();
206
207 NameFamilyPair* list = gNameList.begin();
208 int count = gNameList.count();
209
210 int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
211
212 if (index < 0) {
213 list = gNameList.insert(~index);
214 list->construct(name, family);
215 }
216}
217
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000218static void remove_from_names(FamilyRec* emptyFamily) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219#ifdef SK_DEBUG
220 for (int i = 0; i < 4; i++) {
221 SkASSERT(emptyFamily->fFaces[i] == NULL);
222 }
223#endif
224
225 SkTDArray<NameFamilyPair>& list = gNameList;
226
227 // must go backwards when removing
228 for (int i = list.count() - 1; i >= 0; --i) {
229 NameFamilyPair* pair = &list[i];
230 if (pair->fFamily == emptyFamily) {
231 pair->destruct();
232 list.remove(i);
233 }
234 }
235}
236
237///////////////////////////////////////////////////////////////////////////////
238
239class FamilyTypeface : public SkTypeface {
240public:
reed@google.com36812762011-02-23 14:49:33 +0000241 FamilyTypeface(Style style, bool sysFont, FamilyRec* family, bool isFixedWidth)
242 : SkTypeface(style, sk_atomic_inc(&gUniqueFontID) + 1, isFixedWidth) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000243 fIsSysFont = sysFont;
244
245 SkAutoMutexAcquire ac(gFamilyMutex);
246
247 if (NULL == family) {
248 family = SkNEW(FamilyRec);
249 }
250 family->fFaces[style] = this;
251 fFamilyRec = family; // just record it so we can return it if asked
252 }
253
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000254 virtual ~FamilyTypeface() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255 SkAutoMutexAcquire ac(gFamilyMutex);
256
257 // remove us from our family. If the family is now empty, we return
258 // that and then remove that family from the name list
259 FamilyRec* family = remove_from_family(this);
260 if (NULL != family) {
261 remove_from_names(family);
262 detach_and_delete_family(family);
263 }
264 }
265
266 bool isSysFont() const { return fIsSysFont; }
267 FamilyRec* getFamily() const { return fFamilyRec; }
reed@android.com22dbaaf2009-05-18 00:43:58 +0000268 // openStream returns a SkStream that has been ref-ed
reed@android.com8a1c16f2008-12-17 15:59:43 +0000269 virtual SkStream* openStream() = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000270 virtual const char* getUniqueString() const = 0;
271
272private:
273 FamilyRec* fFamilyRec; // we don't own this, just point to it
274 bool fIsSysFont;
275
276 typedef SkTypeface INHERITED;
277};
278
279///////////////////////////////////////////////////////////////////////////////
280
reed@android.comf244f1b2010-04-16 12:40:08 +0000281/* This subclass is just a place holder for when we have no fonts available.
282 It exists so that our globals (e.g. gFamilyHead) that expect *something*
283 will not be null.
284 */
285class EmptyTypeface : public FamilyTypeface {
286public:
reed@google.com36812762011-02-23 14:49:33 +0000287 EmptyTypeface() : INHERITED(SkTypeface::kNormal, true, NULL, false) {}
reed@android.comf244f1b2010-04-16 12:40:08 +0000288
289 // overrides
290 virtual SkStream* openStream() { return NULL; }
reed@android.comf244f1b2010-04-16 12:40:08 +0000291 virtual const char* getUniqueString() const { return NULL; }
292
293private:
294 typedef FamilyTypeface INHERITED;
295};
296
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297class StreamTypeface : public FamilyTypeface {
298public:
299 StreamTypeface(Style style, bool sysFont, FamilyRec* family,
reed@google.com36812762011-02-23 14:49:33 +0000300 SkStream* stream, bool isFixedWidth)
301 : INHERITED(style, sysFont, family, isFixedWidth) {
reed@android.com1c0c5a02010-04-12 20:16:49 +0000302 stream->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000303 fStream = stream;
304 }
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000305 virtual ~StreamTypeface() {
reed@android.com1c0c5a02010-04-12 20:16:49 +0000306 fStream->unref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000307 }
308
309 // overrides
reed@android.com22dbaaf2009-05-18 00:43:58 +0000310 virtual SkStream* openStream()
311 {
312 // openStream returns a refed stream.
313 fStream->ref();
314 return fStream;
315 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000316 virtual const char* getUniqueString() const { return NULL; }
317
318private:
319 SkStream* fStream;
320
321 typedef FamilyTypeface INHERITED;
322};
323
324class FileTypeface : public FamilyTypeface {
325public:
326 FileTypeface(Style style, bool sysFont, FamilyRec* family,
reed@google.com36812762011-02-23 14:49:33 +0000327 const char path[], bool isFixedWidth)
328 : INHERITED(style, sysFont, family, isFixedWidth) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000329 fPath.set(path);
330 }
331
332 // overrides
333 virtual SkStream* openStream()
334 {
335 SkStream* stream = SkNEW_ARGS(SkMMAPStream, (fPath.c_str()));
336
337 // check for failure
338 if (stream->getLength() <= 0) {
339 SkDELETE(stream);
340 // maybe MMAP isn't supported. try FILE
341 stream = SkNEW_ARGS(SkFILEStream, (fPath.c_str()));
342 if (stream->getLength() <= 0) {
343 SkDELETE(stream);
344 stream = NULL;
345 }
346 }
347 return stream;
348 }
reed@android.com51709c72010-04-16 12:51:29 +0000349
reed@android.com8a1c16f2008-12-17 15:59:43 +0000350 virtual const char* getUniqueString() const {
351 const char* str = strrchr(fPath.c_str(), '/');
352 if (str) {
353 str += 1; // skip the '/'
354 }
355 return str;
356 }
357
358private:
359 SkString fPath;
360
361 typedef FamilyTypeface INHERITED;
362};
363
364///////////////////////////////////////////////////////////////////////////////
365///////////////////////////////////////////////////////////////////////////////
366
367static bool get_name_and_style(const char path[], SkString* name,
reed@google.com36812762011-02-23 14:49:33 +0000368 SkTypeface::Style* style, bool* isFixedWidth) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000369 SkMMAPStream stream(path);
370 if (stream.getLength() > 0) {
reed@google.com36812762011-02-23 14:49:33 +0000371 *style = find_name_and_attributes(&stream, name, isFixedWidth);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000372 return true;
373 }
374 else {
375 SkFILEStream stream(path);
376 if (stream.getLength() > 0) {
reed@google.com36812762011-02-23 14:49:33 +0000377 *style = find_name_and_attributes(&stream, name, isFixedWidth);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000378 return true;
379 }
380 }
381
382 SkDebugf("---- failed to open <%s> as a font\n", path);
383 return false;
384}
385
386// these globals are assigned (once) by load_system_fonts()
387static SkTypeface* gFallBackTypeface;
388static FamilyRec* gDefaultFamily;
389static SkTypeface* gDefaultNormal;
390
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000391static void load_system_fonts() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000392 // check if we've already be called
393 if (NULL != gDefaultNormal) {
reed@android.comf2afb672009-09-28 16:12:48 +0000394 printf("---- default font %p\n", gDefaultNormal);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000395 return;
396 }
reed@android.comf2afb672009-09-28 16:12:48 +0000397
reed@android.comf244f1b2010-04-16 12:40:08 +0000398 SkOSFile::Iter iter(SK_FONT_FILE_PREFIX, ".ttf");
399 SkString name;
400 int count = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000401
402 while (iter.next(&name, false)) {
403 SkString filename;
404 GetFullPathForSysFonts(&filename, name.c_str());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000405
reed@google.com36812762011-02-23 14:49:33 +0000406 bool isFixedWidth;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000407 SkString realname;
reed@google.com6963af22011-01-04 12:52:02 +0000408 SkTypeface::Style style = SkTypeface::kNormal; // avoid uninitialized warning
reed@android.com8a1c16f2008-12-17 15:59:43 +0000409
reed@google.com36812762011-02-23 14:49:33 +0000410 if (!get_name_and_style(filename.c_str(), &realname, &style, &isFixedWidth)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000411 SkDebugf("------ can't load <%s> as a font\n", filename.c_str());
412 continue;
413 }
reed@android.comf2afb672009-09-28 16:12:48 +0000414
reed@android.com8a1c16f2008-12-17 15:59:43 +0000415// SkDebugf("font: <%s> %d <%s>\n", realname.c_str(), style, filename.c_str());
reed@android.comf2afb672009-09-28 16:12:48 +0000416
reed@android.com8a1c16f2008-12-17 15:59:43 +0000417 FamilyRec* family = find_familyrec(realname.c_str());
reed@android.com887e4f32010-04-15 14:04:52 +0000418 if (family && family->fFaces[style]) {
419// SkDebugf("---- skipping duplicate typeface %s style %d\n",
420// realname.c_str(), style);
421 continue;
422 }
423
reed@android.com8a1c16f2008-12-17 15:59:43 +0000424 // this constructor puts us into the global gFamilyHead llist
425 FamilyTypeface* tf = SkNEW_ARGS(FileTypeface,
426 (style,
427 true, // system-font (cannot delete)
428 family, // what family to join
reed@google.com36812762011-02-23 14:49:33 +0000429 filename.c_str(),
430 isFixedWidth) // filename
reed@android.com8a1c16f2008-12-17 15:59:43 +0000431 );
432
433 if (NULL == family) {
434 add_name(realname.c_str(), tf->getFamily());
435 }
reed@android.comf244f1b2010-04-16 12:40:08 +0000436 count += 1;
437 }
438
439 if (0 == count) {
440 SkNEW(EmptyTypeface);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000441 }
reed@android.comf2afb672009-09-28 16:12:48 +0000442
reed@android.com8a1c16f2008-12-17 15:59:43 +0000443 // do this after all fonts are loaded. This is our default font, and it
444 // acts as a sentinel so we only execute load_system_fonts() once
445 static const char* gDefaultNames[] = {
446 "Arial", "Verdana", "Times New Roman", NULL
447 };
448 const char** names = gDefaultNames;
449 while (*names) {
450 SkTypeface* tf = find_typeface(*names++, SkTypeface::kNormal);
451 if (tf) {
452 gDefaultNormal = tf;
453 break;
454 }
455 }
456 // check if we found *something*
457 if (NULL == gDefaultNormal) {
458 if (NULL == gFamilyHead) {
459 sk_throw();
460 }
461 for (int i = 0; i < 4; i++) {
462 if ((gDefaultNormal = gFamilyHead->fFaces[i]) != NULL) {
463 break;
464 }
465 }
466 }
467 if (NULL == gDefaultNormal) {
468 sk_throw();
469 }
470 gFallBackTypeface = gDefaultNormal;
471 gDefaultFamily = find_family(gDefaultNormal);
472
473// SkDebugf("---- default %p head %p family %p\n", gDefaultNormal, gFamilyHead, gDefaultFamily);
474}
475
476///////////////////////////////////////////////////////////////////////////////
477
478void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
479#if 0
480 const char* name = ((FamilyTypeface*)face)->getUniqueString();
481
482 stream->write8((uint8_t)face->getStyle());
483
484 if (NULL == name || 0 == *name) {
485 stream->writePackedUInt(0);
486 // SkDebugf("--- fonthost serialize null\n");
487 } else {
488 uint32_t len = strlen(name);
489 stream->writePackedUInt(len);
490 stream->write(name, len);
491 // SkDebugf("--- fonthost serialize <%s> %d\n", name, face->getStyle());
492 }
493#endif
494 sk_throw();
495}
496
497SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
498#if 0
499 load_system_fonts();
500
501 int style = stream->readU8();
502
503 int len = stream->readPackedUInt();
504 if (len > 0) {
505 SkString str;
506 str.resize(len);
507 stream->read(str.writable_str(), len);
508
509 const FontInitRec* rec = gSystemFonts;
510 for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
511 if (strcmp(rec[i].fFileName, str.c_str()) == 0) {
512 // backup until we hit the fNames
513 for (int j = i; j >= 0; --j) {
514 if (rec[j].fNames != NULL) {
agl@chromium.org5f6a0762010-04-20 22:06:40 +0000515 return SkFontHost::CreateTypeface(NULL, rec[j].fNames[0], NULL, 0,
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000516 (SkTypeface::Style)style);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000517 }
518 }
519 }
520 }
521 }
agl@chromium.org5f6a0762010-04-20 22:06:40 +0000522 return SkFontHost::CreateTypeface(NULL, NULL, NULL, 0, (SkTypeface::Style)style);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000523#endif
524 sk_throw();
reed@android.com6f252972009-01-14 16:46:16 +0000525 return NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000526}
527
528///////////////////////////////////////////////////////////////////////////////
529
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000530SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
531 const char familyName[],
agl@chromium.org5f6a0762010-04-20 22:06:40 +0000532 const void* data, size_t bytelength,
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000533 SkTypeface::Style style) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000534 load_system_fonts();
535
536 SkAutoMutexAcquire ac(gFamilyMutex);
537
538 // clip to legal style bits
539 style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
540
541 SkTypeface* tf = NULL;
542
543 if (NULL != familyFace) {
544 tf = find_typeface(familyFace, style);
545 } else if (NULL != familyName) {
546 // SkDebugf("======= familyName <%s>\n", familyName);
547 tf = find_typeface(familyName, style);
548 }
549
550 if (NULL == tf) {
551 tf = find_best_face(gDefaultFamily, style);
552 }
reed@android.com887e4f32010-04-15 14:04:52 +0000553
554 SkSafeRef(tf);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000555 return tf;
556}
557
reed@android.comf2afb672009-09-28 16:12:48 +0000558bool SkFontHost::ValidFontID(uint32_t fontID) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000559 SkAutoMutexAcquire ac(gFamilyMutex);
560
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000561 return valid_uniqueID(fontID);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000562}
563
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000564SkStream* SkFontHost::OpenStream(uint32_t fontID) {
reed@android.comf2afb672009-09-28 16:12:48 +0000565 FamilyTypeface* tf = (FamilyTypeface*)find_from_uniqueID(fontID);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000566 SkStream* stream = tf ? tf->openStream() : NULL;
567
reed@android.com1c0c5a02010-04-12 20:16:49 +0000568 if (stream && stream->getLength() == 0) {
569 stream->unref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000570 stream = NULL;
571 }
572 return stream;
573}
574
reed@android.comac981542009-07-31 16:17:01 +0000575size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
576 int32_t* index) {
577 SkDebugf("SkFontHost::GetFileName unimplemented\n");
578 return 0;
579}
580
reed@android.comf2afb672009-09-28 16:12:48 +0000581uint32_t SkFontHost::NextLogicalFont(uint32_t fontID) {
582 return 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000583}
584
585///////////////////////////////////////////////////////////////////////////////
586
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000587SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000588 if (NULL == stream || stream->getLength() <= 0) {
589 SkDELETE(stream);
590 return NULL;
591 }
reed@google.com36812762011-02-23 14:49:33 +0000592
593 bool isFixedWidth;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000594 SkString name;
reed@google.com36812762011-02-23 14:49:33 +0000595 SkTypeface::Style style = find_name_and_attributes(stream, &name, &isFixedWidth);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000596
reed@google.com36812762011-02-23 14:49:33 +0000597 return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream, isFixedWidth));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000598}
599
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000600SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
601 SkTypeface* face = NULL;
602 SkFILEStream* stream = SkNEW_ARGS(SkFILEStream, (path));
603
604 if (stream->isValid()) {
reed@android.comf2afb672009-09-28 16:12:48 +0000605 face = CreateTypefaceFromStream(stream);
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000606 }
607 stream->unref();
reed@android.comf2afb672009-09-28 16:12:48 +0000608 return face;
reed@android.com0becfc5b2009-01-13 13:26:44 +0000609}
610
reed@android.com8a1c16f2008-12-17 15:59:43 +0000611///////////////////////////////////////////////////////////////////////////////
612
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000613size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000614 if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET)
615 return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET;
616 else
617 return 0; // nothing to do
618}
619