blob: 3a4c02e539d2f0fbd4d8f90bde28c2daa7d5f952 [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;
djsollen@google.combfae9d32013-05-21 16:53:50 +000058 bool fIsValid;
djsollen@google.com40078cb2013-05-24 20:31:57 +000059 FamilyRecID fFamilyRecID;
djsollen@google.combfae9d32013-05-21 16:53:50 +000060};
61
djsollen@google.combfae9d32013-05-21 16:53:50 +000062struct 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];
djsollen@google.comb27eba72013-09-06 12:59:50 +000069 bool fIsFallbackFont;
70 SkPaintOptionsAndroid fPaintOptions;
djsollen@google.combfae9d32013-05-21 16:53:50 +000071};
72
djsollen@google.combfae9d32013-05-21 16:53:50 +000073
djsollen@google.comb27eba72013-09-06 12:59:50 +000074typedef SkTDArray<FamilyRecID> FallbackFontList;
djsollen@google.combfae9d32013-05-21 16:53:50 +000075
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 */
djsollen@google.com9902c382013-09-19 18:22:30 +000098 bool getFallbackFamilyNameForChar(SkUnichar uni, const char* lang, SkString* name);
djsollen@google.combfae9d32013-05-21 16:53:50 +000099 /**
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:
djsollen@google.comb27eba72013-09-06 12:59:50 +0000108 void addFallbackFamily(FamilyRecID fontRecID);
djsollen@google.com40078cb2013-05-24 20:31:57 +0000109 SkTypeface* getTypefaceForFontRec(FontRecID fontRecID);
djsollen@google.com9a70f342013-06-25 18:07:45 +0000110 FallbackFontList* getCurrentLocaleFallbackFontList();
djsollen@google.com40078cb2013-05-24 20:31:57 +0000111 FallbackFontList* findFallbackFontList(const SkLanguage& lang, bool isOriginal = true);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000112
113 SkTArray<FontRec> fFonts;
114 SkTArray<FamilyRec> fFontFamilies;
115 SkTDict<FamilyRecID> fFamilyNameDict;
116 FamilyRecID fDefaultFamilyRecID;
117
118 // (SkLanguage)<->(fallback chain index) translation
119 SkTDict<FallbackFontList*> fFallbackFontDict;
djsollen@google.com40078cb2013-05-24 20:31:57 +0000120 SkTDict<FallbackFontList*> fFallbackFontAliasDict;
djsollen@google.combfae9d32013-05-21 16:53:50 +0000121 FallbackFontList fDefaultFallbackList;
djsollen@google.com9a70f342013-06-25 18:07:45 +0000122
123 // fallback info for current locale
124 SkString fCachedLocale;
125 FallbackFontList* fLocaleFallbackFontList;
djsollen@google.combfae9d32013-05-21 16:53:50 +0000126};
127
128///////////////////////////////////////////////////////////////////////////////
129
130static SkFontConfigInterfaceAndroid* getSingletonInterface() {
131 SK_DECLARE_STATIC_MUTEX(gMutex);
132 static SkFontConfigInterfaceAndroid* gFontConfigInterface;
133
134 SkAutoMutexAcquire ac(gMutex);
135 if (NULL == gFontConfigInterface) {
136 // load info from a configuration file that we can use to populate the
137 // system/fallback font structures
138 SkTDArray<FontFamily*> fontFamilies;
139 if (!gTestMainConfigFile) {
140 SkFontConfigParser::GetFontFamilies(fontFamilies);
141 } else {
142 SkFontConfigParser::GetTestFontFamilies(fontFamilies, gTestMainConfigFile,
143 gTestFallbackConfigFile);
144 }
145
146 gFontConfigInterface = new SkFontConfigInterfaceAndroid(fontFamilies);
147
148 // cleanup the data we received from the parser
149 fontFamilies.deleteAll();
150 }
151 return gFontConfigInterface;
152}
153
154SkFontConfigInterface* SkFontConfigInterface::GetSingletonDirectInterface() {
155 return getSingletonInterface();
156}
157
158///////////////////////////////////////////////////////////////////////////////
159
160static bool has_font(const SkTArray<FontRec>& array, const SkString& filename) {
161 for (int i = 0; i < array.count(); i++) {
162 if (array[i].fFileName == filename) {
163 return true;
164 }
165 }
166 return false;
167}
168
169#ifndef SK_FONT_FILE_PREFIX
170 #define SK_FONT_FILE_PREFIX "/fonts/"
171#endif
172
173static void get_path_for_sys_fonts(SkString* full, const char name[]) {
174 if (gTestFontFilePrefix) {
175 full->set(gTestFontFilePrefix);
176 } else {
177 full->set(getenv("ANDROID_ROOT"));
178 full->append(SK_FONT_FILE_PREFIX);
179 }
180 full->append(name);
181}
182
183static void insert_into_name_dict(SkTDict<FamilyRecID>& familyNameDict,
184 const char* name, FamilyRecID familyRecID) {
185 SkAutoAsciiToLC tolc(name);
djsollen@google.com92e3f082013-08-27 17:40:03 +0000186 if (familyNameDict.find(tolc.lc())) {
187 SkDebugf("---- system font attempting to use a the same name [%s] for"
188 "multiple families. skipping subsequent occurrences", tolc.lc());
189 } else {
190 familyNameDict.set(tolc.lc(), familyRecID);
191 }
djsollen@google.combfae9d32013-05-21 16:53:50 +0000192}
193
194// Defined in SkFontHost_FreeType.cpp
195bool find_name_and_attributes(SkStream* stream, SkString* name,
196 SkTypeface::Style* style, bool* isFixedWidth);
197
198///////////////////////////////////////////////////////////////////////////////
199
200SkFontConfigInterfaceAndroid::SkFontConfigInterfaceAndroid(SkTDArray<FontFamily*>& fontFamilies) :
201 fFonts(fontFamilies.count()),
202 fFontFamilies(fontFamilies.count() / FamilyRec::FONT_STYLE_COUNT),
203 fFamilyNameDict(1024),
204 fDefaultFamilyRecID(INVALID_FAMILY_REC_ID),
djsollen@google.com40078cb2013-05-24 20:31:57 +0000205 fFallbackFontDict(128),
djsollen@google.com9a70f342013-06-25 18:07:45 +0000206 fFallbackFontAliasDict(128),
207 fLocaleFallbackFontList(NULL) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000208
209 for (int i = 0; i < fontFamilies.count(); ++i) {
210 FontFamily* family = fontFamilies[i];
211
212 // defer initializing the familyRec until we can be sure that at least
213 // one of it's children contains a valid font file
214 FamilyRec* familyRec = NULL;
215 FamilyRecID familyRecID = INVALID_FAMILY_REC_ID;
216
217 for (int j = 0; j < family->fFontFiles.count(); ++j) {
218 SkString filename;
219 get_path_for_sys_fonts(&filename, family->fFontFiles[j]->fFileName);
220
221 if (has_font(fFonts, filename)) {
222 SkDebugf("---- system font and fallback font files specify a duplicate "
223 "font %s, skipping the second occurrence", filename.c_str());
224 continue;
225 }
226
227 FontRec& fontRec = fFonts.push_back();
228 fontRec.fFileName = filename;
229 fontRec.fStyle = SkTypeface::kNormal;
djsollen@google.combfae9d32013-05-21 16:53:50 +0000230 fontRec.fIsValid = false;
djsollen@google.com40078cb2013-05-24 20:31:57 +0000231 fontRec.fFamilyRecID = familyRecID;
djsollen@google.combfae9d32013-05-21 16:53:50 +0000232
233 const FontRecID fontRecID = fFonts.count() - 1;
234
235 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(filename.c_str()));
236 if (stream.get() != NULL) {
237 bool isFixedWidth;
238 SkString name;
239 fontRec.fIsValid = find_name_and_attributes(stream.get(), &name,
240 &fontRec.fStyle, &isFixedWidth);
241 } else {
djsollen@google.comb27eba72013-09-06 12:59:50 +0000242 if (!family->fIsFallbackFont) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000243 SkDebugf("---- failed to open <%s> as a font\n", filename.c_str());
244 }
245 }
246
247 if (fontRec.fIsValid) {
248 DEBUG_FONT(("---- SystemFonts[%d][%d] fallback=%d file=%s",
djsollen@google.com9902c382013-09-19 18:22:30 +0000249 i, fFonts.count() - 1, family->fIsFallbackFont, filename.c_str()));
djsollen@google.combfae9d32013-05-21 16:53:50 +0000250 } else {
251 DEBUG_FONT(("---- SystemFonts[%d][%d] fallback=%d file=%s (INVALID)",
djsollen@google.com9902c382013-09-19 18:22:30 +0000252 i, fFonts.count() - 1, family->fIsFallbackFont, filename.c_str()));
djsollen@google.combfae9d32013-05-21 16:53:50 +0000253 continue;
254 }
255
256 // create a familyRec now that we know that at least one font in
257 // the family is valid
258 if (familyRec == NULL) {
259 familyRec = &fFontFamilies.push_back();
260 familyRecID = fFontFamilies.count() - 1;
djsollen@google.com40078cb2013-05-24 20:31:57 +0000261 fontRec.fFamilyRecID = familyRecID;
djsollen@google.comb27eba72013-09-06 12:59:50 +0000262
263 familyRec->fIsFallbackFont = family->fIsFallbackFont;
264 familyRec->fPaintOptions = family->fFontFiles[j]->fPaintOptions;
265
266 // if this is a fallback font then add it to the appropriate fallback chains
267 if (familyRec->fIsFallbackFont) {
268 addFallbackFamily(familyRecID);
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();
djsollen@google.combfae9d32013-05-21 16:53:50 +0000274 }
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
djsollen@google.combfae9d32013-05-21 16:53:50 +0000284 // add the fallback file name to the name dictionary. This is needed
285 // by getFallbackFamilyNameForChar() so that fallback families can be
286 // requested by the filenames of the fonts they contain.
djsollen@google.comb27eba72013-09-06 12:59:50 +0000287 if (familyRec && familyRec->fIsFallbackFont) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000288 insert_into_name_dict(fFamilyNameDict, fontRec.fFileName.c_str(), familyRecID);
289 }
290 }
291
292 // add the names that map to this family to the dictionary for easy lookup
djsollen@google.comb27eba72013-09-06 12:59:50 +0000293 if (familyRec && !familyRec->fIsFallbackFont) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000294 SkTDArray<const char*> names = family->fNames;
295 if (names.isEmpty()) {
296 SkDEBUGFAIL("ERROR: non-fallback font with no name");
297 continue;
298 }
299
300 for (int i = 0; i < names.count(); i++) {
301 insert_into_name_dict(fFamilyNameDict, names[i], familyRecID);
302 }
303 }
304
305 }
306
307 DEBUG_FONT(("---- We have %d system fonts", fFonts.count()));
308
309 if (fFontFamilies.count() > 0) {
310 fDefaultFamilyRecID = 0;
311 }
312
313 // scans the default fallback font chain, adding every entry to every other
314 // fallback font chain to which it does not belong. this results in every
315 // language-specific fallback font chain having all of its fallback fonts at
316 // the front of the chain, and everything else at the end.
317 FallbackFontList* fallbackList;
318 SkTDict<FallbackFontList*>::Iter iter(fFallbackFontDict);
319 const char* fallbackLang = iter.next(&fallbackList);
320 while(fallbackLang != NULL) {
321 for (int i = 0; i < fDefaultFallbackList.count(); i++) {
djsollen@google.comb27eba72013-09-06 12:59:50 +0000322 FamilyRecID familyRecID = fDefaultFallbackList[i];
323 const SkString& fontLang = fFontFamilies[familyRecID].fPaintOptions.getLanguage().getTag();
djsollen@google.combfae9d32013-05-21 16:53:50 +0000324 if (strcmp(fallbackLang, fontLang.c_str()) != 0) {
djsollen@google.comb27eba72013-09-06 12:59:50 +0000325 fallbackList->push(familyRecID);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000326 }
327 }
328 // move to the next fallback list in the dictionary
329 fallbackLang = iter.next(&fallbackList);
330 }
331}
332
333SkFontConfigInterfaceAndroid::~SkFontConfigInterfaceAndroid() {
334 // iterate through and cleanup fFallbackFontDict
335 SkTDict<FallbackFontList*>::Iter iter(fFallbackFontDict);
336 FallbackFontList* fallbackList;
337 while(iter.next(&fallbackList) != NULL) {
338 SkDELETE(fallbackList);
339 }
340}
341
djsollen@google.comb27eba72013-09-06 12:59:50 +0000342void SkFontConfigInterfaceAndroid::addFallbackFamily(FamilyRecID familyRecID) {
343 SkASSERT(familyRecID < fFontFamilies.count());
344 const FamilyRec& familyRec = fFontFamilies[familyRecID];
345 SkASSERT(familyRec.fIsFallbackFont);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000346
347 // add to the default fallback list
djsollen@google.comb27eba72013-09-06 12:59:50 +0000348 fDefaultFallbackList.push(familyRecID);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000349
350 // stop here if it is the default language tag
djsollen@google.comb27eba72013-09-06 12:59:50 +0000351 const SkString& languageTag = familyRec.fPaintOptions.getLanguage().getTag();
djsollen@google.combfae9d32013-05-21 16:53:50 +0000352 if (languageTag.isEmpty()) {
353 return;
354 }
355
356 // add to the appropriate language's custom fallback list
357 FallbackFontList* customList = NULL;
358 if (!fFallbackFontDict.find(languageTag.c_str(), &customList)) {
359 DEBUG_FONT(("---- Created fallback list for \"%s\"", languageTag.c_str()));
360 customList = SkNEW(FallbackFontList);
361 fFallbackFontDict.set(languageTag.c_str(), customList);
362 }
363 SkASSERT(customList != NULL);
djsollen@google.comb27eba72013-09-06 12:59:50 +0000364 customList->push(familyRecID);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000365}
366
367
368static FontRecID find_best_style(const FamilyRec& family, SkTypeface::Style style) {
369
370 const FontRecID* fontRecIDs = family.fFontRecID;
371
372 if (fontRecIDs[style] != INVALID_FONT_REC_ID) { // exact match
373 return fontRecIDs[style];
374 }
375 // look for a matching bold
376 style = (SkTypeface::Style)(style ^ SkTypeface::kItalic);
377 if (fontRecIDs[style] != INVALID_FONT_REC_ID) {
378 return fontRecIDs[style];
379 }
380 // look for the plain
381 if (fontRecIDs[SkTypeface::kNormal] != INVALID_FONT_REC_ID) {
382 return fontRecIDs[SkTypeface::kNormal];
383 }
384 // look for anything
385 for (int i = 0; i < FamilyRec::FONT_STYLE_COUNT; i++) {
386 if (fontRecIDs[i] != INVALID_FONT_REC_ID) {
387 return fontRecIDs[i];
388 }
389 }
390 // should never get here, since the fontRecID list should not be empty
391 SkDEBUGFAIL("No valid fonts exist for this family");
392 return -1;
393}
394
395bool SkFontConfigInterfaceAndroid::matchFamilyName(const char familyName[],
396 SkTypeface::Style style,
397 FontIdentity* outFontIdentifier,
398 SkString* outFamilyName,
robertphillips@google.comb7457d02013-05-22 00:12:43 +0000399 SkTypeface::Style* outStyle) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000400 // clip to legal style bits
401 style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
402
403 bool exactNameMatch = false;
404
405 FamilyRecID familyRecID = INVALID_FAMILY_REC_ID;
406 if (NULL != familyName) {
djsollen@google.com2e08f192013-05-21 20:08:10 +0000407 SkAutoAsciiToLC tolc(familyName);
408 if (fFamilyNameDict.find(tolc.lc(), &familyRecID)) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000409 exactNameMatch = true;
410 }
411 } else {
412 familyRecID = fDefaultFamilyRecID;
413
414 }
415
djsollen@google.com1f584ed2013-09-19 12:08:40 +0000416 // If no matching family name is found then return false. This allows clients
417 // to be able to search for other fonts instead of forcing them to use the
418 // default font.
djsollen@google.combfae9d32013-05-21 16:53:50 +0000419 if (INVALID_FAMILY_REC_ID == familyRecID) {
djsollen@google.com1f584ed2013-09-19 12:08:40 +0000420 return false;
djsollen@google.combfae9d32013-05-21 16:53:50 +0000421 }
422
423 FontRecID fontRecID = find_best_style(fFontFamilies[familyRecID], style);
424 FontRec& fontRec = fFonts[fontRecID];
425
426 if (NULL != outFontIdentifier) {
427 outFontIdentifier->fID = fontRecID;
428 outFontIdentifier->fTTCIndex = 0;
429 outFontIdentifier->fString.set(fontRec.fFileName);
430// outFontIdentifier->fStyle = fontRec.fStyle;
431 }
432
433 if (NULL != outFamilyName) {
434 if (exactNameMatch) {
435 outFamilyName->set(familyName);
436 } else {
437 // find familyName from list of names
438 const char* familyName = NULL;
djsollen@google.comab6eeb92013-05-21 17:15:27 +0000439 SkAssertResult(fFamilyNameDict.findKey(familyRecID, &familyName));
440 SkASSERT(familyName);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000441 outFamilyName->set(familyName);
442 }
443 }
444
445 if (NULL != outStyle) {
446 *outStyle = fontRec.fStyle;
447 }
448
449 return true;
450}
451
robertphillips@google.comb7457d02013-05-22 00:12:43 +0000452SkStream* SkFontConfigInterfaceAndroid::openStream(const FontIdentity& identity) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000453 return SkStream::NewFromFile(identity.fString.c_str());
454}
455
robertphillips@google.comb7457d02013-05-22 00:12:43 +0000456SkDataTable* SkFontConfigInterfaceAndroid::getFamilyNames() {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000457 SkTDArray<const char*> names;
458 SkTDArray<size_t> sizes;
459
460 SkTDict<FamilyRecID>::Iter iter(fFamilyNameDict);
461 const char* familyName = iter.next(NULL);
462 while(familyName != NULL) {
463 *names.append() = familyName;
464 *sizes.append() = strlen(familyName) + 1;
465
466 // move to the next familyName in the dictionary
467 familyName = iter.next(NULL);
468 }
469
470 return SkDataTable::NewCopyArrays((const void*const*)names.begin(),
471 sizes.begin(), names.count());
472}
473
474bool SkFontConfigInterfaceAndroid::matchFamilySet(const char inFamilyName[],
475 SkString* outFamilyName,
robertphillips@google.comb7457d02013-05-22 00:12:43 +0000476 SkTArray<FontIdentity>*) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000477 return false;
478}
479
djsollen@google.com40078cb2013-05-24 20:31:57 +0000480static bool find_proc(SkTypeface* face, SkTypeface::Style style, void* ctx) {
481 const FontRecID* fontRecID = (const FontRecID*)ctx;
482 FontRecID currFontRecID = ((FontConfigTypeface*)face)->getIdentity().fID;
483 return currFontRecID == *fontRecID;
484}
485
486SkTypeface* SkFontConfigInterfaceAndroid::getTypefaceForFontRec(FontRecID fontRecID) {
487 FontRec& fontRec = fFonts[fontRecID];
djsollen@google.combfae9d32013-05-21 16:53:50 +0000488 SkTypeface* face = fontRec.fTypeface.get();
489 if (!face) {
djsollen@google.com40078cb2013-05-24 20:31:57 +0000490 // look for it in the typeface cache
491 face = SkTypefaceCache::FindByProcAndRef(find_proc, &fontRecID);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000492
493 // if it is not in the cache then create it
djsollen@google.com40078cb2013-05-24 20:31:57 +0000494 if (!face) {
495 const char* familyName = NULL;
496 SkAssertResult(fFamilyNameDict.findKey(fontRec.fFamilyRecID, &familyName));
497 SkASSERT(familyName);
498 face = SkTypeface::CreateFromName(familyName, fontRec.fStyle);
499 }
djsollen@google.combfae9d32013-05-21 16:53:50 +0000500
501 // store the result for subsequent lookups
502 fontRec.fTypeface = face;
503 }
504 SkASSERT(face);
505 return face;
506}
507
djsollen@google.com9902c382013-09-19 18:22:30 +0000508bool SkFontConfigInterfaceAndroid::getFallbackFamilyNameForChar(SkUnichar uni,
509 const char* lang,
510 SkString* name) {
511 FallbackFontList* fallbackFontList = this->findFallbackFontList(lang);
djsollen@google.com9a70f342013-06-25 18:07:45 +0000512 for (int i = 0; i < fallbackFontList->count(); i++) {
djsollen@google.comb27eba72013-09-06 12:59:50 +0000513 FamilyRecID familyRecID = fallbackFontList->getAt(i);
djsollen@google.com9902c382013-09-19 18:22:30 +0000514
515 // if it is not one of the accepted variants then move to the next family
516 int32_t acceptedVariants = SkPaintOptionsAndroid::kDefault_Variant |
517 SkPaintOptionsAndroid::kElegant_Variant;
518 if (!(fFontFamilies[familyRecID].fPaintOptions.getFontVariant() & acceptedVariants)) {
519 continue;
520 }
521
djsollen@google.comb27eba72013-09-06 12:59:50 +0000522 FontRecID fontRecID = find_best_style(fFontFamilies[familyRecID], SkTypeface::kNormal);
djsollen@google.com40078cb2013-05-24 20:31:57 +0000523 SkTypeface* face = this->getTypefaceForFontRec(fontRecID);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000524
525 SkPaint paint;
526 paint.setTypeface(face);
527 paint.setTextEncoding(SkPaint::kUTF32_TextEncoding);
528
529 uint16_t glyphID;
530 paint.textToGlyphs(&uni, sizeof(uni), &glyphID);
531 if (glyphID != 0) {
532 name->set(fFonts[fontRecID].fFileName);
533 return true;
534 }
535 }
536 return false;
537}
538
539SkTypeface* SkFontConfigInterfaceAndroid::getTypefaceForChar(SkUnichar uni,
540 SkTypeface::Style style,
541 SkPaintOptionsAndroid::FontVariant fontVariant) {
542 FontRecID fontRecID = find_best_style(fFontFamilies[fDefaultFamilyRecID], style);
djsollen@google.com40078cb2013-05-24 20:31:57 +0000543 SkTypeface* face = this->getTypefaceForFontRec(fontRecID);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000544
545 SkPaintOptionsAndroid paintOptions;
546 paintOptions.setFontVariant(fontVariant);
547 paintOptions.setUseFontFallbacks(true);
548
549 SkPaint paint;
550 paint.setTypeface(face);
551 paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
552 paint.setPaintOptionsAndroid(paintOptions);
553
554 SkAutoGlyphCache autoCache(paint, NULL, NULL);
555 SkGlyphCache* cache = autoCache.getCache();
556
557 SkScalerContext* ctx = cache->getScalerContext();
558 if (ctx) {
559 SkFontID fontID = ctx->findTypefaceIdForChar(uni);
560 return SkTypefaceCache::FindByID(fontID);
561 }
562 return NULL;
563}
564
djsollen@google.com9a70f342013-06-25 18:07:45 +0000565FallbackFontList* SkFontConfigInterfaceAndroid::getCurrentLocaleFallbackFontList() {
566 SkString locale = SkFontConfigParser::GetLocale();
567 if (NULL == fLocaleFallbackFontList || locale != fCachedLocale) {
568 fCachedLocale = locale;
569 fLocaleFallbackFontList = this->findFallbackFontList(locale);
570 }
571 return fLocaleFallbackFontList;
572}
573
djsollen@google.com40078cb2013-05-24 20:31:57 +0000574FallbackFontList* SkFontConfigInterfaceAndroid::findFallbackFontList(const SkLanguage& lang,
575 bool isOriginal) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000576 const SkString& langTag = lang.getTag();
577 if (langTag.isEmpty()) {
578 return &fDefaultFallbackList;
579 }
580
581 FallbackFontList* fallbackFontList;
djsollen@google.com40078cb2013-05-24 20:31:57 +0000582 if (fFallbackFontDict.find(langTag.c_str(), langTag.size(), &fallbackFontList) ||
583 fFallbackFontAliasDict.find(langTag.c_str(), langTag.size(), &fallbackFontList)) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000584 return fallbackFontList;
585 }
586
587 // attempt a recursive fuzzy match
djsollen@google.combfae9d32013-05-21 16:53:50 +0000588 SkLanguage parent = lang.getParent();
djsollen@google.com40078cb2013-05-24 20:31:57 +0000589 fallbackFontList = findFallbackFontList(parent, false);
590
591 // cache the original lang so we don't have to do the recursion again.
592 if (isOriginal) {
593 DEBUG_FONT(("---- Created fallback list alias for \"%s\"", langTag.c_str()));
594 fFallbackFontAliasDict.set(langTag.c_str(), fallbackFontList);
595 }
596 return fallbackFontList;
djsollen@google.combfae9d32013-05-21 16:53:50 +0000597}
598
599SkTypeface* SkFontConfigInterfaceAndroid::nextLogicalTypeface(SkFontID currFontID,
600 SkFontID origFontID,
601 const SkPaintOptionsAndroid& opts) {
602 // Skia does not support font fallback by default. This enables clients such
603 // as WebKit to customize their font selection. In any case, clients can use
604 // GetFallbackFamilyNameForChar() to get the fallback font for individual
605 // characters.
606 if (!opts.isUsingFontFallbacks()) {
607 return NULL;
608 }
609
djsollen@google.combfae9d32013-05-21 16:53:50 +0000610 FallbackFontList* currentFallbackList = findFallbackFontList(opts.getLanguage());
611 SkASSERT(currentFallbackList);
612
djsollen@google.comb27eba72013-09-06 12:59:50 +0000613 SkTypeface::Style origStyle = SkTypeface::kNormal;
614 const SkTypeface* origTypeface = SkTypefaceCache::FindByID(origFontID);
615 if (NULL != origTypeface) {
616 origStyle = origTypeface->style();
617 }
618
djsollen@google.combfae9d32013-05-21 16:53:50 +0000619 // we must convert currTypeface into a FontRecID
djsollen@google.come47e7d12013-06-06 21:25:09 +0000620 FontRecID currFontRecID = INVALID_FONT_REC_ID;
621 const SkTypeface* currTypeface = SkTypefaceCache::FindByID(currFontID);
622 // non-system fonts are not in the font cache so if we are asked to fallback
623 // for a non-system font we will start at the front of the chain.
djsollen@google.com29bf8622013-07-31 15:48:10 +0000624 if (NULL != currTypeface && currFontID != origFontID) {
djsollen@google.come47e7d12013-06-06 21:25:09 +0000625 currFontRecID = ((FontConfigTypeface*)currTypeface)->getIdentity().fID;
626 SkASSERT(INVALID_FONT_REC_ID != currFontRecID);
627 }
djsollen@google.combfae9d32013-05-21 16:53:50 +0000628
djsollen@google.comb27eba72013-09-06 12:59:50 +0000629 FamilyRecID currFamilyRecID = INVALID_FAMILY_REC_ID;
630 if (INVALID_FONT_REC_ID != currFontRecID) {
631 currFamilyRecID = fFonts[currFontRecID].fFamilyRecID;
632 }
633
djsollen@google.come47e7d12013-06-06 21:25:09 +0000634 // lookup the index next font in the chain
djsollen@google.comb27eba72013-09-06 12:59:50 +0000635 int currFallbackFontIndex = currentFallbackList->find(currFamilyRecID);
djsollen@google.come47e7d12013-06-06 21:25:09 +0000636 // We add 1 to the returned index for 2 reasons: (1) if find succeeds it moves
637 // our index to the next entry in the list; (2) if find() fails it returns
638 // -1 and incrementing it will set our starting index to 0 (the head of the list)
djsollen@google.combfae9d32013-05-21 16:53:50 +0000639 int nextFallbackFontIndex = currFallbackFontIndex + 1;
djsollen@google.combfae9d32013-05-21 16:53:50 +0000640
djsollen@google.com40078cb2013-05-24 20:31:57 +0000641 if(nextFallbackFontIndex >= currentFallbackList->count()) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000642 return NULL;
643 }
644
645 // If a rec object is set to prefer "kDefault_Variant" it means they have no preference
646 // In this case, we set the value to "kCompact_Variant"
647 SkPaintOptionsAndroid::FontVariant variant = opts.getFontVariant();
648 if (variant == SkPaintOptionsAndroid::kDefault_Variant) {
649 variant = SkPaintOptionsAndroid::kCompact_Variant;
650 }
651
652 int32_t acceptedVariants = SkPaintOptionsAndroid::kDefault_Variant | variant;
653
654 SkTypeface* nextLogicalTypeface = 0;
655 while (nextFallbackFontIndex < currentFallbackList->count()) {
djsollen@google.comb27eba72013-09-06 12:59:50 +0000656 FamilyRecID familyRecID = currentFallbackList->getAt(nextFallbackFontIndex);
657 if ((fFontFamilies[familyRecID].fPaintOptions.getFontVariant() & acceptedVariants) != 0) {
658 FontRecID matchedFont = find_best_style(fFontFamilies[familyRecID], origStyle);
659 nextLogicalTypeface = this->getTypefaceForFontRec(matchedFont);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000660 break;
661 }
662 nextFallbackFontIndex++;
663 }
664
665 DEBUG_FONT(("---- nextLogicalFont: currFontID=%d, origFontID=%d, currRecID=%d, "
djsollen@google.com40078cb2013-05-24 20:31:57 +0000666 "lang=%s, variant=%d, nextFallbackIndex[%d,%d] => nextLogicalTypeface=%d",
djsollen@google.combfae9d32013-05-21 16:53:50 +0000667 currFontID, origFontID, currFontRecID, opts.getLanguage().getTag().c_str(),
djsollen@google.com40078cb2013-05-24 20:31:57 +0000668 variant, nextFallbackFontIndex, currentFallbackList->getAt(nextFallbackFontIndex),
djsollen@google.combfae9d32013-05-21 16:53:50 +0000669 (nextLogicalTypeface) ? nextLogicalTypeface->uniqueID() : 0));
670 return SkSafeRef(nextLogicalTypeface);
671}
672
673///////////////////////////////////////////////////////////////////////////////
674
675bool SkGetFallbackFamilyNameForChar(SkUnichar uni, SkString* name) {
djsollen@google.com9902c382013-09-19 18:22:30 +0000676 SkString locale = SkFontConfigParser::GetLocale();
djsollen@google.combfae9d32013-05-21 16:53:50 +0000677 SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
djsollen@google.com9902c382013-09-19 18:22:30 +0000678 return fontConfig->getFallbackFamilyNameForChar(uni, locale.c_str(), name);
679}
680
681bool SkGetFallbackFamilyNameForChar(SkUnichar uni, const char* lang, SkString* name) {
682 SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
683 return fontConfig->getFallbackFamilyNameForChar(uni, lang, name);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000684}
685
686void SkUseTestFontConfigFile(const char* mainconf, const char* fallbackconf,
687 const char* fontsdir) {
688 gTestMainConfigFile = mainconf;
689 gTestFallbackConfigFile = fallbackconf;
690 gTestFontFilePrefix = fontsdir;
691 SkASSERT(gTestMainConfigFile);
692 SkASSERT(gTestFallbackConfigFile);
693 SkASSERT(gTestFontFilePrefix);
694 SkDEBUGF(("Use Test Config File Main %s, Fallback %s, Font Dir %s",
695 gTestMainConfigFile, gTestFallbackConfigFile, gTestFontFilePrefix));
696}
697
698SkTypeface* SkAndroidNextLogicalTypeface(SkFontID currFontID, SkFontID origFontID,
699 const SkPaintOptionsAndroid& options) {
700 SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
701 return fontConfig->nextLogicalTypeface(currFontID, origFontID, options);
702
703}
704
705///////////////////////////////////////////////////////////////////////////////
706
djsollen@google.com40078cb2013-05-24 20:31:57 +0000707#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
708
709struct HB_UnicodeMapping {
710 // TODO: when the WebView no longer needs harfbuzz_old, remove
711 HB_Script script_old;
712 hb_script_t script;
713 const SkUnichar unicode;
714};
715
716/*
717 * The following scripts are not complex fonts and we do not expect them to be parsed by this table
718 * HB_SCRIPT_COMMON,
719 * HB_SCRIPT_GREEK,
720 * HB_SCRIPT_CYRILLIC,
721 * HB_SCRIPT_HANGUL
722 * HB_SCRIPT_INHERITED
723 */
724
725/* Harfbuzz (old) is missing a number of scripts in its table. For these,
726 * we include a value which can never happen. We won't get complex script
727 * shaping in these cases, but the library wouldn't know how to shape
728 * them anyway. */
729#define HB_Script_Unknown HB_ScriptCount
730
731static HB_UnicodeMapping HB_UnicodeMappingArray[] = {
732 {HB_Script_Armenian, HB_SCRIPT_ARMENIAN, 0x0531},
733 {HB_Script_Hebrew, HB_SCRIPT_HEBREW, 0x0591},
734 {HB_Script_Arabic, HB_SCRIPT_ARABIC, 0x0600},
735 {HB_Script_Syriac, HB_SCRIPT_SYRIAC, 0x0710},
736 {HB_Script_Thaana, HB_SCRIPT_THAANA, 0x0780},
737 {HB_Script_Nko, HB_SCRIPT_NKO, 0x07C0},
738 {HB_Script_Devanagari, HB_SCRIPT_DEVANAGARI, 0x0901},
739 {HB_Script_Bengali, HB_SCRIPT_BENGALI, 0x0981},
740 {HB_Script_Gurmukhi, HB_SCRIPT_GURMUKHI, 0x0A10},
741 {HB_Script_Gujarati, HB_SCRIPT_GUJARATI, 0x0A90},
742 {HB_Script_Oriya, HB_SCRIPT_ORIYA, 0x0B10},
743 {HB_Script_Tamil, HB_SCRIPT_TAMIL, 0x0B82},
744 {HB_Script_Telugu, HB_SCRIPT_TELUGU, 0x0C10},
745 {HB_Script_Kannada, HB_SCRIPT_KANNADA, 0x0C90},
746 {HB_Script_Malayalam, HB_SCRIPT_MALAYALAM, 0x0D10},
747 {HB_Script_Sinhala, HB_SCRIPT_SINHALA, 0x0D90},
748 {HB_Script_Thai, HB_SCRIPT_THAI, 0x0E01},
749 {HB_Script_Lao, HB_SCRIPT_LAO, 0x0E81},
750 {HB_Script_Tibetan, HB_SCRIPT_TIBETAN, 0x0F00},
751 {HB_Script_Myanmar, HB_SCRIPT_MYANMAR, 0x1000},
752 {HB_Script_Georgian, HB_SCRIPT_GEORGIAN, 0x10A0},
753 {HB_Script_Unknown, HB_SCRIPT_ETHIOPIC, 0x1200},
754 {HB_Script_Unknown, HB_SCRIPT_CHEROKEE, 0x13A0},
755 {HB_Script_Ogham, HB_SCRIPT_OGHAM, 0x1680},
756 {HB_Script_Runic, HB_SCRIPT_RUNIC, 0x16A0},
757 {HB_Script_Khmer, HB_SCRIPT_KHMER, 0x1780},
758 {HB_Script_Unknown, HB_SCRIPT_TAI_LE, 0x1950},
759 {HB_Script_Unknown, HB_SCRIPT_NEW_TAI_LUE, 0x1980},
760 {HB_Script_Unknown, HB_SCRIPT_TAI_THAM, 0x1A20},
761 {HB_Script_Unknown, HB_SCRIPT_CHAM, 0xAA00},
762};
763
764static hb_script_t getHBScriptFromHBScriptOld(HB_Script script_old) {
765 hb_script_t script = HB_SCRIPT_INVALID;
766 int numSupportedFonts = sizeof(HB_UnicodeMappingArray) / sizeof(HB_UnicodeMapping);
767 for (int i = 0; i < numSupportedFonts; i++) {
768 if (script_old == HB_UnicodeMappingArray[i].script_old) {
769 script = HB_UnicodeMappingArray[i].script;
770 break;
771 }
772 }
773 return script;
774}
775
776// returns 0 for "Not Found"
777static SkUnichar getUnicodeFromHBScript(hb_script_t script) {
778 SkUnichar unichar = 0;
779 int numSupportedFonts = sizeof(HB_UnicodeMappingArray) / sizeof(HB_UnicodeMapping);
780 for (int i = 0; i < numSupportedFonts; i++) {
781 if (script == HB_UnicodeMappingArray[i].script) {
782 unichar = HB_UnicodeMappingArray[i].unicode;
783 break;
784 }
785 }
786 return unichar;
787}
788
789struct TypefaceLookupStruct {
790 hb_script_t script;
791 SkTypeface::Style style;
792 SkPaintOptionsAndroid::FontVariant fontVariant;
793 SkTypeface* typeface;
794};
795
796SK_DECLARE_STATIC_MUTEX(gTypefaceTableMutex); // This is the mutex for gTypefaceTable
797static SkTDArray<TypefaceLookupStruct> gTypefaceTable; // This is protected by gTypefaceTableMutex
798
799static int typefaceLookupCompare(const TypefaceLookupStruct& first,
800 const TypefaceLookupStruct& second) {
801 if (first.script != second.script) {
802 return (first.script > second.script) ? 1 : -1;
803 }
804 if (first.style != second.style) {
805 return (first.style > second.style) ? 1 : -1;
806 }
807 if (first.fontVariant != second.fontVariant) {
808 return (first.fontVariant > second.fontVariant) ? 1 : -1;
809 }
810 return 0;
811}
812
813SkTypeface* SkCreateTypefaceForScriptNG(hb_script_t script, SkTypeface::Style style,
814 SkPaintOptionsAndroid::FontVariant fontVariant) {
815 SkAutoMutexAcquire ac(gTypefaceTableMutex);
816
817 TypefaceLookupStruct key;
818 key.script = script;
819 key.style = style;
820 key.fontVariant = fontVariant;
821
822 int index = SkTSearch<TypefaceLookupStruct>(
823 (const TypefaceLookupStruct*) gTypefaceTable.begin(),
824 gTypefaceTable.count(), key, sizeof(TypefaceLookupStruct),
825 typefaceLookupCompare);
826
827 SkTypeface* retTypeface = NULL;
828 if (index >= 0) {
829 retTypeface = gTypefaceTable[index].typeface;
830 }
831 else {
832 SkUnichar unichar = getUnicodeFromHBScript(script);
833 if (!unichar) {
834 return NULL;
835 }
836
837 SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
838 retTypeface = fontConfig->getTypefaceForChar(unichar, style, fontVariant);
839
840 // add to the lookup table
841 key.typeface = retTypeface;
842 *gTypefaceTable.insert(~index) = key;
843 }
844
845 // we ref(), the caller is expected to unref when they are done
846 return SkSafeRef(retTypeface);
847}
848
849SkTypeface* SkCreateTypefaceForScript(HB_Script script, SkTypeface::Style style,
850 SkPaintOptionsAndroid::FontVariant fontVariant) {
851 return SkCreateTypefaceForScriptNG(getHBScriptFromHBScriptOld(script), style, fontVariant);
852}
853
854#endif
855
856///////////////////////////////////////////////////////////////////////////////
857
djsollen@google.combfae9d32013-05-21 16:53:50 +0000858SkFontMgr* SkFontMgr::Factory() {
859 return NULL;
860}