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