blob: 94662f5d5949844ec9a77fee69dcfd924c73f1ff [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"
bungeman3a21d612014-07-11 08:52:26 -070014#include "SkFontHost_FreeType_common.h"
djsollen@google.combfae9d32013-05-21 16:53:50 +000015#include "SkFontMgr.h"
16#include "SkGlyphCache.h"
17#include "SkPaint.h"
djsollen@google.combfae9d32013-05-21 16:53:50 +000018#include "SkString.h"
19#include "SkStream.h"
20#include "SkThread.h"
21#include "SkTypefaceCache.h"
22#include "SkTArray.h"
23#include "SkTDict.h"
24#include "SkTSearch.h"
25
26#include <stdio.h>
27#include <string.h>
28
29#ifndef SK_DEBUG_FONTS
30 #define SK_DEBUG_FONTS 0
31#endif
32
33#if SK_DEBUG_FONTS
34 #define DEBUG_FONT(args) SkDebugf args
35#else
36 #define DEBUG_FONT(args)
37#endif
38
39///////////////////////////////////////////////////////////////////////////////
40
41// For test only.
42static const char* gTestMainConfigFile = NULL;
43static const char* gTestFallbackConfigFile = NULL;
44static const char* gTestFontFilePrefix = NULL;
45
46///////////////////////////////////////////////////////////////////////////////
47
djsollen@google.com40078cb2013-05-24 20:31:57 +000048typedef int32_t FontRecID;
49#define INVALID_FONT_REC_ID -1
50
51typedef int32_t FamilyRecID;
52#define INVALID_FAMILY_REC_ID -1
53
djsollen@google.combfae9d32013-05-21 16:53:50 +000054// used to record our notion of the pre-existing fonts
55struct FontRec {
bungeman733418f2014-07-17 12:17:55 -070056 SkAutoTUnref<SkTypeface> fTypeface;
djsollen@google.combfae9d32013-05-21 16:53:50 +000057 SkString fFileName;
58 SkTypeface::Style fStyle;
djsollen@google.combfae9d32013-05-21 16:53:50 +000059 bool fIsValid;
djsollen@google.com40078cb2013-05-24 20:31:57 +000060 FamilyRecID fFamilyRecID;
djsollen@google.combfae9d32013-05-21 16:53:50 +000061};
62
djsollen@google.combfae9d32013-05-21 16:53:50 +000063struct FamilyRec {
64 FamilyRec() {
65 memset(fFontRecID, INVALID_FONT_REC_ID, sizeof(fFontRecID));
66 }
67
68 static const int FONT_STYLE_COUNT = 4;
69 FontRecID fFontRecID[FONT_STYLE_COUNT];
djsollen@google.comb27eba72013-09-06 12:59:50 +000070 bool fIsFallbackFont;
djsollen@google.com39a7c702013-09-24 20:08:47 +000071 SkString fFallbackName;
djsollen@google.comb27eba72013-09-06 12:59:50 +000072 SkPaintOptionsAndroid fPaintOptions;
djsollen@google.combfae9d32013-05-21 16:53:50 +000073};
74
djsollen@google.combfae9d32013-05-21 16:53:50 +000075
djsollen@google.comb27eba72013-09-06 12:59:50 +000076typedef SkTDArray<FamilyRecID> FallbackFontList;
djsollen@google.combfae9d32013-05-21 16:53:50 +000077
78class SkFontConfigInterfaceAndroid : public SkFontConfigInterface {
79public:
80 SkFontConfigInterfaceAndroid(SkTDArray<FontFamily*>& fontFamilies);
81 virtual ~SkFontConfigInterfaceAndroid();
82
83 virtual bool matchFamilyName(const char familyName[],
84 SkTypeface::Style requested,
85 FontIdentity* outFontIdentifier,
86 SkString* outFamilyName,
87 SkTypeface::Style* outStyle) SK_OVERRIDE;
88 virtual SkStream* openStream(const FontIdentity&) SK_OVERRIDE;
89
90 // new APIs
91 virtual SkDataTable* getFamilyNames() SK_OVERRIDE;
92 virtual bool matchFamilySet(const char inFamilyName[],
93 SkString* outFamilyName,
94 SkTArray<FontIdentity>*) SK_OVERRIDE;
95
96 /**
97 * Get the family name of the font in the default fallback font list that
98 * contains the specified chararacter. if no font is found, returns false.
99 */
djsollen@google.com9902c382013-09-19 18:22:30 +0000100 bool getFallbackFamilyNameForChar(SkUnichar uni, const char* lang, SkString* name);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000101 /**
102 *
103 */
104 SkTypeface* getTypefaceForChar(SkUnichar uni, SkTypeface::Style style,
105 SkPaintOptionsAndroid::FontVariant fontVariant);
106 SkTypeface* nextLogicalTypeface(SkFontID currFontID, SkFontID origFontID,
107 const SkPaintOptionsAndroid& options);
djsollen@google.com5df5e612013-10-03 14:42:24 +0000108 SkTypeface* getTypefaceForGlyphID(uint16_t glyphID, const SkTypeface* origTypeface,
109 const SkPaintOptionsAndroid& options,
110 int* lowerBounds, int* upperBounds);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000111
112private:
djsollen@google.comb27eba72013-09-06 12:59:50 +0000113 void addFallbackFamily(FamilyRecID fontRecID);
djsollen@google.com40078cb2013-05-24 20:31:57 +0000114 SkTypeface* getTypefaceForFontRec(FontRecID fontRecID);
djsollen@google.com9a70f342013-06-25 18:07:45 +0000115 FallbackFontList* getCurrentLocaleFallbackFontList();
djsollen@google.com40078cb2013-05-24 20:31:57 +0000116 FallbackFontList* findFallbackFontList(const SkLanguage& lang, bool isOriginal = true);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000117
bungeman733418f2014-07-17 12:17:55 -0700118 SkTArray<FontRec, true> fFonts;
119 SkTArray<FamilyRec, true> fFontFamilies;
djsollen@google.combfae9d32013-05-21 16:53:50 +0000120 SkTDict<FamilyRecID> fFamilyNameDict;
121 FamilyRecID fDefaultFamilyRecID;
122
123 // (SkLanguage)<->(fallback chain index) translation
124 SkTDict<FallbackFontList*> fFallbackFontDict;
djsollen@google.com40078cb2013-05-24 20:31:57 +0000125 SkTDict<FallbackFontList*> fFallbackFontAliasDict;
djsollen@google.combfae9d32013-05-21 16:53:50 +0000126 FallbackFontList fDefaultFallbackList;
djsollen@google.com9a70f342013-06-25 18:07:45 +0000127
128 // fallback info for current locale
129 SkString fCachedLocale;
130 FallbackFontList* fLocaleFallbackFontList;
djsollen@google.combfae9d32013-05-21 16:53:50 +0000131};
132
133///////////////////////////////////////////////////////////////////////////////
134
bungemand6aeb6d2014-07-25 11:52:47 -0700135SK_DECLARE_STATIC_MUTEX(gGetSingletonInterfaceMutex);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000136static SkFontConfigInterfaceAndroid* getSingletonInterface() {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000137 static SkFontConfigInterfaceAndroid* gFontConfigInterface;
138
bungemand6aeb6d2014-07-25 11:52:47 -0700139 SkAutoMutexAcquire ac(gGetSingletonInterfaceMutex);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000140 if (NULL == gFontConfigInterface) {
141 // load info from a configuration file that we can use to populate the
142 // system/fallback font structures
143 SkTDArray<FontFamily*> fontFamilies;
144 if (!gTestMainConfigFile) {
145 SkFontConfigParser::GetFontFamilies(fontFamilies);
146 } else {
147 SkFontConfigParser::GetTestFontFamilies(fontFamilies, gTestMainConfigFile,
148 gTestFallbackConfigFile);
149 }
150
151 gFontConfigInterface = new SkFontConfigInterfaceAndroid(fontFamilies);
152
153 // cleanup the data we received from the parser
154 fontFamilies.deleteAll();
155 }
156 return gFontConfigInterface;
157}
158
tomhudsone438ddb2014-07-01 18:54:41 -0700159SkFontConfigInterface* SkFontConfigInterface::GetSingletonDirectInterface(SkBaseMutex*) {
160 // Doesn't need passed-in mutex because getSingletonInterface() uses one
djsollen@google.combfae9d32013-05-21 16:53:50 +0000161 return getSingletonInterface();
162}
163
164///////////////////////////////////////////////////////////////////////////////
165
bungeman733418f2014-07-17 12:17:55 -0700166static bool has_font(const SkTArray<FontRec, true>& array, const SkString& filename) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000167 for (int i = 0; i < array.count(); i++) {
168 if (array[i].fFileName == filename) {
169 return true;
170 }
171 }
172 return false;
173}
174
175#ifndef SK_FONT_FILE_PREFIX
176 #define SK_FONT_FILE_PREFIX "/fonts/"
177#endif
178
commit-bot@chromium.org31db71d2014-04-04 18:14:39 +0000179static void get_path_for_sys_fonts(SkString* full, const SkString& name) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000180 if (gTestFontFilePrefix) {
181 full->set(gTestFontFilePrefix);
182 } else {
183 full->set(getenv("ANDROID_ROOT"));
184 full->append(SK_FONT_FILE_PREFIX);
185 }
186 full->append(name);
187}
188
189static void insert_into_name_dict(SkTDict<FamilyRecID>& familyNameDict,
190 const char* name, FamilyRecID familyRecID) {
191 SkAutoAsciiToLC tolc(name);
djsollen@google.com92e3f082013-08-27 17:40:03 +0000192 if (familyNameDict.find(tolc.lc())) {
193 SkDebugf("---- system font attempting to use a the same name [%s] for"
194 "multiple families. skipping subsequent occurrences", tolc.lc());
195 } else {
196 familyNameDict.set(tolc.lc(), familyRecID);
197 }
djsollen@google.combfae9d32013-05-21 16:53:50 +0000198}
199
djsollen@google.combfae9d32013-05-21 16:53:50 +0000200///////////////////////////////////////////////////////////////////////////////
201
202SkFontConfigInterfaceAndroid::SkFontConfigInterfaceAndroid(SkTDArray<FontFamily*>& fontFamilies) :
203 fFonts(fontFamilies.count()),
204 fFontFamilies(fontFamilies.count() / FamilyRec::FONT_STYLE_COUNT),
205 fFamilyNameDict(1024),
206 fDefaultFamilyRecID(INVALID_FAMILY_REC_ID),
djsollen@google.com40078cb2013-05-24 20:31:57 +0000207 fFallbackFontDict(128),
djsollen@google.com9a70f342013-06-25 18:07:45 +0000208 fFallbackFontAliasDict(128),
209 fLocaleFallbackFontList(NULL) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000210
211 for (int i = 0; i < fontFamilies.count(); ++i) {
212 FontFamily* family = fontFamilies[i];
213
214 // defer initializing the familyRec until we can be sure that at least
215 // one of it's children contains a valid font file
216 FamilyRec* familyRec = NULL;
217 FamilyRecID familyRecID = INVALID_FAMILY_REC_ID;
218
219 for (int j = 0; j < family->fFontFiles.count(); ++j) {
220 SkString filename;
commit-bot@chromium.org31db71d2014-04-04 18:14:39 +0000221 get_path_for_sys_fonts(&filename, family->fFontFiles[j].fFileName);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000222
223 if (has_font(fFonts, filename)) {
224 SkDebugf("---- system font and fallback font files specify a duplicate "
225 "font %s, skipping the second occurrence", filename.c_str());
226 continue;
227 }
228
229 FontRec& fontRec = fFonts.push_back();
230 fontRec.fFileName = filename;
231 fontRec.fStyle = SkTypeface::kNormal;
djsollen@google.combfae9d32013-05-21 16:53:50 +0000232 fontRec.fIsValid = false;
djsollen@google.com40078cb2013-05-24 20:31:57 +0000233 fontRec.fFamilyRecID = familyRecID;
djsollen@google.combfae9d32013-05-21 16:53:50 +0000234
235 const FontRecID fontRecID = fFonts.count() - 1;
236
237 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(filename.c_str()));
238 if (stream.get() != NULL) {
239 bool isFixedWidth;
240 SkString name;
bungeman3a21d612014-07-11 08:52:26 -0700241 fontRec.fIsValid = SkTypeface_FreeType::ScanFont(stream.get(), 0,
242 &name, &fontRec.fStyle,
243 &isFixedWidth);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000244 } else {
djsollen@google.comb27eba72013-09-06 12:59:50 +0000245 if (!family->fIsFallbackFont) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000246 SkDebugf("---- failed to open <%s> as a font\n", filename.c_str());
247 }
248 }
249
250 if (fontRec.fIsValid) {
251 DEBUG_FONT(("---- SystemFonts[%d][%d] fallback=%d file=%s",
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 } else {
254 DEBUG_FONT(("---- SystemFonts[%d][%d] fallback=%d file=%s (INVALID)",
djsollen@google.com9902c382013-09-19 18:22:30 +0000255 i, fFonts.count() - 1, family->fIsFallbackFont, filename.c_str()));
djsollen@google.combfae9d32013-05-21 16:53:50 +0000256 continue;
257 }
258
259 // create a familyRec now that we know that at least one font in
260 // the family is valid
261 if (familyRec == NULL) {
262 familyRec = &fFontFamilies.push_back();
263 familyRecID = fFontFamilies.count() - 1;
djsollen@google.com40078cb2013-05-24 20:31:57 +0000264 fontRec.fFamilyRecID = familyRecID;
djsollen@google.comb27eba72013-09-06 12:59:50 +0000265
266 familyRec->fIsFallbackFont = family->fIsFallbackFont;
commit-bot@chromium.org31db71d2014-04-04 18:14:39 +0000267 familyRec->fPaintOptions = family->fFontFiles[j].fPaintOptions;
djsollen@google.comb27eba72013-09-06 12:59:50 +0000268
commit-bot@chromium.org31db71d2014-04-04 18:14:39 +0000269 } else if (familyRec->fPaintOptions != family->fFontFiles[j].fPaintOptions) {
djsollen@google.comb27eba72013-09-06 12:59:50 +0000270 SkDebugf("Every font file within a family must have identical"
271 "language and variant attributes");
272 sk_throw();
djsollen@google.combfae9d32013-05-21 16:53:50 +0000273 }
274
275 // add this font to the current familyRec
276 if (INVALID_FONT_REC_ID != familyRec->fFontRecID[fontRec.fStyle]) {
277 DEBUG_FONT(("Overwriting familyRec for style[%d] old,new:(%d,%d)",
278 fontRec.fStyle, familyRec->fFontRecID[fontRec.fStyle],
279 fontRecID));
280 }
281 familyRec->fFontRecID[fontRec.fStyle] = fontRecID;
djsollen@google.combfae9d32013-05-21 16:53:50 +0000282 }
283
djsollen@google.com39a7c702013-09-24 20:08:47 +0000284 if (familyRec) {
285 if (familyRec->fIsFallbackFont) {
286 // add the font to the appropriate fallback chains and also insert a
287 // unique name into the familyNameDict for internal usage
288 addFallbackFamily(familyRecID);
289 } else {
290 // add the names that map to this family to the dictionary for easy lookup
commit-bot@chromium.org31db71d2014-04-04 18:14:39 +0000291 const SkTArray<SkString>& names = family->fNames;
292 if (names.empty()) {
djsollen@google.com39a7c702013-09-24 20:08:47 +0000293 SkDEBUGFAIL("ERROR: non-fallback font with no name");
294 continue;
295 }
djsollen@google.combfae9d32013-05-21 16:53:50 +0000296
djsollen@google.com39a7c702013-09-24 20:08:47 +0000297 for (int i = 0; i < names.count(); i++) {
commit-bot@chromium.org31db71d2014-04-04 18:14:39 +0000298 insert_into_name_dict(fFamilyNameDict, names[i].c_str(), familyRecID);
djsollen@google.com39a7c702013-09-24 20:08:47 +0000299 }
djsollen@google.combfae9d32013-05-21 16:53:50 +0000300 }
301 }
djsollen@google.combfae9d32013-05-21 16:53:50 +0000302 }
303
304 DEBUG_FONT(("---- We have %d system fonts", fFonts.count()));
305
306 if (fFontFamilies.count() > 0) {
307 fDefaultFamilyRecID = 0;
308 }
309
310 // scans the default fallback font chain, adding every entry to every other
311 // fallback font chain to which it does not belong. this results in every
312 // language-specific fallback font chain having all of its fallback fonts at
313 // the front of the chain, and everything else at the end.
314 FallbackFontList* fallbackList;
315 SkTDict<FallbackFontList*>::Iter iter(fFallbackFontDict);
316 const char* fallbackLang = iter.next(&fallbackList);
317 while(fallbackLang != NULL) {
318 for (int i = 0; i < fDefaultFallbackList.count(); i++) {
djsollen@google.comb27eba72013-09-06 12:59:50 +0000319 FamilyRecID familyRecID = fDefaultFallbackList[i];
320 const SkString& fontLang = fFontFamilies[familyRecID].fPaintOptions.getLanguage().getTag();
djsollen@google.combfae9d32013-05-21 16:53:50 +0000321 if (strcmp(fallbackLang, fontLang.c_str()) != 0) {
djsollen@google.comb27eba72013-09-06 12:59:50 +0000322 fallbackList->push(familyRecID);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000323 }
324 }
325 // move to the next fallback list in the dictionary
326 fallbackLang = iter.next(&fallbackList);
327 }
328}
329
330SkFontConfigInterfaceAndroid::~SkFontConfigInterfaceAndroid() {
331 // iterate through and cleanup fFallbackFontDict
332 SkTDict<FallbackFontList*>::Iter iter(fFallbackFontDict);
333 FallbackFontList* fallbackList;
334 while(iter.next(&fallbackList) != NULL) {
335 SkDELETE(fallbackList);
336 }
337}
338
djsollen@google.comb27eba72013-09-06 12:59:50 +0000339void SkFontConfigInterfaceAndroid::addFallbackFamily(FamilyRecID familyRecID) {
340 SkASSERT(familyRecID < fFontFamilies.count());
djsollen@google.com39a7c702013-09-24 20:08:47 +0000341 FamilyRec& familyRec = fFontFamilies[familyRecID];
djsollen@google.comb27eba72013-09-06 12:59:50 +0000342 SkASSERT(familyRec.fIsFallbackFont);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000343
djsollen@google.com39a7c702013-09-24 20:08:47 +0000344 // add the fallback family to the name dictionary. This is
345 // needed by getFallbackFamilyNameForChar() so that fallback
346 // families can be identified by a unique name. The unique
347 // identifier that we've chosen is the familyID in hex (e.g. '0F##fallback').
348 familyRec.fFallbackName.printf("%.2x##fallback", familyRecID);
349 insert_into_name_dict(fFamilyNameDict, familyRec.fFallbackName.c_str(), familyRecID);
350
djsollen@google.combfae9d32013-05-21 16:53:50 +0000351 // add to the default fallback list
djsollen@google.comb27eba72013-09-06 12:59:50 +0000352 fDefaultFallbackList.push(familyRecID);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000353
354 // stop here if it is the default language tag
djsollen@google.comb27eba72013-09-06 12:59:50 +0000355 const SkString& languageTag = familyRec.fPaintOptions.getLanguage().getTag();
djsollen@google.combfae9d32013-05-21 16:53:50 +0000356 if (languageTag.isEmpty()) {
357 return;
358 }
359
360 // add to the appropriate language's custom fallback list
361 FallbackFontList* customList = NULL;
362 if (!fFallbackFontDict.find(languageTag.c_str(), &customList)) {
363 DEBUG_FONT(("---- Created fallback list for \"%s\"", languageTag.c_str()));
364 customList = SkNEW(FallbackFontList);
365 fFallbackFontDict.set(languageTag.c_str(), customList);
366 }
367 SkASSERT(customList != NULL);
djsollen@google.comb27eba72013-09-06 12:59:50 +0000368 customList->push(familyRecID);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000369}
370
371
372static FontRecID find_best_style(const FamilyRec& family, SkTypeface::Style style) {
373
374 const FontRecID* fontRecIDs = family.fFontRecID;
375
376 if (fontRecIDs[style] != INVALID_FONT_REC_ID) { // exact match
377 return fontRecIDs[style];
378 }
379 // look for a matching bold
380 style = (SkTypeface::Style)(style ^ SkTypeface::kItalic);
381 if (fontRecIDs[style] != INVALID_FONT_REC_ID) {
382 return fontRecIDs[style];
383 }
384 // look for the plain
385 if (fontRecIDs[SkTypeface::kNormal] != INVALID_FONT_REC_ID) {
386 return fontRecIDs[SkTypeface::kNormal];
387 }
388 // look for anything
389 for (int i = 0; i < FamilyRec::FONT_STYLE_COUNT; i++) {
390 if (fontRecIDs[i] != INVALID_FONT_REC_ID) {
391 return fontRecIDs[i];
392 }
393 }
394 // should never get here, since the fontRecID list should not be empty
395 SkDEBUGFAIL("No valid fonts exist for this family");
396 return -1;
397}
398
399bool SkFontConfigInterfaceAndroid::matchFamilyName(const char familyName[],
400 SkTypeface::Style style,
401 FontIdentity* outFontIdentifier,
402 SkString* outFamilyName,
robertphillips@google.comb7457d02013-05-22 00:12:43 +0000403 SkTypeface::Style* outStyle) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000404 // clip to legal style bits
405 style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
406
407 bool exactNameMatch = false;
408
409 FamilyRecID familyRecID = INVALID_FAMILY_REC_ID;
410 if (NULL != familyName) {
djsollen@google.com2e08f192013-05-21 20:08:10 +0000411 SkAutoAsciiToLC tolc(familyName);
412 if (fFamilyNameDict.find(tolc.lc(), &familyRecID)) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000413 exactNameMatch = true;
414 }
415 } else {
416 familyRecID = fDefaultFamilyRecID;
417
418 }
419
djsollen@google.com1f584ed2013-09-19 12:08:40 +0000420 // If no matching family name is found then return false. This allows clients
421 // to be able to search for other fonts instead of forcing them to use the
422 // default font.
djsollen@google.combfae9d32013-05-21 16:53:50 +0000423 if (INVALID_FAMILY_REC_ID == familyRecID) {
djsollen@google.com1f584ed2013-09-19 12:08:40 +0000424 return false;
djsollen@google.combfae9d32013-05-21 16:53:50 +0000425 }
426
427 FontRecID fontRecID = find_best_style(fFontFamilies[familyRecID], style);
428 FontRec& fontRec = fFonts[fontRecID];
429
430 if (NULL != outFontIdentifier) {
431 outFontIdentifier->fID = fontRecID;
432 outFontIdentifier->fTTCIndex = 0;
433 outFontIdentifier->fString.set(fontRec.fFileName);
434// outFontIdentifier->fStyle = fontRec.fStyle;
435 }
436
437 if (NULL != outFamilyName) {
438 if (exactNameMatch) {
439 outFamilyName->set(familyName);
440 } else {
441 // find familyName from list of names
442 const char* familyName = NULL;
djsollen@google.comab6eeb92013-05-21 17:15:27 +0000443 SkAssertResult(fFamilyNameDict.findKey(familyRecID, &familyName));
444 SkASSERT(familyName);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000445 outFamilyName->set(familyName);
446 }
447 }
448
449 if (NULL != outStyle) {
450 *outStyle = fontRec.fStyle;
451 }
452
453 return true;
454}
455
robertphillips@google.comb7457d02013-05-22 00:12:43 +0000456SkStream* SkFontConfigInterfaceAndroid::openStream(const FontIdentity& identity) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000457 return SkStream::NewFromFile(identity.fString.c_str());
458}
459
robertphillips@google.comb7457d02013-05-22 00:12:43 +0000460SkDataTable* SkFontConfigInterfaceAndroid::getFamilyNames() {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000461 SkTDArray<const char*> names;
462 SkTDArray<size_t> sizes;
463
464 SkTDict<FamilyRecID>::Iter iter(fFamilyNameDict);
465 const char* familyName = iter.next(NULL);
466 while(familyName != NULL) {
467 *names.append() = familyName;
468 *sizes.append() = strlen(familyName) + 1;
469
470 // move to the next familyName in the dictionary
471 familyName = iter.next(NULL);
472 }
473
474 return SkDataTable::NewCopyArrays((const void*const*)names.begin(),
475 sizes.begin(), names.count());
476}
477
478bool SkFontConfigInterfaceAndroid::matchFamilySet(const char inFamilyName[],
479 SkString* outFamilyName,
robertphillips@google.comb7457d02013-05-22 00:12:43 +0000480 SkTArray<FontIdentity>*) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000481 return false;
482}
483
djsollen@google.com40078cb2013-05-24 20:31:57 +0000484static bool find_proc(SkTypeface* face, SkTypeface::Style style, void* ctx) {
485 const FontRecID* fontRecID = (const FontRecID*)ctx;
486 FontRecID currFontRecID = ((FontConfigTypeface*)face)->getIdentity().fID;
487 return currFontRecID == *fontRecID;
488}
489
490SkTypeface* SkFontConfigInterfaceAndroid::getTypefaceForFontRec(FontRecID fontRecID) {
491 FontRec& fontRec = fFonts[fontRecID];
djsollen@google.combfae9d32013-05-21 16:53:50 +0000492 SkTypeface* face = fontRec.fTypeface.get();
493 if (!face) {
djsollen@google.com40078cb2013-05-24 20:31:57 +0000494 // look for it in the typeface cache
495 face = SkTypefaceCache::FindByProcAndRef(find_proc, &fontRecID);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000496
497 // if it is not in the cache then create it
djsollen@google.com40078cb2013-05-24 20:31:57 +0000498 if (!face) {
499 const char* familyName = NULL;
500 SkAssertResult(fFamilyNameDict.findKey(fontRec.fFamilyRecID, &familyName));
501 SkASSERT(familyName);
502 face = SkTypeface::CreateFromName(familyName, fontRec.fStyle);
503 }
djsollen@google.combfae9d32013-05-21 16:53:50 +0000504
505 // store the result for subsequent lookups
bungeman733418f2014-07-17 12:17:55 -0700506 fontRec.fTypeface.reset(face);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000507 }
508 SkASSERT(face);
509 return face;
510}
511
djsollen@google.com9902c382013-09-19 18:22:30 +0000512bool SkFontConfigInterfaceAndroid::getFallbackFamilyNameForChar(SkUnichar uni,
513 const char* lang,
514 SkString* name) {
commit-bot@chromium.orgc0445fe2013-10-07 19:49:13 +0000515 FallbackFontList* fallbackFontList = NULL;
516 const SkString langTag(lang);
517 if (langTag.isEmpty()) {
518 fallbackFontList = this->getCurrentLocaleFallbackFontList();
519 } else {
520 fallbackFontList = this->findFallbackFontList(langTag);
521 }
522
djsollen@google.com9a70f342013-06-25 18:07:45 +0000523 for (int i = 0; i < fallbackFontList->count(); i++) {
djsollen@google.comb27eba72013-09-06 12:59:50 +0000524 FamilyRecID familyRecID = fallbackFontList->getAt(i);
djsollen@google.com9902c382013-09-19 18:22:30 +0000525
526 // if it is not one of the accepted variants then move to the next family
527 int32_t acceptedVariants = SkPaintOptionsAndroid::kDefault_Variant |
528 SkPaintOptionsAndroid::kElegant_Variant;
529 if (!(fFontFamilies[familyRecID].fPaintOptions.getFontVariant() & acceptedVariants)) {
530 continue;
531 }
532
djsollen@google.comb27eba72013-09-06 12:59:50 +0000533 FontRecID fontRecID = find_best_style(fFontFamilies[familyRecID], SkTypeface::kNormal);
djsollen@google.com40078cb2013-05-24 20:31:57 +0000534 SkTypeface* face = this->getTypefaceForFontRec(fontRecID);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000535
536 SkPaint paint;
537 paint.setTypeface(face);
538 paint.setTextEncoding(SkPaint::kUTF32_TextEncoding);
539
540 uint16_t glyphID;
541 paint.textToGlyphs(&uni, sizeof(uni), &glyphID);
542 if (glyphID != 0) {
djsollen@google.com39a7c702013-09-24 20:08:47 +0000543 name->set(fFontFamilies[familyRecID].fFallbackName);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000544 return true;
545 }
546 }
547 return false;
548}
549
550SkTypeface* SkFontConfigInterfaceAndroid::getTypefaceForChar(SkUnichar uni,
551 SkTypeface::Style style,
552 SkPaintOptionsAndroid::FontVariant fontVariant) {
553 FontRecID fontRecID = find_best_style(fFontFamilies[fDefaultFamilyRecID], style);
djsollen@google.com40078cb2013-05-24 20:31:57 +0000554 SkTypeface* face = this->getTypefaceForFontRec(fontRecID);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000555
556 SkPaintOptionsAndroid paintOptions;
557 paintOptions.setFontVariant(fontVariant);
558 paintOptions.setUseFontFallbacks(true);
559
560 SkPaint paint;
561 paint.setTypeface(face);
562 paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
563 paint.setPaintOptionsAndroid(paintOptions);
564
565 SkAutoGlyphCache autoCache(paint, NULL, NULL);
566 SkGlyphCache* cache = autoCache.getCache();
567
568 SkScalerContext* ctx = cache->getScalerContext();
569 if (ctx) {
570 SkFontID fontID = ctx->findTypefaceIdForChar(uni);
571 return SkTypefaceCache::FindByID(fontID);
572 }
573 return NULL;
574}
575
djsollen@google.com9a70f342013-06-25 18:07:45 +0000576FallbackFontList* SkFontConfigInterfaceAndroid::getCurrentLocaleFallbackFontList() {
577 SkString locale = SkFontConfigParser::GetLocale();
578 if (NULL == fLocaleFallbackFontList || locale != fCachedLocale) {
579 fCachedLocale = locale;
580 fLocaleFallbackFontList = this->findFallbackFontList(locale);
581 }
582 return fLocaleFallbackFontList;
583}
584
djsollen@google.com40078cb2013-05-24 20:31:57 +0000585FallbackFontList* SkFontConfigInterfaceAndroid::findFallbackFontList(const SkLanguage& lang,
586 bool isOriginal) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000587 const SkString& langTag = lang.getTag();
588 if (langTag.isEmpty()) {
589 return &fDefaultFallbackList;
590 }
591
592 FallbackFontList* fallbackFontList;
djsollen@google.com40078cb2013-05-24 20:31:57 +0000593 if (fFallbackFontDict.find(langTag.c_str(), langTag.size(), &fallbackFontList) ||
594 fFallbackFontAliasDict.find(langTag.c_str(), langTag.size(), &fallbackFontList)) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000595 return fallbackFontList;
596 }
597
598 // attempt a recursive fuzzy match
djsollen@google.combfae9d32013-05-21 16:53:50 +0000599 SkLanguage parent = lang.getParent();
djsollen@google.com40078cb2013-05-24 20:31:57 +0000600 fallbackFontList = findFallbackFontList(parent, false);
601
602 // cache the original lang so we don't have to do the recursion again.
603 if (isOriginal) {
604 DEBUG_FONT(("---- Created fallback list alias for \"%s\"", langTag.c_str()));
605 fFallbackFontAliasDict.set(langTag.c_str(), fallbackFontList);
606 }
607 return fallbackFontList;
djsollen@google.combfae9d32013-05-21 16:53:50 +0000608}
609
610SkTypeface* SkFontConfigInterfaceAndroid::nextLogicalTypeface(SkFontID currFontID,
611 SkFontID origFontID,
612 const SkPaintOptionsAndroid& opts) {
613 // Skia does not support font fallback by default. This enables clients such
614 // as WebKit to customize their font selection. In any case, clients can use
615 // GetFallbackFamilyNameForChar() to get the fallback font for individual
616 // characters.
617 if (!opts.isUsingFontFallbacks()) {
618 return NULL;
619 }
620
djsollen@google.combfae9d32013-05-21 16:53:50 +0000621 FallbackFontList* currentFallbackList = findFallbackFontList(opts.getLanguage());
622 SkASSERT(currentFallbackList);
623
djsollen@google.comb27eba72013-09-06 12:59:50 +0000624 SkTypeface::Style origStyle = SkTypeface::kNormal;
625 const SkTypeface* origTypeface = SkTypefaceCache::FindByID(origFontID);
626 if (NULL != origTypeface) {
627 origStyle = origTypeface->style();
628 }
629
djsollen@google.combfae9d32013-05-21 16:53:50 +0000630 // we must convert currTypeface into a FontRecID
djsollen@google.come47e7d12013-06-06 21:25:09 +0000631 FontRecID currFontRecID = INVALID_FONT_REC_ID;
632 const SkTypeface* currTypeface = SkTypefaceCache::FindByID(currFontID);
633 // non-system fonts are not in the font cache so if we are asked to fallback
634 // for a non-system font we will start at the front of the chain.
commit-bot@chromium.org94da31d2014-01-23 17:21:28 +0000635 if (NULL != currTypeface) {
djsollen@google.come47e7d12013-06-06 21:25:09 +0000636 currFontRecID = ((FontConfigTypeface*)currTypeface)->getIdentity().fID;
637 SkASSERT(INVALID_FONT_REC_ID != currFontRecID);
638 }
djsollen@google.combfae9d32013-05-21 16:53:50 +0000639
djsollen@google.comb27eba72013-09-06 12:59:50 +0000640 FamilyRecID currFamilyRecID = INVALID_FAMILY_REC_ID;
641 if (INVALID_FONT_REC_ID != currFontRecID) {
642 currFamilyRecID = fFonts[currFontRecID].fFamilyRecID;
643 }
644
djsollen@google.come47e7d12013-06-06 21:25:09 +0000645 // lookup the index next font in the chain
djsollen@google.comb27eba72013-09-06 12:59:50 +0000646 int currFallbackFontIndex = currentFallbackList->find(currFamilyRecID);
djsollen@google.come47e7d12013-06-06 21:25:09 +0000647 // We add 1 to the returned index for 2 reasons: (1) if find succeeds it moves
648 // our index to the next entry in the list; (2) if find() fails it returns
649 // -1 and incrementing it will set our starting index to 0 (the head of the list)
djsollen@google.combfae9d32013-05-21 16:53:50 +0000650 int nextFallbackFontIndex = currFallbackFontIndex + 1;
djsollen@google.combfae9d32013-05-21 16:53:50 +0000651
djsollen@google.com40078cb2013-05-24 20:31:57 +0000652 if(nextFallbackFontIndex >= currentFallbackList->count()) {
djsollen@google.combfae9d32013-05-21 16:53:50 +0000653 return NULL;
654 }
655
656 // If a rec object is set to prefer "kDefault_Variant" it means they have no preference
657 // In this case, we set the value to "kCompact_Variant"
658 SkPaintOptionsAndroid::FontVariant variant = opts.getFontVariant();
659 if (variant == SkPaintOptionsAndroid::kDefault_Variant) {
660 variant = SkPaintOptionsAndroid::kCompact_Variant;
661 }
662
663 int32_t acceptedVariants = SkPaintOptionsAndroid::kDefault_Variant | variant;
664
665 SkTypeface* nextLogicalTypeface = 0;
666 while (nextFallbackFontIndex < currentFallbackList->count()) {
djsollen@google.comb27eba72013-09-06 12:59:50 +0000667 FamilyRecID familyRecID = currentFallbackList->getAt(nextFallbackFontIndex);
668 if ((fFontFamilies[familyRecID].fPaintOptions.getFontVariant() & acceptedVariants) != 0) {
669 FontRecID matchedFont = find_best_style(fFontFamilies[familyRecID], origStyle);
670 nextLogicalTypeface = this->getTypefaceForFontRec(matchedFont);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000671 break;
672 }
673 nextFallbackFontIndex++;
674 }
675
676 DEBUG_FONT(("---- nextLogicalFont: currFontID=%d, origFontID=%d, currRecID=%d, "
djsollen@google.com40078cb2013-05-24 20:31:57 +0000677 "lang=%s, variant=%d, nextFallbackIndex[%d,%d] => nextLogicalTypeface=%d",
djsollen@google.combfae9d32013-05-21 16:53:50 +0000678 currFontID, origFontID, currFontRecID, opts.getLanguage().getTag().c_str(),
djsollen@google.com40078cb2013-05-24 20:31:57 +0000679 variant, nextFallbackFontIndex, currentFallbackList->getAt(nextFallbackFontIndex),
djsollen@google.combfae9d32013-05-21 16:53:50 +0000680 (nextLogicalTypeface) ? nextLogicalTypeface->uniqueID() : 0));
681 return SkSafeRef(nextLogicalTypeface);
682}
683
djsollen@google.com5df5e612013-10-03 14:42:24 +0000684SkTypeface* SkFontConfigInterfaceAndroid::getTypefaceForGlyphID(uint16_t glyphID,
685 const SkTypeface* origTypeface,
686 const SkPaintOptionsAndroid& opts,
687 int* lBounds, int* uBounds) {
688 // If we aren't using fallbacks then we shouldn't be calling this
689 SkASSERT(opts.isUsingFontFallbacks());
690 SkASSERT(origTypeface);
691
692 SkTypeface* currentTypeface = NULL;
693 int lowerBounds = 0; //inclusive
694 int upperBounds = origTypeface->countGlyphs(); //exclusive
695
696 // check to see if the glyph is in the bounds of the origTypeface
697 if (glyphID < upperBounds) {
698 currentTypeface = const_cast<SkTypeface*>(origTypeface);
699 } else {
700 FallbackFontList* currentFallbackList = findFallbackFontList(opts.getLanguage());
701 SkASSERT(currentFallbackList);
702
703 // If an object is set to prefer "kDefault_Variant" it means they have no preference
704 // In this case, we set the value to "kCompact_Variant"
705 SkPaintOptionsAndroid::FontVariant variant = opts.getFontVariant();
706 if (variant == SkPaintOptionsAndroid::kDefault_Variant) {
707 variant = SkPaintOptionsAndroid::kCompact_Variant;
708 }
709
710 int32_t acceptedVariants = SkPaintOptionsAndroid::kDefault_Variant | variant;
711 SkTypeface::Style origStyle = origTypeface->style();
712
713 for (int x = 0; x < currentFallbackList->count(); ++x) {
714 const FamilyRecID familyRecID = currentFallbackList->getAt(x);
715 const SkPaintOptionsAndroid& familyOptions = fFontFamilies[familyRecID].fPaintOptions;
716 if ((familyOptions.getFontVariant() & acceptedVariants) != 0) {
717 FontRecID matchedFont = find_best_style(fFontFamilies[familyRecID], origStyle);
718 currentTypeface = this->getTypefaceForFontRec(matchedFont);
719 lowerBounds = upperBounds;
720 upperBounds += currentTypeface->countGlyphs();
721 if (glyphID < upperBounds) {
722 break;
723 }
724 }
725 }
726 }
727
728 if (NULL != currentTypeface) {
729 if (lBounds) {
730 *lBounds = lowerBounds;
731 }
732 if (uBounds) {
733 *uBounds = upperBounds;
734 }
735 }
736 return currentTypeface;
737}
738
djsollen@google.combfae9d32013-05-21 16:53:50 +0000739///////////////////////////////////////////////////////////////////////////////
740
741bool SkGetFallbackFamilyNameForChar(SkUnichar uni, SkString* name) {
742 SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
commit-bot@chromium.orgc0445fe2013-10-07 19:49:13 +0000743 return fontConfig->getFallbackFamilyNameForChar(uni, NULL, name);
djsollen@google.com9902c382013-09-19 18:22:30 +0000744}
745
746bool SkGetFallbackFamilyNameForChar(SkUnichar uni, const char* lang, SkString* name) {
747 SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
748 return fontConfig->getFallbackFamilyNameForChar(uni, lang, name);
djsollen@google.combfae9d32013-05-21 16:53:50 +0000749}
750
751void SkUseTestFontConfigFile(const char* mainconf, const char* fallbackconf,
752 const char* fontsdir) {
753 gTestMainConfigFile = mainconf;
754 gTestFallbackConfigFile = fallbackconf;
755 gTestFontFilePrefix = fontsdir;
756 SkASSERT(gTestMainConfigFile);
757 SkASSERT(gTestFallbackConfigFile);
758 SkASSERT(gTestFontFilePrefix);
759 SkDEBUGF(("Use Test Config File Main %s, Fallback %s, Font Dir %s",
760 gTestMainConfigFile, gTestFallbackConfigFile, gTestFontFilePrefix));
761}
762
763SkTypeface* SkAndroidNextLogicalTypeface(SkFontID currFontID, SkFontID origFontID,
764 const SkPaintOptionsAndroid& options) {
765 SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
766 return fontConfig->nextLogicalTypeface(currFontID, origFontID, options);
767
768}
769
djsollen@google.com5df5e612013-10-03 14:42:24 +0000770SkTypeface* SkGetTypefaceForGlyphID(uint16_t glyphID, const SkTypeface* origTypeface,
771 const SkPaintOptionsAndroid& options,
772 int* lowerBounds, int* upperBounds) {
773 SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
774 return fontConfig->getTypefaceForGlyphID(glyphID, origTypeface, options,
775 lowerBounds, upperBounds);
776}
777
djsollen@google.combfae9d32013-05-21 16:53:50 +0000778///////////////////////////////////////////////////////////////////////////////
779
djsollen@google.com40078cb2013-05-24 20:31:57 +0000780#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
781
782struct HB_UnicodeMapping {
djsollen@google.com40078cb2013-05-24 20:31:57 +0000783 hb_script_t script;
784 const SkUnichar unicode;
785};
786
787/*
788 * The following scripts are not complex fonts and we do not expect them to be parsed by this table
789 * HB_SCRIPT_COMMON,
790 * HB_SCRIPT_GREEK,
791 * HB_SCRIPT_CYRILLIC,
792 * HB_SCRIPT_HANGUL
793 * HB_SCRIPT_INHERITED
794 */
795
796/* Harfbuzz (old) is missing a number of scripts in its table. For these,
797 * we include a value which can never happen. We won't get complex script
798 * shaping in these cases, but the library wouldn't know how to shape
799 * them anyway. */
800#define HB_Script_Unknown HB_ScriptCount
801
802static HB_UnicodeMapping HB_UnicodeMappingArray[] = {
commit-bot@chromium.org98000ef2013-12-18 19:49:27 +0000803 {HB_SCRIPT_ARMENIAN, 0x0531},
804 {HB_SCRIPT_HEBREW, 0x0591},
805 {HB_SCRIPT_ARABIC, 0x0600},
806 {HB_SCRIPT_SYRIAC, 0x0710},
807 {HB_SCRIPT_THAANA, 0x0780},
808 {HB_SCRIPT_NKO, 0x07C0},
809 {HB_SCRIPT_DEVANAGARI, 0x0901},
810 {HB_SCRIPT_BENGALI, 0x0981},
811 {HB_SCRIPT_GURMUKHI, 0x0A10},
812 {HB_SCRIPT_GUJARATI, 0x0A90},
813 {HB_SCRIPT_ORIYA, 0x0B10},
814 {HB_SCRIPT_TAMIL, 0x0B82},
815 {HB_SCRIPT_TELUGU, 0x0C10},
816 {HB_SCRIPT_KANNADA, 0x0C90},
817 {HB_SCRIPT_MALAYALAM, 0x0D10},
818 {HB_SCRIPT_SINHALA, 0x0D90},
819 {HB_SCRIPT_THAI, 0x0E01},
820 {HB_SCRIPT_LAO, 0x0E81},
821 {HB_SCRIPT_TIBETAN, 0x0F00},
822 {HB_SCRIPT_MYANMAR, 0x1000},
823 {HB_SCRIPT_GEORGIAN, 0x10A0},
824 {HB_SCRIPT_ETHIOPIC, 0x1200},
825 {HB_SCRIPT_CHEROKEE, 0x13A0},
826 {HB_SCRIPT_OGHAM, 0x1680},
827 {HB_SCRIPT_RUNIC, 0x16A0},
828 {HB_SCRIPT_KHMER, 0x1780},
829 {HB_SCRIPT_TAI_LE, 0x1950},
830 {HB_SCRIPT_NEW_TAI_LUE, 0x1980},
831 {HB_SCRIPT_TAI_THAM, 0x1A20},
832 {HB_SCRIPT_CHAM, 0xAA00},
djsollen@google.com40078cb2013-05-24 20:31:57 +0000833};
834
djsollen@google.com40078cb2013-05-24 20:31:57 +0000835// returns 0 for "Not Found"
836static SkUnichar getUnicodeFromHBScript(hb_script_t script) {
837 SkUnichar unichar = 0;
838 int numSupportedFonts = sizeof(HB_UnicodeMappingArray) / sizeof(HB_UnicodeMapping);
839 for (int i = 0; i < numSupportedFonts; i++) {
840 if (script == HB_UnicodeMappingArray[i].script) {
841 unichar = HB_UnicodeMappingArray[i].unicode;
842 break;
843 }
844 }
845 return unichar;
846}
847
848struct TypefaceLookupStruct {
849 hb_script_t script;
850 SkTypeface::Style style;
851 SkPaintOptionsAndroid::FontVariant fontVariant;
852 SkTypeface* typeface;
853};
854
855SK_DECLARE_STATIC_MUTEX(gTypefaceTableMutex); // This is the mutex for gTypefaceTable
856static SkTDArray<TypefaceLookupStruct> gTypefaceTable; // This is protected by gTypefaceTableMutex
857
858static int typefaceLookupCompare(const TypefaceLookupStruct& first,
859 const TypefaceLookupStruct& second) {
860 if (first.script != second.script) {
861 return (first.script > second.script) ? 1 : -1;
862 }
863 if (first.style != second.style) {
864 return (first.style > second.style) ? 1 : -1;
865 }
866 if (first.fontVariant != second.fontVariant) {
867 return (first.fontVariant > second.fontVariant) ? 1 : -1;
868 }
869 return 0;
870}
871
commit-bot@chromium.org98000ef2013-12-18 19:49:27 +0000872SkTypeface* SkCreateTypefaceForScript(hb_script_t script, SkTypeface::Style style,
873 SkPaintOptionsAndroid::FontVariant fontVariant) {
djsollen@google.com40078cb2013-05-24 20:31:57 +0000874 SkAutoMutexAcquire ac(gTypefaceTableMutex);
875
876 TypefaceLookupStruct key;
877 key.script = script;
878 key.style = style;
879 key.fontVariant = fontVariant;
880
881 int index = SkTSearch<TypefaceLookupStruct>(
882 (const TypefaceLookupStruct*) gTypefaceTable.begin(),
883 gTypefaceTable.count(), key, sizeof(TypefaceLookupStruct),
884 typefaceLookupCompare);
885
886 SkTypeface* retTypeface = NULL;
887 if (index >= 0) {
888 retTypeface = gTypefaceTable[index].typeface;
889 }
890 else {
891 SkUnichar unichar = getUnicodeFromHBScript(script);
892 if (!unichar) {
893 return NULL;
894 }
895
896 SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
897 retTypeface = fontConfig->getTypefaceForChar(unichar, style, fontVariant);
898
899 // add to the lookup table
900 key.typeface = retTypeface;
901 *gTypefaceTable.insert(~index) = key;
902 }
903
904 // we ref(), the caller is expected to unref when they are done
905 return SkSafeRef(retTypeface);
906}
907
djsollen@google.com40078cb2013-05-24 20:31:57 +0000908#endif
909