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