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
271 private:
272 bool fIsSysFont;
273
274 typedef SkTypeface INHERITED;
275 };
276
277 ///////////////////////////////////////////////////////////////////////////////
278
279 class StreamTypeface : public FamilyTypeface {
280 public:
StreamTypeface(Style style,bool sysFont,SkTypeface * familyMember,SkStream * stream)281 StreamTypeface(Style style, bool sysFont, SkTypeface* familyMember,
282 SkStream* stream)
283 : INHERITED(style, sysFont, familyMember) {
284 SkASSERT(stream);
285 stream->ref();
286 fStream = stream;
287 }
~StreamTypeface()288 virtual ~StreamTypeface() {
289 fStream->unref();
290 }
291
292 // overrides
openStream()293 virtual SkStream* openStream() {
294 // we just ref our existing stream, since the caller will call unref()
295 // when they are through
296 fStream->ref();
297 return fStream;
298 }
getUniqueString() const299 virtual const char* getUniqueString() const { return NULL; }
300
301 private:
302 SkStream* fStream;
303
304 typedef FamilyTypeface INHERITED;
305 };
306
307 class FileTypeface : public FamilyTypeface {
308 public:
FileTypeface(Style style,bool sysFont,SkTypeface * familyMember,const char path[])309 FileTypeface(Style style, bool sysFont, SkTypeface* familyMember,
310 const char path[])
311 : INHERITED(style, sysFont, familyMember) {
312 SkString fullpath;
313
314 if (sysFont) {
315 GetFullPathForSysFonts(&fullpath, path);
316 path = fullpath.c_str();
317 }
318 fPath.set(path);
319 }
320
321 // overrides
openStream()322 virtual SkStream* openStream() {
323 SkStream* stream = SkNEW_ARGS(SkMMAPStream, (fPath.c_str()));
324
325 // check for failure
326 if (stream->getLength() <= 0) {
327 SkDELETE(stream);
328 // maybe MMAP isn't supported. try FILE
329 stream = SkNEW_ARGS(SkFILEStream, (fPath.c_str()));
330 if (stream->getLength() <= 0) {
331 SkDELETE(stream);
332 stream = NULL;
333 }
334 }
335 return stream;
336 }
getUniqueString() const337 virtual const char* getUniqueString() const {
338 const char* str = strrchr(fPath.c_str(), '/');
339 if (str) {
340 str += 1; // skip the '/'
341 }
342 return str;
343 }
344
345 private:
346 SkString fPath;
347
348 typedef FamilyTypeface INHERITED;
349 };
350
351 ///////////////////////////////////////////////////////////////////////////////
352 ///////////////////////////////////////////////////////////////////////////////
353
get_name_and_style(const char path[],SkString * name,SkTypeface::Style * style,bool isExpected)354 static bool get_name_and_style(const char path[], SkString* name,
355 SkTypeface::Style* style, bool isExpected) {
356 SkString fullpath;
357 GetFullPathForSysFonts(&fullpath, path);
358
359 SkMMAPStream stream(fullpath.c_str());
360 if (stream.getLength() > 0) {
361 *style = find_name_and_style(&stream, name);
362 return true;
363 }
364 else {
365 SkFILEStream stream(fullpath.c_str());
366 if (stream.getLength() > 0) {
367 *style = find_name_and_style(&stream, name);
368 return true;
369 }
370 }
371
372 if (isExpected) {
373 SkDebugf("---- failed to open <%s> as a font\n", fullpath.c_str());
374 }
375 return false;
376 }
377
378 // used to record our notion of the pre-existing fonts
379 struct FontInitRec {
380 const char* fFileName;
381 const char* const* fNames; // null-terminated list
382 };
383
384 static const char* gSansNames[] = {
385 "sans-serif", "arial", "helvetica", "tahoma", "verdana", NULL
386 };
387
388 static const char* gSerifNames[] = {
389 "serif", "times", "times new roman", "palatino", "georgia", "baskerville",
390 "goudy", "fantasy", "cursive", "ITC Stone Serif", NULL
391 };
392
393 static const char* gMonoNames[] = {
394 "monospace", "courier", "courier new", "monaco", NULL
395 };
396
397 // deliberately empty, but we use the address to identify fallback fonts
398 static const char* gFBNames[] = { NULL };
399
400 /* Fonts must be grouped by family, with the first font in a family having the
401 list of names (even if that list is empty), and the following members having
402 null for the list. The names list must be NULL-terminated
403 */
404 static const FontInitRec gSystemFonts[] = {
405 { "DroidSans.ttf", gSansNames },
406 { "DroidSans-Bold.ttf", NULL },
407 { "DroidSerif-Regular.ttf", gSerifNames },
408 { "DroidSerif-Bold.ttf", NULL },
409 { "DroidSerif-Italic.ttf", NULL },
410 { "DroidSerif-BoldItalic.ttf", NULL },
411 { "DroidSansMono.ttf", gMonoNames },
412 /* These are optional, and can be ignored if not found in the file system.
413 These are appended to gFallbackFonts[] as they are seen, so we list
414 them in the order we want them to be accessed by NextLogicalFont().
415 */
416 { "DroidSansJapanese.ttf", gFBNames },
417 { "DroidSansFallback.ttf", gFBNames }
418 };
419
420 #define DEFAULT_NAMES gSansNames
421
422 // these globals are assigned (once) by load_system_fonts()
423 static FamilyRec* gDefaultFamily;
424 static SkTypeface* gDefaultNormal;
425
426 /* This is sized conservatively, assuming that it will never be a size issue.
427 It will be initialized in load_system_fonts(), and will be filled with the
428 fontIDs that can be used for fallback consideration, in sorted order (sorted
429 meaning element[0] should be used first, then element[1], etc. When we hit
430 a fontID==0 in the array, the list is done, hence our allocation size is
431 +1 the total number of possible system fonts. Also see NextLogicalFont().
432 */
433 static uint32_t gFallbackFonts[SK_ARRAY_COUNT(gSystemFonts)+1];
434
435 /* Called once (ensured by the sentinel check at the beginning of our body).
436 Initializes all the globals, and register the system fonts.
437 */
load_system_fonts()438 static void load_system_fonts() {
439 // check if we've already be called
440 if (NULL != gDefaultNormal) {
441 return;
442 }
443
444 const FontInitRec* rec = gSystemFonts;
445 SkTypeface* firstInFamily = NULL;
446 int fallbackCount = 0;
447
448 for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
449 // if we're the first in a new family, clear firstInFamily
450 if (rec[i].fNames != NULL) {
451 firstInFamily = NULL;
452 }
453
454 SkString name;
455 SkTypeface::Style style;
456
457 // we expect all the fonts, except the "fallback" fonts
458 bool isExpected = (rec[i].fNames != gFBNames);
459 if (!get_name_and_style(rec[i].fFileName, &name, &style, isExpected)) {
460 continue;
461 }
462
463 SkTypeface* tf = SkNEW_ARGS(FileTypeface,
464 (style,
465 true, // system-font (cannot delete)
466 firstInFamily, // what family to join
467 rec[i].fFileName) // filename
468 );
469
470 if (rec[i].fNames != NULL) {
471 // see if this is one of our fallback fonts
472 if (rec[i].fNames == gFBNames) {
473 // SkDebugf("---- adding %s as fallback[%d] fontID %d\n",
474 // rec[i].fFileName, fallbackCount, tf->uniqueID());
475 gFallbackFonts[fallbackCount++] = tf->uniqueID();
476 }
477
478 firstInFamily = tf;
479 FamilyRec* family = find_family(tf);
480 const char* const* names = rec[i].fNames;
481
482 // record the default family if this is it
483 if (names == DEFAULT_NAMES) {
484 gDefaultFamily = family;
485 }
486 // add the names to map to this family
487 while (*names) {
488 add_name(*names, family);
489 names += 1;
490 }
491 }
492 }
493
494 // do this after all fonts are loaded. This is our default font, and it
495 // acts as a sentinel so we only execute load_system_fonts() once
496 gDefaultNormal = find_best_face(gDefaultFamily, SkTypeface::kNormal);
497 // now terminate our fallback list with the sentinel value
498 gFallbackFonts[fallbackCount] = 0;
499 }
500
501 ///////////////////////////////////////////////////////////////////////////////
502
Serialize(const SkTypeface * face,SkWStream * stream)503 void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
504 const char* name = ((FamilyTypeface*)face)->getUniqueString();
505
506 stream->write8((uint8_t)face->style());
507
508 if (NULL == name || 0 == *name) {
509 stream->writePackedUInt(0);
510 // SkDebugf("--- fonthost serialize null\n");
511 } else {
512 uint32_t len = strlen(name);
513 stream->writePackedUInt(len);
514 stream->write(name, len);
515 // SkDebugf("--- fonthost serialize <%s> %d\n", name, face->style());
516 }
517 }
518
Deserialize(SkStream * stream)519 SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
520 load_system_fonts();
521
522 int style = stream->readU8();
523
524 int len = stream->readPackedUInt();
525 if (len > 0) {
526 SkString str;
527 str.resize(len);
528 stream->read(str.writable_str(), len);
529
530 const FontInitRec* rec = gSystemFonts;
531 for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
532 if (strcmp(rec[i].fFileName, str.c_str()) == 0) {
533 // backup until we hit the fNames
534 for (int j = i; j >= 0; --j) {
535 if (rec[j].fNames != NULL) {
536 return SkFontHost::CreateTypeface(NULL,
537 rec[j].fNames[0], (SkTypeface::Style)style);
538 }
539 }
540 }
541 }
542 }
543 return NULL;
544 }
545
546 ///////////////////////////////////////////////////////////////////////////////
547
CreateTypeface(const SkTypeface * familyFace,const char familyName[],SkTypeface::Style style)548 SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
549 const char familyName[],
550 SkTypeface::Style style) {
551 load_system_fonts();
552
553 SkAutoMutexAcquire ac(gFamilyMutex);
554
555 // clip to legal style bits
556 style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
557
558 SkTypeface* tf = NULL;
559
560 if (NULL != familyFace) {
561 tf = find_typeface(familyFace, style);
562 } else if (NULL != familyName) {
563 // SkDebugf("======= familyName <%s>\n", familyName);
564 tf = find_typeface(familyName, style);
565 }
566
567 if (NULL == tf) {
568 tf = find_best_face(gDefaultFamily, style);
569 }
570
571 // we ref(), since the symantic is to return a new instance
572 tf->ref();
573 return tf;
574 }
575
ValidFontID(uint32_t fontID)576 bool SkFontHost::ValidFontID(uint32_t fontID) {
577 SkAutoMutexAcquire ac(gFamilyMutex);
578
579 return find_from_uniqueID(fontID) != NULL;
580 }
581
OpenStream(uint32_t fontID)582 SkStream* SkFontHost::OpenStream(uint32_t fontID) {
583 SkAutoMutexAcquire ac(gFamilyMutex);
584
585 FamilyTypeface* tf = (FamilyTypeface*)find_from_uniqueID(fontID);
586 SkStream* stream = tf ? tf->openStream() : NULL;
587
588 if (stream && stream->getLength() == 0) {
589 stream->unref();
590 stream = NULL;
591 }
592 return stream;
593 }
594
NextLogicalFont(uint32_t fontID)595 uint32_t SkFontHost::NextLogicalFont(uint32_t fontID) {
596 load_system_fonts();
597
598 /* First see if fontID is already one of our fallbacks. If so, return
599 its successor. If fontID is not in our list, then return the first one
600 in our list. Note: list is zero-terminated, and returning zero means
601 we have no more fonts to use for fallbacks.
602 */
603 const uint32_t* list = gFallbackFonts;
604 for (int i = 0; list[i] != 0; i++) {
605 if (list[i] == fontID) {
606 return list[i+1];
607 }
608 }
609 return list[0];
610 }
611
612 ///////////////////////////////////////////////////////////////////////////////
613
CreateTypefaceFromStream(SkStream * stream)614 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
615 if (NULL == stream || stream->getLength() <= 0) {
616 return NULL;
617 }
618
619 SkString name;
620 SkTypeface::Style style = find_name_and_style(stream, &name);
621
622 return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream));
623 }
624
CreateTypefaceFromFile(const char path[])625 SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
626 SkStream* stream = SkNEW_ARGS(SkMMAPStream, (path));
627 SkTypeface* face = SkFontHost::CreateTypefaceFromStream(stream);
628 // since we created the stream, we let go of our ref() here
629 stream->unref();
630 return face;
631 }
632
633 ///////////////////////////////////////////////////////////////////////////////
634
ShouldPurgeFontCache(size_t sizeAllocatedSoFar)635 size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) {
636 if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET)
637 return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET;
638 else
639 return 0; // nothing to do
640 }
641
642