SkFontHost_android.cpp revision 956f20cebc0d9c7a1c59dc18a556b7aaff22b39c
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
34bool find_name_and_style(SkStream* stream, SkString* name, SkTypeface::Style* style);
35
36static 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
44struct 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*/
51struct NameFamilyPair {
52    const char* fName;      // we own this
53    FamilyRec*  fFamily;    // we don't own this, we just reference it
54
55    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
60    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
67static int32_t gUniqueFontID;
68
69// this is the mutex that protects these globals
70static SkMutex gFamilyMutex;
71static FamilyRec* gFamilyHead;
72static SkTDArray<NameFamilyPair> gNameList;
73
74struct FamilyRec {
75    FamilyRec*  fNext;
76    SkTypeface* fFaces[4];
77
78    FamilyRec()
79    {
80        fNext = gFamilyHead;
81        memset(fFaces, 0, sizeof(fFaces));
82        gFamilyHead = this;
83    }
84};
85
86static 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
113static 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 */
129static 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*/
146static 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
160static 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
181static 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
193static 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
199static 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
214static 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
236class FamilyTypeface : public SkTypeface {
237public:
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
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
266    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
272private:
273    bool    fIsSysFont;
274
275    typedef SkTypeface INHERITED;
276};
277
278///////////////////////////////////////////////////////////////////////////////
279
280class StreamTypeface : public FamilyTypeface {
281public:
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    }
289    virtual ~StreamTypeface() {
290        fStream->unref();
291    }
292
293    // overrides
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    }
300    virtual const char* getUniqueString() const { return NULL; }
301    virtual const char* getFilePath() const { return NULL; }
302
303private:
304    SkStream* fStream;
305
306    typedef FamilyTypeface INHERITED;
307};
308
309class FileTypeface : public FamilyTypeface {
310public:
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
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    }
339    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    }
346    virtual const char* getFilePath() const {
347        return fPath.c_str();
348    }
349
350private:
351    SkString fPath;
352
353    typedef FamilyTypeface INHERITED;
354};
355
356///////////////////////////////////////////////////////////////////////////////
357///////////////////////////////////////////////////////////////////////////////
358
359static 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
382struct FontInitRec {
383    const char*         fFileName;
384    const char* const*  fNames;     // null-terminated list
385};
386
387static const char* gSansNames[] = {
388    "sans-serif", "arial", "helvetica", "tahoma", "verdana", NULL
389};
390
391static const char* gSerifNames[] = {
392    "serif", "times", "times new roman", "palatino", "georgia", "baskerville",
393    "goudy", "fantasy", "cursive", "ITC Stone Serif", NULL
394};
395
396static const char* gMonoNames[] = {
397    "monospace", "courier", "courier new", "monaco", NULL
398};
399
400// deliberately empty, but we use the address to identify fallback fonts
401static 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*/
407static 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()
431static FamilyRec* gDefaultFamily;
432static 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 */
441static 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 */
446static 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
511void 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
527SkTypeface* 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
556SkTypeface* 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
584bool SkFontHost::ValidFontID(uint32_t fontID) {
585    SkAutoMutexAcquire  ac(gFamilyMutex);
586
587    return find_from_uniqueID(fontID) != NULL;
588}
589
590SkStream* 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
603size_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
624uint32_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
643SkTypeface* 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
658SkTypeface* 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
668size_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