1
2/*
3 * Copyright 2013 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#include "SkFontConfigInterface.h"
10#include "SkTypeface_android.h"
11
12#include "SkFontConfigParser_android.h"
13#include "SkFontConfigTypeface.h"
14#include "SkFontMgr.h"
15#include "SkGlyphCache.h"
16#include "SkPaint.h"
17#include "SkString.h"
18#include "SkStream.h"
19#include "SkThread.h"
20#include "SkTypefaceCache.h"
21#include "SkTArray.h"
22#include "SkTDict.h"
23#include "SkTSearch.h"
24
25#include <stdio.h>
26#include <string.h>
27
28#ifndef SK_DEBUG_FONTS
29    #define SK_DEBUG_FONTS 0
30#endif
31
32#if SK_DEBUG_FONTS
33    #define DEBUG_FONT(args) SkDebugf args
34#else
35    #define DEBUG_FONT(args)
36#endif
37
38///////////////////////////////////////////////////////////////////////////////
39
40// For test only.
41static const char* gTestMainConfigFile = NULL;
42static const char* gTestFallbackConfigFile = NULL;
43static const char* gTestFontFilePrefix = NULL;
44
45///////////////////////////////////////////////////////////////////////////////
46
47typedef int32_t FontRecID;
48#define INVALID_FONT_REC_ID -1
49
50typedef int32_t FamilyRecID;
51#define INVALID_FAMILY_REC_ID -1
52
53// used to record our notion of the pre-existing fonts
54struct FontRec {
55    SkRefPtr<SkTypeface> fTypeface;
56    SkString fFileName;
57    SkTypeface::Style fStyle;
58    bool fIsValid;
59    FamilyRecID fFamilyRecID;
60};
61
62struct FamilyRec {
63    FamilyRec() {
64        memset(fFontRecID, INVALID_FONT_REC_ID, sizeof(fFontRecID));
65    }
66
67    static const int FONT_STYLE_COUNT = 4;
68    FontRecID fFontRecID[FONT_STYLE_COUNT];
69    bool fIsFallbackFont;
70    SkPaintOptionsAndroid fPaintOptions;
71};
72
73
74typedef SkTDArray<FamilyRecID> FallbackFontList;
75
76class SkFontConfigInterfaceAndroid : public SkFontConfigInterface {
77public:
78    SkFontConfigInterfaceAndroid(SkTDArray<FontFamily*>& fontFamilies);
79    virtual ~SkFontConfigInterfaceAndroid();
80
81    virtual bool matchFamilyName(const char familyName[],
82                                 SkTypeface::Style requested,
83                                 FontIdentity* outFontIdentifier,
84                                 SkString* outFamilyName,
85                                 SkTypeface::Style* outStyle) SK_OVERRIDE;
86    virtual SkStream* openStream(const FontIdentity&) SK_OVERRIDE;
87
88    // new APIs
89    virtual SkDataTable* getFamilyNames() SK_OVERRIDE;
90    virtual bool matchFamilySet(const char inFamilyName[],
91                                SkString* outFamilyName,
92                                SkTArray<FontIdentity>*) SK_OVERRIDE;
93
94    /**
95     *  Get the family name of the font in the default fallback font list that
96     *  contains the specified chararacter. if no font is found, returns false.
97     */
98    bool getFallbackFamilyNameForChar(SkUnichar uni, const char* lang, SkString* name);
99    /**
100     *
101     */
102    SkTypeface* getTypefaceForChar(SkUnichar uni, SkTypeface::Style style,
103                                   SkPaintOptionsAndroid::FontVariant fontVariant);
104    SkTypeface* nextLogicalTypeface(SkFontID currFontID, SkFontID origFontID,
105                                    const SkPaintOptionsAndroid& options);
106    SkTypeface* getTypefaceForGlyphID(uint16_t glyphID, const SkTypeface* origTypeface,
107                                      const SkPaintOptionsAndroid& options,
108                                      int* lowerBounds, int* upperBounds);
109
110private:
111    void addFallbackFamily(FamilyRecID fontRecID);
112    SkTypeface* getTypefaceForFontRec(FontRecID fontRecID);
113    FallbackFontList* getCurrentLocaleFallbackFontList();
114    FallbackFontList* findFallbackFontList(const SkLanguage& lang, bool isOriginal = true);
115
116    SkTArray<FontRec> fFonts;
117    SkTArray<FamilyRec> fFontFamilies;
118    SkTDict<FamilyRecID> fFamilyNameDict;
119    FamilyRecID fDefaultFamilyRecID;
120
121    // (SkLanguage)<->(fallback chain index) translation
122    SkTDict<FallbackFontList*> fFallbackFontDict;
123    SkTDict<FallbackFontList*> fFallbackFontAliasDict;
124    FallbackFontList fDefaultFallbackList;
125
126    // fallback info for current locale
127    SkString fCachedLocale;
128    FallbackFontList* fLocaleFallbackFontList;
129};
130
131///////////////////////////////////////////////////////////////////////////////
132
133static SkFontConfigInterfaceAndroid* getSingletonInterface() {
134    SK_DECLARE_STATIC_MUTEX(gMutex);
135    static SkFontConfigInterfaceAndroid* gFontConfigInterface;
136
137    SkAutoMutexAcquire ac(gMutex);
138    if (NULL == gFontConfigInterface) {
139        // load info from a configuration file that we can use to populate the
140        // system/fallback font structures
141        SkTDArray<FontFamily*> fontFamilies;
142        if (!gTestMainConfigFile) {
143            SkFontConfigParser::GetFontFamilies(fontFamilies);
144        } else {
145            SkFontConfigParser::GetTestFontFamilies(fontFamilies, gTestMainConfigFile,
146                                                    gTestFallbackConfigFile);
147        }
148
149        gFontConfigInterface = new SkFontConfigInterfaceAndroid(fontFamilies);
150
151        // cleanup the data we received from the parser
152        fontFamilies.deleteAll();
153    }
154    return gFontConfigInterface;
155}
156
157SkFontConfigInterface* SkFontConfigInterface::GetSingletonDirectInterface() {
158    return getSingletonInterface();
159}
160
161///////////////////////////////////////////////////////////////////////////////
162
163static bool has_font(const SkTArray<FontRec>& array, const SkString& filename) {
164    for (int i = 0; i < array.count(); i++) {
165        if (array[i].fFileName == filename) {
166            return true;
167        }
168    }
169    return false;
170}
171
172#ifndef SK_FONT_FILE_PREFIX
173    #define SK_FONT_FILE_PREFIX          "/fonts/"
174#endif
175
176static void get_path_for_sys_fonts(SkString* full, const char name[]) {
177    if (gTestFontFilePrefix) {
178        full->set(gTestFontFilePrefix);
179    } else {
180        full->set(getenv("ANDROID_ROOT"));
181        full->append(SK_FONT_FILE_PREFIX);
182    }
183    full->append(name);
184}
185
186static void insert_into_name_dict(SkTDict<FamilyRecID>& familyNameDict,
187                                  const char* name, FamilyRecID familyRecID) {
188    SkAutoAsciiToLC tolc(name);
189    if (familyNameDict.find(tolc.lc())) {
190        SkDebugf("---- system font attempting to use a the same name [%s] for"
191                 "multiple families. skipping subsequent occurrences", tolc.lc());
192    } else {
193        familyNameDict.set(tolc.lc(), familyRecID);
194    }
195}
196
197// Defined in SkFontHost_FreeType.cpp
198bool find_name_and_attributes(SkStream* stream, SkString* name,
199                              SkTypeface::Style* style, bool* isFixedWidth);
200
201///////////////////////////////////////////////////////////////////////////////
202
203SkFontConfigInterfaceAndroid::SkFontConfigInterfaceAndroid(SkTDArray<FontFamily*>& fontFamilies) :
204        fFonts(fontFamilies.count()),
205        fFontFamilies(fontFamilies.count() / FamilyRec::FONT_STYLE_COUNT),
206        fFamilyNameDict(1024),
207        fDefaultFamilyRecID(INVALID_FAMILY_REC_ID),
208        fFallbackFontDict(128),
209        fFallbackFontAliasDict(128),
210        fLocaleFallbackFontList(NULL) {
211
212    for (int i = 0; i < fontFamilies.count(); ++i) {
213        FontFamily* family = fontFamilies[i];
214
215        // defer initializing the familyRec until we can be sure that at least
216        // one of it's children contains a valid font file
217        FamilyRec* familyRec = NULL;
218        FamilyRecID familyRecID = INVALID_FAMILY_REC_ID;
219
220        for (int j = 0; j < family->fFontFiles.count(); ++j) {
221            SkString filename;
222            get_path_for_sys_fonts(&filename, family->fFontFiles[j]->fFileName);
223
224            if (has_font(fFonts, filename)) {
225                SkDebugf("---- system font and fallback font files specify a duplicate "
226                        "font %s, skipping the second occurrence", filename.c_str());
227                continue;
228            }
229
230            FontRec& fontRec = fFonts.push_back();
231            fontRec.fFileName = filename;
232            fontRec.fStyle = SkTypeface::kNormal;
233            fontRec.fIsValid = false;
234            fontRec.fFamilyRecID = familyRecID;
235
236            const FontRecID fontRecID = fFonts.count() - 1;
237
238            SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(filename.c_str()));
239            if (stream.get() != NULL) {
240                bool isFixedWidth;
241                SkString name;
242                fontRec.fIsValid = find_name_and_attributes(stream.get(), &name,
243                                                            &fontRec.fStyle, &isFixedWidth);
244            } else {
245                if (!family->fIsFallbackFont) {
246                    SkDebugf("---- failed to open <%s> as a font\n", filename.c_str());
247                }
248            }
249
250            if (fontRec.fIsValid) {
251                DEBUG_FONT(("---- SystemFonts[%d][%d] fallback=%d file=%s",
252                           i, fFonts.count() - 1, family->fIsFallbackFont, filename.c_str()));
253            } else {
254                DEBUG_FONT(("---- SystemFonts[%d][%d] fallback=%d file=%s (INVALID)",
255                           i, fFonts.count() - 1, family->fIsFallbackFont, filename.c_str()));
256                continue;
257            }
258
259            // create a familyRec now that we know that at least one font in
260            // the family is valid
261            if (familyRec == NULL) {
262                familyRec = &fFontFamilies.push_back();
263                familyRecID = fFontFamilies.count() - 1;
264                fontRec.fFamilyRecID = familyRecID;
265
266                familyRec->fIsFallbackFont = family->fIsFallbackFont;
267                familyRec->fPaintOptions = family->fFontFiles[j]->fPaintOptions;
268
269                // if this is a fallback font then add it to the appropriate fallback chains
270                if (familyRec->fIsFallbackFont) {
271                    addFallbackFamily(familyRecID);
272                }
273            } else if (familyRec->fPaintOptions != family->fFontFiles[j]->fPaintOptions) {
274                SkDebugf("Every font file within a family must have identical"
275                         "language and variant attributes");
276                sk_throw();
277            }
278
279            // add this font to the current familyRec
280            if (INVALID_FONT_REC_ID != familyRec->fFontRecID[fontRec.fStyle]) {
281                DEBUG_FONT(("Overwriting familyRec for style[%d] old,new:(%d,%d)",
282                            fontRec.fStyle, familyRec->fFontRecID[fontRec.fStyle],
283                            fontRecID));
284            }
285            familyRec->fFontRecID[fontRec.fStyle] = fontRecID;
286
287            // add the fallback file name to the name dictionary.  This is needed
288            // by getFallbackFamilyNameForChar() so that fallback families can be
289            // requested by the filenames of the fonts they contain.
290            if (familyRec && familyRec->fIsFallbackFont) {
291                insert_into_name_dict(fFamilyNameDict, fontRec.fFileName.c_str(), familyRecID);
292            }
293        }
294
295        // add the names that map to this family to the dictionary for easy lookup
296        if (familyRec && !familyRec->fIsFallbackFont) {
297            SkTDArray<const char*> names = family->fNames;
298            if (names.isEmpty()) {
299                SkDEBUGFAIL("ERROR: non-fallback font with no name");
300                continue;
301            }
302
303            for (int i = 0; i < names.count(); i++) {
304                insert_into_name_dict(fFamilyNameDict, names[i], familyRecID);
305            }
306        }
307
308    }
309
310    DEBUG_FONT(("---- We have %d system fonts", fFonts.count()));
311
312    if (fFontFamilies.count() > 0) {
313        fDefaultFamilyRecID = 0;
314    }
315
316    // scans the default fallback font chain, adding every entry to every other
317    // fallback font chain to which it does not belong. this results in every
318    // language-specific fallback font chain having all of its fallback fonts at
319    // the front of the chain, and everything else at the end.
320    FallbackFontList* fallbackList;
321    SkTDict<FallbackFontList*>::Iter iter(fFallbackFontDict);
322    const char* fallbackLang = iter.next(&fallbackList);
323    while(fallbackLang != NULL) {
324        for (int i = 0; i < fDefaultFallbackList.count(); i++) {
325            FamilyRecID familyRecID = fDefaultFallbackList[i];
326            const SkString& fontLang = fFontFamilies[familyRecID].fPaintOptions.getLanguage().getTag();
327            if (strcmp(fallbackLang, fontLang.c_str()) != 0) {
328                fallbackList->push(familyRecID);
329            }
330        }
331        // move to the next fallback list in the dictionary
332        fallbackLang = iter.next(&fallbackList);
333    }
334}
335
336SkFontConfigInterfaceAndroid::~SkFontConfigInterfaceAndroid() {
337    // iterate through and cleanup fFallbackFontDict
338    SkTDict<FallbackFontList*>::Iter iter(fFallbackFontDict);
339    FallbackFontList* fallbackList;
340    while(iter.next(&fallbackList) != NULL) {
341        SkDELETE(fallbackList);
342    }
343}
344
345void SkFontConfigInterfaceAndroid::addFallbackFamily(FamilyRecID familyRecID) {
346    SkASSERT(familyRecID < fFontFamilies.count());
347    const FamilyRec& familyRec = fFontFamilies[familyRecID];
348    SkASSERT(familyRec.fIsFallbackFont);
349
350    // add to the default fallback list
351    fDefaultFallbackList.push(familyRecID);
352
353    // stop here if it is the default language tag
354    const SkString& languageTag = familyRec.fPaintOptions.getLanguage().getTag();
355    if (languageTag.isEmpty()) {
356        return;
357    }
358
359    // add to the appropriate language's custom fallback list
360    FallbackFontList* customList = NULL;
361    if (!fFallbackFontDict.find(languageTag.c_str(), &customList)) {
362        DEBUG_FONT(("----  Created fallback list for \"%s\"", languageTag.c_str()));
363        customList = SkNEW(FallbackFontList);
364        fFallbackFontDict.set(languageTag.c_str(), customList);
365    }
366    SkASSERT(customList != NULL);
367    customList->push(familyRecID);
368}
369
370
371static FontRecID find_best_style(const FamilyRec& family, SkTypeface::Style style) {
372
373    const FontRecID* fontRecIDs = family.fFontRecID;
374
375    if (fontRecIDs[style] != INVALID_FONT_REC_ID) { // exact match
376        return fontRecIDs[style];
377    }
378    // look for a matching bold
379    style = (SkTypeface::Style)(style ^ SkTypeface::kItalic);
380    if (fontRecIDs[style] != INVALID_FONT_REC_ID) {
381        return fontRecIDs[style];
382    }
383    // look for the plain
384    if (fontRecIDs[SkTypeface::kNormal] != INVALID_FONT_REC_ID) {
385        return fontRecIDs[SkTypeface::kNormal];
386    }
387    // look for anything
388    for (int i = 0; i < FamilyRec::FONT_STYLE_COUNT; i++) {
389        if (fontRecIDs[i] != INVALID_FONT_REC_ID) {
390            return fontRecIDs[i];
391        }
392    }
393    // should never get here, since the fontRecID list should not be empty
394    SkDEBUGFAIL("No valid fonts exist for this family");
395    return -1;
396}
397
398bool SkFontConfigInterfaceAndroid::matchFamilyName(const char familyName[],
399                                                   SkTypeface::Style style,
400                                                   FontIdentity* outFontIdentifier,
401                                                   SkString* outFamilyName,
402                                                   SkTypeface::Style* outStyle) {
403    // clip to legal style bits
404    style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
405
406    bool exactNameMatch = false;
407
408    FamilyRecID familyRecID = INVALID_FAMILY_REC_ID;
409    if (NULL != familyName) {
410        SkAutoAsciiToLC tolc(familyName);
411        if (fFamilyNameDict.find(tolc.lc(), &familyRecID)) {
412            exactNameMatch = true;
413        }
414    } else {
415        familyRecID = fDefaultFamilyRecID;
416
417    }
418
419    // If no matching family name is found then return false. This allows clients
420    // to be able to search for other fonts instead of forcing them to use the
421    // default font.
422    if (INVALID_FAMILY_REC_ID == familyRecID) {
423        return false;
424    }
425
426    FontRecID fontRecID = find_best_style(fFontFamilies[familyRecID], style);
427    FontRec& fontRec = fFonts[fontRecID];
428
429    if (NULL != outFontIdentifier) {
430        outFontIdentifier->fID = fontRecID;
431        outFontIdentifier->fTTCIndex = 0;
432        outFontIdentifier->fString.set(fontRec.fFileName);
433//        outFontIdentifier->fStyle = fontRec.fStyle;
434    }
435
436    if (NULL != outFamilyName) {
437        if (exactNameMatch) {
438            outFamilyName->set(familyName);
439        } else {
440            // find familyName from list of names
441            const char* familyName = NULL;
442            SkAssertResult(fFamilyNameDict.findKey(familyRecID, &familyName));
443            SkASSERT(familyName);
444            outFamilyName->set(familyName);
445        }
446    }
447
448    if (NULL != outStyle) {
449        *outStyle = fontRec.fStyle;
450    }
451
452    return true;
453}
454
455SkStream* SkFontConfigInterfaceAndroid::openStream(const FontIdentity& identity) {
456    return SkStream::NewFromFile(identity.fString.c_str());
457}
458
459SkDataTable* SkFontConfigInterfaceAndroid::getFamilyNames() {
460    SkTDArray<const char*> names;
461    SkTDArray<size_t> sizes;
462
463    SkTDict<FamilyRecID>::Iter iter(fFamilyNameDict);
464    const char* familyName = iter.next(NULL);
465    while(familyName != NULL) {
466        *names.append() = familyName;
467        *sizes.append() = strlen(familyName) + 1;
468
469        // move to the next familyName in the dictionary
470        familyName = iter.next(NULL);
471    }
472
473    return SkDataTable::NewCopyArrays((const void*const*)names.begin(),
474                                      sizes.begin(), names.count());
475}
476
477bool SkFontConfigInterfaceAndroid::matchFamilySet(const char inFamilyName[],
478                                                  SkString* outFamilyName,
479                                                  SkTArray<FontIdentity>*) {
480    return false;
481}
482
483static bool find_proc(SkTypeface* face, SkTypeface::Style style, void* ctx) {
484    const FontRecID* fontRecID = (const FontRecID*)ctx;
485    FontRecID currFontRecID = ((FontConfigTypeface*)face)->getIdentity().fID;
486    return currFontRecID == *fontRecID;
487}
488
489SkTypeface* SkFontConfigInterfaceAndroid::getTypefaceForFontRec(FontRecID fontRecID) {
490    FontRec& fontRec = fFonts[fontRecID];
491    SkTypeface* face = fontRec.fTypeface.get();
492    if (!face) {
493        // look for it in the typeface cache
494        face = SkTypefaceCache::FindByProcAndRef(find_proc, &fontRecID);
495
496        // if it is not in the cache then create it
497        if (!face) {
498            const char* familyName = NULL;
499            SkAssertResult(fFamilyNameDict.findKey(fontRec.fFamilyRecID, &familyName));
500            SkASSERT(familyName);
501            face = SkTypeface::CreateFromName(familyName, fontRec.fStyle);
502        }
503
504        // store the result for subsequent lookups
505        fontRec.fTypeface = face;
506    }
507    SkASSERT(face);
508    return face;
509}
510
511bool SkFontConfigInterfaceAndroid::getFallbackFamilyNameForChar(SkUnichar uni,
512                                                                const char* lang,
513                                                                SkString* name) {
514    FallbackFontList* fallbackFontList = NULL;
515    const SkString langTag(lang);
516    if (langTag.isEmpty()) {
517        fallbackFontList = this->getCurrentLocaleFallbackFontList();
518    } else {
519        fallbackFontList = this->findFallbackFontList(langTag);
520    }
521
522    for (int i = 0; i < fallbackFontList->count(); i++) {
523        FamilyRecID familyRecID = fallbackFontList->getAt(i);
524
525        // if it is not one of the accepted variants then move to the next family
526        int32_t acceptedVariants = SkPaintOptionsAndroid::kDefault_Variant |
527                                   SkPaintOptionsAndroid::kElegant_Variant;
528        if (!(fFontFamilies[familyRecID].fPaintOptions.getFontVariant() & acceptedVariants)) {
529            continue;
530        }
531
532        FontRecID fontRecID = find_best_style(fFontFamilies[familyRecID], SkTypeface::kNormal);
533        SkTypeface* face = this->getTypefaceForFontRec(fontRecID);
534
535        SkPaint paint;
536        paint.setTypeface(face);
537        paint.setTextEncoding(SkPaint::kUTF32_TextEncoding);
538
539        uint16_t glyphID;
540        paint.textToGlyphs(&uni, sizeof(uni), &glyphID);
541        if (glyphID != 0) {
542            name->set(fFonts[fontRecID].fFileName);
543            return true;
544        }
545    }
546    return false;
547}
548
549SkTypeface* SkFontConfigInterfaceAndroid::getTypefaceForChar(SkUnichar uni,
550                                                             SkTypeface::Style style,
551                                                             SkPaintOptionsAndroid::FontVariant fontVariant) {
552    FontRecID fontRecID = find_best_style(fFontFamilies[fDefaultFamilyRecID], style);
553    SkTypeface* face = this->getTypefaceForFontRec(fontRecID);
554
555    SkPaintOptionsAndroid paintOptions;
556    paintOptions.setFontVariant(fontVariant);
557    paintOptions.setUseFontFallbacks(true);
558
559    SkPaint paint;
560    paint.setTypeface(face);
561    paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
562    paint.setPaintOptionsAndroid(paintOptions);
563
564    SkAutoGlyphCache autoCache(paint, NULL, NULL);
565    SkGlyphCache*    cache = autoCache.getCache();
566
567    SkScalerContext* ctx = cache->getScalerContext();
568    if (ctx) {
569        SkFontID fontID = ctx->findTypefaceIdForChar(uni);
570        return SkTypefaceCache::FindByID(fontID);
571    }
572    return NULL;
573}
574
575FallbackFontList* SkFontConfigInterfaceAndroid::getCurrentLocaleFallbackFontList() {
576    SkString locale = SkFontConfigParser::GetLocale();
577    if (NULL == fLocaleFallbackFontList || locale != fCachedLocale) {
578        fCachedLocale = locale;
579        fLocaleFallbackFontList = this->findFallbackFontList(locale);
580    }
581    return fLocaleFallbackFontList;
582}
583
584FallbackFontList* SkFontConfigInterfaceAndroid::findFallbackFontList(const SkLanguage& lang,
585                                                                     bool isOriginal) {
586    const SkString& langTag = lang.getTag();
587    if (langTag.isEmpty()) {
588        return &fDefaultFallbackList;
589    }
590
591    FallbackFontList* fallbackFontList;
592    if (fFallbackFontDict.find(langTag.c_str(), langTag.size(), &fallbackFontList) ||
593        fFallbackFontAliasDict.find(langTag.c_str(), langTag.size(), &fallbackFontList)) {
594        return fallbackFontList;
595    }
596
597    // attempt a recursive fuzzy match
598    SkLanguage parent = lang.getParent();
599    fallbackFontList = findFallbackFontList(parent, false);
600
601    // cache the original lang so we don't have to do the recursion again.
602    if (isOriginal) {
603        DEBUG_FONT(("----  Created fallback list alias for \"%s\"", langTag.c_str()));
604        fFallbackFontAliasDict.set(langTag.c_str(), fallbackFontList);
605    }
606    return fallbackFontList;
607}
608
609SkTypeface* SkFontConfigInterfaceAndroid::nextLogicalTypeface(SkFontID currFontID,
610                                                              SkFontID origFontID,
611                                                              const SkPaintOptionsAndroid& opts) {
612    // Skia does not support font fallback by default. This enables clients such
613    // as WebKit to customize their font selection. In any case, clients can use
614    // GetFallbackFamilyNameForChar() to get the fallback font for individual
615    // characters.
616    if (!opts.isUsingFontFallbacks()) {
617        return NULL;
618    }
619
620    FallbackFontList* currentFallbackList = findFallbackFontList(opts.getLanguage());
621    SkASSERT(currentFallbackList);
622
623    SkTypeface::Style origStyle = SkTypeface::kNormal;
624    const SkTypeface* origTypeface = SkTypefaceCache::FindByID(origFontID);
625    if (NULL != origTypeface) {
626        origStyle = origTypeface->style();
627    }
628
629    // we must convert currTypeface into a FontRecID
630    FontRecID currFontRecID = INVALID_FONT_REC_ID;
631    const SkTypeface* currTypeface = SkTypefaceCache::FindByID(currFontID);
632    // non-system fonts are not in the font cache so if we are asked to fallback
633    // for a non-system font we will start at the front of the chain.
634    if (NULL != currTypeface) {
635        currFontRecID = ((FontConfigTypeface*)currTypeface)->getIdentity().fID;
636        SkASSERT(INVALID_FONT_REC_ID != currFontRecID);
637    }
638
639    FamilyRecID currFamilyRecID = INVALID_FAMILY_REC_ID;
640    if (INVALID_FONT_REC_ID != currFontRecID) {
641        currFamilyRecID = fFonts[currFontRecID].fFamilyRecID;
642    }
643
644    // lookup the index next font in the chain
645    int currFallbackFontIndex = currentFallbackList->find(currFamilyRecID);
646    // We add 1 to the returned index for 2 reasons: (1) if find succeeds it moves
647    // our index to the next entry in the list; (2) if find() fails it returns
648    // -1 and incrementing it will set our starting index to 0 (the head of the list)
649    int nextFallbackFontIndex = currFallbackFontIndex + 1;
650
651    if(nextFallbackFontIndex >= currentFallbackList->count()) {
652        return NULL;
653    }
654
655    // If a rec object is set to prefer "kDefault_Variant" it means they have no preference
656    // In this case, we set the value to "kCompact_Variant"
657    SkPaintOptionsAndroid::FontVariant variant = opts.getFontVariant();
658    if (variant == SkPaintOptionsAndroid::kDefault_Variant) {
659        variant = SkPaintOptionsAndroid::kCompact_Variant;
660    }
661
662    int32_t acceptedVariants = SkPaintOptionsAndroid::kDefault_Variant | variant;
663
664    SkTypeface* nextLogicalTypeface = 0;
665    while (nextFallbackFontIndex < currentFallbackList->count()) {
666        FamilyRecID familyRecID = currentFallbackList->getAt(nextFallbackFontIndex);
667        if ((fFontFamilies[familyRecID].fPaintOptions.getFontVariant() & acceptedVariants) != 0) {
668            FontRecID matchedFont = find_best_style(fFontFamilies[familyRecID], origStyle);
669            nextLogicalTypeface = this->getTypefaceForFontRec(matchedFont);
670            break;
671        }
672        nextFallbackFontIndex++;
673    }
674
675    DEBUG_FONT(("---- nextLogicalFont: currFontID=%d, origFontID=%d, currRecID=%d, "
676                "lang=%s, variant=%d, nextFallbackIndex[%d,%d] => nextLogicalTypeface=%d",
677                currFontID, origFontID, currFontRecID, opts.getLanguage().getTag().c_str(),
678                variant, nextFallbackFontIndex, currentFallbackList->getAt(nextFallbackFontIndex),
679                (nextLogicalTypeface) ? nextLogicalTypeface->uniqueID() : 0));
680    return SkSafeRef(nextLogicalTypeface);
681}
682
683SkTypeface* SkFontConfigInterfaceAndroid::getTypefaceForGlyphID(uint16_t glyphID,
684                                                                const SkTypeface* origTypeface,
685                                                                const SkPaintOptionsAndroid& opts,
686                                                                int* lBounds, int* uBounds) {
687    // If we aren't using fallbacks then we shouldn't be calling this
688    SkASSERT(opts.isUsingFontFallbacks());
689    SkASSERT(origTypeface);
690
691    SkTypeface* currentTypeface = NULL;
692    int lowerBounds = 0; //inclusive
693    int upperBounds = origTypeface->countGlyphs(); //exclusive
694
695    // check to see if the glyph is in the bounds of the origTypeface
696    if (glyphID < upperBounds) {
697        currentTypeface = const_cast<SkTypeface*>(origTypeface);
698    } else {
699        FallbackFontList* currentFallbackList = findFallbackFontList(opts.getLanguage());
700        SkASSERT(currentFallbackList);
701
702        // If an object is set to prefer "kDefault_Variant" it means they have no preference
703        // In this case, we set the value to "kCompact_Variant"
704        SkPaintOptionsAndroid::FontVariant variant = opts.getFontVariant();
705        if (variant == SkPaintOptionsAndroid::kDefault_Variant) {
706            variant = SkPaintOptionsAndroid::kCompact_Variant;
707        }
708
709        int32_t acceptedVariants = SkPaintOptionsAndroid::kDefault_Variant | variant;
710        SkTypeface::Style origStyle = origTypeface->style();
711
712        for (int x = 0; x < currentFallbackList->count(); ++x) {
713            const FamilyRecID familyRecID = currentFallbackList->getAt(x);
714            const SkPaintOptionsAndroid& familyOptions = fFontFamilies[familyRecID].fPaintOptions;
715            if ((familyOptions.getFontVariant() & acceptedVariants) != 0) {
716                FontRecID matchedFont = find_best_style(fFontFamilies[familyRecID], origStyle);
717                currentTypeface = this->getTypefaceForFontRec(matchedFont);
718                lowerBounds = upperBounds;
719                upperBounds += currentTypeface->countGlyphs();
720                if (glyphID < upperBounds) {
721                    break;
722                }
723            }
724        }
725    }
726
727    if (NULL != currentTypeface) {
728        if (lBounds) {
729            *lBounds = lowerBounds;
730        }
731        if (uBounds) {
732            *uBounds = upperBounds;
733        }
734    }
735    return currentTypeface;
736}
737
738///////////////////////////////////////////////////////////////////////////////
739
740bool SkGetFallbackFamilyNameForChar(SkUnichar uni, SkString* name) {
741    SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
742    return fontConfig->getFallbackFamilyNameForChar(uni, NULL, name);
743}
744
745bool SkGetFallbackFamilyNameForChar(SkUnichar uni, const char* lang, SkString* name) {
746    SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
747    return fontConfig->getFallbackFamilyNameForChar(uni, lang, name);
748}
749
750void SkUseTestFontConfigFile(const char* mainconf, const char* fallbackconf,
751                             const char* fontsdir) {
752    gTestMainConfigFile = mainconf;
753    gTestFallbackConfigFile = fallbackconf;
754    gTestFontFilePrefix = fontsdir;
755    SkASSERT(gTestMainConfigFile);
756    SkASSERT(gTestFallbackConfigFile);
757    SkASSERT(gTestFontFilePrefix);
758    SkDEBUGF(("Use Test Config File Main %s, Fallback %s, Font Dir %s",
759              gTestMainConfigFile, gTestFallbackConfigFile, gTestFontFilePrefix));
760}
761
762SkTypeface* SkAndroidNextLogicalTypeface(SkFontID currFontID, SkFontID origFontID,
763                                         const SkPaintOptionsAndroid& options) {
764    SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
765    return fontConfig->nextLogicalTypeface(currFontID, origFontID, options);
766
767}
768
769SkTypeface* SkGetTypefaceForGlyphID(uint16_t glyphID, const SkTypeface* origTypeface,
770                                    const SkPaintOptionsAndroid& options,
771                                    int* lowerBounds, int* upperBounds) {
772    SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
773    return fontConfig->getTypefaceForGlyphID(glyphID, origTypeface, options,
774                                             lowerBounds, upperBounds);
775}
776
777///////////////////////////////////////////////////////////////////////////////
778
779#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
780
781struct HB_UnicodeMapping {
782    // TODO: when the WebView no longer needs harfbuzz_old, remove
783    HB_Script script_old;
784    hb_script_t script;
785    const SkUnichar unicode;
786};
787
788/*
789 * The following scripts are not complex fonts and we do not expect them to be parsed by this table
790 * HB_SCRIPT_COMMON,
791 * HB_SCRIPT_GREEK,
792 * HB_SCRIPT_CYRILLIC,
793 * HB_SCRIPT_HANGUL
794 * HB_SCRIPT_INHERITED
795 */
796
797/* Harfbuzz (old) is missing a number of scripts in its table. For these,
798 * we include a value which can never happen. We won't get complex script
799 * shaping in these cases, but the library wouldn't know how to shape
800 * them anyway. */
801#define HB_Script_Unknown HB_ScriptCount
802
803static HB_UnicodeMapping HB_UnicodeMappingArray[] = {
804    {HB_Script_Armenian,   HB_SCRIPT_ARMENIAN,    0x0531},
805    {HB_Script_Hebrew,     HB_SCRIPT_HEBREW,      0x0591},
806    {HB_Script_Arabic,     HB_SCRIPT_ARABIC,      0x0600},
807    {HB_Script_Syriac,     HB_SCRIPT_SYRIAC,      0x0710},
808    {HB_Script_Thaana,     HB_SCRIPT_THAANA,      0x0780},
809    {HB_Script_Nko,        HB_SCRIPT_NKO,         0x07C0},
810    {HB_Script_Devanagari, HB_SCRIPT_DEVANAGARI,  0x0901},
811    {HB_Script_Bengali,    HB_SCRIPT_BENGALI,     0x0981},
812    {HB_Script_Gurmukhi,   HB_SCRIPT_GURMUKHI,    0x0A10},
813    {HB_Script_Gujarati,   HB_SCRIPT_GUJARATI,    0x0A90},
814    {HB_Script_Oriya,      HB_SCRIPT_ORIYA,       0x0B10},
815    {HB_Script_Tamil,      HB_SCRIPT_TAMIL,       0x0B82},
816    {HB_Script_Telugu,     HB_SCRIPT_TELUGU,      0x0C10},
817    {HB_Script_Kannada,    HB_SCRIPT_KANNADA,     0x0C90},
818    {HB_Script_Malayalam,  HB_SCRIPT_MALAYALAM,   0x0D10},
819    {HB_Script_Sinhala,    HB_SCRIPT_SINHALA,     0x0D90},
820    {HB_Script_Thai,       HB_SCRIPT_THAI,        0x0E01},
821    {HB_Script_Lao,        HB_SCRIPT_LAO,         0x0E81},
822    {HB_Script_Tibetan,    HB_SCRIPT_TIBETAN,     0x0F00},
823    {HB_Script_Myanmar,    HB_SCRIPT_MYANMAR,     0x1000},
824    {HB_Script_Georgian,   HB_SCRIPT_GEORGIAN,    0x10A0},
825    {HB_Script_Unknown,    HB_SCRIPT_ETHIOPIC,    0x1200},
826    {HB_Script_Unknown,    HB_SCRIPT_CHEROKEE,    0x13A0},
827    {HB_Script_Ogham,      HB_SCRIPT_OGHAM,       0x1680},
828    {HB_Script_Runic,      HB_SCRIPT_RUNIC,       0x16A0},
829    {HB_Script_Khmer,      HB_SCRIPT_KHMER,       0x1780},
830    {HB_Script_Unknown,    HB_SCRIPT_TAI_LE,      0x1950},
831    {HB_Script_Unknown,    HB_SCRIPT_NEW_TAI_LUE, 0x1980},
832    {HB_Script_Unknown,    HB_SCRIPT_TAI_THAM,    0x1A20},
833    {HB_Script_Unknown,    HB_SCRIPT_CHAM,        0xAA00},
834};
835
836static hb_script_t getHBScriptFromHBScriptOld(HB_Script script_old) {
837    hb_script_t script = HB_SCRIPT_INVALID;
838    int numSupportedFonts = sizeof(HB_UnicodeMappingArray) / sizeof(HB_UnicodeMapping);
839    for (int i = 0; i < numSupportedFonts; i++) {
840        if (script_old == HB_UnicodeMappingArray[i].script_old) {
841            script = HB_UnicodeMappingArray[i].script;
842            break;
843        }
844    }
845    return script;
846}
847
848// returns 0 for "Not Found"
849static SkUnichar getUnicodeFromHBScript(hb_script_t script) {
850    SkUnichar unichar = 0;
851    int numSupportedFonts = sizeof(HB_UnicodeMappingArray) / sizeof(HB_UnicodeMapping);
852    for (int i = 0; i < numSupportedFonts; i++) {
853        if (script == HB_UnicodeMappingArray[i].script) {
854            unichar = HB_UnicodeMappingArray[i].unicode;
855            break;
856        }
857    }
858    return unichar;
859}
860
861struct TypefaceLookupStruct {
862    hb_script_t script;
863    SkTypeface::Style style;
864    SkPaintOptionsAndroid::FontVariant fontVariant;
865    SkTypeface* typeface;
866};
867
868SK_DECLARE_STATIC_MUTEX(gTypefaceTableMutex);  // This is the mutex for gTypefaceTable
869static SkTDArray<TypefaceLookupStruct> gTypefaceTable;  // This is protected by gTypefaceTableMutex
870
871static int typefaceLookupCompare(const TypefaceLookupStruct& first,
872                                 const TypefaceLookupStruct& second) {
873    if (first.script != second.script) {
874        return (first.script > second.script) ? 1 : -1;
875    }
876    if (first.style != second.style) {
877        return (first.style > second.style) ? 1 : -1;
878    }
879    if (first.fontVariant != second.fontVariant) {
880        return (first.fontVariant > second.fontVariant) ? 1 : -1;
881    }
882    return 0;
883}
884
885SkTypeface* SkCreateTypefaceForScriptNG(hb_script_t script, SkTypeface::Style style,
886                                        SkPaintOptionsAndroid::FontVariant fontVariant) {
887    SkAutoMutexAcquire ac(gTypefaceTableMutex);
888
889    TypefaceLookupStruct key;
890    key.script = script;
891    key.style = style;
892    key.fontVariant = fontVariant;
893
894    int index = SkTSearch<TypefaceLookupStruct>(
895            (const TypefaceLookupStruct*) gTypefaceTable.begin(),
896            gTypefaceTable.count(), key, sizeof(TypefaceLookupStruct),
897            typefaceLookupCompare);
898
899    SkTypeface* retTypeface = NULL;
900    if (index >= 0) {
901        retTypeface = gTypefaceTable[index].typeface;
902    }
903    else {
904        SkUnichar unichar = getUnicodeFromHBScript(script);
905        if (!unichar) {
906            return NULL;
907        }
908
909        SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
910        retTypeface = fontConfig->getTypefaceForChar(unichar, style, fontVariant);
911
912        // add to the lookup table
913        key.typeface = retTypeface;
914        *gTypefaceTable.insert(~index) = key;
915    }
916
917    // we ref(), the caller is expected to unref when they are done
918    return SkSafeRef(retTypeface);
919}
920
921SkTypeface* SkCreateTypefaceForScript(HB_Script script, SkTypeface::Style style,
922                                      SkPaintOptionsAndroid::FontVariant fontVariant) {
923    return SkCreateTypefaceForScriptNG(getHBScriptFromHBScriptOld(script), style, fontVariant);
924}
925
926#endif
927
928///////////////////////////////////////////////////////////////////////////////
929
930SkFontMgr* SkFontMgr::Factory() {
931    return NULL;
932}
933