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