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 bool find_name_and_style(SkStream* stream, SkString* name, SkTypeface::Style* style);
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 return find_name_and_style(&stream, name, style);
367 }
368 else {
369 SkFILEStream stream(fullpath.c_str());
370 if (stream.getLength() > 0) {
371 return find_name_and_style(&stream, name, style);
372 }
373 }
374
375 if (isExpected) {
376 SkDebugf("---- failed to open <%s> as a font\n", fullpath.c_str());
377 }
378 return false;
379 }
380
381 // used to record our notion of the pre-existing fonts
382 struct FontInitRec {
383 const char* fFileName;
384 const char* const* fNames; // null-terminated list
385 };
386
387 static const char* gSansNames[] = {
388 "sans-serif", "arial", "helvetica", "tahoma", "verdana", NULL
389 };
390
391 static const char* gSerifNames[] = {
392 "serif", "times", "times new roman", "palatino", "georgia", "baskerville",
393 "goudy", "fantasy", "cursive", "ITC Stone Serif", NULL
394 };
395
396 static const char* gMonoNames[] = {
397 "monospace", "courier", "courier new", "monaco", NULL
398 };
399
400 // deliberately empty, but we use the address to identify fallback fonts
401 static const char* gFBNames[] = { NULL };
402
403 /* Fonts must be grouped by family, with the first font in a family having the
404 list of names (even if that list is empty), and the following members having
405 null for the list. The names list must be NULL-terminated
406 */
407 static const FontInitRec gSystemFonts[] = {
408 { "DroidSans.ttf", gSansNames },
409 { "DroidSans-Bold.ttf", NULL },
410 { "DroidSerif-Regular.ttf", gSerifNames },
411 { "DroidSerif-Bold.ttf", NULL },
412 { "DroidSerif-Italic.ttf", NULL },
413 { "DroidSerif-BoldItalic.ttf", NULL },
414 { "DroidSansMono.ttf", gMonoNames },
415 /* These are optional, and can be ignored if not found in the file system.
416 These are appended to gFallbackFonts[] as they are seen, so we list
417 them in the order we want them to be accessed by NextLogicalFont().
418 */
419 { "DroidSansArabic.ttf", gFBNames },
420 { "DroidSansHebrew.ttf", gFBNames },
421 { "DroidSansThai.ttf", gFBNames },
422 { "MTLmr3m.ttf", gFBNames }, // Motoya Japanese Font
423 { "MTLc3m.ttf", gFBNames }, // Motoya Japanese Font
424 { "DroidSansJapanese.ttf", gFBNames },
425 { "DroidSansFallback.ttf", gFBNames }
426 };
427
428 #define DEFAULT_NAMES gSansNames
429
430 // these globals are assigned (once) by load_system_fonts()
431 static FamilyRec* gDefaultFamily;
432 static SkTypeface* gDefaultNormal;
433
434 /* This is sized conservatively, assuming that it will never be a size issue.
435 It will be initialized in load_system_fonts(), and will be filled with the
436 fontIDs that can be used for fallback consideration, in sorted order (sorted
437 meaning element[0] should be used first, then element[1], etc. When we hit
438 a fontID==0 in the array, the list is done, hence our allocation size is
439 +1 the total number of possible system fonts. Also see NextLogicalFont().
440 */
441 static uint32_t gFallbackFonts[SK_ARRAY_COUNT(gSystemFonts)+1];
442
443 /* Called once (ensured by the sentinel check at the beginning of our body).
444 Initializes all the globals, and register the system fonts.
445 */
load_system_fonts()446 static void load_system_fonts() {
447 // check if we've already be called
448 if (NULL != gDefaultNormal) {
449 return;
450 }
451
452 const FontInitRec* rec = gSystemFonts;
453 SkTypeface* firstInFamily = NULL;
454 int fallbackCount = 0;
455
456 for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
457 // if we're the first in a new family, clear firstInFamily
458 if (rec[i].fNames != NULL) {
459 firstInFamily = NULL;
460 }
461
462 SkString name;
463 SkTypeface::Style style;
464
465 // we expect all the fonts, except the "fallback" fonts
466 bool isExpected = (rec[i].fNames != gFBNames);
467 if (!get_name_and_style(rec[i].fFileName, &name, &style, isExpected)) {
468 continue;
469 }
470
471 SkTypeface* tf = SkNEW_ARGS(FileTypeface,
472 (style,
473 true, // system-font (cannot delete)
474 firstInFamily, // what family to join
475 rec[i].fFileName) // filename
476 );
477
478 if (rec[i].fNames != NULL) {
479 // see if this is one of our fallback fonts
480 if (rec[i].fNames == gFBNames) {
481 // SkDebugf("---- adding %s as fallback[%d] fontID %d\n",
482 // rec[i].fFileName, fallbackCount, tf->uniqueID());
483 gFallbackFonts[fallbackCount++] = tf->uniqueID();
484 }
485
486 firstInFamily = tf;
487 FamilyRec* family = find_family(tf);
488 const char* const* names = rec[i].fNames;
489
490 // record the default family if this is it
491 if (names == DEFAULT_NAMES) {
492 gDefaultFamily = family;
493 }
494 // add the names to map to this family
495 while (*names) {
496 add_name(*names, family);
497 names += 1;
498 }
499 }
500 }
501
502 // do this after all fonts are loaded. This is our default font, and it
503 // acts as a sentinel so we only execute load_system_fonts() once
504 gDefaultNormal = find_best_face(gDefaultFamily, SkTypeface::kNormal);
505 // now terminate our fallback list with the sentinel value
506 gFallbackFonts[fallbackCount] = 0;
507 }
508
509 ///////////////////////////////////////////////////////////////////////////////
510
Serialize(const SkTypeface * face,SkWStream * stream)511 void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
512 const char* name = ((FamilyTypeface*)face)->getUniqueString();
513
514 stream->write8((uint8_t)face->style());
515
516 if (NULL == name || 0 == *name) {
517 stream->writePackedUInt(0);
518 // SkDebugf("--- fonthost serialize null\n");
519 } else {
520 uint32_t len = strlen(name);
521 stream->writePackedUInt(len);
522 stream->write(name, len);
523 // SkDebugf("--- fonthost serialize <%s> %d\n", name, face->style());
524 }
525 }
526
Deserialize(SkStream * stream)527 SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
528 load_system_fonts();
529
530 int style = stream->readU8();
531
532 int len = stream->readPackedUInt();
533 if (len > 0) {
534 SkString str;
535 str.resize(len);
536 stream->read(str.writable_str(), len);
537
538 const FontInitRec* rec = gSystemFonts;
539 for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
540 if (strcmp(rec[i].fFileName, str.c_str()) == 0) {
541 // backup until we hit the fNames
542 for (int j = i; j >= 0; --j) {
543 if (rec[j].fNames != NULL) {
544 return SkFontHost::CreateTypeface(NULL,
545 rec[j].fNames[0], (SkTypeface::Style)style);
546 }
547 }
548 }
549 }
550 }
551 return NULL;
552 }
553
554 ///////////////////////////////////////////////////////////////////////////////
555
CreateTypeface(const SkTypeface * familyFace,const char familyName[],SkTypeface::Style style)556 SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
557 const char familyName[],
558 SkTypeface::Style style) {
559 load_system_fonts();
560
561 SkAutoMutexAcquire ac(gFamilyMutex);
562
563 // clip to legal style bits
564 style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
565
566 SkTypeface* tf = NULL;
567
568 if (NULL != familyFace) {
569 tf = find_typeface(familyFace, style);
570 } else if (NULL != familyName) {
571 // SkDebugf("======= familyName <%s>\n", familyName);
572 tf = find_typeface(familyName, style);
573 }
574
575 if (NULL == tf) {
576 tf = find_best_face(gDefaultFamily, style);
577 }
578
579 // we ref(), since the symantic is to return a new instance
580 tf->ref();
581 return tf;
582 }
583
ValidFontID(uint32_t fontID)584 bool SkFontHost::ValidFontID(uint32_t fontID) {
585 SkAutoMutexAcquire ac(gFamilyMutex);
586
587 return find_from_uniqueID(fontID) != NULL;
588 }
589
OpenStream(uint32_t fontID)590 SkStream* SkFontHost::OpenStream(uint32_t fontID) {
591 SkAutoMutexAcquire ac(gFamilyMutex);
592
593 FamilyTypeface* tf = (FamilyTypeface*)find_from_uniqueID(fontID);
594 SkStream* stream = tf ? tf->openStream() : NULL;
595
596 if (stream && stream->getLength() == 0) {
597 stream->unref();
598 stream = NULL;
599 }
600 return stream;
601 }
602
GetFileName(SkFontID fontID,char path[],size_t length,int32_t * index)603 size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
604 int32_t* index) {
605 SkAutoMutexAcquire ac(gFamilyMutex);
606
607 FamilyTypeface* tf = (FamilyTypeface*)find_from_uniqueID(fontID);
608 const char* src = tf ? tf->getFilePath() : NULL;
609
610 if (src) {
611 size_t size = strlen(src);
612 if (path) {
613 memcpy(path, src, SkMin32(size, length));
614 }
615 if (index) {
616 *index = 0; // we don't have collections (yet)
617 }
618 return size;
619 } else {
620 return 0;
621 }
622 }
623
NextLogicalFont(uint32_t fontID)624 uint32_t SkFontHost::NextLogicalFont(uint32_t fontID) {
625 load_system_fonts();
626
627 /* First see if fontID is already one of our fallbacks. If so, return
628 its successor. If fontID is not in our list, then return the first one
629 in our list. Note: list is zero-terminated, and returning zero means
630 we have no more fonts to use for fallbacks.
631 */
632 const uint32_t* list = gFallbackFonts;
633 for (int i = 0; list[i] != 0; i++) {
634 if (list[i] == fontID) {
635 return list[i+1];
636 }
637 }
638 return list[0];
639 }
640
641 ///////////////////////////////////////////////////////////////////////////////
642
CreateTypefaceFromStream(SkStream * stream)643 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
644 if (NULL == stream || stream->getLength() <= 0) {
645 return NULL;
646 }
647
648 SkString name;
649 SkTypeface::Style style;
650
651 if (find_name_and_style(stream, &name, &style)) {
652 return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream));
653 } else {
654 return NULL;
655 }
656 }
657
CreateTypefaceFromFile(const char path[])658 SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
659 SkStream* stream = SkNEW_ARGS(SkMMAPStream, (path));
660 SkTypeface* face = SkFontHost::CreateTypefaceFromStream(stream);
661 // since we created the stream, we let go of our ref() here
662 stream->unref();
663 return face;
664 }
665
666 ///////////////////////////////////////////////////////////////////////////////
667
ShouldPurgeFontCache(size_t sizeAllocatedSoFar)668 size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) {
669 if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET)
670 return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET;
671 else
672 return 0; // nothing to do
673 }
674
675