• 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 SkTypeface::Style find_name_and_style(SkStream* stream, SkString* name);
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         *style = find_name_and_style(&stream, name);
367         return true;
368     }
369     else {
370         SkFILEStream stream(fullpath.c_str());
371         if (stream.getLength() > 0) {
372             *style = find_name_and_style(&stream, name);
373             return true;
374         }
375     }
376 
377     if (isExpected) {
378         SkDebugf("---- failed to open <%s> as a font\n", fullpath.c_str());
379     }
380     return false;
381 }
382 
383 // used to record our notion of the pre-existing fonts
384 struct FontInitRec {
385     const char*         fFileName;
386     const char* const*  fNames;     // null-terminated list
387 };
388 
389 static const char* gSansNames[] = {
390     "sans-serif", "arial", "helvetica", "tahoma", "verdana", NULL
391 };
392 
393 static const char* gSerifNames[] = {
394     "serif", "times", "times new roman", "palatino", "georgia", "baskerville",
395     "goudy", "fantasy", "cursive", "ITC Stone Serif", NULL
396 };
397 
398 static const char* gMonoNames[] = {
399     "monospace", "courier", "courier new", "monaco", NULL
400 };
401 
402 // deliberately empty, but we use the address to identify fallback fonts
403 static const char* gFBNames[] = { NULL };
404 
405 /*  Fonts must be grouped by family, with the first font in a family having the
406     list of names (even if that list is empty), and the following members having
407     null for the list. The names list must be NULL-terminated
408 */
409 static const FontInitRec gSystemFonts[] = {
410     { "DroidSans.ttf",              gSansNames  },
411     { "DroidSans-Bold.ttf",         NULL        },
412     { "DroidSerif-Regular.ttf",     gSerifNames },
413     { "DroidSerif-Bold.ttf",        NULL        },
414     { "DroidSerif-Italic.ttf",      NULL        },
415     { "DroidSerif-BoldItalic.ttf",  NULL        },
416     { "DroidSansMono.ttf",          gMonoNames  },
417     /*  These are optional, and can be ignored if not found in the file system.
418         These are appended to gFallbackFonts[] as they are seen, so we list
419         them in the order we want them to be accessed by NextLogicalFont().
420      */
421     { "DroidSansJapanese.ttf",      gFBNames    },
422     { "DroidSansFallback.ttf",      gFBNames    }
423 };
424 
425 #define DEFAULT_NAMES   gSansNames
426 
427 // these globals are assigned (once) by load_system_fonts()
428 static FamilyRec* gDefaultFamily;
429 static SkTypeface* gDefaultNormal;
430 
431 /*  This is sized conservatively, assuming that it will never be a size issue.
432     It will be initialized in load_system_fonts(), and will be filled with the
433     fontIDs that can be used for fallback consideration, in sorted order (sorted
434     meaning element[0] should be used first, then element[1], etc. When we hit
435     a fontID==0 in the array, the list is done, hence our allocation size is
436     +1 the total number of possible system fonts. Also see NextLogicalFont().
437  */
438 static uint32_t gFallbackFonts[SK_ARRAY_COUNT(gSystemFonts)+1];
439 
440 /*  Called once (ensured by the sentinel check at the beginning of our body).
441     Initializes all the globals, and register the system fonts.
442  */
load_system_fonts()443 static void load_system_fonts() {
444     // check if we've already be called
445     if (NULL != gDefaultNormal) {
446         return;
447     }
448 
449     const FontInitRec* rec = gSystemFonts;
450     SkTypeface* firstInFamily = NULL;
451     int fallbackCount = 0;
452 
453     for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
454         // if we're the first in a new family, clear firstInFamily
455         if (rec[i].fNames != NULL) {
456             firstInFamily = NULL;
457         }
458 
459         SkString name;
460         SkTypeface::Style style;
461 
462         // we expect all the fonts, except the "fallback" fonts
463         bool isExpected = (rec[i].fNames != gFBNames);
464         if (!get_name_and_style(rec[i].fFileName, &name, &style, isExpected)) {
465             continue;
466         }
467 
468         SkTypeface* tf = SkNEW_ARGS(FileTypeface,
469                                     (style,
470                                      true,  // system-font (cannot delete)
471                                      firstInFamily, // what family to join
472                                      rec[i].fFileName) // filename
473                                     );
474 
475         if (rec[i].fNames != NULL) {
476             // see if this is one of our fallback fonts
477             if (rec[i].fNames == gFBNames) {
478             //    SkDebugf("---- adding %s as fallback[%d] fontID %d\n",
479             //             rec[i].fFileName, fallbackCount, tf->uniqueID());
480                 gFallbackFonts[fallbackCount++] = tf->uniqueID();
481             }
482 
483             firstInFamily = tf;
484             FamilyRec* family = find_family(tf);
485             const char* const* names = rec[i].fNames;
486 
487             // record the default family if this is it
488             if (names == DEFAULT_NAMES) {
489                 gDefaultFamily = family;
490             }
491             // add the names to map to this family
492             while (*names) {
493                 add_name(*names, family);
494                 names += 1;
495             }
496         }
497     }
498 
499     // do this after all fonts are loaded. This is our default font, and it
500     // acts as a sentinel so we only execute load_system_fonts() once
501     gDefaultNormal = find_best_face(gDefaultFamily, SkTypeface::kNormal);
502     // now terminate our fallback list with the sentinel value
503     gFallbackFonts[fallbackCount] = 0;
504 }
505 
506 ///////////////////////////////////////////////////////////////////////////////
507 
Serialize(const SkTypeface * face,SkWStream * stream)508 void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
509     const char* name = ((FamilyTypeface*)face)->getUniqueString();
510 
511     stream->write8((uint8_t)face->style());
512 
513     if (NULL == name || 0 == *name) {
514         stream->writePackedUInt(0);
515 //        SkDebugf("--- fonthost serialize null\n");
516     } else {
517         uint32_t len = strlen(name);
518         stream->writePackedUInt(len);
519         stream->write(name, len);
520 //      SkDebugf("--- fonthost serialize <%s> %d\n", name, face->style());
521     }
522 }
523 
Deserialize(SkStream * stream)524 SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
525     load_system_fonts();
526 
527     int style = stream->readU8();
528 
529     int len = stream->readPackedUInt();
530     if (len > 0) {
531         SkString str;
532         str.resize(len);
533         stream->read(str.writable_str(), len);
534 
535         const FontInitRec* rec = gSystemFonts;
536         for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
537             if (strcmp(rec[i].fFileName, str.c_str()) == 0) {
538                 // backup until we hit the fNames
539                 for (int j = i; j >= 0; --j) {
540                     if (rec[j].fNames != NULL) {
541                         return SkFontHost::CreateTypeface(NULL,
542                                     rec[j].fNames[0], (SkTypeface::Style)style);
543                     }
544                 }
545             }
546         }
547     }
548     return NULL;
549 }
550 
551 ///////////////////////////////////////////////////////////////////////////////
552 
CreateTypeface(const SkTypeface * familyFace,const char familyName[],SkTypeface::Style style)553 SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
554                                        const char familyName[],
555                                        SkTypeface::Style style) {
556     load_system_fonts();
557 
558     SkAutoMutexAcquire  ac(gFamilyMutex);
559 
560     // clip to legal style bits
561     style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
562 
563     SkTypeface* tf = NULL;
564 
565     if (NULL != familyFace) {
566         tf = find_typeface(familyFace, style);
567     } else if (NULL != familyName) {
568 //        SkDebugf("======= familyName <%s>\n", familyName);
569         tf = find_typeface(familyName, style);
570     }
571 
572     if (NULL == tf) {
573         tf = find_best_face(gDefaultFamily, style);
574     }
575 
576     // we ref(), since the symantic is to return a new instance
577     tf->ref();
578     return tf;
579 }
580 
ValidFontID(uint32_t fontID)581 bool SkFontHost::ValidFontID(uint32_t fontID) {
582     SkAutoMutexAcquire  ac(gFamilyMutex);
583 
584     return find_from_uniqueID(fontID) != NULL;
585 }
586 
OpenStream(uint32_t fontID)587 SkStream* SkFontHost::OpenStream(uint32_t fontID) {
588     SkAutoMutexAcquire  ac(gFamilyMutex);
589 
590     FamilyTypeface* tf = (FamilyTypeface*)find_from_uniqueID(fontID);
591     SkStream* stream = tf ? tf->openStream() : NULL;
592 
593     if (stream && stream->getLength() == 0) {
594         stream->unref();
595         stream = NULL;
596     }
597     return stream;
598 }
599 
GetFileName(SkFontID fontID,char path[],size_t length,int32_t * index)600 size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
601                                int32_t* index) {
602     SkAutoMutexAcquire  ac(gFamilyMutex);
603 
604     FamilyTypeface* tf = (FamilyTypeface*)find_from_uniqueID(fontID);
605     const char* src = tf ? tf->getFilePath() : NULL;
606 
607     if (src) {
608         size_t size = strlen(src);
609         if (path) {
610             memcpy(path, src, SkMin32(size, length));
611         }
612         if (index) {
613             *index = 0; // we don't have collections (yet)
614         }
615         return size;
616     } else {
617         return 0;
618     }
619 }
620 
NextLogicalFont(uint32_t fontID)621 uint32_t SkFontHost::NextLogicalFont(uint32_t fontID) {
622     load_system_fonts();
623 
624     /*  First see if fontID is already one of our fallbacks. If so, return
625         its successor. If fontID is not in our list, then return the first one
626         in our list. Note: list is zero-terminated, and returning zero means
627         we have no more fonts to use for fallbacks.
628      */
629     const uint32_t* list = gFallbackFonts;
630     for (int i = 0; list[i] != 0; i++) {
631         if (list[i] == fontID) {
632             return list[i+1];
633         }
634     }
635     return list[0];
636 }
637 
638 ///////////////////////////////////////////////////////////////////////////////
639 
CreateTypefaceFromStream(SkStream * stream)640 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
641     if (NULL == stream || stream->getLength() <= 0) {
642         return NULL;
643     }
644 
645     SkString name;
646     SkTypeface::Style style = find_name_and_style(stream, &name);
647 
648     return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream));
649 }
650 
CreateTypefaceFromFile(const char path[])651 SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
652     SkStream* stream = SkNEW_ARGS(SkMMAPStream, (path));
653     SkTypeface* face = SkFontHost::CreateTypefaceFromStream(stream);
654     // since we created the stream, we let go of our ref() here
655     stream->unref();
656     return face;
657 }
658 
659 ///////////////////////////////////////////////////////////////////////////////
660 
ShouldPurgeFontCache(size_t sizeAllocatedSoFar)661 size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) {
662     if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET)
663         return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET;
664     else
665         return 0;   // nothing to do
666 }
667 
668