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