• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
41 static const char* gTestMainConfigFile = NULL;
42 static const char* gTestFallbackConfigFile = NULL;
43 static const char* gTestFontFilePrefix = NULL;
44 
45 ///////////////////////////////////////////////////////////////////////////////
46 
47 typedef int32_t FontRecID;
48 #define INVALID_FONT_REC_ID -1
49 
50 typedef int32_t FamilyRecID;
51 #define INVALID_FAMILY_REC_ID -1
52 
53 // used to record our notion of the pre-existing fonts
54 struct FontRec {
55     SkRefPtr<SkTypeface> fTypeface;
56     SkString fFileName;
57     SkTypeface::Style fStyle;
58     bool fIsValid;
59     FamilyRecID fFamilyRecID;
60 };
61 
62 struct FamilyRec {
FamilyRecFamilyRec63     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 
75 typedef SkTDArray<FamilyRecID> FallbackFontList;
76 
77 class SkFontConfigInterfaceAndroid : public SkFontConfigInterface {
78 public:
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 
111 private:
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 
getSingletonInterface()134 static 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 
GetSingletonDirectInterface()158 SkFontConfigInterface* SkFontConfigInterface::GetSingletonDirectInterface() {
159     return getSingletonInterface();
160 }
161 
162 ///////////////////////////////////////////////////////////////////////////////
163 
has_font(const SkTArray<FontRec> & array,const SkString & filename)164 static 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 
get_path_for_sys_fonts(SkString * full,const SkString & name)177 static 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 
insert_into_name_dict(SkTDict<FamilyRecID> & familyNameDict,const char * name,FamilyRecID familyRecID)187 static 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
199 bool find_name_and_attributes(SkStream* stream, SkString* name,
200                               SkTypeface::Style* style, bool* isFixedWidth);
201 
202 ///////////////////////////////////////////////////////////////////////////////
203 
SkFontConfigInterfaceAndroid(SkTDArray<FontFamily * > & fontFamilies)204 SkFontConfigInterfaceAndroid::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 
~SkFontConfigInterfaceAndroid()331 SkFontConfigInterfaceAndroid::~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 
addFallbackFamily(FamilyRecID familyRecID)340 void 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 
find_best_style(const FamilyRec & family,SkTypeface::Style style)373 static 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 
matchFamilyName(const char familyName[],SkTypeface::Style style,FontIdentity * outFontIdentifier,SkString * outFamilyName,SkTypeface::Style * outStyle)400 bool 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 
openStream(const FontIdentity & identity)457 SkStream* SkFontConfigInterfaceAndroid::openStream(const FontIdentity& identity) {
458     return SkStream::NewFromFile(identity.fString.c_str());
459 }
460 
getFamilyNames()461 SkDataTable* 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 
matchFamilySet(const char inFamilyName[],SkString * outFamilyName,SkTArray<FontIdentity> *)479 bool SkFontConfigInterfaceAndroid::matchFamilySet(const char inFamilyName[],
480                                                   SkString* outFamilyName,
481                                                   SkTArray<FontIdentity>*) {
482     return false;
483 }
484 
find_proc(SkTypeface * face,SkTypeface::Style style,void * ctx)485 static 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 
getTypefaceForFontRec(FontRecID fontRecID)491 SkTypeface* 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 
getFallbackFamilyNameForChar(SkUnichar uni,const char * lang,SkString * name)513 bool 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 
getTypefaceForChar(SkUnichar uni,SkTypeface::Style style,SkPaintOptionsAndroid::FontVariant fontVariant)551 SkTypeface* 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 
getCurrentLocaleFallbackFontList()577 FallbackFontList* 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 
findFallbackFontList(const SkLanguage & lang,bool isOriginal)586 FallbackFontList* 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 
nextLogicalTypeface(SkFontID currFontID,SkFontID origFontID,const SkPaintOptionsAndroid & opts)611 SkTypeface* 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 
getTypefaceForGlyphID(uint16_t glyphID,const SkTypeface * origTypeface,const SkPaintOptionsAndroid & opts,int * lBounds,int * uBounds)685 SkTypeface* 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 
SkGetFallbackFamilyNameForChar(SkUnichar uni,SkString * name)742 bool SkGetFallbackFamilyNameForChar(SkUnichar uni, SkString* name) {
743     SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
744     return fontConfig->getFallbackFamilyNameForChar(uni, NULL, name);
745 }
746 
SkGetFallbackFamilyNameForChar(SkUnichar uni,const char * lang,SkString * name)747 bool SkGetFallbackFamilyNameForChar(SkUnichar uni, const char* lang, SkString* name) {
748     SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
749     return fontConfig->getFallbackFamilyNameForChar(uni, lang, name);
750 }
751 
SkUseTestFontConfigFile(const char * mainconf,const char * fallbackconf,const char * fontsdir)752 void 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 
SkAndroidNextLogicalTypeface(SkFontID currFontID,SkFontID origFontID,const SkPaintOptionsAndroid & options)764 SkTypeface* SkAndroidNextLogicalTypeface(SkFontID currFontID, SkFontID origFontID,
765                                          const SkPaintOptionsAndroid& options) {
766     SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
767     return fontConfig->nextLogicalTypeface(currFontID, origFontID, options);
768 
769 }
770 
SkGetTypefaceForGlyphID(uint16_t glyphID,const SkTypeface * origTypeface,const SkPaintOptionsAndroid & options,int * lowerBounds,int * upperBounds)771 SkTypeface* 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 
783 struct 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 
803 static 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"
getUnicodeFromHBScript(hb_script_t script)837 static 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 
849 struct TypefaceLookupStruct {
850     hb_script_t script;
851     SkTypeface::Style style;
852     SkPaintOptionsAndroid::FontVariant fontVariant;
853     SkTypeface* typeface;
854 };
855 
856 SK_DECLARE_STATIC_MUTEX(gTypefaceTableMutex);  // This is the mutex for gTypefaceTable
857 static SkTDArray<TypefaceLookupStruct> gTypefaceTable;  // This is protected by gTypefaceTableMutex
858 
typefaceLookupCompare(const TypefaceLookupStruct & first,const TypefaceLookupStruct & second)859 static 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 
SkCreateTypefaceForScript(hb_script_t script,SkTypeface::Style style,SkPaintOptionsAndroid::FontVariant fontVariant)873 SkTypeface* 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 
Factory()913 SkFontMgr* SkFontMgr::Factory() {
914     return NULL;
915 }
916