OLD | NEW |
| (Empty) |
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 | |
36 static 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 | |
45 struct 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 */ | |
52 struct 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 | |
69 static int32_t gUniqueFontID; | |
70 | |
71 // this is the mutex that protects these globals | |
72 static SkMutex gFamilyMutex; | |
73 static FamilyRec* gFamilyHead; | |
74 static SkTDArray<NameFamilyPair> gNameList; | |
75 | |
76 struct 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 | |
88 static 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 | |
116 static 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 | |
130 static 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 */ | |
148 static 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 | |
163 static 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 | |
185 static 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 | |
198 static 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 | |
205 static 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 | |
221 static 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 | |
243 class FamilyTypeface : public SkTypeface { | |
244 public: | |
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 | |
281 private: | |
282 bool fIsSysFont; | |
283 | |
284 typedef SkTypeface INHERITED; | |
285 }; | |
286 | |
287 /////////////////////////////////////////////////////////////////////////////// | |
288 | |
289 class StreamTypeface : public FamilyTypeface { | |
290 public: | |
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 | |
307 private: | |
308 SkStream* fStream; | |
309 | |
310 typedef FamilyTypeface INHERITED; | |
311 }; | |
312 | |
313 class FileTypeface : public FamilyTypeface { | |
314 public: | |
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 | |
357 private: | |
358 SkString fPath; | |
359 | |
360 typedef FamilyTypeface INHERITED; | |
361 }; | |
362 | |
363 /////////////////////////////////////////////////////////////////////////////// | |
364 /////////////////////////////////////////////////////////////////////////////// | |
365 | |
366 static 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 | |
389 struct FontInitRec { | |
390 const char* fFileName; | |
391 const char* const* fNames; // null-terminated list | |
392 }; | |
393 | |
394 static const char* gSansNames[] = { | |
395 "sans-serif", "arial", "helvetica", "tahoma", "verdana", NULL | |
396 }; | |
397 | |
398 static const char* gSerifNames[] = { | |
399 "serif", "times", "times new roman", "palatino", "georgia", "baskerville", | |
400 "goudy", "fantasy", "cursive", "ITC Stone Serif", NULL | |
401 }; | |
402 | |
403 static const char* gMonoNames[] = { | |
404 "monospace", "courier", "courier new", "monaco", NULL | |
405 }; | |
406 | |
407 static 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 */ | |
413 static 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 { "DroidSansFallback.ttf", gFBNames } | |
422 }; | |
423 | |
424 #define DEFAULT_NAMES gSansNames | |
425 | |
426 // these globals are assigned (once) by load_system_fonts() | |
427 static SkTypeface* gFallBackTypeface; | |
428 static FamilyRec* gDefaultFamily; | |
429 static SkTypeface* gDefaultNormal; | |
430 | |
431 static void load_system_fonts() | |
432 { | |
433 // check if we've already be called | |
434 if (NULL != gDefaultNormal) { | |
435 return; | |
436 } | |
437 | |
438 const FontInitRec* rec = gSystemFonts; | |
439 SkTypeface* firstInFamily = NULL; | |
440 | |
441 for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) { | |
442 // if we're the first in a new family, clear firstInFamily | |
443 if (rec[i].fNames != NULL) { | |
444 firstInFamily = NULL; | |
445 } | |
446 | |
447 SkString name; | |
448 SkTypeface::Style style; | |
449 | |
450 if (!get_name_and_style(rec[i].fFileName, &name, &style)) { | |
451 SkDebugf("------ can't load <%s> as a font\n", rec[i].fFileName); | |
452 continue; | |
453 } | |
454 | |
455 SkTypeface* tf = SkNEW_ARGS(FileTypeface, | |
456 (style, | |
457 true, // system-font (cannot delete) | |
458 firstInFamily, // what family to join | |
459 rec[i].fFileName) // filename | |
460 ); | |
461 | |
462 if (rec[i].fNames != NULL) { | |
463 firstInFamily = tf; | |
464 const char* const* names = rec[i].fNames; | |
465 | |
466 // record the fallback if this is it | |
467 if (names == gFBNames) { | |
468 gFallBackTypeface = tf; | |
469 } | |
470 // record the default family if this is it | |
471 if (names == DEFAULT_NAMES) { | |
472 gDefaultFamily = find_family(tf); | |
473 } | |
474 // add the names to map to this family | |
475 FamilyRec* family = find_family(tf); | |
476 while (*names) { | |
477 add_name(*names, family); | |
478 names += 1; | |
479 } | |
480 } | |
481 | |
482 } | |
483 | |
484 // do this after all fonts are loaded. This is our default font, and it | |
485 // acts as a sentinel so we only execute load_system_fonts() once | |
486 gDefaultNormal = find_best_face(gDefaultFamily, SkTypeface::kNormal); | |
487 } | |
488 | |
489 /////////////////////////////////////////////////////////////////////////////// | |
490 | |
491 void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) { | |
492 const char* name = ((FamilyTypeface*)face)->getUniqueString(); | |
493 | |
494 stream->write8((uint8_t)face->getStyle()); | |
495 | |
496 if (NULL == name || 0 == *name) { | |
497 stream->writePackedUInt(0); | |
498 // SkDebugf("--- fonthost serialize null\n"); | |
499 } else { | |
500 uint32_t len = strlen(name); | |
501 stream->writePackedUInt(len); | |
502 stream->write(name, len); | |
503 // SkDebugf("--- fonthost serialize <%s> %d\n", name, face->getStyle()); | |
504 } | |
505 } | |
506 | |
507 SkTypeface* SkFontHost::Deserialize(SkStream* stream) { | |
508 load_system_fonts(); | |
509 | |
510 int style = stream->readU8(); | |
511 | |
512 int len = stream->readPackedUInt(); | |
513 if (len > 0) { | |
514 SkString str; | |
515 str.resize(len); | |
516 stream->read(str.writable_str(), len); | |
517 | |
518 const FontInitRec* rec = gSystemFonts; | |
519 for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) { | |
520 if (strcmp(rec[i].fFileName, str.c_str()) == 0) { | |
521 // backup until we hit the fNames | |
522 for (int j = i; j >= 0; --j) { | |
523 if (rec[j].fNames != NULL) { | |
524 return SkFontHost::FindTypeface(NULL, rec[j].fNames[0], | |
525 (SkTypeface::Style)style); | |
526 } | |
527 } | |
528 } | |
529 } | |
530 } | |
531 return SkFontHost::FindTypeface(NULL, NULL, (SkTypeface::Style)style); | |
532 } | |
533 | |
534 /////////////////////////////////////////////////////////////////////////////// | |
535 | |
536 SkTypeface* SkFontHost::FindTypeface(const SkTypeface* familyFace, | |
537 const char familyName[], | |
538 SkTypeface::Style style) | |
539 { | |
540 load_system_fonts(); | |
541 | |
542 SkAutoMutexAcquire ac(gFamilyMutex); | |
543 | |
544 // clip to legal style bits | |
545 style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic); | |
546 | |
547 SkTypeface* tf = NULL; | |
548 | |
549 if (NULL != familyFace) { | |
550 tf = find_typeface(familyFace, style); | |
551 } else if (NULL != familyName) { | |
552 // SkDebugf("======= familyName <%s>\n", familyName); | |
553 tf = find_typeface(familyName, style); | |
554 } | |
555 | |
556 if (NULL == tf) { | |
557 tf = find_best_face(gDefaultFamily, style); | |
558 } | |
559 | |
560 return tf; | |
561 } | |
562 | |
563 SkTypeface* SkFontHost::ResolveTypeface(uint32_t fontID) | |
564 { | |
565 SkAutoMutexAcquire ac(gFamilyMutex); | |
566 | |
567 return resolve_uniqueID(fontID); | |
568 } | |
569 | |
570 SkStream* SkFontHost::OpenStream(uint32_t fontID) | |
571 { | |
572 | |
573 FamilyTypeface* tf = (FamilyTypeface*)SkFontHost::ResolveTypeface(fontID); | |
574 SkStream* stream = tf ? tf->openStream() : NULL; | |
575 | |
576 if (NULL == stream || stream->getLength() == 0) { | |
577 delete stream; | |
578 stream = NULL; | |
579 } | |
580 return stream; | |
581 } | |
582 | |
583 void SkFontHost::CloseStream(uint32_t fontID, SkStream* stream) | |
584 { | |
585 FamilyTypeface* tf = (FamilyTypeface*)SkFontHost::ResolveTypeface(fontID); | |
586 if (NULL != tf) { | |
587 tf->closeStream(stream); | |
588 } | |
589 } | |
590 | |
591 SkScalerContext* SkFontHost::CreateFallbackScalerContext( | |
592 const SkScalerContext::Rec& rec) | |
593 { | |
594 load_system_fonts(); | |
595 | |
596 SkAutoDescriptor ad(sizeof(rec) + SkDescriptor::ComputeOverhead(1)); | |
597 SkDescriptor* desc = ad.getDesc(); | |
598 | |
599 desc->init(); | |
600 SkScalerContext::Rec* newRec = | |
601 (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag, | |
602 sizeof(rec), &rec); | |
603 newRec->fFontID = gFallBackTypeface->uniqueID(); | |
604 desc->computeChecksum(); | |
605 | |
606 return SkFontHost::CreateScalerContext(desc); | |
607 } | |
608 | |
609 /////////////////////////////////////////////////////////////////////////////// | |
610 | |
611 SkTypeface* SkFontHost::CreateTypeface(SkStream* stream) | |
612 { | |
613 if (NULL == stream || stream->getLength() <= 0) { | |
614 SkDELETE(stream); | |
615 return NULL; | |
616 } | |
617 | |
618 SkString name; | |
619 SkTypeface::Style style = find_name_and_style(stream, &name); | |
620 | |
621 return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream)); | |
622 } | |
623 | |
624 /////////////////////////////////////////////////////////////////////////////// | |
625 | |
626 size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) | |
627 { | |
628 if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET) | |
629 return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET; | |
630 else | |
631 return 0; // nothing to do | |
632 } | |
633 | |
OLD | NEW |