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 "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 | |
35 SkTypeface::Style find_name_and_style(SkStream* stream, SkString* name); | |
36 | |
37 static void GetFullPathForSysFonts(SkString* full, const char name[]) | |
38 { | |
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 FamilyRec* find_familyrec(const char name[]) { | |
186 const NameFamilyPair* list = gNameList.begin(); | |
187 int index = SkStrLCSearch(&list[0].fName, gNameList.count(), name, | |
188 sizeof(list[0])); | |
189 return index >= 0 ? list[index].fFamily : NULL; | |
190 } | |
191 | |
192 static SkTypeface* find_typeface(const char name[], SkTypeface::Style style) { | |
193 FamilyRec* rec = find_familyrec(name); | |
194 return rec ? find_best_face(rec, style) : NULL; | |
195 } | |
196 | |
197 static SkTypeface* find_typeface(const SkTypeface* familyMember, | |
198 SkTypeface::Style style) | |
199 { | |
200 const FamilyRec* family = find_family(familyMember); | |
201 return family ? find_best_face(family, style) : NULL; | |
202 } | |
203 | |
204 static void add_name(const char name[], FamilyRec* family) | |
205 { | |
206 SkAutoAsciiToLC tolc(name); | |
207 name = tolc.lc(); | |
208 | |
209 NameFamilyPair* list = gNameList.begin(); | |
210 int count = gNameList.count(); | |
211 | |
212 int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0])); | |
213 | |
214 if (index < 0) { | |
215 list = gNameList.insert(~index); | |
216 list->construct(name, family); | |
217 } | |
218 } | |
219 | |
220 static void remove_from_names(FamilyRec* emptyFamily) | |
221 { | |
222 #ifdef SK_DEBUG | |
223 for (int i = 0; i < 4; i++) { | |
224 SkASSERT(emptyFamily->fFaces[i] == NULL); | |
225 } | |
226 #endif | |
227 | |
228 SkTDArray<NameFamilyPair>& list = gNameList; | |
229 | |
230 // must go backwards when removing | |
231 for (int i = list.count() - 1; i >= 0; --i) { | |
232 NameFamilyPair* pair = &list[i]; | |
233 if (pair->fFamily == emptyFamily) { | |
234 pair->destruct(); | |
235 list.remove(i); | |
236 } | |
237 } | |
238 } | |
239 | |
240 /////////////////////////////////////////////////////////////////////////////// | |
241 | |
242 class FamilyTypeface : public SkTypeface { | |
243 public: | |
244 FamilyTypeface(Style style, bool sysFont, FamilyRec* family) | |
245 : SkTypeface(style, sk_atomic_inc(&gUniqueFontID) + 1) | |
246 { | |
247 fIsSysFont = sysFont; | |
248 | |
249 SkAutoMutexAcquire ac(gFamilyMutex); | |
250 | |
251 if (NULL == family) { | |
252 family = SkNEW(FamilyRec); | |
253 } | |
254 family->fFaces[style] = this; | |
255 fFamilyRec = family; // just record it so we can return it if asked | |
256 } | |
257 | |
258 virtual ~FamilyTypeface() | |
259 { | |
260 SkAutoMutexAcquire ac(gFamilyMutex); | |
261 | |
262 // remove us from our family. If the family is now empty, we return | |
263 // that and then remove that family from the name list | |
264 FamilyRec* family = remove_from_family(this); | |
265 if (NULL != family) { | |
266 remove_from_names(family); | |
267 detach_and_delete_family(family); | |
268 } | |
269 } | |
270 | |
271 bool isSysFont() const { return fIsSysFont; } | |
272 FamilyRec* getFamily() const { return fFamilyRec; } | |
273 | |
274 virtual SkStream* openStream() = 0; | |
275 virtual void closeStream(SkStream*) = 0; | |
276 virtual const char* getUniqueString() const = 0; | |
277 | |
278 private: | |
279 FamilyRec* fFamilyRec; // we don't own this, just point to it | |
280 bool fIsSysFont; | |
281 | |
282 typedef SkTypeface INHERITED; | |
283 }; | |
284 | |
285 /////////////////////////////////////////////////////////////////////////////// | |
286 | |
287 class StreamTypeface : public FamilyTypeface { | |
288 public: | |
289 StreamTypeface(Style style, bool sysFont, FamilyRec* family, | |
290 SkStream* stream) | |
291 : INHERITED(style, sysFont, family) | |
292 { | |
293 fStream = stream; | |
294 } | |
295 virtual ~StreamTypeface() | |
296 { | |
297 SkDELETE(fStream); | |
298 } | |
299 | |
300 // overrides | |
301 virtual SkStream* openStream() { return fStream; } | |
302 virtual void closeStream(SkStream*) {} | |
303 virtual const char* getUniqueString() const { return NULL; } | |
304 | |
305 private: | |
306 SkStream* fStream; | |
307 | |
308 typedef FamilyTypeface INHERITED; | |
309 }; | |
310 | |
311 class FileTypeface : public FamilyTypeface { | |
312 public: | |
313 FileTypeface(Style style, bool sysFont, FamilyRec* family, | |
314 const char path[]) | |
315 : INHERITED(style, sysFont, family) { | |
316 fPath.set(path); | |
317 } | |
318 | |
319 // overrides | |
320 virtual SkStream* openStream() | |
321 { | |
322 SkStream* stream = SkNEW_ARGS(SkMMAPStream, (fPath.c_str())); | |
323 | |
324 // check for failure | |
325 if (stream->getLength() <= 0) { | |
326 SkDELETE(stream); | |
327 // maybe MMAP isn't supported. try FILE | |
328 stream = SkNEW_ARGS(SkFILEStream, (fPath.c_str())); | |
329 if (stream->getLength() <= 0) { | |
330 SkDELETE(stream); | |
331 stream = NULL; | |
332 } | |
333 } | |
334 return stream; | |
335 } | |
336 virtual void closeStream(SkStream* stream) | |
337 { | |
338 SkDELETE(stream); | |
339 } | |
340 virtual const char* getUniqueString() const { | |
341 const char* str = strrchr(fPath.c_str(), '/'); | |
342 if (str) { | |
343 str += 1; // skip the '/' | |
344 } | |
345 return str; | |
346 } | |
347 | |
348 private: | |
349 SkString fPath; | |
350 | |
351 typedef FamilyTypeface INHERITED; | |
352 }; | |
353 | |
354 /////////////////////////////////////////////////////////////////////////////// | |
355 /////////////////////////////////////////////////////////////////////////////// | |
356 | |
357 static bool get_name_and_style(const char path[], SkString* name, | |
358 SkTypeface::Style* style) | |
359 { | |
360 SkMMAPStream stream(path); | |
361 if (stream.getLength() > 0) { | |
362 *style = find_name_and_style(&stream, name); | |
363 return true; | |
364 } | |
365 else { | |
366 SkFILEStream stream(path); | |
367 if (stream.getLength() > 0) { | |
368 *style = find_name_and_style(&stream, name); | |
369 return true; | |
370 } | |
371 } | |
372 | |
373 SkDebugf("---- failed to open <%s> as a font\n", path); | |
374 return false; | |
375 } | |
376 | |
377 // these globals are assigned (once) by load_system_fonts() | |
378 static SkTypeface* gFallBackTypeface; | |
379 static FamilyRec* gDefaultFamily; | |
380 static SkTypeface* gDefaultNormal; | |
381 | |
382 static void load_system_fonts() | |
383 { | |
384 // check if we've already be called | |
385 if (NULL != gDefaultNormal) { | |
386 return; | |
387 } | |
388 | |
389 SkOSFile::Iter iter(SK_FONT_FILE_PREFIX, ".ttf"); | |
390 SkString name; | |
391 | |
392 while (iter.next(&name, false)) { | |
393 SkString filename; | |
394 GetFullPathForSysFonts(&filename, name.c_str()); | |
395 // while (filename.size() == 0) { filename.set("/usr/share/fonts/truetype/mst
tcorefonts/Arial.ttf"); | |
396 | |
397 SkString realname; | |
398 SkTypeface::Style style; | |
399 | |
400 if (!get_name_and_style(filename.c_str(), &realname, &style)) { | |
401 SkDebugf("------ can't load <%s> as a font\n", filename.c_str()); | |
402 continue; | |
403 } | |
404 | |
405 // SkDebugf("font: <%s> %d <%s>\n", realname.c_str(), style, filename.c_s
tr()); | |
406 | |
407 FamilyRec* family = find_familyrec(realname.c_str()); | |
408 // this constructor puts us into the global gFamilyHead llist | |
409 FamilyTypeface* tf = SkNEW_ARGS(FileTypeface, | |
410 (style, | |
411 true, // system-font (cannot delete) | |
412 family, // what family to join | |
413 filename.c_str()) // filename | |
414 ); | |
415 | |
416 if (NULL == family) { | |
417 add_name(realname.c_str(), tf->getFamily()); | |
418 } | |
419 } | |
420 | |
421 // do this after all fonts are loaded. This is our default font, and it | |
422 // acts as a sentinel so we only execute load_system_fonts() once | |
423 static const char* gDefaultNames[] = { | |
424 "Arial", "Verdana", "Times New Roman", NULL | |
425 }; | |
426 const char** names = gDefaultNames; | |
427 while (*names) { | |
428 SkTypeface* tf = find_typeface(*names++, SkTypeface::kNormal); | |
429 if (tf) { | |
430 gDefaultNormal = tf; | |
431 break; | |
432 } | |
433 } | |
434 // check if we found *something* | |
435 if (NULL == gDefaultNormal) { | |
436 if (NULL == gFamilyHead) { | |
437 sk_throw(); | |
438 } | |
439 for (int i = 0; i < 4; i++) { | |
440 if ((gDefaultNormal = gFamilyHead->fFaces[i]) != NULL) { | |
441 break; | |
442 } | |
443 } | |
444 } | |
445 if (NULL == gDefaultNormal) { | |
446 sk_throw(); | |
447 } | |
448 gFallBackTypeface = gDefaultNormal; | |
449 gDefaultFamily = find_family(gDefaultNormal); | |
450 | |
451 // SkDebugf("---- default %p head %p family %p\n", gDefaultNormal, gFamilyHea
d, gDefaultFamily); | |
452 } | |
453 | |
454 /////////////////////////////////////////////////////////////////////////////// | |
455 | |
456 void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) { | |
457 #if 0 | |
458 const char* name = ((FamilyTypeface*)face)->getUniqueString(); | |
459 | |
460 stream->write8((uint8_t)face->getStyle()); | |
461 | |
462 if (NULL == name || 0 == *name) { | |
463 stream->writePackedUInt(0); | |
464 // SkDebugf("--- fonthost serialize null\n"); | |
465 } else { | |
466 uint32_t len = strlen(name); | |
467 stream->writePackedUInt(len); | |
468 stream->write(name, len); | |
469 // SkDebugf("--- fonthost serialize <%s> %d\n", name, face->getStyl
e()); | |
470 } | |
471 #endif | |
472 sk_throw(); | |
473 } | |
474 | |
475 SkTypeface* SkFontHost::Deserialize(SkStream* stream) { | |
476 #if 0 | |
477 load_system_fonts(); | |
478 | |
479 int style = stream->readU8(); | |
480 | |
481 int len = stream->readPackedUInt(); | |
482 if (len > 0) { | |
483 SkString str; | |
484 str.resize(len); | |
485 stream->read(str.writable_str(), len); | |
486 | |
487 const FontInitRec* rec = gSystemFonts; | |
488 for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) { | |
489 if (strcmp(rec[i].fFileName, str.c_str()) == 0) { | |
490 // backup until we hit the fNames | |
491 for (int j = i; j >= 0; --j) { | |
492 if (rec[j].fNames != NULL) { | |
493 return SkFontHost::FindTypeface(NULL, rec[j].fNames[0], | |
494 (SkTypeface::Style)style
); | |
495 } | |
496 } | |
497 } | |
498 } | |
499 } | |
500 return SkFontHost::FindTypeface(NULL, NULL, (SkTypeface::Style)style); | |
501 #endif | |
502 sk_throw(); | |
503 } | |
504 | |
505 /////////////////////////////////////////////////////////////////////////////// | |
506 | |
507 SkTypeface* SkFontHost::FindTypeface(const SkTypeface* familyFace, | |
508 const char familyName[], | |
509 SkTypeface::Style style) | |
510 { | |
511 load_system_fonts(); | |
512 | |
513 SkAutoMutexAcquire ac(gFamilyMutex); | |
514 | |
515 // clip to legal style bits | |
516 style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic); | |
517 | |
518 SkTypeface* tf = NULL; | |
519 | |
520 if (NULL != familyFace) { | |
521 tf = find_typeface(familyFace, style); | |
522 } else if (NULL != familyName) { | |
523 // SkDebugf("======= familyName <%s>\n", familyName); | |
524 tf = find_typeface(familyName, style); | |
525 } | |
526 | |
527 if (NULL == tf) { | |
528 tf = find_best_face(gDefaultFamily, style); | |
529 } | |
530 | |
531 return tf; | |
532 } | |
533 | |
534 SkTypeface* SkFontHost::ResolveTypeface(uint32_t fontID) | |
535 { | |
536 SkAutoMutexAcquire ac(gFamilyMutex); | |
537 | |
538 return resolve_uniqueID(fontID); | |
539 } | |
540 | |
541 SkStream* SkFontHost::OpenStream(uint32_t fontID) | |
542 { | |
543 | |
544 FamilyTypeface* tf = (FamilyTypeface*)SkFontHost::ResolveTypeface(fontID); | |
545 SkStream* stream = tf ? tf->openStream() : NULL; | |
546 | |
547 if (NULL == stream || stream->getLength() == 0) { | |
548 delete stream; | |
549 stream = NULL; | |
550 } | |
551 return stream; | |
552 } | |
553 | |
554 void SkFontHost::CloseStream(uint32_t fontID, SkStream* stream) | |
555 { | |
556 FamilyTypeface* tf = (FamilyTypeface*)SkFontHost::ResolveTypeface(fontID); | |
557 if (NULL != tf) { | |
558 tf->closeStream(stream); | |
559 } | |
560 } | |
561 | |
562 SkScalerContext* SkFontHost::CreateFallbackScalerContext( | |
563 const SkScalerContext::
Rec& rec) | |
564 { | |
565 load_system_fonts(); | |
566 | |
567 SkAutoDescriptor ad(sizeof(rec) + SkDescriptor::ComputeOverhead(1)); | |
568 SkDescriptor* desc = ad.getDesc(); | |
569 | |
570 desc->init(); | |
571 SkScalerContext::Rec* newRec = | |
572 (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag, | |
573 sizeof(rec), &rec); | |
574 newRec->fFontID = gFallBackTypeface->uniqueID(); | |
575 desc->computeChecksum(); | |
576 | |
577 return SkFontHost::CreateScalerContext(desc); | |
578 } | |
579 | |
580 /////////////////////////////////////////////////////////////////////////////// | |
581 | |
582 SkTypeface* SkFontHost::CreateTypeface(SkStream* stream) | |
583 { | |
584 if (NULL == stream || stream->getLength() <= 0) { | |
585 SkDELETE(stream); | |
586 return NULL; | |
587 } | |
588 | |
589 SkString name; | |
590 SkTypeface::Style style = find_name_and_style(stream, &name); | |
591 | |
592 return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream)); | |
593 } | |
594 | |
595 /////////////////////////////////////////////////////////////////////////////// | |
596 | |
597 size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) | |
598 { | |
599 if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET) | |
600 return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET; | |
601 else | |
602 return 0; // nothing to do | |
603 } | |
604 | |
OLD | NEW |