|
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 { |
|
63 FamilyRec() { |
|
64 memset(fFontRecID, INVALID_FONT_REC_ID, sizeof(fFontRecID)); |
|
65 } |
|
66 |
|
67 static const int FONT_STYLE_COUNT = 4; |
|
68 FontRecID fFontRecID[FONT_STYLE_COUNT]; |
|
69 bool fIsFallbackFont; |
|
70 SkString fFallbackName; |
|
71 SkPaintOptionsAndroid fPaintOptions; |
|
72 }; |
|
73 |
|
74 |
|
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 |
|
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 |
|
158 SkFontConfigInterface* SkFontConfigInterface::GetSingletonDirectInterface() { |
|
159 return getSingletonInterface(); |
|
160 } |
|
161 |
|
162 /////////////////////////////////////////////////////////////////////////////// |
|
163 |
|
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 |
|
177 static void get_path_for_sys_fonts(SkString* full, const char 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 |
|
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 |
|
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 SkTDArray<const char*>& names = family->fNames; |
|
293 if (names.isEmpty()) { |
|
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], 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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
457 SkStream* SkFontConfigInterfaceAndroid::openStream(const FontIdentity& identity) { |
|
458 return SkStream::NewFromFile(identity.fString.c_str()); |
|
459 } |
|
460 |
|
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 |
|
479 bool SkFontConfigInterfaceAndroid::matchFamilySet(const char inFamilyName[], |
|
480 SkString* outFamilyName, |
|
481 SkTArray<FontIdentity>*) { |
|
482 return false; |
|
483 } |
|
484 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
742 bool SkGetFallbackFamilyNameForChar(SkUnichar uni, SkString* name) { |
|
743 SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface(); |
|
744 return fontConfig->getFallbackFamilyNameForChar(uni, NULL, name); |
|
745 } |
|
746 |
|
747 bool SkGetFallbackFamilyNameForChar(SkUnichar uni, const char* lang, SkString* name) { |
|
748 SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface(); |
|
749 return fontConfig->getFallbackFamilyNameForChar(uni, lang, name); |
|
750 } |
|
751 |
|
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 |
|
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 |
|
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" |
|
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 |
|
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 |
|
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 |
|
913 SkFontMgr* SkFontMgr::Factory() { |
|
914 return NULL; |
|
915 } |