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