OLD | NEW |
---|---|
(Empty) | |
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 "SkFontHost_FreeType_common.h" | |
15 #include "SkFontMgr.h" | |
16 #include "SkGlyphCache.h" | |
17 #include "SkPaint.h" | |
18 #include "SkString.h" | |
19 #include "SkStream.h" | |
20 #include "SkThread.h" | |
21 #include "SkTypefaceCache.h" | |
22 #include "SkTArray.h" | |
23 #include "SkTDict.h" | |
24 #include "SkTSearch.h" | |
25 | |
26 #include <stdio.h> | |
27 #include <string.h> | |
28 | |
29 #ifndef SK_DEBUG_FONTS | |
30 #define SK_DEBUG_FONTS 0 | |
31 #endif | |
32 | |
33 #if SK_DEBUG_FONTS | |
34 #define DEBUG_FONT(args) SkDebugf args | |
35 #else | |
36 #define DEBUG_FONT(args) | |
37 #endif | |
38 | |
39 /////////////////////////////////////////////////////////////////////////////// | |
40 | |
41 // For test only. | |
42 static const char* gTestMainConfigFile = NULL; | |
43 static const char* gTestFallbackConfigFile = NULL; | |
44 static const char* gTestFontFilePrefix = NULL; | |
45 | |
46 /////////////////////////////////////////////////////////////////////////////// | |
47 | |
48 typedef int32_t FontRecID; | |
49 #define INVALID_FONT_REC_ID -1 | |
50 | |
51 typedef int32_t FamilyRecID; | |
52 #define INVALID_FAMILY_REC_ID -1 | |
53 | |
54 // used to record our notion of the pre-existing fonts | |
55 struct FontRec { | |
56 SkAutoTUnref<SkTypeface> fTypeface; | |
57 SkString fFileName; | |
58 SkTypeface::Style fStyle; | |
59 bool fIsValid; | |
60 FamilyRecID fFamilyRecID; | |
61 }; | |
62 | |
63 struct FamilyRec { | |
64 FamilyRec() { | |
65 memset(fFontRecID, INVALID_FONT_REC_ID, sizeof(fFontRecID)); | |
66 } | |
67 | |
68 static const int FONT_STYLE_COUNT = 4; | |
69 FontRecID fFontRecID[FONT_STYLE_COUNT]; | |
70 bool fIsFallbackFont; | |
71 SkString fFallbackName; | |
72 SkPaintOptionsAndroid fPaintOptions; | |
73 }; | |
74 | |
75 | |
76 typedef SkTDArray<FamilyRecID> FallbackFontList; | |
77 | |
78 class SkFontConfigInterfaceAndroid : public SkFontConfigInterface { | |
79 public: | |
80 SkFontConfigInterfaceAndroid(SkTDArray<FontFamily*>& fontFamilies); | |
81 virtual ~SkFontConfigInterfaceAndroid(); | |
82 | |
83 virtual bool matchFamilyName(const char familyName[], | |
84 SkTypeface::Style requested, | |
85 FontIdentity* outFontIdentifier, | |
86 SkString* outFamilyName, | |
87 SkTypeface::Style* outStyle) SK_OVERRIDE; | |
88 virtual SkStream* openStream(const FontIdentity&) SK_OVERRIDE; | |
89 | |
90 // new APIs | |
91 virtual SkDataTable* getFamilyNames() SK_OVERRIDE; | |
92 virtual bool matchFamilySet(const char inFamilyName[], | |
93 SkString* outFamilyName, | |
94 SkTArray<FontIdentity>*) SK_OVERRIDE; | |
95 | |
96 /** | |
97 * Get the family name of the font in the default fallback font list that | |
98 * contains the specified chararacter. if no font is found, returns false. | |
99 */ | |
100 bool getFallbackFamilyNameForChar(SkUnichar uni, const char* lang, SkString* name); | |
101 | |
102 private: | |
103 void addFallbackFamily(FamilyRecID fontRecID); | |
104 SkTypeface* getTypefaceForFontRec(FontRecID fontRecID); | |
105 FallbackFontList* getCurrentLocaleFallbackFontList(); | |
106 FallbackFontList* findFallbackFontList(const SkLanguage& lang, bool isOrigin al = true); | |
107 | |
108 SkTArray<FontRec, true> fFonts; | |
109 SkTArray<FamilyRec, true> fFontFamilies; | |
110 SkTDict<FamilyRecID> fFamilyNameDict; | |
111 FamilyRecID fDefaultFamilyRecID; | |
112 | |
113 // (SkLanguage)<->(fallback chain index) translation | |
114 SkTDict<FallbackFontList*> fFallbackFontDict; | |
115 SkTDict<FallbackFontList*> fFallbackFontAliasDict; | |
116 FallbackFontList fDefaultFallbackList; | |
117 | |
118 // fallback info for current locale | |
119 SkString fCachedLocale; | |
120 FallbackFontList* fLocaleFallbackFontList; | |
121 }; | |
122 | |
123 /////////////////////////////////////////////////////////////////////////////// | |
124 | |
125 SK_DECLARE_STATIC_MUTEX(gGetSingletonInterfaceMutex); | |
126 static SkFontConfigInterfaceAndroid* getSingletonInterface() { | |
127 static SkFontConfigInterfaceAndroid* gFontConfigInterface; | |
128 | |
129 SkAutoMutexAcquire ac(gGetSingletonInterfaceMutex); | |
130 if (NULL == gFontConfigInterface) { | |
131 // load info from a configuration file that we can use to populate the | |
132 // system/fallback font structures | |
133 SkTDArray<FontFamily*> fontFamilies; | |
134 if (!gTestMainConfigFile) { | |
135 SkFontConfigParser::GetFontFamilies(fontFamilies); | |
136 } else { | |
137 SkFontConfigParser::GetTestFontFamilies(fontFamilies, gTestMainConfi gFile, | |
138 gTestFallbackConfigFile); | |
139 } | |
140 | |
141 gFontConfigInterface = new SkFontConfigInterfaceAndroid(fontFamilies); | |
142 | |
143 // cleanup the data we received from the parser | |
144 fontFamilies.deleteAll(); | |
145 } | |
146 return gFontConfigInterface; | |
147 } | |
148 | |
149 SkFontConfigInterface* SkFontConfigInterface::GetSingletonDirectInterface(SkBase Mutex*) { | |
150 // Doesn't need passed-in mutex because getSingletonInterface() uses one | |
151 return getSingletonInterface(); | |
152 } | |
153 | |
154 /////////////////////////////////////////////////////////////////////////////// | |
155 | |
156 static bool has_font(const SkTArray<FontRec, true>& array, const SkString& filen ame) { | |
157 for (int i = 0; i < array.count(); i++) { | |
158 if (array[i].fFileName == filename) { | |
159 return true; | |
160 } | |
161 } | |
162 return false; | |
163 } | |
164 | |
165 #ifndef SK_FONT_FILE_PREFIX | |
166 #define SK_FONT_FILE_PREFIX "/fonts/" | |
167 #endif | |
168 | |
169 static void get_path_for_sys_fonts(SkString* full, const SkString& name) { | |
170 if (gTestFontFilePrefix) { | |
171 full->set(gTestFontFilePrefix); | |
172 } else { | |
173 full->set(getenv("ANDROID_ROOT")); | |
174 full->append(SK_FONT_FILE_PREFIX); | |
175 } | |
176 full->append(name); | |
177 } | |
178 | |
179 static void insert_into_name_dict(SkTDict<FamilyRecID>& familyNameDict, | |
180 const char* name, FamilyRecID familyRecID) { | |
181 SkAutoAsciiToLC tolc(name); | |
182 if (familyNameDict.find(tolc.lc())) { | |
183 SkDebugf("---- system font attempting to use a the same name [%s] for" | |
184 "multiple families. skipping subsequent occurrences", tolc.lc() ); | |
185 } else { | |
186 familyNameDict.set(tolc.lc(), familyRecID); | |
187 } | |
188 } | |
189 | |
190 /////////////////////////////////////////////////////////////////////////////// | |
191 | |
192 SkFontConfigInterfaceAndroid::SkFontConfigInterfaceAndroid(SkTDArray<FontFamily* >& fontFamilies) : | |
193 fFonts(fontFamilies.count()), | |
194 fFontFamilies(fontFamilies.count() / FamilyRec::FONT_STYLE_COUNT), | |
195 fFamilyNameDict(1024), | |
196 fDefaultFamilyRecID(INVALID_FAMILY_REC_ID), | |
197 fFallbackFontDict(128), | |
198 fFallbackFontAliasDict(128), | |
199 fLocaleFallbackFontList(NULL) { | |
200 | |
201 for (int i = 0; i < fontFamilies.count(); ++i) { | |
202 FontFamily* family = fontFamilies[i]; | |
203 | |
204 // defer initializing the familyRec until we can be sure that at least | |
205 // one of it's children contains a valid font file | |
206 FamilyRec* familyRec = NULL; | |
207 FamilyRecID familyRecID = INVALID_FAMILY_REC_ID; | |
208 | |
209 for (int j = 0; j < family->fFontFiles.count(); ++j) { | |
210 SkString filename; | |
211 get_path_for_sys_fonts(&filename, family->fFontFiles[j].fFileName); | |
212 | |
213 if (has_font(fFonts, filename)) { | |
214 SkDebugf("---- system font and fallback font files specify a dup licate " | |
215 "font %s, skipping the second occurrence", filename.c_st r()); | |
216 continue; | |
217 } | |
218 | |
219 FontRec& fontRec = fFonts.push_back(); | |
220 fontRec.fFileName = filename; | |
221 fontRec.fStyle = SkTypeface::kNormal; | |
222 fontRec.fIsValid = false; | |
223 fontRec.fFamilyRecID = familyRecID; | |
224 | |
225 const FontRecID fontRecID = fFonts.count() - 1; | |
226 | |
227 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(filename.c_str() )); | |
228 if (stream.get() != NULL) { | |
229 bool isFixedWidth; | |
230 SkString name; | |
231 fontRec.fIsValid = SkTypeface_FreeType::ScanFont(stream.get(), 0 , | |
232 &name, &fontRec .fStyle, | |
233 &isFixedWidth); | |
234 } else { | |
235 if (!family->fIsFallbackFont) { | |
236 SkDebugf("---- failed to open <%s> as a font\n", filename.c_ str()); | |
237 } | |
238 } | |
239 | |
240 if (fontRec.fIsValid) { | |
241 DEBUG_FONT(("---- SystemFonts[%d][%d] fallback=%d file=%s", | |
242 i, fFonts.count() - 1, family->fIsFallbackFont, filen ame.c_str())); | |
243 } else { | |
244 DEBUG_FONT(("---- SystemFonts[%d][%d] fallback=%d file=%s (INVAL ID)", | |
245 i, fFonts.count() - 1, family->fIsFallbackFont, filen ame.c_str())); | |
246 continue; | |
247 } | |
248 | |
249 // create a familyRec now that we know that at least one font in | |
250 // the family is valid | |
251 if (familyRec == NULL) { | |
252 familyRec = &fFontFamilies.push_back(); | |
253 familyRecID = fFontFamilies.count() - 1; | |
254 fontRec.fFamilyRecID = familyRecID; | |
255 | |
256 familyRec->fIsFallbackFont = family->fIsFallbackFont; | |
257 familyRec->fPaintOptions = family->fFontFiles[j].fPaintOptions; | |
258 | |
259 } else if (familyRec->fPaintOptions != family->fFontFiles[j].fPaintO ptions) { | |
260 SkDebugf("Every font file within a family must have identical" | |
261 "language and variant attributes"); | |
262 sk_throw(); | |
263 } | |
264 | |
265 // add this font to the current familyRec | |
266 if (INVALID_FONT_REC_ID != familyRec->fFontRecID[fontRec.fStyle]) { | |
267 DEBUG_FONT(("Overwriting familyRec for style[%d] old,new:(%d,%d) ", | |
268 fontRec.fStyle, familyRec->fFontRecID[fontRec.fStyle ], | |
269 fontRecID)); | |
270 } | |
271 familyRec->fFontRecID[fontRec.fStyle] = fontRecID; | |
272 } | |
273 | |
274 if (familyRec) { | |
275 if (familyRec->fIsFallbackFont) { | |
276 // add the font to the appropriate fallback chains and also inse rt a | |
277 // unique name into the familyNameDict for internal usage | |
278 addFallbackFamily(familyRecID); | |
279 } else { | |
280 // add the names that map to this family to the dictionary for e asy lookup | |
281 const SkTArray<SkString>& names = family->fNames; | |
282 if (names.empty()) { | |
283 SkDEBUGFAIL("ERROR: non-fallback font with no name"); | |
284 continue; | |
285 } | |
286 | |
287 for (int i = 0; i < names.count(); i++) { | |
288 insert_into_name_dict(fFamilyNameDict, names[i].c_str(), fam ilyRecID); | |
289 } | |
290 } | |
291 } | |
292 } | |
293 | |
294 DEBUG_FONT(("---- We have %d system fonts", fFonts.count())); | |
295 | |
296 if (fFontFamilies.count() > 0) { | |
297 fDefaultFamilyRecID = 0; | |
298 } | |
299 | |
300 // scans the default fallback font chain, adding every entry to every other | |
301 // fallback font chain to which it does not belong. this results in every | |
302 // language-specific fallback font chain having all of its fallback fonts at | |
303 // the front of the chain, and everything else at the end. | |
304 FallbackFontList* fallbackList; | |
305 SkTDict<FallbackFontList*>::Iter iter(fFallbackFontDict); | |
306 const char* fallbackLang = iter.next(&fallbackList); | |
307 while(fallbackLang != NULL) { | |
308 for (int i = 0; i < fDefaultFallbackList.count(); i++) { | |
309 FamilyRecID familyRecID = fDefaultFallbackList[i]; | |
310 const SkString& fontLang = fFontFamilies[familyRecID].fPaintOptions. getLanguage().getTag(); | |
311 if (strcmp(fallbackLang, fontLang.c_str()) != 0) { | |
312 fallbackList->push(familyRecID); | |
313 } | |
314 } | |
315 // move to the next fallback list in the dictionary | |
316 fallbackLang = iter.next(&fallbackList); | |
317 } | |
318 } | |
319 | |
320 SkFontConfigInterfaceAndroid::~SkFontConfigInterfaceAndroid() { | |
321 // iterate through and cleanup fFallbackFontDict | |
322 SkTDict<FallbackFontList*>::Iter iter(fFallbackFontDict); | |
323 FallbackFontList* fallbackList; | |
324 while(iter.next(&fallbackList) != NULL) { | |
325 SkDELETE(fallbackList); | |
326 } | |
327 } | |
328 | |
329 void SkFontConfigInterfaceAndroid::addFallbackFamily(FamilyRecID familyRecID) { | |
330 SkASSERT(familyRecID < fFontFamilies.count()); | |
331 FamilyRec& familyRec = fFontFamilies[familyRecID]; | |
332 SkASSERT(familyRec.fIsFallbackFont); | |
333 | |
334 // add the fallback family to the name dictionary. This is | |
335 // needed by getFallbackFamilyNameForChar() so that fallback | |
336 // families can be identified by a unique name. The unique | |
337 // identifier that we've chosen is the familyID in hex (e.g. '0F##fallback') . | |
338 familyRec.fFallbackName.printf("%.2x##fallback", familyRecID); | |
339 insert_into_name_dict(fFamilyNameDict, familyRec.fFallbackName.c_str(), fami lyRecID); | |
340 | |
341 // add to the default fallback list | |
342 fDefaultFallbackList.push(familyRecID); | |
343 | |
344 // stop here if it is the default language tag | |
345 const SkString& languageTag = familyRec.fPaintOptions.getLanguage().getTag() ; | |
346 if (languageTag.isEmpty()) { | |
347 return; | |
348 } | |
349 | |
350 // add to the appropriate language's custom fallback list | |
351 FallbackFontList* customList = NULL; | |
352 if (!fFallbackFontDict.find(languageTag.c_str(), &customList)) { | |
353 DEBUG_FONT(("---- Created fallback list for \"%s\"", languageTag.c_str( ))); | |
354 customList = SkNEW(FallbackFontList); | |
355 fFallbackFontDict.set(languageTag.c_str(), customList); | |
356 } | |
357 SkASSERT(customList != NULL); | |
358 customList->push(familyRecID); | |
359 } | |
360 | |
361 | |
362 static FontRecID find_best_style(const FamilyRec& family, SkTypeface::Style styl e) { | |
363 | |
364 const FontRecID* fontRecIDs = family.fFontRecID; | |
365 | |
366 if (fontRecIDs[style] != INVALID_FONT_REC_ID) { // exact match | |
367 return fontRecIDs[style]; | |
368 } | |
369 // look for a matching bold | |
370 style = (SkTypeface::Style)(style ^ SkTypeface::kItalic); | |
371 if (fontRecIDs[style] != INVALID_FONT_REC_ID) { | |
372 return fontRecIDs[style]; | |
373 } | |
374 // look for the plain | |
375 if (fontRecIDs[SkTypeface::kNormal] != INVALID_FONT_REC_ID) { | |
376 return fontRecIDs[SkTypeface::kNormal]; | |
377 } | |
378 // look for anything | |
379 for (int i = 0; i < FamilyRec::FONT_STYLE_COUNT; i++) { | |
380 if (fontRecIDs[i] != INVALID_FONT_REC_ID) { | |
381 return fontRecIDs[i]; | |
382 } | |
383 } | |
384 // should never get here, since the fontRecID list should not be empty | |
385 SkDEBUGFAIL("No valid fonts exist for this family"); | |
386 return -1; | |
387 } | |
388 | |
389 bool SkFontConfigInterfaceAndroid::matchFamilyName(const char familyName[], | |
390 SkTypeface::Style style, | |
391 FontIdentity* outFontIdentifi er, | |
392 SkString* outFamilyName, | |
393 SkTypeface::Style* outStyle) { | |
394 // clip to legal style bits | |
395 style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic); | |
396 | |
397 bool exactNameMatch = false; | |
398 | |
399 FamilyRecID familyRecID = INVALID_FAMILY_REC_ID; | |
400 if (NULL != familyName) { | |
401 SkAutoAsciiToLC tolc(familyName); | |
402 if (fFamilyNameDict.find(tolc.lc(), &familyRecID)) { | |
403 exactNameMatch = true; | |
404 } | |
405 } else { | |
406 familyRecID = fDefaultFamilyRecID; | |
407 | |
408 } | |
409 | |
410 // If no matching family name is found then return false. This allows client s | |
411 // to be able to search for other fonts instead of forcing them to use the | |
412 // default font. | |
413 if (INVALID_FAMILY_REC_ID == familyRecID) { | |
414 return false; | |
415 } | |
416 | |
417 FontRecID fontRecID = find_best_style(fFontFamilies[familyRecID], style); | |
418 FontRec& fontRec = fFonts[fontRecID]; | |
419 | |
420 if (NULL != outFontIdentifier) { | |
421 outFontIdentifier->fID = fontRecID; | |
422 outFontIdentifier->fTTCIndex = 0; | |
423 outFontIdentifier->fString.set(fontRec.fFileName); | |
424 // outFontIdentifier->fStyle = fontRec.fStyle; | |
425 } | |
426 | |
427 if (NULL != outFamilyName) { | |
428 if (exactNameMatch) { | |
429 outFamilyName->set(familyName); | |
430 } else { | |
431 // find familyName from list of names | |
432 const char* familyName = NULL; | |
433 SkAssertResult(fFamilyNameDict.findKey(familyRecID, &familyName)); | |
434 SkASSERT(familyName); | |
435 outFamilyName->set(familyName); | |
436 } | |
437 } | |
438 | |
439 if (NULL != outStyle) { | |
440 *outStyle = fontRec.fStyle; | |
441 } | |
442 | |
443 return true; | |
444 } | |
445 | |
446 SkStream* SkFontConfigInterfaceAndroid::openStream(const FontIdentity& identity) { | |
447 return SkStream::NewFromFile(identity.fString.c_str()); | |
448 } | |
449 | |
450 SkDataTable* SkFontConfigInterfaceAndroid::getFamilyNames() { | |
451 SkTDArray<const char*> names; | |
452 SkTDArray<size_t> sizes; | |
453 | |
454 SkTDict<FamilyRecID>::Iter iter(fFamilyNameDict); | |
455 const char* familyName = iter.next(NULL); | |
456 while(familyName != NULL) { | |
457 *names.append() = familyName; | |
458 *sizes.append() = strlen(familyName) + 1; | |
459 | |
460 // move to the next familyName in the dictionary | |
461 familyName = iter.next(NULL); | |
462 } | |
463 | |
464 return SkDataTable::NewCopyArrays((const void*const*)names.begin(), | |
465 sizes.begin(), names.count()); | |
466 } | |
467 | |
468 bool SkFontConfigInterfaceAndroid::matchFamilySet(const char inFamilyName[], | |
469 SkString* outFamilyName, | |
470 SkTArray<FontIdentity>*) { | |
471 return false; | |
472 } | |
473 | |
474 static bool find_proc(SkTypeface* face, SkTypeface::Style style, void* ctx) { | |
475 const FontRecID* fontRecID = (const FontRecID*)ctx; | |
476 FontRecID currFontRecID = ((FontConfigTypeface*)face)->getIdentity().fID; | |
477 return currFontRecID == *fontRecID; | |
478 } | |
479 | |
480 SkTypeface* SkFontConfigInterfaceAndroid::getTypefaceForFontRec(FontRecID fontRe cID) { | |
481 FontRec& fontRec = fFonts[fontRecID]; | |
482 SkTypeface* face = fontRec.fTypeface.get(); | |
483 if (!face) { | |
484 // look for it in the typeface cache | |
485 face = SkTypefaceCache::FindByProcAndRef(find_proc, &fontRecID); | |
486 | |
487 // if it is not in the cache then create it | |
488 if (!face) { | |
489 const char* familyName = NULL; | |
490 SkAssertResult(fFamilyNameDict.findKey(fontRec.fFamilyRecID, &family Name)); | |
491 SkASSERT(familyName); | |
492 face = SkTypeface::CreateFromName(familyName, fontRec.fStyle); | |
493 } | |
494 | |
495 // store the result for subsequent lookups | |
496 fontRec.fTypeface.reset(face); | |
497 } | |
498 SkASSERT(face); | |
499 return face; | |
500 } | |
501 | |
502 bool SkFontConfigInterfaceAndroid::getFallbackFamilyNameForChar(SkUnichar uni, | |
503 const char* lang , | |
504 SkString* name) { | |
505 FallbackFontList* fallbackFontList = NULL; | |
506 const SkString langTag(lang); | |
507 if (langTag.isEmpty()) { | |
508 fallbackFontList = this->getCurrentLocaleFallbackFontList(); | |
509 } else { | |
510 fallbackFontList = this->findFallbackFontList(langTag); | |
511 } | |
512 | |
513 for (int i = 0; i < fallbackFontList->count(); i++) { | |
514 FamilyRecID familyRecID = fallbackFontList->getAt(i); | |
515 | |
516 // if it is not one of the accepted variants then move to the next famil y | |
517 int32_t acceptedVariants = SkPaintOptionsAndroid::kDefault_Variant | | |
518 SkPaintOptionsAndroid::kElegant_Variant; | |
519 if (!(fFontFamilies[familyRecID].fPaintOptions.getFontVariant() & accept edVariants)) { | |
520 continue; | |
521 } | |
522 | |
523 FontRecID fontRecID = find_best_style(fFontFamilies[familyRecID], SkType face::kNormal); | |
524 SkTypeface* face = this->getTypefaceForFontRec(fontRecID); | |
525 | |
526 SkPaint paint; | |
527 paint.setTypeface(face); | |
528 paint.setTextEncoding(SkPaint::kUTF32_TextEncoding); | |
529 | |
530 uint16_t glyphID; | |
531 paint.textToGlyphs(&uni, sizeof(uni), &glyphID); | |
532 if (glyphID != 0) { | |
533 name->set(fFontFamilies[familyRecID].fFallbackName); | |
534 return true; | |
535 } | |
536 } | |
537 return false; | |
538 } | |
539 | |
540 FallbackFontList* SkFontConfigInterfaceAndroid::getCurrentLocaleFallbackFontList () { | |
541 SkString locale = SkFontConfigParser::GetLocale(); | |
542 if (NULL == fLocaleFallbackFontList || locale != fCachedLocale) { | |
543 fCachedLocale = locale; | |
544 fLocaleFallbackFontList = this->findFallbackFontList(locale); | |
545 } | |
546 return fLocaleFallbackFontList; | |
547 } | |
548 | |
549 FallbackFontList* SkFontConfigInterfaceAndroid::findFallbackFontList(const SkLan guage& lang, | |
550 bool isOrig inal) { | |
551 const SkString& langTag = lang.getTag(); | |
552 if (langTag.isEmpty()) { | |
553 return &fDefaultFallbackList; | |
554 } | |
555 | |
556 FallbackFontList* fallbackFontList; | |
557 if (fFallbackFontDict.find(langTag.c_str(), langTag.size(), &fallbackFontLis t) || | |
558 fFallbackFontAliasDict.find(langTag.c_str(), langTag.size(), &fallbackFo ntList)) { | |
559 return fallbackFontList; | |
560 } | |
561 | |
562 // attempt a recursive fuzzy match | |
563 SkLanguage parent = lang.getParent(); | |
564 fallbackFontList = findFallbackFontList(parent, false); | |
565 | |
566 // cache the original lang so we don't have to do the recursion again. | |
567 if (isOriginal) { | |
568 DEBUG_FONT(("---- Created fallback list alias for \"%s\"", langTag.c_st r())); | |
569 fFallbackFontAliasDict.set(langTag.c_str(), fallbackFontList); | |
570 } | |
571 return fallbackFontList; | |
572 } | |
573 | |
574 /////////////////////////////////////////////////////////////////////////////// | |
575 | |
576 bool SkGetFallbackFamilyNameForChar(SkUnichar uni, const char* lang, SkString* n ame) { | |
bungeman-skia
2014/08/06 20:29:43
Clank still needs this until it switches, is it sa
djsollen
2014/08/07 14:03:42
It is not safe yet, as we will need your chromium
| |
577 SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface(); | |
578 return fontConfig->getFallbackFamilyNameForChar(uni, lang, name); | |
579 } | |
580 | |
581 void SkUseTestFontConfigFile(const char* mainconf, const char* fallbackconf, | |
582 const char* fontsdir) { | |
583 gTestMainConfigFile = mainconf; | |
584 gTestFallbackConfigFile = fallbackconf; | |
585 gTestFontFilePrefix = fontsdir; | |
586 SkASSERT(gTestMainConfigFile); | |
587 SkASSERT(gTestFallbackConfigFile); | |
588 SkASSERT(gTestFontFilePrefix); | |
589 SkDEBUGF(("Use Test Config File Main %s, Fallback %s, Font Dir %s", | |
590 gTestMainConfigFile, gTestFallbackConfigFile, gTestFontFilePrefix) ); | |
591 } | |
OLD | NEW |