blob: 8627106023c39ae3acdb68faa1d155e29fe8547f [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 "SkOSFile.h"
22#include "SkPaint.h"
23#include "SkString.h"
24#include "SkStream.h"
25#include "SkThread.h"
26#include "SkTSearch.h"
27#include <stdio.h>
28
29#define FONT_CACHE_MEMORY_BUDGET (1 * 1024 * 1024)
30
31#ifndef SK_FONT_FILE_PREFIX
32 #define SK_FONT_FILE_PREFIX "/usr/share/fonts/truetype/msttcorefonts/"
33#endif
34
35SkTypeface::Style find_name_and_style(SkStream* stream, SkString* name);
36
37static void GetFullPathForSysFonts(SkString* full, const char name[])
38{
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,
reed@android.com1bfd0ca2009-02-20 14:22:36 +000089 SkTypeface::Style style) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000090 SkTypeface* const* faces = family->fFaces;
91
92 if (faces[style] != NULL) { // exact match
93 return faces[style];
94 }
95 // look for a matching bold
96 style = (SkTypeface::Style)(style ^ SkTypeface::kItalic);
97 if (faces[style] != NULL) {
98 return faces[style];
99 }
100 // look for the plain
101 if (faces[SkTypeface::kNormal] != NULL) {
102 return faces[SkTypeface::kNormal];
103 }
104 // look for anything
105 for (int i = 0; i < 4; i++) {
106 if (faces[i] != NULL) {
107 return faces[i];
108 }
109 }
110 // should never get here, since the faces list should not be empty
111 SkASSERT(!"faces list is empty");
112 return NULL;
113}
114
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000115static FamilyRec* find_family(const SkTypeface* member) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000116 FamilyRec* curr = gFamilyHead;
117 while (curr != NULL) {
118 for (int i = 0; i < 4; i++) {
119 if (curr->fFaces[i] == member) {
120 return curr;
121 }
122 }
123 curr = curr->fNext;
124 }
125 return NULL;
126}
127
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000128static bool valid_uniqueID(uint32_t uniqueID) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000129 FamilyRec* curr = gFamilyHead;
130 while (curr != NULL) {
131 for (int i = 0; i < 4; i++) {
132 SkTypeface* face = curr->fFaces[i];
133 if (face != NULL && face->uniqueID() == uniqueID) {
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000134 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000135 }
136 }
137 curr = curr->fNext;
138 }
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000139 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000140}
141
142/* Remove reference to this face from its family. If the resulting family
143 is empty (has no faces), return that family, otherwise return NULL
144 */
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000145static FamilyRec* remove_from_family(const SkTypeface* face) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146 FamilyRec* family = find_family(face);
147 SkASSERT(family->fFaces[face->style()] == face);
148 family->fFaces[face->style()] = NULL;
149
150 for (int i = 0; i < 4; i++) {
151 if (family->fFaces[i] != NULL) { // family is non-empty
152 return NULL;
153 }
154 }
155 return family; // return the empty family
156}
157
158// maybe we should make FamilyRec be doubly-linked
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000159static void detach_and_delete_family(FamilyRec* family) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000160 FamilyRec* curr = gFamilyHead;
161 FamilyRec* prev = NULL;
162
163 while (curr != NULL) {
164 FamilyRec* next = curr->fNext;
165 if (curr == family) {
166 if (prev == NULL) {
167 gFamilyHead = next;
168 } else {
169 prev->fNext = next;
170 }
171 SkDELETE(family);
172 return;
173 }
174 prev = curr;
175 curr = next;
176 }
177 SkASSERT(!"Yikes, couldn't find family in our list to remove/delete");
178}
179
180static FamilyRec* find_familyrec(const char name[]) {
181 const NameFamilyPair* list = gNameList.begin();
182 int index = SkStrLCSearch(&list[0].fName, gNameList.count(), name,
183 sizeof(list[0]));
184 return index >= 0 ? list[index].fFamily : NULL;
185}
186
187static SkTypeface* find_typeface(const char name[], SkTypeface::Style style) {
188 FamilyRec* rec = find_familyrec(name);
189 return rec ? find_best_face(rec, style) : NULL;
190}
191
192static SkTypeface* find_typeface(const SkTypeface* familyMember,
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000193 SkTypeface::Style style) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000194 const FamilyRec* family = find_family(familyMember);
195 return family ? find_best_face(family, style) : NULL;
196}
197
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000198static void add_name(const char name[], FamilyRec* family) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000199 SkAutoAsciiToLC tolc(name);
200 name = tolc.lc();
201
202 NameFamilyPair* list = gNameList.begin();
203 int count = gNameList.count();
204
205 int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
206
207 if (index < 0) {
208 list = gNameList.insert(~index);
209 list->construct(name, family);
210 }
211}
212
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000213static void remove_from_names(FamilyRec* emptyFamily) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000214#ifdef SK_DEBUG
215 for (int i = 0; i < 4; i++) {
216 SkASSERT(emptyFamily->fFaces[i] == NULL);
217 }
218#endif
219
220 SkTDArray<NameFamilyPair>& list = gNameList;
221
222 // must go backwards when removing
223 for (int i = list.count() - 1; i >= 0; --i) {
224 NameFamilyPair* pair = &list[i];
225 if (pair->fFamily == emptyFamily) {
226 pair->destruct();
227 list.remove(i);
228 }
229 }
230}
231
232///////////////////////////////////////////////////////////////////////////////
233
234class FamilyTypeface : public SkTypeface {
235public:
236 FamilyTypeface(Style style, bool sysFont, FamilyRec* family)
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000237 : SkTypeface(style, sk_atomic_inc(&gUniqueFontID) + 1) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238 fIsSysFont = sysFont;
239
240 SkAutoMutexAcquire ac(gFamilyMutex);
241
242 if (NULL == family) {
243 family = SkNEW(FamilyRec);
244 }
245 family->fFaces[style] = this;
246 fFamilyRec = family; // just record it so we can return it if asked
247 }
248
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000249 virtual ~FamilyTypeface() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000250 SkAutoMutexAcquire ac(gFamilyMutex);
251
252 // remove us from our family. If the family is now empty, we return
253 // that and then remove that family from the name list
254 FamilyRec* family = remove_from_family(this);
255 if (NULL != family) {
256 remove_from_names(family);
257 detach_and_delete_family(family);
258 }
259 }
260
261 bool isSysFont() const { return fIsSysFont; }
262 FamilyRec* getFamily() const { return fFamilyRec; }
reed@android.com22dbaaf2009-05-18 00:43:58 +0000263 // openStream returns a SkStream that has been ref-ed
reed@android.com8a1c16f2008-12-17 15:59:43 +0000264 virtual SkStream* openStream() = 0;
265 virtual void closeStream(SkStream*) = 0;
266 virtual const char* getUniqueString() const = 0;
267
268private:
269 FamilyRec* fFamilyRec; // we don't own this, just point to it
270 bool fIsSysFont;
271
272 typedef SkTypeface INHERITED;
273};
274
275///////////////////////////////////////////////////////////////////////////////
276
277class StreamTypeface : public FamilyTypeface {
278public:
279 StreamTypeface(Style style, bool sysFont, FamilyRec* family,
280 SkStream* stream)
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000281 : INHERITED(style, sysFont, family) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000282 fStream = stream;
283 }
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000284 virtual ~StreamTypeface() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000285 SkDELETE(fStream);
286 }
287
288 // overrides
reed@android.com22dbaaf2009-05-18 00:43:58 +0000289 virtual SkStream* openStream()
290 {
291 // openStream returns a refed stream.
292 fStream->ref();
293 return fStream;
294 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000295 virtual void closeStream(SkStream*) {}
296 virtual const char* getUniqueString() const { return NULL; }
297
298private:
299 SkStream* fStream;
300
301 typedef FamilyTypeface INHERITED;
302};
303
304class FileTypeface : public FamilyTypeface {
305public:
306 FileTypeface(Style style, bool sysFont, FamilyRec* family,
307 const char path[])
308 : INHERITED(style, sysFont, family) {
309 fPath.set(path);
310 }
311
312 // overrides
313 virtual SkStream* openStream()
314 {
315 SkStream* stream = SkNEW_ARGS(SkMMAPStream, (fPath.c_str()));
316
317 // check for failure
318 if (stream->getLength() <= 0) {
319 SkDELETE(stream);
320 // maybe MMAP isn't supported. try FILE
321 stream = SkNEW_ARGS(SkFILEStream, (fPath.c_str()));
322 if (stream->getLength() <= 0) {
323 SkDELETE(stream);
324 stream = NULL;
325 }
326 }
327 return stream;
328 }
329 virtual void closeStream(SkStream* stream)
330 {
331 SkDELETE(stream);
332 }
333 virtual const char* getUniqueString() const {
334 const char* str = strrchr(fPath.c_str(), '/');
335 if (str) {
336 str += 1; // skip the '/'
337 }
338 return str;
339 }
340
341private:
342 SkString fPath;
343
344 typedef FamilyTypeface INHERITED;
345};
346
347///////////////////////////////////////////////////////////////////////////////
348///////////////////////////////////////////////////////////////////////////////
349
350static bool get_name_and_style(const char path[], SkString* name,
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000351 SkTypeface::Style* style) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000352 SkMMAPStream stream(path);
353 if (stream.getLength() > 0) {
354 *style = find_name_and_style(&stream, name);
355 return true;
356 }
357 else {
358 SkFILEStream stream(path);
359 if (stream.getLength() > 0) {
360 *style = find_name_and_style(&stream, name);
361 return true;
362 }
363 }
364
365 SkDebugf("---- failed to open <%s> as a font\n", path);
366 return false;
367}
368
369// these globals are assigned (once) by load_system_fonts()
370static SkTypeface* gFallBackTypeface;
371static FamilyRec* gDefaultFamily;
372static SkTypeface* gDefaultNormal;
373
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000374static void load_system_fonts() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000375 // check if we've already be called
376 if (NULL != gDefaultNormal) {
377 return;
378 }
379
380 SkOSFile::Iter iter(SK_FONT_FILE_PREFIX, ".ttf");
381 SkString name;
382
383 while (iter.next(&name, false)) {
384 SkString filename;
385 GetFullPathForSysFonts(&filename, name.c_str());
386// while (filename.size() == 0) { filename.set("/usr/share/fonts/truetype/msttcorefonts/Arial.ttf");
387
388 SkString realname;
389 SkTypeface::Style style;
390
391 if (!get_name_and_style(filename.c_str(), &realname, &style)) {
392 SkDebugf("------ can't load <%s> as a font\n", filename.c_str());
393 continue;
394 }
395
396// SkDebugf("font: <%s> %d <%s>\n", realname.c_str(), style, filename.c_str());
397
398 FamilyRec* family = find_familyrec(realname.c_str());
399 // this constructor puts us into the global gFamilyHead llist
400 FamilyTypeface* tf = SkNEW_ARGS(FileTypeface,
401 (style,
402 true, // system-font (cannot delete)
403 family, // what family to join
404 filename.c_str()) // filename
405 );
406
407 if (NULL == family) {
408 add_name(realname.c_str(), tf->getFamily());
409 }
410 }
411
412 // do this after all fonts are loaded. This is our default font, and it
413 // acts as a sentinel so we only execute load_system_fonts() once
414 static const char* gDefaultNames[] = {
415 "Arial", "Verdana", "Times New Roman", NULL
416 };
417 const char** names = gDefaultNames;
418 while (*names) {
419 SkTypeface* tf = find_typeface(*names++, SkTypeface::kNormal);
420 if (tf) {
421 gDefaultNormal = tf;
422 break;
423 }
424 }
425 // check if we found *something*
426 if (NULL == gDefaultNormal) {
427 if (NULL == gFamilyHead) {
428 sk_throw();
429 }
430 for (int i = 0; i < 4; i++) {
431 if ((gDefaultNormal = gFamilyHead->fFaces[i]) != NULL) {
432 break;
433 }
434 }
435 }
436 if (NULL == gDefaultNormal) {
437 sk_throw();
438 }
439 gFallBackTypeface = gDefaultNormal;
440 gDefaultFamily = find_family(gDefaultNormal);
441
442// SkDebugf("---- default %p head %p family %p\n", gDefaultNormal, gFamilyHead, gDefaultFamily);
443}
444
445///////////////////////////////////////////////////////////////////////////////
446
447void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
448#if 0
449 const char* name = ((FamilyTypeface*)face)->getUniqueString();
450
451 stream->write8((uint8_t)face->getStyle());
452
453 if (NULL == name || 0 == *name) {
454 stream->writePackedUInt(0);
455 // SkDebugf("--- fonthost serialize null\n");
456 } else {
457 uint32_t len = strlen(name);
458 stream->writePackedUInt(len);
459 stream->write(name, len);
460 // SkDebugf("--- fonthost serialize <%s> %d\n", name, face->getStyle());
461 }
462#endif
463 sk_throw();
464}
465
466SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
467#if 0
468 load_system_fonts();
469
470 int style = stream->readU8();
471
472 int len = stream->readPackedUInt();
473 if (len > 0) {
474 SkString str;
475 str.resize(len);
476 stream->read(str.writable_str(), len);
477
478 const FontInitRec* rec = gSystemFonts;
479 for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
480 if (strcmp(rec[i].fFileName, str.c_str()) == 0) {
481 // backup until we hit the fNames
482 for (int j = i; j >= 0; --j) {
483 if (rec[j].fNames != NULL) {
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000484 return SkFontHost::CreateTypeface(NULL, rec[j].fNames[0],
485 (SkTypeface::Style)style);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000486 }
487 }
488 }
489 }
490 }
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000491 return SkFontHost::CreateTypeface(NULL, NULL, (SkTypeface::Style)style);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000492#endif
493 sk_throw();
reed@android.com6f252972009-01-14 16:46:16 +0000494 return NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000495}
496
497///////////////////////////////////////////////////////////////////////////////
498
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000499SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
500 const char familyName[],
501 SkTypeface::Style style) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000502 load_system_fonts();
503
504 SkAutoMutexAcquire ac(gFamilyMutex);
505
506 // clip to legal style bits
507 style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
508
509 SkTypeface* tf = NULL;
510
511 if (NULL != familyFace) {
512 tf = find_typeface(familyFace, style);
513 } else if (NULL != familyName) {
514 // SkDebugf("======= familyName <%s>\n", familyName);
515 tf = find_typeface(familyName, style);
516 }
517
518 if (NULL == tf) {
519 tf = find_best_face(gDefaultFamily, style);
520 }
521
522 return tf;
523}
524
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000525SkTypeface* SkFontHost::ValidFontID(uint32_t fontID) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000526 SkAutoMutexAcquire ac(gFamilyMutex);
527
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000528 return valid_uniqueID(fontID);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000529}
530
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000531SkStream* SkFontHost::OpenStream(uint32_t fontID) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000532 FamilyTypeface* tf = (FamilyTypeface*)SkFontHost::ResolveTypeface(fontID);
533 SkStream* stream = tf ? tf->openStream() : NULL;
534
535 if (NULL == stream || stream->getLength() == 0) {
536 delete stream;
537 stream = NULL;
538 }
539 return stream;
540}
541
reed@android.comac981542009-07-31 16:17:01 +0000542size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
543 int32_t* index) {
544 SkDebugf("SkFontHost::GetFileName unimplemented\n");
545 return 0;
546}
547
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000548void SkFontHost::CloseStream(uint32_t fontID, SkStream* stream) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000549 FamilyTypeface* tf = (FamilyTypeface*)SkFontHost::ResolveTypeface(fontID);
550 if (NULL != tf) {
551 tf->closeStream(stream);
552 }
553}
554
555SkScalerContext* SkFontHost::CreateFallbackScalerContext(
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000556 const SkScalerContext::Rec& rec) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000557 load_system_fonts();
558
559 SkAutoDescriptor ad(sizeof(rec) + SkDescriptor::ComputeOverhead(1));
560 SkDescriptor* desc = ad.getDesc();
561
562 desc->init();
563 SkScalerContext::Rec* newRec =
564 (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag,
565 sizeof(rec), &rec);
566 newRec->fFontID = gFallBackTypeface->uniqueID();
567 desc->computeChecksum();
568
569 return SkFontHost::CreateScalerContext(desc);
570}
571
572///////////////////////////////////////////////////////////////////////////////
573
reed@android.comb1d9d2e2009-03-04 17:37:51 +0000574SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000575 if (NULL == stream || stream->getLength() <= 0) {
576 SkDELETE(stream);
577 return NULL;
578 }
579
580 SkString name;
581 SkTypeface::Style style = find_name_and_style(stream, &name);
582
583 return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream));
584}
585
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000586SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
587 SkTypeface* face = NULL;
588 SkFILEStream* stream = SkNEW_ARGS(SkFILEStream, (path));
589
590 if (stream->isValid()) {
reed@android.comff7f3892009-02-20 21:11:40 +0000591 return CreateTypeface(stream);
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000592 }
593 stream->unref();
reed@android.comff7f3892009-02-20 21:11:40 +0000594 return NULL;
reed@android.com0becfc5b2009-01-13 13:26:44 +0000595}
596
reed@android.com8a1c16f2008-12-17 15:59:43 +0000597///////////////////////////////////////////////////////////////////////////////
598
reed@android.com1bfd0ca2009-02-20 14:22:36 +0000599size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000600 if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET)
601 return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET;
602 else
603 return 0; // nothing to do
604}
605