blob: 9e126bccf82a78daea58c16c48094cefb50d21eb [file] [log] [blame]
reed@android.com9d3a9852010-01-08 14:07:42 +00001#include "SkFontHost.h"
2#include "SkDescriptor.h"
3#include "SkMMapStream.h"
4#include "SkPaint.h"
5#include "SkString.h"
6#include "SkStream.h"
7#include "SkThread.h"
8#include "SkTSearch.h"
9#include <stdio.h>
10
11#define FONT_CACHE_MEMORY_BUDGET (768 * 1024)
12
13#define SK_FONT_FILE_PREFIX "/skimages/"
14
15SkTypeface::Style find_name_and_style(SkStream* stream, SkString* name);
16
17static void GetFullPathForSysFonts(SkString* full, const char name[]) {
18 full->set(SK_FONT_FILE_PREFIX);
19 full->append(name);
20}
21
22///////////////////////////////////////////////////////////////////////////////
23
24struct FamilyRec;
25
26/* This guy holds a mapping of a name -> family, used for looking up fonts.
27 Since it is stored in a stretchy array that doesn't preserve object
28 semantics, we don't use constructor/destructors, but just have explicit
29 helpers to manage our internal bookkeeping.
30*/
31struct NameFamilyPair {
32 const char* fName; // we own this
33 FamilyRec* fFamily; // we don't own this, we just reference it
34
35 void construct(const char name[], FamilyRec* family) {
36 fName = strdup(name);
37 fFamily = family; // we don't own this, so just record the referene
38 }
39
40 void destruct() {
41 free((char*)fName);
42 // we don't own family, so just ignore our reference
43 }
44};
45
46// we use atomic_inc to grow this for each typeface we create
47static int32_t gUniqueFontID;
48
49// this is the mutex that protects these globals
50static SkMutex gFamilyMutex;
51static FamilyRec* gFamilyHead;
52static SkTDArray<NameFamilyPair> gNameList;
53
54struct FamilyRec {
55 FamilyRec* fNext;
56 SkTypeface* fFaces[4];
57
58 FamilyRec()
59 {
60 fNext = gFamilyHead;
61 memset(fFaces, 0, sizeof(fFaces));
62 gFamilyHead = this;
63 }
64};
65
66static SkTypeface* find_best_face(const FamilyRec* family,
67 SkTypeface::Style style) {
68 SkTypeface* const* faces = family->fFaces;
69
70 if (faces[style] != NULL) { // exact match
71 return faces[style];
72 }
73 // look for a matching bold
74 style = (SkTypeface::Style)(style ^ SkTypeface::kItalic);
75 if (faces[style] != NULL) {
76 return faces[style];
77 }
78 // look for the plain
79 if (faces[SkTypeface::kNormal] != NULL) {
80 return faces[SkTypeface::kNormal];
81 }
82 // look for anything
83 for (int i = 0; i < 4; i++) {
84 if (faces[i] != NULL) {
85 return faces[i];
86 }
87 }
88 // should never get here, since the faces list should not be empty
89 SkASSERT(!"faces list is empty");
90 return NULL;
91}
92
93static FamilyRec* find_family(const SkTypeface* member) {
94 FamilyRec* curr = gFamilyHead;
95 while (curr != NULL) {
96 for (int i = 0; i < 4; i++) {
97 if (curr->fFaces[i] == member) {
98 return curr;
99 }
100 }
101 curr = curr->fNext;
102 }
103 return NULL;
104}
105
106/* Returns the matching typeface, or NULL. If a typeface is found, its refcnt
107 is not modified.
108 */
109static SkTypeface* find_from_uniqueID(uint32_t uniqueID) {
110 FamilyRec* curr = gFamilyHead;
111 while (curr != NULL) {
112 for (int i = 0; i < 4; i++) {
113 SkTypeface* face = curr->fFaces[i];
114 if (face != NULL && face->uniqueID() == uniqueID) {
115 return face;
116 }
117 }
118 curr = curr->fNext;
119 }
120 return NULL;
121}
122
123/* Remove reference to this face from its family. If the resulting family
124 is empty (has no faces), return that family, otherwise return NULL
125*/
126static FamilyRec* remove_from_family(const SkTypeface* face) {
127 FamilyRec* family = find_family(face);
128 SkASSERT(family->fFaces[face->style()] == face);
129 family->fFaces[face->style()] = NULL;
130
131 for (int i = 0; i < 4; i++) {
132 if (family->fFaces[i] != NULL) { // family is non-empty
133 return NULL;
134 }
135 }
136 return family; // return the empty family
137}
138
139// maybe we should make FamilyRec be doubly-linked
140static void detach_and_delete_family(FamilyRec* family) {
141 FamilyRec* curr = gFamilyHead;
142 FamilyRec* prev = NULL;
143
144 while (curr != NULL) {
145 FamilyRec* next = curr->fNext;
146 if (curr == family) {
147 if (prev == NULL) {
148 gFamilyHead = next;
149 } else {
150 prev->fNext = next;
151 }
152 SkDELETE(family);
153 return;
154 }
155 prev = curr;
156 curr = next;
157 }
158 SkASSERT(!"Yikes, couldn't find family in our list to remove/delete");
159}
160
161static SkTypeface* find_typeface(const char name[], SkTypeface::Style style) {
162 NameFamilyPair* list = gNameList.begin();
163 int count = gNameList.count();
164
165 int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
166
167 if (index >= 0) {
168 return find_best_face(list[index].fFamily, style);
169 }
170 return NULL;
171}
172
173static SkTypeface* find_typeface(const SkTypeface* familyMember,
174 SkTypeface::Style style) {
175 const FamilyRec* family = find_family(familyMember);
176 return family ? find_best_face(family, style) : NULL;
177}
178
179static void add_name(const char name[], FamilyRec* family) {
180 SkAutoAsciiToLC tolc(name);
181 name = tolc.lc();
182
183 NameFamilyPair* list = gNameList.begin();
184 int count = gNameList.count();
185
186 int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
187
188 if (index < 0) {
189 list = gNameList.insert(~index);
190 list->construct(name, family);
191 }
192}
193
194static void remove_from_names(FamilyRec* emptyFamily)
195{
196#ifdef SK_DEBUG
197 for (int i = 0; i < 4; i++) {
198 SkASSERT(emptyFamily->fFaces[i] == NULL);
199 }
200#endif
201
202 SkTDArray<NameFamilyPair>& list = gNameList;
203
204 // must go backwards when removing
205 for (int i = list.count() - 1; i >= 0; --i) {
206 NameFamilyPair* pair = &list[i];
207 if (pair->fFamily == emptyFamily) {
208 pair->destruct();
209 list.remove(i);
210 }
211 }
212}
213
214///////////////////////////////////////////////////////////////////////////////
215
216class FamilyTypeface : public SkTypeface {
217public:
218 FamilyTypeface(Style style, bool sysFont, SkTypeface* familyMember)
219 : SkTypeface(style, sk_atomic_inc(&gUniqueFontID) + 1) {
220 fIsSysFont = sysFont;
221
222 SkAutoMutexAcquire ac(gFamilyMutex);
223
224 FamilyRec* rec = NULL;
225 if (familyMember) {
226 rec = find_family(familyMember);
227 SkASSERT(rec);
228 } else {
229 rec = SkNEW(FamilyRec);
230 }
231 rec->fFaces[style] = this;
232 }
233
234 virtual ~FamilyTypeface() {
235 SkAutoMutexAcquire ac(gFamilyMutex);
236
237 // remove us from our family. If the family is now empty, we return
238 // that and then remove that family from the name list
239 FamilyRec* family = remove_from_family(this);
240 if (NULL != family) {
241 remove_from_names(family);
242 detach_and_delete_family(family);
243 }
244 }
245
246 bool isSysFont() const { return fIsSysFont; }
247
248 virtual SkStream* openStream() = 0;
249 virtual const char* getUniqueString() const = 0;
250 virtual const char* getFilePath() const = 0;
251
252private:
253 bool fIsSysFont;
254
255 typedef SkTypeface INHERITED;
256};
257
258///////////////////////////////////////////////////////////////////////////////
259
260class StreamTypeface : public FamilyTypeface {
261public:
262 StreamTypeface(Style style, bool sysFont, SkTypeface* familyMember,
263 SkStream* stream)
264 : INHERITED(style, sysFont, familyMember) {
265 SkASSERT(stream);
266 stream->ref();
267 fStream = stream;
268 }
269 virtual ~StreamTypeface() {
270 fStream->unref();
271 }
272
273 // overrides
274 virtual SkStream* openStream() {
275 // we just ref our existing stream, since the caller will call unref()
276 // when they are through
277 fStream->ref();
278 return fStream;
279 }
280 virtual const char* getUniqueString() const { return NULL; }
281 virtual const char* getFilePath() const { return NULL; }
282
283private:
284 SkStream* fStream;
285
286 typedef FamilyTypeface INHERITED;
287};
288
289class FileTypeface : public FamilyTypeface {
290public:
291 FileTypeface(Style style, bool sysFont, SkTypeface* familyMember,
292 const char path[])
293 : INHERITED(style, sysFont, familyMember) {
294 SkString fullpath;
295
296 if (sysFont) {
297 GetFullPathForSysFonts(&fullpath, path);
298 path = fullpath.c_str();
299 }
300 fPath.set(path);
301 }
302
303 // overrides
304 virtual SkStream* openStream() {
305 SkStream* stream = SkNEW_ARGS(SkMMAPStream, (fPath.c_str()));
306
307 // check for failure
308 if (stream->getLength() <= 0) {
309 SkDELETE(stream);
310 // maybe MMAP isn't supported. try FILE
311 stream = SkNEW_ARGS(SkFILEStream, (fPath.c_str()));
312 if (stream->getLength() <= 0) {
313 SkDELETE(stream);
314 stream = NULL;
315 }
316 }
317 return stream;
318 }
319 virtual const char* getUniqueString() const {
320 const char* str = strrchr(fPath.c_str(), '/');
321 if (str) {
322 str += 1; // skip the '/'
323 }
324 return str;
325 }
326 virtual const char* getFilePath() const {
327 return fPath.c_str();
328 }
329
330private:
331 SkString fPath;
332
333 typedef FamilyTypeface INHERITED;
334};
335
336///////////////////////////////////////////////////////////////////////////////
337///////////////////////////////////////////////////////////////////////////////
338
339static bool get_name_and_style(const char path[], SkString* name,
340 SkTypeface::Style* style, bool isExpected) {
341 SkString fullpath;
342 GetFullPathForSysFonts(&fullpath, path);
343
344 SkMMAPStream stream(fullpath.c_str());
345 if (stream.getLength() > 0) {
346 *style = find_name_and_style(&stream, name);
347 return true;
348 }
349 else {
350 SkFILEStream stream(fullpath.c_str());
351 if (stream.getLength() > 0) {
352 *style = find_name_and_style(&stream, name);
353 return true;
354 }
355 }
356
357 if (isExpected) {
358 SkDebugf("---- failed to open <%s> as a font\n", fullpath.c_str());
359 }
360 return false;
361}
362
363// used to record our notion of the pre-existing fonts
364struct FontInitRec {
365 const char* fFileName;
366 const char* const* fNames; // null-terminated list
367};
368
369static const char* gSansNames[] = {
370 "sans-serif", "arial", "helvetica", "tahoma", "verdana", NULL
371};
372
373static const char* gSerifNames[] = {
374 "serif", "times", "times new roman", "palatino", "georgia", "baskerville",
375 "goudy", "fantasy", "cursive", "ITC Stone Serif", NULL
376};
377
378static const char* gMonoNames[] = {
379 "monospace", "courier", "courier new", "monaco", NULL
380};
381
382// deliberately empty, but we use the address to identify fallback fonts
383static const char* gFBNames[] = { NULL };
384
385/* Fonts must be grouped by family, with the first font in a family having the
386 list of names (even if that list is empty), and the following members having
387 null for the list. The names list must be NULL-terminated
388*/
389static const FontInitRec gSystemFonts[] = {
390 { "samplefont.ttf", gSansNames },
391};
392
393#define DEFAULT_NAMES gSansNames
394
395// these globals are assigned (once) by load_system_fonts()
396static FamilyRec* gDefaultFamily;
397static SkTypeface* gDefaultNormal;
398
399/* This is sized conservatively, assuming that it will never be a size issue.
400 It will be initialized in load_system_fonts(), and will be filled with the
401 fontIDs that can be used for fallback consideration, in sorted order (sorted
402 meaning element[0] should be used first, then element[1], etc. When we hit
403 a fontID==0 in the array, the list is done, hence our allocation size is
404 +1 the total number of possible system fonts. Also see NextLogicalFont().
405 */
406static uint32_t gFallbackFonts[SK_ARRAY_COUNT(gSystemFonts)+1];
407
408/* Called once (ensured by the sentinel check at the beginning of our body).
409 Initializes all the globals, and register the system fonts.
410 */
411static void load_system_fonts() {
412 // check if we've already be called
413 if (NULL != gDefaultNormal) {
414 return;
415 }
416
417 const FontInitRec* rec = gSystemFonts;
418 SkTypeface* firstInFamily = NULL;
419 int fallbackCount = 0;
420
421 for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
422 // if we're the first in a new family, clear firstInFamily
423 if (rec[i].fNames != NULL) {
424 firstInFamily = NULL;
425 }
426
427 SkString name;
428 SkTypeface::Style style;
429
430 // we expect all the fonts, except the "fallback" fonts
431 bool isExpected = (rec[i].fNames != gFBNames);
432 if (!get_name_and_style(rec[i].fFileName, &name, &style, isExpected)) {
433 continue;
434 }
435
436 SkTypeface* tf = SkNEW_ARGS(FileTypeface,
437 (style,
438 true, // system-font (cannot delete)
439 firstInFamily, // what family to join
440 rec[i].fFileName) // filename
441 );
442
443 if (rec[i].fNames != NULL) {
444 // see if this is one of our fallback fonts
445 if (rec[i].fNames == gFBNames) {
446 // SkDebugf("---- adding %s as fallback[%d] fontID %d\n",
447 // rec[i].fFileName, fallbackCount, tf->uniqueID());
448 gFallbackFonts[fallbackCount++] = tf->uniqueID();
449 }
450
451 firstInFamily = tf;
452 FamilyRec* family = find_family(tf);
453 const char* const* names = rec[i].fNames;
454
455 // record the default family if this is it
456 if (names == DEFAULT_NAMES) {
457 gDefaultFamily = family;
458 }
459 // add the names to map to this family
460 while (*names) {
461 add_name(*names, family);
462 names += 1;
463 }
464 }
465 }
466
467 // do this after all fonts are loaded. This is our default font, and it
468 // acts as a sentinel so we only execute load_system_fonts() once
469 gDefaultNormal = find_best_face(gDefaultFamily, SkTypeface::kNormal);
470 // now terminate our fallback list with the sentinel value
471 gFallbackFonts[fallbackCount] = 0;
472}
473
474///////////////////////////////////////////////////////////////////////////////
475
476void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
477 const char* name = ((FamilyTypeface*)face)->getUniqueString();
478
479 stream->write8((uint8_t)face->style());
480
481 if (NULL == name || 0 == *name) {
482 stream->writePackedUInt(0);
483// SkDebugf("--- fonthost serialize null\n");
484 } else {
485 uint32_t len = strlen(name);
486 stream->writePackedUInt(len);
487 stream->write(name, len);
488// SkDebugf("--- fonthost serialize <%s> %d\n", name, face->style());
489 }
490}
491
492SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
493 load_system_fonts();
494
495 int style = stream->readU8();
496
497 int len = stream->readPackedUInt();
498 if (len > 0) {
499 SkString str;
500 str.resize(len);
501 stream->read(str.writable_str(), len);
502
503 const FontInitRec* rec = gSystemFonts;
504 for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
505 if (strcmp(rec[i].fFileName, str.c_str()) == 0) {
506 // backup until we hit the fNames
507 for (int j = i; j >= 0; --j) {
508 if (rec[j].fNames != NULL) {
509 return SkFontHost::CreateTypeface(NULL,
agl@chromium.org5f6a0762010-04-20 22:06:40 +0000510 rec[j].fNames[0], NULL, 0, (SkTypeface::Style)style);
reed@android.com9d3a9852010-01-08 14:07:42 +0000511 }
512 }
513 }
514 }
515 }
516 return NULL;
517}
518
519///////////////////////////////////////////////////////////////////////////////
520
521SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
522 const char familyName[],
agl@chromium.org5f6a0762010-04-20 22:06:40 +0000523 const void* data, size_t bytelength,
reed@android.com9d3a9852010-01-08 14:07:42 +0000524 SkTypeface::Style style) {
525 load_system_fonts();
526
527 SkAutoMutexAcquire ac(gFamilyMutex);
528
529 // clip to legal style bits
530 style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
531
532 SkTypeface* tf = NULL;
533
534 if (NULL != familyFace) {
535 tf = find_typeface(familyFace, style);
536 } else if (NULL != familyName) {
537// SkDebugf("======= familyName <%s>\n", familyName);
538 tf = find_typeface(familyName, style);
539 }
540
541 if (NULL == tf) {
542 tf = find_best_face(gDefaultFamily, style);
543 }
544
545 // we ref(), since the symantic is to return a new instance
546 tf->ref();
547 return tf;
548}
549
550bool SkFontHost::ValidFontID(uint32_t fontID) {
551 SkAutoMutexAcquire ac(gFamilyMutex);
552
553 return find_from_uniqueID(fontID) != NULL;
554}
555
556SkStream* SkFontHost::OpenStream(uint32_t fontID) {
557 SkAutoMutexAcquire ac(gFamilyMutex);
558
559 FamilyTypeface* tf = (FamilyTypeface*)find_from_uniqueID(fontID);
560 SkStream* stream = tf ? tf->openStream() : NULL;
561
562 if (stream && stream->getLength() == 0) {
563 stream->unref();
564 stream = NULL;
565 }
566 return stream;
567}
568
569size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
570 int32_t* index) {
571 SkAutoMutexAcquire ac(gFamilyMutex);
572
573 FamilyTypeface* tf = (FamilyTypeface*)find_from_uniqueID(fontID);
574 const char* src = tf ? tf->getFilePath() : NULL;
575
576 if (src) {
577 size_t size = strlen(src);
578 if (path) {
579 memcpy(path, src, SkMin32(size, length));
580 }
581 if (index) {
582 *index = 0; // we don't have collections (yet)
583 }
584 return size;
585 } else {
586 return 0;
587 }
588}
589
590uint32_t SkFontHost::NextLogicalFont(uint32_t fontID) {
591 load_system_fonts();
592
593 /* First see if fontID is already one of our fallbacks. If so, return
594 its successor. If fontID is not in our list, then return the first one
595 in our list. Note: list is zero-terminated, and returning zero means
596 we have no more fonts to use for fallbacks.
597 */
598 const uint32_t* list = gFallbackFonts;
599 for (int i = 0; list[i] != 0; i++) {
600 if (list[i] == fontID) {
601 return list[i+1];
602 }
603 }
604 return list[0];
605}
606
607///////////////////////////////////////////////////////////////////////////////
608
609SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
610 if (NULL == stream || stream->getLength() <= 0) {
611 return NULL;
612 }
613
614 SkString name;
615 SkTypeface::Style style = find_name_and_style(stream, &name);
616
617 return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream));
618}
619
620SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
621 SkStream* stream = SkNEW_ARGS(SkMMAPStream, (path));
622 SkTypeface* face = SkFontHost::CreateTypefaceFromStream(stream);
623 // since we created the stream, we let go of our ref() here
624 stream->unref();
625 return face;
626}
627
628///////////////////////////////////////////////////////////////////////////////
629
630size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) {
631 if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET)
632 return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET;
633 else
634 return 0; // nothing to do
635}
636