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