• 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 
271 private:
272     bool    fIsSysFont;
273 
274     typedef SkTypeface INHERITED;
275 };
276 
277 ///////////////////////////////////////////////////////////////////////////////
278 
279 class StreamTypeface : public FamilyTypeface {
280 public:
StreamTypeface(Style style,bool sysFont,SkTypeface * familyMember,SkStream * stream)281     StreamTypeface(Style style, bool sysFont, SkTypeface* familyMember,
282                    SkStream* stream)
283     : INHERITED(style, sysFont, familyMember) {
284         SkASSERT(stream);
285         stream->ref();
286         fStream = stream;
287     }
~StreamTypeface()288     virtual ~StreamTypeface() {
289         fStream->unref();
290     }
291 
292     // overrides
openStream()293     virtual SkStream* openStream() {
294         // we just ref our existing stream, since the caller will call unref()
295         // when they are through
296         fStream->ref();
297         return fStream;
298     }
getUniqueString() const299     virtual const char* getUniqueString() const { return NULL; }
300 
301 private:
302     SkStream* fStream;
303 
304     typedef FamilyTypeface INHERITED;
305 };
306 
307 class FileTypeface : public FamilyTypeface {
308 public:
FileTypeface(Style style,bool sysFont,SkTypeface * familyMember,const char path[])309     FileTypeface(Style style, bool sysFont, SkTypeface* familyMember,
310                  const char path[])
311     : INHERITED(style, sysFont, familyMember) {
312         SkString fullpath;
313 
314         if (sysFont) {
315             GetFullPathForSysFonts(&fullpath, path);
316             path = fullpath.c_str();
317         }
318         fPath.set(path);
319     }
320 
321     // overrides
openStream()322     virtual SkStream* openStream() {
323         SkStream* stream = SkNEW_ARGS(SkMMAPStream, (fPath.c_str()));
324 
325         // check for failure
326         if (stream->getLength() <= 0) {
327             SkDELETE(stream);
328             // maybe MMAP isn't supported. try FILE
329             stream = SkNEW_ARGS(SkFILEStream, (fPath.c_str()));
330             if (stream->getLength() <= 0) {
331                 SkDELETE(stream);
332                 stream = NULL;
333             }
334         }
335         return stream;
336     }
getUniqueString() const337     virtual const char* getUniqueString() const {
338         const char* str = strrchr(fPath.c_str(), '/');
339         if (str) {
340             str += 1;   // skip the '/'
341         }
342         return str;
343     }
344 
345 private:
346     SkString fPath;
347 
348     typedef FamilyTypeface INHERITED;
349 };
350 
351 ///////////////////////////////////////////////////////////////////////////////
352 ///////////////////////////////////////////////////////////////////////////////
353 
get_name_and_style(const char path[],SkString * name,SkTypeface::Style * style,bool isExpected)354 static bool get_name_and_style(const char path[], SkString* name,
355                                SkTypeface::Style* style, bool isExpected) {
356     SkString        fullpath;
357     GetFullPathForSysFonts(&fullpath, path);
358 
359     SkMMAPStream stream(fullpath.c_str());
360     if (stream.getLength() > 0) {
361         *style = find_name_and_style(&stream, name);
362         return true;
363     }
364     else {
365         SkFILEStream stream(fullpath.c_str());
366         if (stream.getLength() > 0) {
367             *style = find_name_and_style(&stream, name);
368             return true;
369         }
370     }
371 
372     if (isExpected) {
373         SkDebugf("---- failed to open <%s> as a font\n", fullpath.c_str());
374     }
375     return false;
376 }
377 
378 // used to record our notion of the pre-existing fonts
379 struct FontInitRec {
380     const char*         fFileName;
381     const char* const*  fNames;     // null-terminated list
382 };
383 
384 static const char* gSansNames[] = {
385     "sans-serif", "arial", "helvetica", "tahoma", "verdana", NULL
386 };
387 
388 static const char* gSerifNames[] = {
389     "serif", "times", "times new roman", "palatino", "georgia", "baskerville",
390     "goudy", "fantasy", "cursive", "ITC Stone Serif", NULL
391 };
392 
393 static const char* gMonoNames[] = {
394     "monospace", "courier", "courier new", "monaco", NULL
395 };
396 
397 // deliberately empty, but we use the address to identify fallback fonts
398 static const char* gFBNames[] = { NULL };
399 
400 /*  Fonts must be grouped by family, with the first font in a family having the
401     list of names (even if that list is empty), and the following members having
402     null for the list. The names list must be NULL-terminated
403 */
404 static const FontInitRec gSystemFonts[] = {
405     { "DroidSans.ttf",              gSansNames  },
406     { "DroidSans-Bold.ttf",         NULL        },
407     { "DroidSerif-Regular.ttf",     gSerifNames },
408     { "DroidSerif-Bold.ttf",        NULL        },
409     { "DroidSerif-Italic.ttf",      NULL        },
410     { "DroidSerif-BoldItalic.ttf",  NULL        },
411     { "DroidSansMono.ttf",          gMonoNames  },
412     /*  These are optional, and can be ignored if not found in the file system.
413         These are appended to gFallbackFonts[] as they are seen, so we list
414         them in the order we want them to be accessed by NextLogicalFont().
415      */
416     { "DroidSansJapanese.ttf",      gFBNames    },
417     { "DroidSansFallback.ttf",      gFBNames    }
418 };
419 
420 #define DEFAULT_NAMES   gSansNames
421 
422 // these globals are assigned (once) by load_system_fonts()
423 static FamilyRec* gDefaultFamily;
424 static SkTypeface* gDefaultNormal;
425 
426 /*  This is sized conservatively, assuming that it will never be a size issue.
427     It will be initialized in load_system_fonts(), and will be filled with the
428     fontIDs that can be used for fallback consideration, in sorted order (sorted
429     meaning element[0] should be used first, then element[1], etc. When we hit
430     a fontID==0 in the array, the list is done, hence our allocation size is
431     +1 the total number of possible system fonts. Also see NextLogicalFont().
432  */
433 static uint32_t gFallbackFonts[SK_ARRAY_COUNT(gSystemFonts)+1];
434 
435 /*  Called once (ensured by the sentinel check at the beginning of our body).
436     Initializes all the globals, and register the system fonts.
437  */
load_system_fonts()438 static void load_system_fonts() {
439     // check if we've already be called
440     if (NULL != gDefaultNormal) {
441         return;
442     }
443 
444     const FontInitRec* rec = gSystemFonts;
445     SkTypeface* firstInFamily = NULL;
446     int fallbackCount = 0;
447 
448     for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
449         // if we're the first in a new family, clear firstInFamily
450         if (rec[i].fNames != NULL) {
451             firstInFamily = NULL;
452         }
453 
454         SkString name;
455         SkTypeface::Style style;
456 
457         // we expect all the fonts, except the "fallback" fonts
458         bool isExpected = (rec[i].fNames != gFBNames);
459         if (!get_name_and_style(rec[i].fFileName, &name, &style, isExpected)) {
460             continue;
461         }
462 
463         SkTypeface* tf = SkNEW_ARGS(FileTypeface,
464                                     (style,
465                                      true,  // system-font (cannot delete)
466                                      firstInFamily, // what family to join
467                                      rec[i].fFileName) // filename
468                                     );
469 
470         if (rec[i].fNames != NULL) {
471             // see if this is one of our fallback fonts
472             if (rec[i].fNames == gFBNames) {
473             //    SkDebugf("---- adding %s as fallback[%d] fontID %d\n",
474             //             rec[i].fFileName, fallbackCount, tf->uniqueID());
475                 gFallbackFonts[fallbackCount++] = tf->uniqueID();
476             }
477 
478             firstInFamily = tf;
479             FamilyRec* family = find_family(tf);
480             const char* const* names = rec[i].fNames;
481 
482             // record the default family if this is it
483             if (names == DEFAULT_NAMES) {
484                 gDefaultFamily = family;
485             }
486             // add the names to map to this family
487             while (*names) {
488                 add_name(*names, family);
489                 names += 1;
490             }
491         }
492     }
493 
494     // do this after all fonts are loaded. This is our default font, and it
495     // acts as a sentinel so we only execute load_system_fonts() once
496     gDefaultNormal = find_best_face(gDefaultFamily, SkTypeface::kNormal);
497     // now terminate our fallback list with the sentinel value
498     gFallbackFonts[fallbackCount] = 0;
499 }
500 
501 ///////////////////////////////////////////////////////////////////////////////
502 
Serialize(const SkTypeface * face,SkWStream * stream)503 void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
504     const char* name = ((FamilyTypeface*)face)->getUniqueString();
505 
506     stream->write8((uint8_t)face->style());
507 
508     if (NULL == name || 0 == *name) {
509         stream->writePackedUInt(0);
510 //        SkDebugf("--- fonthost serialize null\n");
511     } else {
512         uint32_t len = strlen(name);
513         stream->writePackedUInt(len);
514         stream->write(name, len);
515 //      SkDebugf("--- fonthost serialize <%s> %d\n", name, face->style());
516     }
517 }
518 
Deserialize(SkStream * stream)519 SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
520     load_system_fonts();
521 
522     int style = stream->readU8();
523 
524     int len = stream->readPackedUInt();
525     if (len > 0) {
526         SkString str;
527         str.resize(len);
528         stream->read(str.writable_str(), len);
529 
530         const FontInitRec* rec = gSystemFonts;
531         for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
532             if (strcmp(rec[i].fFileName, str.c_str()) == 0) {
533                 // backup until we hit the fNames
534                 for (int j = i; j >= 0; --j) {
535                     if (rec[j].fNames != NULL) {
536                         return SkFontHost::CreateTypeface(NULL,
537                                     rec[j].fNames[0], (SkTypeface::Style)style);
538                     }
539                 }
540             }
541         }
542     }
543     return NULL;
544 }
545 
546 ///////////////////////////////////////////////////////////////////////////////
547 
CreateTypeface(const SkTypeface * familyFace,const char familyName[],SkTypeface::Style style)548 SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
549                                        const char familyName[],
550                                        SkTypeface::Style style) {
551     load_system_fonts();
552 
553     SkAutoMutexAcquire  ac(gFamilyMutex);
554 
555     // clip to legal style bits
556     style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
557 
558     SkTypeface* tf = NULL;
559 
560     if (NULL != familyFace) {
561         tf = find_typeface(familyFace, style);
562     } else if (NULL != familyName) {
563 //        SkDebugf("======= familyName <%s>\n", familyName);
564         tf = find_typeface(familyName, style);
565     }
566 
567     if (NULL == tf) {
568         tf = find_best_face(gDefaultFamily, style);
569     }
570 
571     // we ref(), since the symantic is to return a new instance
572     tf->ref();
573     return tf;
574 }
575 
ValidFontID(uint32_t fontID)576 bool SkFontHost::ValidFontID(uint32_t fontID) {
577     SkAutoMutexAcquire  ac(gFamilyMutex);
578 
579     return find_from_uniqueID(fontID) != NULL;
580 }
581 
OpenStream(uint32_t fontID)582 SkStream* SkFontHost::OpenStream(uint32_t fontID) {
583     SkAutoMutexAcquire  ac(gFamilyMutex);
584 
585     FamilyTypeface* tf = (FamilyTypeface*)find_from_uniqueID(fontID);
586     SkStream* stream = tf ? tf->openStream() : NULL;
587 
588     if (stream && stream->getLength() == 0) {
589         stream->unref();
590         stream = NULL;
591     }
592     return stream;
593 }
594 
NextLogicalFont(uint32_t fontID)595 uint32_t SkFontHost::NextLogicalFont(uint32_t fontID) {
596     load_system_fonts();
597 
598     /*  First see if fontID is already one of our fallbacks. If so, return
599         its successor. If fontID is not in our list, then return the first one
600         in our list. Note: list is zero-terminated, and returning zero means
601         we have no more fonts to use for fallbacks.
602      */
603     const uint32_t* list = gFallbackFonts;
604     for (int i = 0; list[i] != 0; i++) {
605         if (list[i] == fontID) {
606             return list[i+1];
607         }
608     }
609     return list[0];
610 }
611 
612 ///////////////////////////////////////////////////////////////////////////////
613 
CreateTypefaceFromStream(SkStream * stream)614 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
615     if (NULL == stream || stream->getLength() <= 0) {
616         return NULL;
617     }
618 
619     SkString name;
620     SkTypeface::Style style = find_name_and_style(stream, &name);
621 
622     return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream));
623 }
624 
CreateTypefaceFromFile(const char path[])625 SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
626     SkStream* stream = SkNEW_ARGS(SkMMAPStream, (path));
627     SkTypeface* face = SkFontHost::CreateTypefaceFromStream(stream);
628     // since we created the stream, we let go of our ref() here
629     stream->unref();
630     return face;
631 }
632 
633 ///////////////////////////////////////////////////////////////////////////////
634 
ShouldPurgeFontCache(size_t sizeAllocatedSoFar)635 size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) {
636     if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET)
637         return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET;
638     else
639         return 0;   // nothing to do
640 }
641 
642