blob: 2e2d88d689bbdfaf80cb4d6e221ac5ab291012e5 [file] [log] [blame]
djsollen@google.combfae9d32013-05-21 16:53:50 +00001
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"
djsollen@google.combfae9d32013-05-21 16:53:50 +000017#include "SkString.h"
18#include "SkStream.h"
19#include "SkThread.h"
20#include "SkTypefaceCache.h"
21#include "SkTArray.h"
22#include "SkTDict.h"
23#include "SkTSearch.h"
24
25#include <stdio.h>
26#include <string.h>
27
28#ifndef SK_DEBUG_FONTS
29 #define SK_DEBUG_FONTS 0
30#endif
31
32#if SK_DEBUG_FONTS
33 #define DEBUG_FONT(args) SkDebugf args
34#else
35 #define DEBUG_FONT(args)
36#endif
37
38///////////////////////////////////////////////////////////////////////////////
39
40// For test only.
41static const char* gTestMainConfigFile = NULL;
42static const char* gTestFallbackConfigFile = NULL;
43static const char* gTestFontFilePrefix = NULL;
44
45///////////////////////////////////////////////////////////////////////////////
46
djsollen@google.com40078cb2013-05-24 20:31:57 +000047typedef int32_t FontRecID;
48#define INVALID_FONT_REC_ID -1
49
50typedef int32_t FamilyRecID;
51#define INVALID_FAMILY_REC_ID -1
52
djsollen@google.combfae9d32013-05-21 16:53:50 +000053// used to record our notion of the pre-existing fonts
54struct FontRec {
55 SkRefPtr<SkTypeface> fTypeface;
56 SkString fFileName;
57 SkTypeface::Style fStyle;
58 SkPaintOptionsAndroid fPaintOptions;
59 bool fIsFallbackFont;
60 bool fIsValid;
djsollen@google.com40078cb2013-05-24 20:31:57 +000061 FamilyRecID fFamilyRecID;
djsollen@google.combfae9d32013-05-21 16:53:50 +000062};
63
djsollen@google.combfae9d32013-05-21 16:53:50 +000064struct FamilyRec {
65 FamilyRec() {
66 memset(fFontRecID, INVALID_FONT_REC_ID, sizeof(fFontRecID));
67 }
68
69 static const int FONT_STYLE_COUNT = 4;
70 FontRecID fFontRecID[FONT_STYLE_COUNT];
71};
72
djsollen@google.combfae9d32013-05-21 16:53:50 +000073
74typedef SkTDArray<FontRecID> FallbackFontList;
75
76class SkFontConfigInterfaceAndroid : public SkFontConfigInterface {
77public:
78 SkFontConfigInterfaceAndroid(SkTDArray<FontFamily*>& fontFamilies);
79 virtual ~SkFontConfigInterfaceAndroid();
80
81 virtual bool matchFamilyName(const char familyName[],
82 SkTypeface::Style requested,
83 FontIdentity* outFontIdentifier,
84 SkString* outFamilyName,
85 SkTypeface::Style* outStyle) SK_OVERRIDE;
86 virtual SkStream* openStream(const FontIdentity&) SK_OVERRIDE;
87
88 // new APIs
89 virtual SkDataTable* getFamilyNames() SK_OVERRIDE;
90 virtual bool matchFamilySet(const char inFamilyName[],
91 SkString* outFamilyName,
92 SkTArray<FontIdentity>*) SK_OVERRIDE;
93
94 /**
95 * Get the family name of the font in the default fallback font list that
96 * contains the specified chararacter. if no font is found, returns false.
97 */
98 bool getFallbackFamilyNameForChar(SkUnichar uni, SkString* name);
99 /**
100 *
101 */
102 SkTypeface* getTypefaceForChar(SkUnichar uni, SkTypeface::Style style,
103 SkPaintOptionsAndroid::FontVariant fontVariant);
104 SkTypeface* nextLogicalTypeface(SkFontID currFontID, SkFontID origFontID,
105 const SkPaintOptionsAndroid& options);
106
107private:
108 void addFallbackFont(FontRecID fontRecID);
djsollen@google.com40078cb2013-05-24 20:31:57 +0000109 SkTypeface* getTypefaceForFontRec(FontRecID fontRecID);
110 FallbackFontList* findFallbackFontList(const SkLanguage& lang, bool isOriginal = true);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000111
112 SkTArray<FontRec> fFonts;
113 SkTArray<FamilyRec> fFontFamilies;
114 SkTDict<FamilyRecID> fFamilyNameDict;
115 FamilyRecID fDefaultFamilyRecID;
116
117 // (SkLanguage)<->(fallback chain index) translation
118 SkTDict<FallbackFontList*> fFallbackFontDict;
djsollen@google.com40078cb2013-05-24 20:31:57 +0000119 SkTDict<FallbackFontList*> fFallbackFontAliasDict;
djsollen@google.combfae9d32013-05-21 16:53:50 +0000120 FallbackFontList fDefaultFallbackList;
121};
122
123///////////////////////////////////////////////////////////////////////////////
124
125static SkFontConfigInterfaceAndroid* getSingletonInterface() {
126 SK_DECLARE_STATIC_MUTEX(gMutex);
127 static SkFontConfigInterfaceAndroid* gFontConfigInterface;
128
129 SkAutoMutexAcquire ac(gMutex);
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, gTestMainConfigFile,
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
149SkFontConfigInterface* SkFontConfigInterface::GetSingletonDirectInterface() {
150 return getSingletonInterface();
151}
152
153///////////////////////////////////////////////////////////////////////////////
154
155static bool has_font(const SkTArray<FontRec>& array, const SkString& filename) {
156 for (int i = 0; i < array.count(); i++) {
157 if (array[i].fFileName == filename) {
158 return true;
159 }
160 }
161 return false;
162}
163
164#ifndef SK_FONT_FILE_PREFIX
165 #define SK_FONT_FILE_PREFIX "/fonts/"
166#endif
167
168static void get_path_for_sys_fonts(SkString* full, const char name[]) {
169 if (gTestFontFilePrefix) {
170 full->set(gTestFontFilePrefix);
171 } else {
172 full->set(getenv("ANDROID_ROOT"));
173 full->append(SK_FONT_FILE_PREFIX);
174 }
175 full->append(name);
176}
177
178static void insert_into_name_dict(SkTDict<FamilyRecID>& familyNameDict,
179 const char* name, FamilyRecID familyRecID) {
180 SkAutoAsciiToLC tolc(name);
181 familyNameDict.set(tolc.lc(), familyRecID);
182}
183
184// Defined in SkFontHost_FreeType.cpp
185bool find_name_and_attributes(SkStream* stream, SkString* name,
186 SkTypeface::Style* style, bool* isFixedWidth);
187
188///////////////////////////////////////////////////////////////////////////////
189
190SkFontConfigInterfaceAndroid::SkFontConfigInterfaceAndroid(SkTDArray<FontFamily*>& fontFamilies) :
191 fFonts(fontFamilies.count()),
192 fFontFamilies(fontFamilies.count() / FamilyRec::FONT_STYLE_COUNT),
193 fFamilyNameDict(1024),
194 fDefaultFamilyRecID(INVALID_FAMILY_REC_ID),
djsollen@google.com40078cb2013-05-24 20:31:57 +0000195 fFallbackFontDict(128),
196 fFallbackFontAliasDict(128) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000197
198 for (int i = 0; i < fontFamilies.count(); ++i) {
199 FontFamily* family = fontFamilies[i];
200
201 // defer initializing the familyRec until we can be sure that at least
202 // one of it's children contains a valid font file
203 FamilyRec* familyRec = NULL;
204 FamilyRecID familyRecID = INVALID_FAMILY_REC_ID;
205
206 for (int j = 0; j < family->fFontFiles.count(); ++j) {
207 SkString filename;
208 get_path_for_sys_fonts(&filename, family->fFontFiles[j]->fFileName);
209
210 if (has_font(fFonts, filename)) {
211 SkDebugf("---- system font and fallback font files specify a duplicate "
212 "font %s, skipping the second occurrence", filename.c_str());
213 continue;
214 }
215
216 FontRec& fontRec = fFonts.push_back();
217 fontRec.fFileName = filename;
218 fontRec.fStyle = SkTypeface::kNormal;
219 fontRec.fPaintOptions = family->fFontFiles[j]->fPaintOptions;
220 fontRec.fIsFallbackFont = family->fIsFallbackFont;
221 fontRec.fIsValid = false;
djsollen@google.com40078cb2013-05-24 20:31:57 +0000222 fontRec.fFamilyRecID = familyRecID;
djsollen@google.combfae9d32013-05-21 16:53:50 +0000223
224 const FontRecID fontRecID = fFonts.count() - 1;
225
226 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(filename.c_str()));
227 if (stream.get() != NULL) {
228 bool isFixedWidth;
229 SkString name;
230 fontRec.fIsValid = find_name_and_attributes(stream.get(), &name,
231 &fontRec.fStyle, &isFixedWidth);
232 } else {
233 if (!fontRec.fIsFallbackFont) {
234 SkDebugf("---- failed to open <%s> as a font\n", filename.c_str());
235 }
236 }
237
238 if (fontRec.fIsValid) {
239 DEBUG_FONT(("---- SystemFonts[%d][%d] fallback=%d file=%s",
240 i, fFonts.count() - 1, fontRec.fIsFallbackFont, filename.c_str()));
241 } else {
242 DEBUG_FONT(("---- SystemFonts[%d][%d] fallback=%d file=%s (INVALID)",
243 i, fFonts.count() - 1, fontRec.fIsFallbackFont, filename.c_str()));
244 continue;
245 }
246
247 // create a familyRec now that we know that at least one font in
248 // the family is valid
249 if (familyRec == NULL) {
250 familyRec = &fFontFamilies.push_back();
251 familyRecID = fFontFamilies.count() - 1;
djsollen@google.com40078cb2013-05-24 20:31:57 +0000252 fontRec.fFamilyRecID = familyRecID;
djsollen@google.combfae9d32013-05-21 16:53:50 +0000253 }
254
255 // add this font to the current familyRec
256 if (INVALID_FONT_REC_ID != familyRec->fFontRecID[fontRec.fStyle]) {
257 DEBUG_FONT(("Overwriting familyRec for style[%d] old,new:(%d,%d)",
258 fontRec.fStyle, familyRec->fFontRecID[fontRec.fStyle],
259 fontRecID));
260 }
261 familyRec->fFontRecID[fontRec.fStyle] = fontRecID;
262
263 // if this is a fallback font then add it to the appropriate fallback chains
264 if (fontRec.fIsFallbackFont) {
265 addFallbackFont(fontRecID);
266 }
267
268 // add the fallback file name to the name dictionary. This is needed
269 // by getFallbackFamilyNameForChar() so that fallback families can be
270 // requested by the filenames of the fonts they contain.
271 if (family->fIsFallbackFont && familyRec) {
272 insert_into_name_dict(fFamilyNameDict, fontRec.fFileName.c_str(), familyRecID);
273 }
274 }
275
276 // add the names that map to this family to the dictionary for easy lookup
277 if (familyRec && !family->fIsFallbackFont) {
278 SkTDArray<const char*> names = family->fNames;
279 if (names.isEmpty()) {
280 SkDEBUGFAIL("ERROR: non-fallback font with no name");
281 continue;
282 }
283
284 for (int i = 0; i < names.count(); i++) {
285 insert_into_name_dict(fFamilyNameDict, names[i], familyRecID);
286 }
287 }
288
289 }
290
291 DEBUG_FONT(("---- We have %d system fonts", fFonts.count()));
292
293 if (fFontFamilies.count() > 0) {
294 fDefaultFamilyRecID = 0;
295 }
296
297 // scans the default fallback font chain, adding every entry to every other
298 // fallback font chain to which it does not belong. this results in every
299 // language-specific fallback font chain having all of its fallback fonts at
300 // the front of the chain, and everything else at the end.
301 FallbackFontList* fallbackList;
302 SkTDict<FallbackFontList*>::Iter iter(fFallbackFontDict);
303 const char* fallbackLang = iter.next(&fallbackList);
304 while(fallbackLang != NULL) {
305 for (int i = 0; i < fDefaultFallbackList.count(); i++) {
306 FontRecID fontRecID = fDefaultFallbackList[i];
307 const SkString& fontLang = fFonts[fontRecID].fPaintOptions.getLanguage().getTag();
308 if (strcmp(fallbackLang, fontLang.c_str()) != 0) {
309 fallbackList->push(fontRecID);
310 }
311 }
312 // move to the next fallback list in the dictionary
313 fallbackLang = iter.next(&fallbackList);
314 }
315}
316
317SkFontConfigInterfaceAndroid::~SkFontConfigInterfaceAndroid() {
318 // iterate through and cleanup fFallbackFontDict
319 SkTDict<FallbackFontList*>::Iter iter(fFallbackFontDict);
320 FallbackFontList* fallbackList;
321 while(iter.next(&fallbackList) != NULL) {
322 SkDELETE(fallbackList);
323 }
324}
325
326void SkFontConfigInterfaceAndroid::addFallbackFont(FontRecID fontRecID) {
327 SkASSERT(fontRecID < fFonts.count());
328 const FontRec& fontRec = fFonts[fontRecID];
329 SkASSERT(fontRec.fIsFallbackFont);
330
331 // add to the default fallback list
332 fDefaultFallbackList.push(fontRecID);
333
334 // stop here if it is the default language tag
335 const SkString& languageTag = fontRec.fPaintOptions.getLanguage().getTag();
336 if (languageTag.isEmpty()) {
337 return;
338 }
339
340 // add to the appropriate language's custom fallback list
341 FallbackFontList* customList = NULL;
342 if (!fFallbackFontDict.find(languageTag.c_str(), &customList)) {
343 DEBUG_FONT(("---- Created fallback list for \"%s\"", languageTag.c_str()));
344 customList = SkNEW(FallbackFontList);
345 fFallbackFontDict.set(languageTag.c_str(), customList);
346 }
347 SkASSERT(customList != NULL);
348 customList->push(fontRecID);
349}
350
351
352static FontRecID find_best_style(const FamilyRec& family, SkTypeface::Style style) {
353
354 const FontRecID* fontRecIDs = family.fFontRecID;
355
356 if (fontRecIDs[style] != INVALID_FONT_REC_ID) { // exact match
357 return fontRecIDs[style];
358 }
359 // look for a matching bold
360 style = (SkTypeface::Style)(style ^ SkTypeface::kItalic);
361 if (fontRecIDs[style] != INVALID_FONT_REC_ID) {
362 return fontRecIDs[style];
363 }
364 // look for the plain
365 if (fontRecIDs[SkTypeface::kNormal] != INVALID_FONT_REC_ID) {
366 return fontRecIDs[SkTypeface::kNormal];
367 }
368 // look for anything
369 for (int i = 0; i < FamilyRec::FONT_STYLE_COUNT; i++) {
370 if (fontRecIDs[i] != INVALID_FONT_REC_ID) {
371 return fontRecIDs[i];
372 }
373 }
374 // should never get here, since the fontRecID list should not be empty
375 SkDEBUGFAIL("No valid fonts exist for this family");
376 return -1;
377}
378
379bool SkFontConfigInterfaceAndroid::matchFamilyName(const char familyName[],
380 SkTypeface::Style style,
381 FontIdentity* outFontIdentifier,
382 SkString* outFamilyName,
robertphillips@google.comb7457d02013-05-22 00:12:43 +0000383 SkTypeface::Style* outStyle) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000384 // clip to legal style bits
385 style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
386
387 bool exactNameMatch = false;
388
389 FamilyRecID familyRecID = INVALID_FAMILY_REC_ID;
390 if (NULL != familyName) {
djsollen@google.com2e08f192013-05-21 20:08:10 +0000391 SkAutoAsciiToLC tolc(familyName);
392 if (fFamilyNameDict.find(tolc.lc(), &familyRecID)) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000393 exactNameMatch = true;
394 }
395 } else {
396 familyRecID = fDefaultFamilyRecID;
397
398 }
399
400 if (INVALID_FAMILY_REC_ID == familyRecID) {
401 //TODO this ensures that we always return something
402 familyRecID = fDefaultFamilyRecID;
403 //return false;
404 }
405
406 FontRecID fontRecID = find_best_style(fFontFamilies[familyRecID], style);
407 FontRec& fontRec = fFonts[fontRecID];
408
409 if (NULL != outFontIdentifier) {
410 outFontIdentifier->fID = fontRecID;
411 outFontIdentifier->fTTCIndex = 0;
412 outFontIdentifier->fString.set(fontRec.fFileName);
413// outFontIdentifier->fStyle = fontRec.fStyle;
414 }
415
416 if (NULL != outFamilyName) {
417 if (exactNameMatch) {
418 outFamilyName->set(familyName);
419 } else {
420 // find familyName from list of names
421 const char* familyName = NULL;
djsollen@google.comab6eeb92013-05-21 17:15:27 +0000422 SkAssertResult(fFamilyNameDict.findKey(familyRecID, &familyName));
423 SkASSERT(familyName);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000424 outFamilyName->set(familyName);
425 }
426 }
427
428 if (NULL != outStyle) {
429 *outStyle = fontRec.fStyle;
430 }
431
432 return true;
433}
434
robertphillips@google.comb7457d02013-05-22 00:12:43 +0000435SkStream* SkFontConfigInterfaceAndroid::openStream(const FontIdentity& identity) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000436 return SkStream::NewFromFile(identity.fString.c_str());
437}
438
robertphillips@google.comb7457d02013-05-22 00:12:43 +0000439SkDataTable* SkFontConfigInterfaceAndroid::getFamilyNames() {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000440 SkTDArray<const char*> names;
441 SkTDArray<size_t> sizes;
442
443 SkTDict<FamilyRecID>::Iter iter(fFamilyNameDict);
444 const char* familyName = iter.next(NULL);
445 while(familyName != NULL) {
446 *names.append() = familyName;
447 *sizes.append() = strlen(familyName) + 1;
448
449 // move to the next familyName in the dictionary
450 familyName = iter.next(NULL);
451 }
452
453 return SkDataTable::NewCopyArrays((const void*const*)names.begin(),
454 sizes.begin(), names.count());
455}
456
457bool SkFontConfigInterfaceAndroid::matchFamilySet(const char inFamilyName[],
458 SkString* outFamilyName,
robertphillips@google.comb7457d02013-05-22 00:12:43 +0000459 SkTArray<FontIdentity>*) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000460 return false;
461}
462
djsollen@google.com40078cb2013-05-24 20:31:57 +0000463static bool find_proc(SkTypeface* face, SkTypeface::Style style, void* ctx) {
464 const FontRecID* fontRecID = (const FontRecID*)ctx;
465 FontRecID currFontRecID = ((FontConfigTypeface*)face)->getIdentity().fID;
466 return currFontRecID == *fontRecID;
467}
468
469SkTypeface* SkFontConfigInterfaceAndroid::getTypefaceForFontRec(FontRecID fontRecID) {
470 FontRec& fontRec = fFonts[fontRecID];
djsollen@google.combfae9d32013-05-21 16:53:50 +0000471 SkTypeface* face = fontRec.fTypeface.get();
472 if (!face) {
djsollen@google.com40078cb2013-05-24 20:31:57 +0000473 // look for it in the typeface cache
474 face = SkTypefaceCache::FindByProcAndRef(find_proc, &fontRecID);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000475
476 // if it is not in the cache then create it
djsollen@google.com40078cb2013-05-24 20:31:57 +0000477 if (!face) {
478 const char* familyName = NULL;
479 SkAssertResult(fFamilyNameDict.findKey(fontRec.fFamilyRecID, &familyName));
480 SkASSERT(familyName);
481 face = SkTypeface::CreateFromName(familyName, fontRec.fStyle);
482 }
djsollen@google.combfae9d32013-05-21 16:53:50 +0000483
484 // store the result for subsequent lookups
485 fontRec.fTypeface = face;
486 }
487 SkASSERT(face);
488 return face;
489}
490
491bool SkFontConfigInterfaceAndroid::getFallbackFamilyNameForChar(SkUnichar uni, SkString* name) {
492 for (int i = 0; i < fDefaultFallbackList.count(); i++) {
493 FontRecID fontRecID = fDefaultFallbackList[i];
djsollen@google.com40078cb2013-05-24 20:31:57 +0000494 SkTypeface* face = this->getTypefaceForFontRec(fontRecID);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000495
496 SkPaint paint;
497 paint.setTypeface(face);
498 paint.setTextEncoding(SkPaint::kUTF32_TextEncoding);
499
500 uint16_t glyphID;
501 paint.textToGlyphs(&uni, sizeof(uni), &glyphID);
502 if (glyphID != 0) {
503 name->set(fFonts[fontRecID].fFileName);
504 return true;
505 }
506 }
507 return false;
508}
509
510SkTypeface* SkFontConfigInterfaceAndroid::getTypefaceForChar(SkUnichar uni,
511 SkTypeface::Style style,
512 SkPaintOptionsAndroid::FontVariant fontVariant) {
513 FontRecID fontRecID = find_best_style(fFontFamilies[fDefaultFamilyRecID], style);
djsollen@google.com40078cb2013-05-24 20:31:57 +0000514 SkTypeface* face = this->getTypefaceForFontRec(fontRecID);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000515
516 SkPaintOptionsAndroid paintOptions;
517 paintOptions.setFontVariant(fontVariant);
518 paintOptions.setUseFontFallbacks(true);
519
520 SkPaint paint;
521 paint.setTypeface(face);
522 paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
523 paint.setPaintOptionsAndroid(paintOptions);
524
525 SkAutoGlyphCache autoCache(paint, NULL, NULL);
526 SkGlyphCache* cache = autoCache.getCache();
527
528 SkScalerContext* ctx = cache->getScalerContext();
529 if (ctx) {
530 SkFontID fontID = ctx->findTypefaceIdForChar(uni);
531 return SkTypefaceCache::FindByID(fontID);
532 }
533 return NULL;
534}
535
djsollen@google.com40078cb2013-05-24 20:31:57 +0000536FallbackFontList* SkFontConfigInterfaceAndroid::findFallbackFontList(const SkLanguage& lang,
537 bool isOriginal) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000538 const SkString& langTag = lang.getTag();
539 if (langTag.isEmpty()) {
540 return &fDefaultFallbackList;
541 }
542
543 FallbackFontList* fallbackFontList;
djsollen@google.com40078cb2013-05-24 20:31:57 +0000544 if (fFallbackFontDict.find(langTag.c_str(), langTag.size(), &fallbackFontList) ||
545 fFallbackFontAliasDict.find(langTag.c_str(), langTag.size(), &fallbackFontList)) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000546 return fallbackFontList;
547 }
548
549 // attempt a recursive fuzzy match
djsollen@google.combfae9d32013-05-21 16:53:50 +0000550 SkLanguage parent = lang.getParent();
djsollen@google.com40078cb2013-05-24 20:31:57 +0000551 fallbackFontList = findFallbackFontList(parent, false);
552
553 // cache the original lang so we don't have to do the recursion again.
554 if (isOriginal) {
555 DEBUG_FONT(("---- Created fallback list alias for \"%s\"", langTag.c_str()));
556 fFallbackFontAliasDict.set(langTag.c_str(), fallbackFontList);
557 }
558 return fallbackFontList;
djsollen@google.combfae9d32013-05-21 16:53:50 +0000559}
560
561SkTypeface* SkFontConfigInterfaceAndroid::nextLogicalTypeface(SkFontID currFontID,
562 SkFontID origFontID,
563 const SkPaintOptionsAndroid& opts) {
564 // Skia does not support font fallback by default. This enables clients such
565 // as WebKit to customize their font selection. In any case, clients can use
566 // GetFallbackFamilyNameForChar() to get the fallback font for individual
567 // characters.
568 if (!opts.isUsingFontFallbacks()) {
569 return NULL;
570 }
571
djsollen@google.combfae9d32013-05-21 16:53:50 +0000572 FallbackFontList* currentFallbackList = findFallbackFontList(opts.getLanguage());
573 SkASSERT(currentFallbackList);
574
djsollen@google.combfae9d32013-05-21 16:53:50 +0000575 // we must convert currTypeface into a FontRecID
djsollen@google.come47e7d12013-06-06 21:25:09 +0000576 FontRecID currFontRecID = INVALID_FONT_REC_ID;
577 const SkTypeface* currTypeface = SkTypefaceCache::FindByID(currFontID);
578 // non-system fonts are not in the font cache so if we are asked to fallback
579 // for a non-system font we will start at the front of the chain.
580 if (NULL != currTypeface && currFontID == origFontID) {
581 currFontRecID = ((FontConfigTypeface*)currTypeface)->getIdentity().fID;
582 SkASSERT(INVALID_FONT_REC_ID != currFontRecID);
583 }
djsollen@google.combfae9d32013-05-21 16:53:50 +0000584
djsollen@google.come47e7d12013-06-06 21:25:09 +0000585 // lookup the index next font in the chain
djsollen@google.combfae9d32013-05-21 16:53:50 +0000586 int currFallbackFontIndex = currentFallbackList->find(currFontRecID);
djsollen@google.come47e7d12013-06-06 21:25:09 +0000587 // We add 1 to the returned index for 2 reasons: (1) if find succeeds it moves
588 // our index to the next entry in the list; (2) if find() fails it returns
589 // -1 and incrementing it will set our starting index to 0 (the head of the list)
djsollen@google.combfae9d32013-05-21 16:53:50 +0000590 int nextFallbackFontIndex = currFallbackFontIndex + 1;
djsollen@google.combfae9d32013-05-21 16:53:50 +0000591
djsollen@google.com40078cb2013-05-24 20:31:57 +0000592 if(nextFallbackFontIndex >= currentFallbackList->count()) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000593 return NULL;
594 }
595
596 // If a rec object is set to prefer "kDefault_Variant" it means they have no preference
597 // In this case, we set the value to "kCompact_Variant"
598 SkPaintOptionsAndroid::FontVariant variant = opts.getFontVariant();
599 if (variant == SkPaintOptionsAndroid::kDefault_Variant) {
600 variant = SkPaintOptionsAndroid::kCompact_Variant;
601 }
602
603 int32_t acceptedVariants = SkPaintOptionsAndroid::kDefault_Variant | variant;
604
605 SkTypeface* nextLogicalTypeface = 0;
606 while (nextFallbackFontIndex < currentFallbackList->count()) {
607 FontRecID fontRecID = currentFallbackList->getAt(nextFallbackFontIndex);
djsollen@google.com40078cb2013-05-24 20:31:57 +0000608 if ((fFonts[fontRecID].fPaintOptions.getFontVariant() & acceptedVariants) != 0) {
609 nextLogicalTypeface = this->getTypefaceForFontRec(fontRecID);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000610 break;
611 }
612 nextFallbackFontIndex++;
613 }
614
615 DEBUG_FONT(("---- nextLogicalFont: currFontID=%d, origFontID=%d, currRecID=%d, "
djsollen@google.com40078cb2013-05-24 20:31:57 +0000616 "lang=%s, variant=%d, nextFallbackIndex[%d,%d] => nextLogicalTypeface=%d",
djsollen@google.combfae9d32013-05-21 16:53:50 +0000617 currFontID, origFontID, currFontRecID, opts.getLanguage().getTag().c_str(),
djsollen@google.com40078cb2013-05-24 20:31:57 +0000618 variant, nextFallbackFontIndex, currentFallbackList->getAt(nextFallbackFontIndex),
djsollen@google.combfae9d32013-05-21 16:53:50 +0000619 (nextLogicalTypeface) ? nextLogicalTypeface->uniqueID() : 0));
620 return SkSafeRef(nextLogicalTypeface);
621}
622
623///////////////////////////////////////////////////////////////////////////////
624
625bool SkGetFallbackFamilyNameForChar(SkUnichar uni, SkString* name) {
626 SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
627 return fontConfig->getFallbackFamilyNameForChar(uni, name);
628}
629
630void SkUseTestFontConfigFile(const char* mainconf, const char* fallbackconf,
631 const char* fontsdir) {
632 gTestMainConfigFile = mainconf;
633 gTestFallbackConfigFile = fallbackconf;
634 gTestFontFilePrefix = fontsdir;
635 SkASSERT(gTestMainConfigFile);
636 SkASSERT(gTestFallbackConfigFile);
637 SkASSERT(gTestFontFilePrefix);
638 SkDEBUGF(("Use Test Config File Main %s, Fallback %s, Font Dir %s",
639 gTestMainConfigFile, gTestFallbackConfigFile, gTestFontFilePrefix));
640}
641
642SkTypeface* SkAndroidNextLogicalTypeface(SkFontID currFontID, SkFontID origFontID,
643 const SkPaintOptionsAndroid& options) {
644 SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
645 return fontConfig->nextLogicalTypeface(currFontID, origFontID, options);
646
647}
648
649///////////////////////////////////////////////////////////////////////////////
650
djsollen@google.com40078cb2013-05-24 20:31:57 +0000651#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
652
653struct HB_UnicodeMapping {
654 // TODO: when the WebView no longer needs harfbuzz_old, remove
655 HB_Script script_old;
656 hb_script_t script;
657 const SkUnichar unicode;
658};
659
660/*
661 * The following scripts are not complex fonts and we do not expect them to be parsed by this table
662 * HB_SCRIPT_COMMON,
663 * HB_SCRIPT_GREEK,
664 * HB_SCRIPT_CYRILLIC,
665 * HB_SCRIPT_HANGUL
666 * HB_SCRIPT_INHERITED
667 */
668
669/* Harfbuzz (old) is missing a number of scripts in its table. For these,
670 * we include a value which can never happen. We won't get complex script
671 * shaping in these cases, but the library wouldn't know how to shape
672 * them anyway. */
673#define HB_Script_Unknown HB_ScriptCount
674
675static HB_UnicodeMapping HB_UnicodeMappingArray[] = {
676 {HB_Script_Armenian, HB_SCRIPT_ARMENIAN, 0x0531},
677 {HB_Script_Hebrew, HB_SCRIPT_HEBREW, 0x0591},
678 {HB_Script_Arabic, HB_SCRIPT_ARABIC, 0x0600},
679 {HB_Script_Syriac, HB_SCRIPT_SYRIAC, 0x0710},
680 {HB_Script_Thaana, HB_SCRIPT_THAANA, 0x0780},
681 {HB_Script_Nko, HB_SCRIPT_NKO, 0x07C0},
682 {HB_Script_Devanagari, HB_SCRIPT_DEVANAGARI, 0x0901},
683 {HB_Script_Bengali, HB_SCRIPT_BENGALI, 0x0981},
684 {HB_Script_Gurmukhi, HB_SCRIPT_GURMUKHI, 0x0A10},
685 {HB_Script_Gujarati, HB_SCRIPT_GUJARATI, 0x0A90},
686 {HB_Script_Oriya, HB_SCRIPT_ORIYA, 0x0B10},
687 {HB_Script_Tamil, HB_SCRIPT_TAMIL, 0x0B82},
688 {HB_Script_Telugu, HB_SCRIPT_TELUGU, 0x0C10},
689 {HB_Script_Kannada, HB_SCRIPT_KANNADA, 0x0C90},
690 {HB_Script_Malayalam, HB_SCRIPT_MALAYALAM, 0x0D10},
691 {HB_Script_Sinhala, HB_SCRIPT_SINHALA, 0x0D90},
692 {HB_Script_Thai, HB_SCRIPT_THAI, 0x0E01},
693 {HB_Script_Lao, HB_SCRIPT_LAO, 0x0E81},
694 {HB_Script_Tibetan, HB_SCRIPT_TIBETAN, 0x0F00},
695 {HB_Script_Myanmar, HB_SCRIPT_MYANMAR, 0x1000},
696 {HB_Script_Georgian, HB_SCRIPT_GEORGIAN, 0x10A0},
697 {HB_Script_Unknown, HB_SCRIPT_ETHIOPIC, 0x1200},
698 {HB_Script_Unknown, HB_SCRIPT_CHEROKEE, 0x13A0},
699 {HB_Script_Ogham, HB_SCRIPT_OGHAM, 0x1680},
700 {HB_Script_Runic, HB_SCRIPT_RUNIC, 0x16A0},
701 {HB_Script_Khmer, HB_SCRIPT_KHMER, 0x1780},
702 {HB_Script_Unknown, HB_SCRIPT_TAI_LE, 0x1950},
703 {HB_Script_Unknown, HB_SCRIPT_NEW_TAI_LUE, 0x1980},
704 {HB_Script_Unknown, HB_SCRIPT_TAI_THAM, 0x1A20},
705 {HB_Script_Unknown, HB_SCRIPT_CHAM, 0xAA00},
706};
707
708static hb_script_t getHBScriptFromHBScriptOld(HB_Script script_old) {
709 hb_script_t script = HB_SCRIPT_INVALID;
710 int numSupportedFonts = sizeof(HB_UnicodeMappingArray) / sizeof(HB_UnicodeMapping);
711 for (int i = 0; i < numSupportedFonts; i++) {
712 if (script_old == HB_UnicodeMappingArray[i].script_old) {
713 script = HB_UnicodeMappingArray[i].script;
714 break;
715 }
716 }
717 return script;
718}
719
720// returns 0 for "Not Found"
721static SkUnichar getUnicodeFromHBScript(hb_script_t script) {
722 SkUnichar unichar = 0;
723 int numSupportedFonts = sizeof(HB_UnicodeMappingArray) / sizeof(HB_UnicodeMapping);
724 for (int i = 0; i < numSupportedFonts; i++) {
725 if (script == HB_UnicodeMappingArray[i].script) {
726 unichar = HB_UnicodeMappingArray[i].unicode;
727 break;
728 }
729 }
730 return unichar;
731}
732
733struct TypefaceLookupStruct {
734 hb_script_t script;
735 SkTypeface::Style style;
736 SkPaintOptionsAndroid::FontVariant fontVariant;
737 SkTypeface* typeface;
738};
739
740SK_DECLARE_STATIC_MUTEX(gTypefaceTableMutex); // This is the mutex for gTypefaceTable
741static SkTDArray<TypefaceLookupStruct> gTypefaceTable; // This is protected by gTypefaceTableMutex
742
743static int typefaceLookupCompare(const TypefaceLookupStruct& first,
744 const TypefaceLookupStruct& second) {
745 if (first.script != second.script) {
746 return (first.script > second.script) ? 1 : -1;
747 }
748 if (first.style != second.style) {
749 return (first.style > second.style) ? 1 : -1;
750 }
751 if (first.fontVariant != second.fontVariant) {
752 return (first.fontVariant > second.fontVariant) ? 1 : -1;
753 }
754 return 0;
755}
756
757SkTypeface* SkCreateTypefaceForScriptNG(hb_script_t script, SkTypeface::Style style,
758 SkPaintOptionsAndroid::FontVariant fontVariant) {
759 SkAutoMutexAcquire ac(gTypefaceTableMutex);
760
761 TypefaceLookupStruct key;
762 key.script = script;
763 key.style = style;
764 key.fontVariant = fontVariant;
765
766 int index = SkTSearch<TypefaceLookupStruct>(
767 (const TypefaceLookupStruct*) gTypefaceTable.begin(),
768 gTypefaceTable.count(), key, sizeof(TypefaceLookupStruct),
769 typefaceLookupCompare);
770
771 SkTypeface* retTypeface = NULL;
772 if (index >= 0) {
773 retTypeface = gTypefaceTable[index].typeface;
774 }
775 else {
776 SkUnichar unichar = getUnicodeFromHBScript(script);
777 if (!unichar) {
778 return NULL;
779 }
780
781 SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
782 retTypeface = fontConfig->getTypefaceForChar(unichar, style, fontVariant);
783
784 // add to the lookup table
785 key.typeface = retTypeface;
786 *gTypefaceTable.insert(~index) = key;
787 }
788
789 // we ref(), the caller is expected to unref when they are done
790 return SkSafeRef(retTypeface);
791}
792
793SkTypeface* SkCreateTypefaceForScript(HB_Script script, SkTypeface::Style style,
794 SkPaintOptionsAndroid::FontVariant fontVariant) {
795 return SkCreateTypefaceForScriptNG(getHBScriptFromHBScriptOld(script), style, fontVariant);
796}
797
798#endif
799
800///////////////////////////////////////////////////////////////////////////////
801
djsollen@google.combfae9d32013-05-21 16:53:50 +0000802SkFontMgr* SkFontMgr::Factory() {
803 return NULL;
804}