|
1 |
|
2 /* |
|
3 * Copyright 2006 The Android Open Source Project |
|
4 * |
|
5 * Use of this source code is governed by a BSD-style license that can be |
|
6 * found in the LICENSE file. |
|
7 */ |
|
8 |
|
9 |
|
10 #include "SkFontDescriptor.h" |
|
11 #include "SkFontHost.h" |
|
12 #include "SkFontHost_FreeType_common.h" |
|
13 #include "SkDescriptor.h" |
|
14 #include "SkStream.h" |
|
15 #include "SkPaint.h" |
|
16 #include "SkString.h" |
|
17 #include "SkStream.h" |
|
18 #include "SkThread.h" |
|
19 #include "SkTSearch.h" |
|
20 #include <stdio.h> |
|
21 |
|
22 #define FONT_CACHE_MEMORY_BUDGET (768 * 1024) |
|
23 |
|
24 #ifndef SK_FONT_FILE_PREFIX |
|
25 #define SK_FONT_FILE_PREFIX "/fonts/" |
|
26 #endif |
|
27 |
|
28 bool find_name_and_attributes(SkStream* stream, SkString* name, SkTypeface::Style* style, |
|
29 bool* isFixedWidth); |
|
30 |
|
31 static void GetFullPathForSysFonts(SkString* full, const char name[]) { |
|
32 full->set(getenv("ANDROID_ROOT")); |
|
33 full->append(SK_FONT_FILE_PREFIX); |
|
34 full->append(name); |
|
35 } |
|
36 |
|
37 /////////////////////////////////////////////////////////////////////////////// |
|
38 |
|
39 struct FamilyRec; |
|
40 |
|
41 /* This guy holds a mapping of a name -> family, used for looking up fonts. |
|
42 Since it is stored in a stretchy array that doesn't preserve object |
|
43 semantics, we don't use constructor/destructors, but just have explicit |
|
44 helpers to manage our internal bookkeeping. |
|
45 */ |
|
46 struct NameFamilyPair { |
|
47 const char* fName; // we own this |
|
48 FamilyRec* fFamily; // we don't own this, we just reference it |
|
49 |
|
50 void construct(const char name[], FamilyRec* family) { |
|
51 fName = strdup(name); |
|
52 fFamily = family; // we don't own this, so just record the referene |
|
53 } |
|
54 |
|
55 void destruct() { |
|
56 free((char*)fName); |
|
57 // we don't own family, so just ignore our reference |
|
58 } |
|
59 }; |
|
60 |
|
61 // we use atomic_inc to grow this for each typeface we create |
|
62 static int32_t gUniqueFontID; |
|
63 |
|
64 // this is the mutex that protects these globals |
|
65 static SkMutex gFamilyMutex; |
|
66 static FamilyRec* gFamilyHead; |
|
67 static SkTDArray<NameFamilyPair> gNameList; |
|
68 |
|
69 struct FamilyRec { |
|
70 FamilyRec* fNext; |
|
71 SkTypeface* fFaces[4]; |
|
72 |
|
73 FamilyRec() |
|
74 { |
|
75 fNext = gFamilyHead; |
|
76 memset(fFaces, 0, sizeof(fFaces)); |
|
77 gFamilyHead = this; |
|
78 } |
|
79 }; |
|
80 |
|
81 static SkTypeface* find_best_face(const FamilyRec* family, |
|
82 SkTypeface::Style style) { |
|
83 SkTypeface* const* faces = family->fFaces; |
|
84 |
|
85 if (faces[style] != NULL) { // exact match |
|
86 return faces[style]; |
|
87 } |
|
88 // look for a matching bold |
|
89 style = (SkTypeface::Style)(style ^ SkTypeface::kItalic); |
|
90 if (faces[style] != NULL) { |
|
91 return faces[style]; |
|
92 } |
|
93 // look for the plain |
|
94 if (faces[SkTypeface::kNormal] != NULL) { |
|
95 return faces[SkTypeface::kNormal]; |
|
96 } |
|
97 // look for anything |
|
98 for (int i = 0; i < 4; i++) { |
|
99 if (faces[i] != NULL) { |
|
100 return faces[i]; |
|
101 } |
|
102 } |
|
103 // should never get here, since the faces list should not be empty |
|
104 SkASSERT(!"faces list is empty"); |
|
105 return NULL; |
|
106 } |
|
107 |
|
108 static FamilyRec* find_family(const SkTypeface* member) { |
|
109 FamilyRec* curr = gFamilyHead; |
|
110 while (curr != NULL) { |
|
111 for (int i = 0; i < 4; i++) { |
|
112 if (curr->fFaces[i] == member) { |
|
113 return curr; |
|
114 } |
|
115 } |
|
116 curr = curr->fNext; |
|
117 } |
|
118 return NULL; |
|
119 } |
|
120 |
|
121 /* Returns the matching typeface, or NULL. If a typeface is found, its refcnt |
|
122 is not modified. |
|
123 */ |
|
124 static SkTypeface* find_from_uniqueID(uint32_t uniqueID) { |
|
125 FamilyRec* curr = gFamilyHead; |
|
126 while (curr != NULL) { |
|
127 for (int i = 0; i < 4; i++) { |
|
128 SkTypeface* face = curr->fFaces[i]; |
|
129 if (face != NULL && face->uniqueID() == uniqueID) { |
|
130 return face; |
|
131 } |
|
132 } |
|
133 curr = curr->fNext; |
|
134 } |
|
135 return NULL; |
|
136 } |
|
137 |
|
138 /* Remove reference to this face from its family. If the resulting family |
|
139 is empty (has no faces), return that family, otherwise return NULL |
|
140 */ |
|
141 static FamilyRec* remove_from_family(const SkTypeface* face) { |
|
142 FamilyRec* family = find_family(face); |
|
143 SkASSERT(family->fFaces[face->style()] == face); |
|
144 family->fFaces[face->style()] = NULL; |
|
145 |
|
146 for (int i = 0; i < 4; i++) { |
|
147 if (family->fFaces[i] != NULL) { // family is non-empty |
|
148 return NULL; |
|
149 } |
|
150 } |
|
151 return family; // return the empty family |
|
152 } |
|
153 |
|
154 // maybe we should make FamilyRec be doubly-linked |
|
155 static void detach_and_delete_family(FamilyRec* family) { |
|
156 FamilyRec* curr = gFamilyHead; |
|
157 FamilyRec* prev = NULL; |
|
158 |
|
159 while (curr != NULL) { |
|
160 FamilyRec* next = curr->fNext; |
|
161 if (curr == family) { |
|
162 if (prev == NULL) { |
|
163 gFamilyHead = next; |
|
164 } else { |
|
165 prev->fNext = next; |
|
166 } |
|
167 SkDELETE(family); |
|
168 return; |
|
169 } |
|
170 prev = curr; |
|
171 curr = next; |
|
172 } |
|
173 SkASSERT(!"Yikes, couldn't find family in our list to remove/delete"); |
|
174 } |
|
175 |
|
176 static SkTypeface* find_typeface(const char name[], SkTypeface::Style style) { |
|
177 NameFamilyPair* list = gNameList.begin(); |
|
178 int count = gNameList.count(); |
|
179 |
|
180 int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0])); |
|
181 |
|
182 if (index >= 0) { |
|
183 return find_best_face(list[index].fFamily, style); |
|
184 } |
|
185 return NULL; |
|
186 } |
|
187 |
|
188 static SkTypeface* find_typeface(const SkTypeface* familyMember, |
|
189 SkTypeface::Style style) { |
|
190 const FamilyRec* family = find_family(familyMember); |
|
191 return family ? find_best_face(family, style) : NULL; |
|
192 } |
|
193 |
|
194 static void add_name(const char name[], FamilyRec* family) { |
|
195 SkAutoAsciiToLC tolc(name); |
|
196 name = tolc.lc(); |
|
197 |
|
198 NameFamilyPair* list = gNameList.begin(); |
|
199 int count = gNameList.count(); |
|
200 |
|
201 int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0])); |
|
202 |
|
203 if (index < 0) { |
|
204 list = gNameList.insert(~index); |
|
205 list->construct(name, family); |
|
206 } |
|
207 } |
|
208 |
|
209 static void remove_from_names(FamilyRec* emptyFamily) |
|
210 { |
|
211 #ifdef SK_DEBUG |
|
212 for (int i = 0; i < 4; i++) { |
|
213 SkASSERT(emptyFamily->fFaces[i] == NULL); |
|
214 } |
|
215 #endif |
|
216 |
|
217 SkTDArray<NameFamilyPair>& list = gNameList; |
|
218 |
|
219 // must go backwards when removing |
|
220 for (int i = list.count() - 1; i >= 0; --i) { |
|
221 NameFamilyPair* pair = &list[i]; |
|
222 if (pair->fFamily == emptyFamily) { |
|
223 pair->destruct(); |
|
224 list.remove(i); |
|
225 } |
|
226 } |
|
227 } |
|
228 |
|
229 /////////////////////////////////////////////////////////////////////////////// |
|
230 |
|
231 class FamilyTypeface : public SkTypeface_FreeType { |
|
232 public: |
|
233 FamilyTypeface(Style style, bool sysFont, SkTypeface* familyMember, |
|
234 bool isFixedWidth) |
|
235 : SkTypeface_FreeType(style, sk_atomic_inc(&gUniqueFontID) + 1, isFixedWidth) { |
|
236 fIsSysFont = sysFont; |
|
237 |
|
238 SkAutoMutexAcquire ac(gFamilyMutex); |
|
239 |
|
240 FamilyRec* rec = NULL; |
|
241 if (familyMember) { |
|
242 rec = find_family(familyMember); |
|
243 SkASSERT(rec); |
|
244 } else { |
|
245 rec = SkNEW(FamilyRec); |
|
246 } |
|
247 rec->fFaces[style] = this; |
|
248 } |
|
249 |
|
250 virtual ~FamilyTypeface() { |
|
251 SkAutoMutexAcquire ac(gFamilyMutex); |
|
252 |
|
253 // remove us from our family. If the family is now empty, we return |
|
254 // that and then remove that family from the name list |
|
255 FamilyRec* family = remove_from_family(this); |
|
256 if (NULL != family) { |
|
257 remove_from_names(family); |
|
258 detach_and_delete_family(family); |
|
259 } |
|
260 } |
|
261 |
|
262 bool isSysFont() const { return fIsSysFont; } |
|
263 |
|
264 virtual const char* getUniqueString() const = 0; |
|
265 virtual const char* getFilePath() const = 0; |
|
266 |
|
267 protected: |
|
268 virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE; |
|
269 |
|
270 private: |
|
271 bool fIsSysFont; |
|
272 |
|
273 typedef SkTypeface INHERITED; |
|
274 }; |
|
275 |
|
276 /////////////////////////////////////////////////////////////////////////////// |
|
277 |
|
278 class StreamTypeface : public FamilyTypeface { |
|
279 public: |
|
280 StreamTypeface(Style style, bool sysFont, SkTypeface* familyMember, |
|
281 SkStream* stream, bool isFixedWidth) |
|
282 : INHERITED(style, sysFont, familyMember, isFixedWidth) { |
|
283 SkASSERT(stream); |
|
284 stream->ref(); |
|
285 fStream = stream; |
|
286 } |
|
287 virtual ~StreamTypeface() { |
|
288 fStream->unref(); |
|
289 } |
|
290 |
|
291 // overrides |
|
292 virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE { |
|
293 *ttcIndex = 0; |
|
294 // we just ref our existing stream, since the caller will call unref() |
|
295 // when they are through |
|
296 fStream->ref(); |
|
297 // must rewind each time, since the caller assumes a "new" stream |
|
298 fStream->rewind(); |
|
299 return fStream; |
|
300 } |
|
301 virtual const char* getUniqueString() const { return NULL; } |
|
302 virtual const char* getFilePath() const { return NULL; } |
|
303 |
|
304 private: |
|
305 SkStream* fStream; |
|
306 |
|
307 typedef FamilyTypeface INHERITED; |
|
308 }; |
|
309 |
|
310 class FileTypeface : public FamilyTypeface { |
|
311 public: |
|
312 FileTypeface(Style style, bool sysFont, SkTypeface* familyMember, |
|
313 const char path[], bool isFixedWidth) |
|
314 : INHERITED(style, sysFont, familyMember, isFixedWidth) { |
|
315 SkString fullpath; |
|
316 |
|
317 if (sysFont) { |
|
318 GetFullPathForSysFonts(&fullpath, path); |
|
319 path = fullpath.c_str(); |
|
320 } |
|
321 fPath.set(path); |
|
322 } |
|
323 |
|
324 // overrides |
|
325 virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE { |
|
326 *ttcIndex = 0; |
|
327 SkStream* stream = SkNEW_ARGS(SkFILEStream, (fPath.c_str())); |
|
328 |
|
329 // check for failure |
|
330 if (stream->getLength() <= 0) { |
|
331 SkDELETE(stream); |
|
332 stream = NULL; |
|
333 } |
|
334 return stream; |
|
335 } |
|
336 virtual const char* getUniqueString() const { |
|
337 const char* str = strrchr(fPath.c_str(), '/'); |
|
338 if (str) { |
|
339 str += 1; // skip the '/' |
|
340 } |
|
341 return str; |
|
342 } |
|
343 virtual const char* getFilePath() const { |
|
344 return fPath.c_str(); |
|
345 } |
|
346 |
|
347 private: |
|
348 SkString fPath; |
|
349 |
|
350 typedef FamilyTypeface INHERITED; |
|
351 }; |
|
352 |
|
353 /////////////////////////////////////////////////////////////////////////////// |
|
354 /////////////////////////////////////////////////////////////////////////////// |
|
355 |
|
356 static bool get_name_and_style(const char path[], SkString* name, |
|
357 SkTypeface::Style* style, |
|
358 bool* isFixedWidth, bool isExpected) { |
|
359 SkString fullpath; |
|
360 GetFullPathForSysFonts(&fullpath, path); |
|
361 |
|
362 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(fullpath.c_str())); |
|
363 if (stream.get()) { |
|
364 find_name_and_attributes(stream, name, style, isFixedWidth); |
|
365 return true; |
|
366 } |
|
367 |
|
368 if (isExpected) { |
|
369 SkDebugf("---- failed to open <%s> as a font\n", fullpath.c_str()); |
|
370 } |
|
371 return false; |
|
372 } |
|
373 |
|
374 // used to record our notion of the pre-existing fonts |
|
375 struct FontInitRec { |
|
376 const char* fFileName; |
|
377 const char* const* fNames; // null-terminated list |
|
378 }; |
|
379 |
|
380 static const char* gSansNames[] = { |
|
381 "sans-serif", "arial", "helvetica", "tahoma", "verdana", NULL |
|
382 }; |
|
383 |
|
384 static const char* gSerifNames[] = { |
|
385 "serif", "times", "times new roman", "palatino", "georgia", "baskerville", |
|
386 "goudy", "fantasy", "cursive", "ITC Stone Serif", NULL |
|
387 }; |
|
388 |
|
389 static const char* gMonoNames[] = { |
|
390 "monospace", "courier", "courier new", "monaco", NULL |
|
391 }; |
|
392 |
|
393 // deliberately empty, but we use the address to identify fallback fonts |
|
394 static const char* gFBNames[] = { NULL }; |
|
395 |
|
396 /* Fonts must be grouped by family, with the first font in a family having the |
|
397 list of names (even if that list is empty), and the following members having |
|
398 null for the list. The names list must be NULL-terminated |
|
399 */ |
|
400 static const FontInitRec gSystemFonts[] = { |
|
401 { "DroidSans.ttf", gSansNames }, |
|
402 { "DroidSans-Bold.ttf", NULL }, |
|
403 { "DroidSerif-Regular.ttf", gSerifNames }, |
|
404 { "DroidSerif-Bold.ttf", NULL }, |
|
405 { "DroidSerif-Italic.ttf", NULL }, |
|
406 { "DroidSerif-BoldItalic.ttf", NULL }, |
|
407 { "DroidSansMono.ttf", gMonoNames }, |
|
408 /* These are optional, and can be ignored if not found in the file system. |
|
409 These are appended to gFallbackFonts[] as they are seen, so we list |
|
410 them in the order we want them to be accessed by NextLogicalFont(). |
|
411 */ |
|
412 { "DroidSansArabic.ttf", gFBNames }, |
|
413 { "DroidSansHebrew.ttf", gFBNames }, |
|
414 { "DroidSansThai.ttf", gFBNames }, |
|
415 { "MTLmr3m.ttf", gFBNames }, // Motoya Japanese Font |
|
416 { "MTLc3m.ttf", gFBNames }, // Motoya Japanese Font |
|
417 { "DroidSansJapanese.ttf", gFBNames }, |
|
418 { "DroidSansFallback.ttf", gFBNames } |
|
419 }; |
|
420 |
|
421 #define DEFAULT_NAMES gSansNames |
|
422 |
|
423 // these globals are assigned (once) by load_system_fonts() |
|
424 static FamilyRec* gDefaultFamily; |
|
425 static SkTypeface* gDefaultNormal; |
|
426 |
|
427 /* This is sized conservatively, assuming that it will never be a size issue. |
|
428 It will be initialized in load_system_fonts(), and will be filled with the |
|
429 fontIDs that can be used for fallback consideration, in sorted order (sorted |
|
430 meaning element[0] should be used first, then element[1], etc. When we hit |
|
431 a fontID==0 in the array, the list is done, hence our allocation size is |
|
432 +1 the total number of possible system fonts. Also see NextLogicalFont(). |
|
433 */ |
|
434 static uint32_t gFallbackFonts[SK_ARRAY_COUNT(gSystemFonts)+1]; |
|
435 |
|
436 /* Called once (ensured by the sentinel check at the beginning of our body). |
|
437 Initializes all the globals, and register the system fonts. |
|
438 */ |
|
439 static void load_system_fonts() { |
|
440 // check if we've already be called |
|
441 if (NULL != gDefaultNormal) { |
|
442 return; |
|
443 } |
|
444 |
|
445 const FontInitRec* rec = gSystemFonts; |
|
446 SkTypeface* firstInFamily = NULL; |
|
447 int fallbackCount = 0; |
|
448 |
|
449 for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) { |
|
450 // if we're the first in a new family, clear firstInFamily |
|
451 if (rec[i].fNames != NULL) { |
|
452 firstInFamily = NULL; |
|
453 } |
|
454 |
|
455 bool isFixedWidth; |
|
456 SkString name; |
|
457 SkTypeface::Style style; |
|
458 |
|
459 // we expect all the fonts, except the "fallback" fonts |
|
460 bool isExpected = (rec[i].fNames != gFBNames); |
|
461 if (!get_name_and_style(rec[i].fFileName, &name, &style, |
|
462 &isFixedWidth, isExpected)) { |
|
463 continue; |
|
464 } |
|
465 |
|
466 SkTypeface* tf = SkNEW_ARGS(FileTypeface, |
|
467 (style, |
|
468 true, // system-font (cannot delete) |
|
469 firstInFamily, // what family to join |
|
470 rec[i].fFileName, |
|
471 isFixedWidth) // filename |
|
472 ); |
|
473 |
|
474 if (rec[i].fNames != NULL) { |
|
475 // see if this is one of our fallback fonts |
|
476 if (rec[i].fNames == gFBNames) { |
|
477 // SkDebugf("---- adding %s as fallback[%d] fontID %d\n", |
|
478 // rec[i].fFileName, fallbackCount, tf->uniqueID()); |
|
479 gFallbackFonts[fallbackCount++] = tf->uniqueID(); |
|
480 } |
|
481 |
|
482 firstInFamily = tf; |
|
483 FamilyRec* family = find_family(tf); |
|
484 const char* const* names = rec[i].fNames; |
|
485 |
|
486 // record the default family if this is it |
|
487 if (names == DEFAULT_NAMES) { |
|
488 gDefaultFamily = family; |
|
489 } |
|
490 // add the names to map to this family |
|
491 while (*names) { |
|
492 add_name(*names, family); |
|
493 names += 1; |
|
494 } |
|
495 } |
|
496 } |
|
497 |
|
498 // do this after all fonts are loaded. This is our default font, and it |
|
499 // acts as a sentinel so we only execute load_system_fonts() once |
|
500 gDefaultNormal = find_best_face(gDefaultFamily, SkTypeface::kNormal); |
|
501 // now terminate our fallback list with the sentinel value |
|
502 gFallbackFonts[fallbackCount] = 0; |
|
503 } |
|
504 |
|
505 void FamilyTypeface::onGetFontDescriptor(SkFontDescriptor* desc, |
|
506 bool* isLocalStream) const { |
|
507 { |
|
508 SkAutoMutexAcquire ac(gFamilyMutex); |
|
509 //desc->setFamilyName(find_family_name(this)); |
|
510 desc->setFontFileName(this->getUniqueString()); |
|
511 } |
|
512 *isLocalStream = !this->isSysFont(); |
|
513 } |
|
514 |
|
515 /////////////////////////////////////////////////////////////////////////////// |
|
516 |
|
517 SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, |
|
518 const char familyName[], |
|
519 SkTypeface::Style style) { |
|
520 load_system_fonts(); |
|
521 |
|
522 SkAutoMutexAcquire ac(gFamilyMutex); |
|
523 |
|
524 // clip to legal style bits |
|
525 style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic); |
|
526 |
|
527 SkTypeface* tf = NULL; |
|
528 |
|
529 if (NULL != familyFace) { |
|
530 tf = find_typeface(familyFace, style); |
|
531 } else if (NULL != familyName) { |
|
532 // SkDebugf("======= familyName <%s>\n", familyName); |
|
533 tf = find_typeface(familyName, style); |
|
534 } |
|
535 |
|
536 if (NULL == tf) { |
|
537 tf = find_best_face(gDefaultFamily, style); |
|
538 } |
|
539 |
|
540 // we ref(), since the symantic is to return a new instance |
|
541 tf->ref(); |
|
542 return tf; |
|
543 } |
|
544 |
|
545 SkTypeface* SkAndroidNextLogicalTypeface(SkFontID currFontID, SkFontID origFontID, |
|
546 const SkPaintOptionsAndroid& options) { |
|
547 load_system_fonts(); |
|
548 |
|
549 /* First see if fontID is already one of our fallbacks. If so, return |
|
550 its successor. If fontID is not in our list, then return the first one |
|
551 in our list. Note: list is zero-terminated, and returning zero means |
|
552 we have no more fonts to use for fallbacks. |
|
553 */ |
|
554 const uint32_t* list = gFallbackFonts; |
|
555 for (int i = 0; list[i] != 0; i++) { |
|
556 if (list[i] == currFontID) { |
|
557 return find_from_uniqueID(list[i+1]); |
|
558 } |
|
559 } |
|
560 return find_from_uniqueID(list[0]); |
|
561 } |
|
562 |
|
563 /////////////////////////////////////////////////////////////////////////////// |
|
564 |
|
565 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) { |
|
566 if (NULL == stream || stream->getLength() <= 0) { |
|
567 return NULL; |
|
568 } |
|
569 |
|
570 bool isFixedWidth; |
|
571 SkString name; |
|
572 SkTypeface::Style style; |
|
573 find_name_and_attributes(stream, &name, &style, &isFixedWidth); |
|
574 |
|
575 if (!name.isEmpty()) { |
|
576 return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream, isFixedWidth)); |
|
577 } else { |
|
578 return NULL; |
|
579 } |
|
580 } |
|
581 |
|
582 SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) { |
|
583 SkStream* stream = SkNEW_ARGS(SkFILEStream, (path)); |
|
584 SkTypeface* face = SkFontHost::CreateTypefaceFromStream(stream); |
|
585 // since we created the stream, we let go of our ref() here |
|
586 stream->unref(); |
|
587 return face; |
|
588 } |
|
589 |