gfx/skia/trunk/src/ports/SkFontConfigInterface_android.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1
michael@0 2 /*
michael@0 3 * Copyright 2013 The Android Open Source Project
michael@0 4 *
michael@0 5 * Use of this source code is governed by a BSD-style license that can be
michael@0 6 * found in the LICENSE file.
michael@0 7 */
michael@0 8
michael@0 9 #include "SkFontConfigInterface.h"
michael@0 10 #include "SkTypeface_android.h"
michael@0 11
michael@0 12 #include "SkFontConfigParser_android.h"
michael@0 13 #include "SkFontConfigTypeface.h"
michael@0 14 #include "SkFontMgr.h"
michael@0 15 #include "SkGlyphCache.h"
michael@0 16 #include "SkPaint.h"
michael@0 17 #include "SkString.h"
michael@0 18 #include "SkStream.h"
michael@0 19 #include "SkThread.h"
michael@0 20 #include "SkTypefaceCache.h"
michael@0 21 #include "SkTArray.h"
michael@0 22 #include "SkTDict.h"
michael@0 23 #include "SkTSearch.h"
michael@0 24
michael@0 25 #include <stdio.h>
michael@0 26 #include <string.h>
michael@0 27
michael@0 28 #ifndef SK_DEBUG_FONTS
michael@0 29 #define SK_DEBUG_FONTS 0
michael@0 30 #endif
michael@0 31
michael@0 32 #if SK_DEBUG_FONTS
michael@0 33 #define DEBUG_FONT(args) SkDebugf args
michael@0 34 #else
michael@0 35 #define DEBUG_FONT(args)
michael@0 36 #endif
michael@0 37
michael@0 38 ///////////////////////////////////////////////////////////////////////////////
michael@0 39
michael@0 40 // For test only.
michael@0 41 static const char* gTestMainConfigFile = NULL;
michael@0 42 static const char* gTestFallbackConfigFile = NULL;
michael@0 43 static const char* gTestFontFilePrefix = NULL;
michael@0 44
michael@0 45 ///////////////////////////////////////////////////////////////////////////////
michael@0 46
michael@0 47 typedef int32_t FontRecID;
michael@0 48 #define INVALID_FONT_REC_ID -1
michael@0 49
michael@0 50 typedef int32_t FamilyRecID;
michael@0 51 #define INVALID_FAMILY_REC_ID -1
michael@0 52
michael@0 53 // used to record our notion of the pre-existing fonts
michael@0 54 struct FontRec {
michael@0 55 SkRefPtr<SkTypeface> fTypeface;
michael@0 56 SkString fFileName;
michael@0 57 SkTypeface::Style fStyle;
michael@0 58 bool fIsValid;
michael@0 59 FamilyRecID fFamilyRecID;
michael@0 60 };
michael@0 61
michael@0 62 struct FamilyRec {
michael@0 63 FamilyRec() {
michael@0 64 memset(fFontRecID, INVALID_FONT_REC_ID, sizeof(fFontRecID));
michael@0 65 }
michael@0 66
michael@0 67 static const int FONT_STYLE_COUNT = 4;
michael@0 68 FontRecID fFontRecID[FONT_STYLE_COUNT];
michael@0 69 bool fIsFallbackFont;
michael@0 70 SkString fFallbackName;
michael@0 71 SkPaintOptionsAndroid fPaintOptions;
michael@0 72 };
michael@0 73
michael@0 74
michael@0 75 typedef SkTDArray<FamilyRecID> FallbackFontList;
michael@0 76
michael@0 77 class SkFontConfigInterfaceAndroid : public SkFontConfigInterface {
michael@0 78 public:
michael@0 79 SkFontConfigInterfaceAndroid(SkTDArray<FontFamily*>& fontFamilies);
michael@0 80 virtual ~SkFontConfigInterfaceAndroid();
michael@0 81
michael@0 82 virtual bool matchFamilyName(const char familyName[],
michael@0 83 SkTypeface::Style requested,
michael@0 84 FontIdentity* outFontIdentifier,
michael@0 85 SkString* outFamilyName,
michael@0 86 SkTypeface::Style* outStyle) SK_OVERRIDE;
michael@0 87 virtual SkStream* openStream(const FontIdentity&) SK_OVERRIDE;
michael@0 88
michael@0 89 // new APIs
michael@0 90 virtual SkDataTable* getFamilyNames() SK_OVERRIDE;
michael@0 91 virtual bool matchFamilySet(const char inFamilyName[],
michael@0 92 SkString* outFamilyName,
michael@0 93 SkTArray<FontIdentity>*) SK_OVERRIDE;
michael@0 94
michael@0 95 /**
michael@0 96 * Get the family name of the font in the default fallback font list that
michael@0 97 * contains the specified chararacter. if no font is found, returns false.
michael@0 98 */
michael@0 99 bool getFallbackFamilyNameForChar(SkUnichar uni, const char* lang, SkString* name);
michael@0 100 /**
michael@0 101 *
michael@0 102 */
michael@0 103 SkTypeface* getTypefaceForChar(SkUnichar uni, SkTypeface::Style style,
michael@0 104 SkPaintOptionsAndroid::FontVariant fontVariant);
michael@0 105 SkTypeface* nextLogicalTypeface(SkFontID currFontID, SkFontID origFontID,
michael@0 106 const SkPaintOptionsAndroid& options);
michael@0 107 SkTypeface* getTypefaceForGlyphID(uint16_t glyphID, const SkTypeface* origTypeface,
michael@0 108 const SkPaintOptionsAndroid& options,
michael@0 109 int* lowerBounds, int* upperBounds);
michael@0 110
michael@0 111 private:
michael@0 112 void addFallbackFamily(FamilyRecID fontRecID);
michael@0 113 SkTypeface* getTypefaceForFontRec(FontRecID fontRecID);
michael@0 114 FallbackFontList* getCurrentLocaleFallbackFontList();
michael@0 115 FallbackFontList* findFallbackFontList(const SkLanguage& lang, bool isOriginal = true);
michael@0 116
michael@0 117 SkTArray<FontRec> fFonts;
michael@0 118 SkTArray<FamilyRec> fFontFamilies;
michael@0 119 SkTDict<FamilyRecID> fFamilyNameDict;
michael@0 120 FamilyRecID fDefaultFamilyRecID;
michael@0 121
michael@0 122 // (SkLanguage)<->(fallback chain index) translation
michael@0 123 SkTDict<FallbackFontList*> fFallbackFontDict;
michael@0 124 SkTDict<FallbackFontList*> fFallbackFontAliasDict;
michael@0 125 FallbackFontList fDefaultFallbackList;
michael@0 126
michael@0 127 // fallback info for current locale
michael@0 128 SkString fCachedLocale;
michael@0 129 FallbackFontList* fLocaleFallbackFontList;
michael@0 130 };
michael@0 131
michael@0 132 ///////////////////////////////////////////////////////////////////////////////
michael@0 133
michael@0 134 static SkFontConfigInterfaceAndroid* getSingletonInterface() {
michael@0 135 SK_DECLARE_STATIC_MUTEX(gMutex);
michael@0 136 static SkFontConfigInterfaceAndroid* gFontConfigInterface;
michael@0 137
michael@0 138 SkAutoMutexAcquire ac(gMutex);
michael@0 139 if (NULL == gFontConfigInterface) {
michael@0 140 // load info from a configuration file that we can use to populate the
michael@0 141 // system/fallback font structures
michael@0 142 SkTDArray<FontFamily*> fontFamilies;
michael@0 143 if (!gTestMainConfigFile) {
michael@0 144 SkFontConfigParser::GetFontFamilies(fontFamilies);
michael@0 145 } else {
michael@0 146 SkFontConfigParser::GetTestFontFamilies(fontFamilies, gTestMainConfigFile,
michael@0 147 gTestFallbackConfigFile);
michael@0 148 }
michael@0 149
michael@0 150 gFontConfigInterface = new SkFontConfigInterfaceAndroid(fontFamilies);
michael@0 151
michael@0 152 // cleanup the data we received from the parser
michael@0 153 fontFamilies.deleteAll();
michael@0 154 }
michael@0 155 return gFontConfigInterface;
michael@0 156 }
michael@0 157
michael@0 158 SkFontConfigInterface* SkFontConfigInterface::GetSingletonDirectInterface() {
michael@0 159 return getSingletonInterface();
michael@0 160 }
michael@0 161
michael@0 162 ///////////////////////////////////////////////////////////////////////////////
michael@0 163
michael@0 164 static bool has_font(const SkTArray<FontRec>& array, const SkString& filename) {
michael@0 165 for (int i = 0; i < array.count(); i++) {
michael@0 166 if (array[i].fFileName == filename) {
michael@0 167 return true;
michael@0 168 }
michael@0 169 }
michael@0 170 return false;
michael@0 171 }
michael@0 172
michael@0 173 #ifndef SK_FONT_FILE_PREFIX
michael@0 174 #define SK_FONT_FILE_PREFIX "/fonts/"
michael@0 175 #endif
michael@0 176
michael@0 177 static void get_path_for_sys_fonts(SkString* full, const char name[]) {
michael@0 178 if (gTestFontFilePrefix) {
michael@0 179 full->set(gTestFontFilePrefix);
michael@0 180 } else {
michael@0 181 full->set(getenv("ANDROID_ROOT"));
michael@0 182 full->append(SK_FONT_FILE_PREFIX);
michael@0 183 }
michael@0 184 full->append(name);
michael@0 185 }
michael@0 186
michael@0 187 static void insert_into_name_dict(SkTDict<FamilyRecID>& familyNameDict,
michael@0 188 const char* name, FamilyRecID familyRecID) {
michael@0 189 SkAutoAsciiToLC tolc(name);
michael@0 190 if (familyNameDict.find(tolc.lc())) {
michael@0 191 SkDebugf("---- system font attempting to use a the same name [%s] for"
michael@0 192 "multiple families. skipping subsequent occurrences", tolc.lc());
michael@0 193 } else {
michael@0 194 familyNameDict.set(tolc.lc(), familyRecID);
michael@0 195 }
michael@0 196 }
michael@0 197
michael@0 198 // Defined in SkFontHost_FreeType.cpp
michael@0 199 bool find_name_and_attributes(SkStream* stream, SkString* name,
michael@0 200 SkTypeface::Style* style, bool* isFixedWidth);
michael@0 201
michael@0 202 ///////////////////////////////////////////////////////////////////////////////
michael@0 203
michael@0 204 SkFontConfigInterfaceAndroid::SkFontConfigInterfaceAndroid(SkTDArray<FontFamily*>& fontFamilies) :
michael@0 205 fFonts(fontFamilies.count()),
michael@0 206 fFontFamilies(fontFamilies.count() / FamilyRec::FONT_STYLE_COUNT),
michael@0 207 fFamilyNameDict(1024),
michael@0 208 fDefaultFamilyRecID(INVALID_FAMILY_REC_ID),
michael@0 209 fFallbackFontDict(128),
michael@0 210 fFallbackFontAliasDict(128),
michael@0 211 fLocaleFallbackFontList(NULL) {
michael@0 212
michael@0 213 for (int i = 0; i < fontFamilies.count(); ++i) {
michael@0 214 FontFamily* family = fontFamilies[i];
michael@0 215
michael@0 216 // defer initializing the familyRec until we can be sure that at least
michael@0 217 // one of it's children contains a valid font file
michael@0 218 FamilyRec* familyRec = NULL;
michael@0 219 FamilyRecID familyRecID = INVALID_FAMILY_REC_ID;
michael@0 220
michael@0 221 for (int j = 0; j < family->fFontFiles.count(); ++j) {
michael@0 222 SkString filename;
michael@0 223 get_path_for_sys_fonts(&filename, family->fFontFiles[j]->fFileName);
michael@0 224
michael@0 225 if (has_font(fFonts, filename)) {
michael@0 226 SkDebugf("---- system font and fallback font files specify a duplicate "
michael@0 227 "font %s, skipping the second occurrence", filename.c_str());
michael@0 228 continue;
michael@0 229 }
michael@0 230
michael@0 231 FontRec& fontRec = fFonts.push_back();
michael@0 232 fontRec.fFileName = filename;
michael@0 233 fontRec.fStyle = SkTypeface::kNormal;
michael@0 234 fontRec.fIsValid = false;
michael@0 235 fontRec.fFamilyRecID = familyRecID;
michael@0 236
michael@0 237 const FontRecID fontRecID = fFonts.count() - 1;
michael@0 238
michael@0 239 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(filename.c_str()));
michael@0 240 if (stream.get() != NULL) {
michael@0 241 bool isFixedWidth;
michael@0 242 SkString name;
michael@0 243 fontRec.fIsValid = find_name_and_attributes(stream.get(), &name,
michael@0 244 &fontRec.fStyle, &isFixedWidth);
michael@0 245 } else {
michael@0 246 if (!family->fIsFallbackFont) {
michael@0 247 SkDebugf("---- failed to open <%s> as a font\n", filename.c_str());
michael@0 248 }
michael@0 249 }
michael@0 250
michael@0 251 if (fontRec.fIsValid) {
michael@0 252 DEBUG_FONT(("---- SystemFonts[%d][%d] fallback=%d file=%s",
michael@0 253 i, fFonts.count() - 1, family->fIsFallbackFont, filename.c_str()));
michael@0 254 } else {
michael@0 255 DEBUG_FONT(("---- SystemFonts[%d][%d] fallback=%d file=%s (INVALID)",
michael@0 256 i, fFonts.count() - 1, family->fIsFallbackFont, filename.c_str()));
michael@0 257 continue;
michael@0 258 }
michael@0 259
michael@0 260 // create a familyRec now that we know that at least one font in
michael@0 261 // the family is valid
michael@0 262 if (familyRec == NULL) {
michael@0 263 familyRec = &fFontFamilies.push_back();
michael@0 264 familyRecID = fFontFamilies.count() - 1;
michael@0 265 fontRec.fFamilyRecID = familyRecID;
michael@0 266
michael@0 267 familyRec->fIsFallbackFont = family->fIsFallbackFont;
michael@0 268 familyRec->fPaintOptions = family->fFontFiles[j]->fPaintOptions;
michael@0 269
michael@0 270 } else if (familyRec->fPaintOptions != family->fFontFiles[j]->fPaintOptions) {
michael@0 271 SkDebugf("Every font file within a family must have identical"
michael@0 272 "language and variant attributes");
michael@0 273 sk_throw();
michael@0 274 }
michael@0 275
michael@0 276 // add this font to the current familyRec
michael@0 277 if (INVALID_FONT_REC_ID != familyRec->fFontRecID[fontRec.fStyle]) {
michael@0 278 DEBUG_FONT(("Overwriting familyRec for style[%d] old,new:(%d,%d)",
michael@0 279 fontRec.fStyle, familyRec->fFontRecID[fontRec.fStyle],
michael@0 280 fontRecID));
michael@0 281 }
michael@0 282 familyRec->fFontRecID[fontRec.fStyle] = fontRecID;
michael@0 283 }
michael@0 284
michael@0 285 if (familyRec) {
michael@0 286 if (familyRec->fIsFallbackFont) {
michael@0 287 // add the font to the appropriate fallback chains and also insert a
michael@0 288 // unique name into the familyNameDict for internal usage
michael@0 289 addFallbackFamily(familyRecID);
michael@0 290 } else {
michael@0 291 // add the names that map to this family to the dictionary for easy lookup
michael@0 292 const SkTDArray<const char*>& names = family->fNames;
michael@0 293 if (names.isEmpty()) {
michael@0 294 SkDEBUGFAIL("ERROR: non-fallback font with no name");
michael@0 295 continue;
michael@0 296 }
michael@0 297
michael@0 298 for (int i = 0; i < names.count(); i++) {
michael@0 299 insert_into_name_dict(fFamilyNameDict, names[i], familyRecID);
michael@0 300 }
michael@0 301 }
michael@0 302 }
michael@0 303 }
michael@0 304
michael@0 305 DEBUG_FONT(("---- We have %d system fonts", fFonts.count()));
michael@0 306
michael@0 307 if (fFontFamilies.count() > 0) {
michael@0 308 fDefaultFamilyRecID = 0;
michael@0 309 }
michael@0 310
michael@0 311 // scans the default fallback font chain, adding every entry to every other
michael@0 312 // fallback font chain to which it does not belong. this results in every
michael@0 313 // language-specific fallback font chain having all of its fallback fonts at
michael@0 314 // the front of the chain, and everything else at the end.
michael@0 315 FallbackFontList* fallbackList;
michael@0 316 SkTDict<FallbackFontList*>::Iter iter(fFallbackFontDict);
michael@0 317 const char* fallbackLang = iter.next(&fallbackList);
michael@0 318 while(fallbackLang != NULL) {
michael@0 319 for (int i = 0; i < fDefaultFallbackList.count(); i++) {
michael@0 320 FamilyRecID familyRecID = fDefaultFallbackList[i];
michael@0 321 const SkString& fontLang = fFontFamilies[familyRecID].fPaintOptions.getLanguage().getTag();
michael@0 322 if (strcmp(fallbackLang, fontLang.c_str()) != 0) {
michael@0 323 fallbackList->push(familyRecID);
michael@0 324 }
michael@0 325 }
michael@0 326 // move to the next fallback list in the dictionary
michael@0 327 fallbackLang = iter.next(&fallbackList);
michael@0 328 }
michael@0 329 }
michael@0 330
michael@0 331 SkFontConfigInterfaceAndroid::~SkFontConfigInterfaceAndroid() {
michael@0 332 // iterate through and cleanup fFallbackFontDict
michael@0 333 SkTDict<FallbackFontList*>::Iter iter(fFallbackFontDict);
michael@0 334 FallbackFontList* fallbackList;
michael@0 335 while(iter.next(&fallbackList) != NULL) {
michael@0 336 SkDELETE(fallbackList);
michael@0 337 }
michael@0 338 }
michael@0 339
michael@0 340 void SkFontConfigInterfaceAndroid::addFallbackFamily(FamilyRecID familyRecID) {
michael@0 341 SkASSERT(familyRecID < fFontFamilies.count());
michael@0 342 FamilyRec& familyRec = fFontFamilies[familyRecID];
michael@0 343 SkASSERT(familyRec.fIsFallbackFont);
michael@0 344
michael@0 345 // add the fallback family to the name dictionary. This is
michael@0 346 // needed by getFallbackFamilyNameForChar() so that fallback
michael@0 347 // families can be identified by a unique name. The unique
michael@0 348 // identifier that we've chosen is the familyID in hex (e.g. '0F##fallback').
michael@0 349 familyRec.fFallbackName.printf("%.2x##fallback", familyRecID);
michael@0 350 insert_into_name_dict(fFamilyNameDict, familyRec.fFallbackName.c_str(), familyRecID);
michael@0 351
michael@0 352 // add to the default fallback list
michael@0 353 fDefaultFallbackList.push(familyRecID);
michael@0 354
michael@0 355 // stop here if it is the default language tag
michael@0 356 const SkString& languageTag = familyRec.fPaintOptions.getLanguage().getTag();
michael@0 357 if (languageTag.isEmpty()) {
michael@0 358 return;
michael@0 359 }
michael@0 360
michael@0 361 // add to the appropriate language's custom fallback list
michael@0 362 FallbackFontList* customList = NULL;
michael@0 363 if (!fFallbackFontDict.find(languageTag.c_str(), &customList)) {
michael@0 364 DEBUG_FONT(("---- Created fallback list for \"%s\"", languageTag.c_str()));
michael@0 365 customList = SkNEW(FallbackFontList);
michael@0 366 fFallbackFontDict.set(languageTag.c_str(), customList);
michael@0 367 }
michael@0 368 SkASSERT(customList != NULL);
michael@0 369 customList->push(familyRecID);
michael@0 370 }
michael@0 371
michael@0 372
michael@0 373 static FontRecID find_best_style(const FamilyRec& family, SkTypeface::Style style) {
michael@0 374
michael@0 375 const FontRecID* fontRecIDs = family.fFontRecID;
michael@0 376
michael@0 377 if (fontRecIDs[style] != INVALID_FONT_REC_ID) { // exact match
michael@0 378 return fontRecIDs[style];
michael@0 379 }
michael@0 380 // look for a matching bold
michael@0 381 style = (SkTypeface::Style)(style ^ SkTypeface::kItalic);
michael@0 382 if (fontRecIDs[style] != INVALID_FONT_REC_ID) {
michael@0 383 return fontRecIDs[style];
michael@0 384 }
michael@0 385 // look for the plain
michael@0 386 if (fontRecIDs[SkTypeface::kNormal] != INVALID_FONT_REC_ID) {
michael@0 387 return fontRecIDs[SkTypeface::kNormal];
michael@0 388 }
michael@0 389 // look for anything
michael@0 390 for (int i = 0; i < FamilyRec::FONT_STYLE_COUNT; i++) {
michael@0 391 if (fontRecIDs[i] != INVALID_FONT_REC_ID) {
michael@0 392 return fontRecIDs[i];
michael@0 393 }
michael@0 394 }
michael@0 395 // should never get here, since the fontRecID list should not be empty
michael@0 396 SkDEBUGFAIL("No valid fonts exist for this family");
michael@0 397 return -1;
michael@0 398 }
michael@0 399
michael@0 400 bool SkFontConfigInterfaceAndroid::matchFamilyName(const char familyName[],
michael@0 401 SkTypeface::Style style,
michael@0 402 FontIdentity* outFontIdentifier,
michael@0 403 SkString* outFamilyName,
michael@0 404 SkTypeface::Style* outStyle) {
michael@0 405 // clip to legal style bits
michael@0 406 style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
michael@0 407
michael@0 408 bool exactNameMatch = false;
michael@0 409
michael@0 410 FamilyRecID familyRecID = INVALID_FAMILY_REC_ID;
michael@0 411 if (NULL != familyName) {
michael@0 412 SkAutoAsciiToLC tolc(familyName);
michael@0 413 if (fFamilyNameDict.find(tolc.lc(), &familyRecID)) {
michael@0 414 exactNameMatch = true;
michael@0 415 }
michael@0 416 } else {
michael@0 417 familyRecID = fDefaultFamilyRecID;
michael@0 418
michael@0 419 }
michael@0 420
michael@0 421 // If no matching family name is found then return false. This allows clients
michael@0 422 // to be able to search for other fonts instead of forcing them to use the
michael@0 423 // default font.
michael@0 424 if (INVALID_FAMILY_REC_ID == familyRecID) {
michael@0 425 return false;
michael@0 426 }
michael@0 427
michael@0 428 FontRecID fontRecID = find_best_style(fFontFamilies[familyRecID], style);
michael@0 429 FontRec& fontRec = fFonts[fontRecID];
michael@0 430
michael@0 431 if (NULL != outFontIdentifier) {
michael@0 432 outFontIdentifier->fID = fontRecID;
michael@0 433 outFontIdentifier->fTTCIndex = 0;
michael@0 434 outFontIdentifier->fString.set(fontRec.fFileName);
michael@0 435 // outFontIdentifier->fStyle = fontRec.fStyle;
michael@0 436 }
michael@0 437
michael@0 438 if (NULL != outFamilyName) {
michael@0 439 if (exactNameMatch) {
michael@0 440 outFamilyName->set(familyName);
michael@0 441 } else {
michael@0 442 // find familyName from list of names
michael@0 443 const char* familyName = NULL;
michael@0 444 SkAssertResult(fFamilyNameDict.findKey(familyRecID, &familyName));
michael@0 445 SkASSERT(familyName);
michael@0 446 outFamilyName->set(familyName);
michael@0 447 }
michael@0 448 }
michael@0 449
michael@0 450 if (NULL != outStyle) {
michael@0 451 *outStyle = fontRec.fStyle;
michael@0 452 }
michael@0 453
michael@0 454 return true;
michael@0 455 }
michael@0 456
michael@0 457 SkStream* SkFontConfigInterfaceAndroid::openStream(const FontIdentity& identity) {
michael@0 458 return SkStream::NewFromFile(identity.fString.c_str());
michael@0 459 }
michael@0 460
michael@0 461 SkDataTable* SkFontConfigInterfaceAndroid::getFamilyNames() {
michael@0 462 SkTDArray<const char*> names;
michael@0 463 SkTDArray<size_t> sizes;
michael@0 464
michael@0 465 SkTDict<FamilyRecID>::Iter iter(fFamilyNameDict);
michael@0 466 const char* familyName = iter.next(NULL);
michael@0 467 while(familyName != NULL) {
michael@0 468 *names.append() = familyName;
michael@0 469 *sizes.append() = strlen(familyName) + 1;
michael@0 470
michael@0 471 // move to the next familyName in the dictionary
michael@0 472 familyName = iter.next(NULL);
michael@0 473 }
michael@0 474
michael@0 475 return SkDataTable::NewCopyArrays((const void*const*)names.begin(),
michael@0 476 sizes.begin(), names.count());
michael@0 477 }
michael@0 478
michael@0 479 bool SkFontConfigInterfaceAndroid::matchFamilySet(const char inFamilyName[],
michael@0 480 SkString* outFamilyName,
michael@0 481 SkTArray<FontIdentity>*) {
michael@0 482 return false;
michael@0 483 }
michael@0 484
michael@0 485 static bool find_proc(SkTypeface* face, SkTypeface::Style style, void* ctx) {
michael@0 486 const FontRecID* fontRecID = (const FontRecID*)ctx;
michael@0 487 FontRecID currFontRecID = ((FontConfigTypeface*)face)->getIdentity().fID;
michael@0 488 return currFontRecID == *fontRecID;
michael@0 489 }
michael@0 490
michael@0 491 SkTypeface* SkFontConfigInterfaceAndroid::getTypefaceForFontRec(FontRecID fontRecID) {
michael@0 492 FontRec& fontRec = fFonts[fontRecID];
michael@0 493 SkTypeface* face = fontRec.fTypeface.get();
michael@0 494 if (!face) {
michael@0 495 // look for it in the typeface cache
michael@0 496 face = SkTypefaceCache::FindByProcAndRef(find_proc, &fontRecID);
michael@0 497
michael@0 498 // if it is not in the cache then create it
michael@0 499 if (!face) {
michael@0 500 const char* familyName = NULL;
michael@0 501 SkAssertResult(fFamilyNameDict.findKey(fontRec.fFamilyRecID, &familyName));
michael@0 502 SkASSERT(familyName);
michael@0 503 face = SkTypeface::CreateFromName(familyName, fontRec.fStyle);
michael@0 504 }
michael@0 505
michael@0 506 // store the result for subsequent lookups
michael@0 507 fontRec.fTypeface = face;
michael@0 508 }
michael@0 509 SkASSERT(face);
michael@0 510 return face;
michael@0 511 }
michael@0 512
michael@0 513 bool SkFontConfigInterfaceAndroid::getFallbackFamilyNameForChar(SkUnichar uni,
michael@0 514 const char* lang,
michael@0 515 SkString* name) {
michael@0 516 FallbackFontList* fallbackFontList = NULL;
michael@0 517 const SkString langTag(lang);
michael@0 518 if (langTag.isEmpty()) {
michael@0 519 fallbackFontList = this->getCurrentLocaleFallbackFontList();
michael@0 520 } else {
michael@0 521 fallbackFontList = this->findFallbackFontList(langTag);
michael@0 522 }
michael@0 523
michael@0 524 for (int i = 0; i < fallbackFontList->count(); i++) {
michael@0 525 FamilyRecID familyRecID = fallbackFontList->getAt(i);
michael@0 526
michael@0 527 // if it is not one of the accepted variants then move to the next family
michael@0 528 int32_t acceptedVariants = SkPaintOptionsAndroid::kDefault_Variant |
michael@0 529 SkPaintOptionsAndroid::kElegant_Variant;
michael@0 530 if (!(fFontFamilies[familyRecID].fPaintOptions.getFontVariant() & acceptedVariants)) {
michael@0 531 continue;
michael@0 532 }
michael@0 533
michael@0 534 FontRecID fontRecID = find_best_style(fFontFamilies[familyRecID], SkTypeface::kNormal);
michael@0 535 SkTypeface* face = this->getTypefaceForFontRec(fontRecID);
michael@0 536
michael@0 537 SkPaint paint;
michael@0 538 paint.setTypeface(face);
michael@0 539 paint.setTextEncoding(SkPaint::kUTF32_TextEncoding);
michael@0 540
michael@0 541 uint16_t glyphID;
michael@0 542 paint.textToGlyphs(&uni, sizeof(uni), &glyphID);
michael@0 543 if (glyphID != 0) {
michael@0 544 name->set(fFontFamilies[familyRecID].fFallbackName);
michael@0 545 return true;
michael@0 546 }
michael@0 547 }
michael@0 548 return false;
michael@0 549 }
michael@0 550
michael@0 551 SkTypeface* SkFontConfigInterfaceAndroid::getTypefaceForChar(SkUnichar uni,
michael@0 552 SkTypeface::Style style,
michael@0 553 SkPaintOptionsAndroid::FontVariant fontVariant) {
michael@0 554 FontRecID fontRecID = find_best_style(fFontFamilies[fDefaultFamilyRecID], style);
michael@0 555 SkTypeface* face = this->getTypefaceForFontRec(fontRecID);
michael@0 556
michael@0 557 SkPaintOptionsAndroid paintOptions;
michael@0 558 paintOptions.setFontVariant(fontVariant);
michael@0 559 paintOptions.setUseFontFallbacks(true);
michael@0 560
michael@0 561 SkPaint paint;
michael@0 562 paint.setTypeface(face);
michael@0 563 paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
michael@0 564 paint.setPaintOptionsAndroid(paintOptions);
michael@0 565
michael@0 566 SkAutoGlyphCache autoCache(paint, NULL, NULL);
michael@0 567 SkGlyphCache* cache = autoCache.getCache();
michael@0 568
michael@0 569 SkScalerContext* ctx = cache->getScalerContext();
michael@0 570 if (ctx) {
michael@0 571 SkFontID fontID = ctx->findTypefaceIdForChar(uni);
michael@0 572 return SkTypefaceCache::FindByID(fontID);
michael@0 573 }
michael@0 574 return NULL;
michael@0 575 }
michael@0 576
michael@0 577 FallbackFontList* SkFontConfigInterfaceAndroid::getCurrentLocaleFallbackFontList() {
michael@0 578 SkString locale = SkFontConfigParser::GetLocale();
michael@0 579 if (NULL == fLocaleFallbackFontList || locale != fCachedLocale) {
michael@0 580 fCachedLocale = locale;
michael@0 581 fLocaleFallbackFontList = this->findFallbackFontList(locale);
michael@0 582 }
michael@0 583 return fLocaleFallbackFontList;
michael@0 584 }
michael@0 585
michael@0 586 FallbackFontList* SkFontConfigInterfaceAndroid::findFallbackFontList(const SkLanguage& lang,
michael@0 587 bool isOriginal) {
michael@0 588 const SkString& langTag = lang.getTag();
michael@0 589 if (langTag.isEmpty()) {
michael@0 590 return &fDefaultFallbackList;
michael@0 591 }
michael@0 592
michael@0 593 FallbackFontList* fallbackFontList;
michael@0 594 if (fFallbackFontDict.find(langTag.c_str(), langTag.size(), &fallbackFontList) ||
michael@0 595 fFallbackFontAliasDict.find(langTag.c_str(), langTag.size(), &fallbackFontList)) {
michael@0 596 return fallbackFontList;
michael@0 597 }
michael@0 598
michael@0 599 // attempt a recursive fuzzy match
michael@0 600 SkLanguage parent = lang.getParent();
michael@0 601 fallbackFontList = findFallbackFontList(parent, false);
michael@0 602
michael@0 603 // cache the original lang so we don't have to do the recursion again.
michael@0 604 if (isOriginal) {
michael@0 605 DEBUG_FONT(("---- Created fallback list alias for \"%s\"", langTag.c_str()));
michael@0 606 fFallbackFontAliasDict.set(langTag.c_str(), fallbackFontList);
michael@0 607 }
michael@0 608 return fallbackFontList;
michael@0 609 }
michael@0 610
michael@0 611 SkTypeface* SkFontConfigInterfaceAndroid::nextLogicalTypeface(SkFontID currFontID,
michael@0 612 SkFontID origFontID,
michael@0 613 const SkPaintOptionsAndroid& opts) {
michael@0 614 // Skia does not support font fallback by default. This enables clients such
michael@0 615 // as WebKit to customize their font selection. In any case, clients can use
michael@0 616 // GetFallbackFamilyNameForChar() to get the fallback font for individual
michael@0 617 // characters.
michael@0 618 if (!opts.isUsingFontFallbacks()) {
michael@0 619 return NULL;
michael@0 620 }
michael@0 621
michael@0 622 FallbackFontList* currentFallbackList = findFallbackFontList(opts.getLanguage());
michael@0 623 SkASSERT(currentFallbackList);
michael@0 624
michael@0 625 SkTypeface::Style origStyle = SkTypeface::kNormal;
michael@0 626 const SkTypeface* origTypeface = SkTypefaceCache::FindByID(origFontID);
michael@0 627 if (NULL != origTypeface) {
michael@0 628 origStyle = origTypeface->style();
michael@0 629 }
michael@0 630
michael@0 631 // we must convert currTypeface into a FontRecID
michael@0 632 FontRecID currFontRecID = INVALID_FONT_REC_ID;
michael@0 633 const SkTypeface* currTypeface = SkTypefaceCache::FindByID(currFontID);
michael@0 634 // non-system fonts are not in the font cache so if we are asked to fallback
michael@0 635 // for a non-system font we will start at the front of the chain.
michael@0 636 if (NULL != currTypeface) {
michael@0 637 currFontRecID = ((FontConfigTypeface*)currTypeface)->getIdentity().fID;
michael@0 638 SkASSERT(INVALID_FONT_REC_ID != currFontRecID);
michael@0 639 }
michael@0 640
michael@0 641 FamilyRecID currFamilyRecID = INVALID_FAMILY_REC_ID;
michael@0 642 if (INVALID_FONT_REC_ID != currFontRecID) {
michael@0 643 currFamilyRecID = fFonts[currFontRecID].fFamilyRecID;
michael@0 644 }
michael@0 645
michael@0 646 // lookup the index next font in the chain
michael@0 647 int currFallbackFontIndex = currentFallbackList->find(currFamilyRecID);
michael@0 648 // We add 1 to the returned index for 2 reasons: (1) if find succeeds it moves
michael@0 649 // our index to the next entry in the list; (2) if find() fails it returns
michael@0 650 // -1 and incrementing it will set our starting index to 0 (the head of the list)
michael@0 651 int nextFallbackFontIndex = currFallbackFontIndex + 1;
michael@0 652
michael@0 653 if(nextFallbackFontIndex >= currentFallbackList->count()) {
michael@0 654 return NULL;
michael@0 655 }
michael@0 656
michael@0 657 // If a rec object is set to prefer "kDefault_Variant" it means they have no preference
michael@0 658 // In this case, we set the value to "kCompact_Variant"
michael@0 659 SkPaintOptionsAndroid::FontVariant variant = opts.getFontVariant();
michael@0 660 if (variant == SkPaintOptionsAndroid::kDefault_Variant) {
michael@0 661 variant = SkPaintOptionsAndroid::kCompact_Variant;
michael@0 662 }
michael@0 663
michael@0 664 int32_t acceptedVariants = SkPaintOptionsAndroid::kDefault_Variant | variant;
michael@0 665
michael@0 666 SkTypeface* nextLogicalTypeface = 0;
michael@0 667 while (nextFallbackFontIndex < currentFallbackList->count()) {
michael@0 668 FamilyRecID familyRecID = currentFallbackList->getAt(nextFallbackFontIndex);
michael@0 669 if ((fFontFamilies[familyRecID].fPaintOptions.getFontVariant() & acceptedVariants) != 0) {
michael@0 670 FontRecID matchedFont = find_best_style(fFontFamilies[familyRecID], origStyle);
michael@0 671 nextLogicalTypeface = this->getTypefaceForFontRec(matchedFont);
michael@0 672 break;
michael@0 673 }
michael@0 674 nextFallbackFontIndex++;
michael@0 675 }
michael@0 676
michael@0 677 DEBUG_FONT(("---- nextLogicalFont: currFontID=%d, origFontID=%d, currRecID=%d, "
michael@0 678 "lang=%s, variant=%d, nextFallbackIndex[%d,%d] => nextLogicalTypeface=%d",
michael@0 679 currFontID, origFontID, currFontRecID, opts.getLanguage().getTag().c_str(),
michael@0 680 variant, nextFallbackFontIndex, currentFallbackList->getAt(nextFallbackFontIndex),
michael@0 681 (nextLogicalTypeface) ? nextLogicalTypeface->uniqueID() : 0));
michael@0 682 return SkSafeRef(nextLogicalTypeface);
michael@0 683 }
michael@0 684
michael@0 685 SkTypeface* SkFontConfigInterfaceAndroid::getTypefaceForGlyphID(uint16_t glyphID,
michael@0 686 const SkTypeface* origTypeface,
michael@0 687 const SkPaintOptionsAndroid& opts,
michael@0 688 int* lBounds, int* uBounds) {
michael@0 689 // If we aren't using fallbacks then we shouldn't be calling this
michael@0 690 SkASSERT(opts.isUsingFontFallbacks());
michael@0 691 SkASSERT(origTypeface);
michael@0 692
michael@0 693 SkTypeface* currentTypeface = NULL;
michael@0 694 int lowerBounds = 0; //inclusive
michael@0 695 int upperBounds = origTypeface->countGlyphs(); //exclusive
michael@0 696
michael@0 697 // check to see if the glyph is in the bounds of the origTypeface
michael@0 698 if (glyphID < upperBounds) {
michael@0 699 currentTypeface = const_cast<SkTypeface*>(origTypeface);
michael@0 700 } else {
michael@0 701 FallbackFontList* currentFallbackList = findFallbackFontList(opts.getLanguage());
michael@0 702 SkASSERT(currentFallbackList);
michael@0 703
michael@0 704 // If an object is set to prefer "kDefault_Variant" it means they have no preference
michael@0 705 // In this case, we set the value to "kCompact_Variant"
michael@0 706 SkPaintOptionsAndroid::FontVariant variant = opts.getFontVariant();
michael@0 707 if (variant == SkPaintOptionsAndroid::kDefault_Variant) {
michael@0 708 variant = SkPaintOptionsAndroid::kCompact_Variant;
michael@0 709 }
michael@0 710
michael@0 711 int32_t acceptedVariants = SkPaintOptionsAndroid::kDefault_Variant | variant;
michael@0 712 SkTypeface::Style origStyle = origTypeface->style();
michael@0 713
michael@0 714 for (int x = 0; x < currentFallbackList->count(); ++x) {
michael@0 715 const FamilyRecID familyRecID = currentFallbackList->getAt(x);
michael@0 716 const SkPaintOptionsAndroid& familyOptions = fFontFamilies[familyRecID].fPaintOptions;
michael@0 717 if ((familyOptions.getFontVariant() & acceptedVariants) != 0) {
michael@0 718 FontRecID matchedFont = find_best_style(fFontFamilies[familyRecID], origStyle);
michael@0 719 currentTypeface = this->getTypefaceForFontRec(matchedFont);
michael@0 720 lowerBounds = upperBounds;
michael@0 721 upperBounds += currentTypeface->countGlyphs();
michael@0 722 if (glyphID < upperBounds) {
michael@0 723 break;
michael@0 724 }
michael@0 725 }
michael@0 726 }
michael@0 727 }
michael@0 728
michael@0 729 if (NULL != currentTypeface) {
michael@0 730 if (lBounds) {
michael@0 731 *lBounds = lowerBounds;
michael@0 732 }
michael@0 733 if (uBounds) {
michael@0 734 *uBounds = upperBounds;
michael@0 735 }
michael@0 736 }
michael@0 737 return currentTypeface;
michael@0 738 }
michael@0 739
michael@0 740 ///////////////////////////////////////////////////////////////////////////////
michael@0 741
michael@0 742 bool SkGetFallbackFamilyNameForChar(SkUnichar uni, SkString* name) {
michael@0 743 SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
michael@0 744 return fontConfig->getFallbackFamilyNameForChar(uni, NULL, name);
michael@0 745 }
michael@0 746
michael@0 747 bool SkGetFallbackFamilyNameForChar(SkUnichar uni, const char* lang, SkString* name) {
michael@0 748 SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
michael@0 749 return fontConfig->getFallbackFamilyNameForChar(uni, lang, name);
michael@0 750 }
michael@0 751
michael@0 752 void SkUseTestFontConfigFile(const char* mainconf, const char* fallbackconf,
michael@0 753 const char* fontsdir) {
michael@0 754 gTestMainConfigFile = mainconf;
michael@0 755 gTestFallbackConfigFile = fallbackconf;
michael@0 756 gTestFontFilePrefix = fontsdir;
michael@0 757 SkASSERT(gTestMainConfigFile);
michael@0 758 SkASSERT(gTestFallbackConfigFile);
michael@0 759 SkASSERT(gTestFontFilePrefix);
michael@0 760 SkDEBUGF(("Use Test Config File Main %s, Fallback %s, Font Dir %s",
michael@0 761 gTestMainConfigFile, gTestFallbackConfigFile, gTestFontFilePrefix));
michael@0 762 }
michael@0 763
michael@0 764 SkTypeface* SkAndroidNextLogicalTypeface(SkFontID currFontID, SkFontID origFontID,
michael@0 765 const SkPaintOptionsAndroid& options) {
michael@0 766 SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
michael@0 767 return fontConfig->nextLogicalTypeface(currFontID, origFontID, options);
michael@0 768
michael@0 769 }
michael@0 770
michael@0 771 SkTypeface* SkGetTypefaceForGlyphID(uint16_t glyphID, const SkTypeface* origTypeface,
michael@0 772 const SkPaintOptionsAndroid& options,
michael@0 773 int* lowerBounds, int* upperBounds) {
michael@0 774 SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
michael@0 775 return fontConfig->getTypefaceForGlyphID(glyphID, origTypeface, options,
michael@0 776 lowerBounds, upperBounds);
michael@0 777 }
michael@0 778
michael@0 779 ///////////////////////////////////////////////////////////////////////////////
michael@0 780
michael@0 781 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
michael@0 782
michael@0 783 struct HB_UnicodeMapping {
michael@0 784 hb_script_t script;
michael@0 785 const SkUnichar unicode;
michael@0 786 };
michael@0 787
michael@0 788 /*
michael@0 789 * The following scripts are not complex fonts and we do not expect them to be parsed by this table
michael@0 790 * HB_SCRIPT_COMMON,
michael@0 791 * HB_SCRIPT_GREEK,
michael@0 792 * HB_SCRIPT_CYRILLIC,
michael@0 793 * HB_SCRIPT_HANGUL
michael@0 794 * HB_SCRIPT_INHERITED
michael@0 795 */
michael@0 796
michael@0 797 /* Harfbuzz (old) is missing a number of scripts in its table. For these,
michael@0 798 * we include a value which can never happen. We won't get complex script
michael@0 799 * shaping in these cases, but the library wouldn't know how to shape
michael@0 800 * them anyway. */
michael@0 801 #define HB_Script_Unknown HB_ScriptCount
michael@0 802
michael@0 803 static HB_UnicodeMapping HB_UnicodeMappingArray[] = {
michael@0 804 {HB_SCRIPT_ARMENIAN, 0x0531},
michael@0 805 {HB_SCRIPT_HEBREW, 0x0591},
michael@0 806 {HB_SCRIPT_ARABIC, 0x0600},
michael@0 807 {HB_SCRIPT_SYRIAC, 0x0710},
michael@0 808 {HB_SCRIPT_THAANA, 0x0780},
michael@0 809 {HB_SCRIPT_NKO, 0x07C0},
michael@0 810 {HB_SCRIPT_DEVANAGARI, 0x0901},
michael@0 811 {HB_SCRIPT_BENGALI, 0x0981},
michael@0 812 {HB_SCRIPT_GURMUKHI, 0x0A10},
michael@0 813 {HB_SCRIPT_GUJARATI, 0x0A90},
michael@0 814 {HB_SCRIPT_ORIYA, 0x0B10},
michael@0 815 {HB_SCRIPT_TAMIL, 0x0B82},
michael@0 816 {HB_SCRIPT_TELUGU, 0x0C10},
michael@0 817 {HB_SCRIPT_KANNADA, 0x0C90},
michael@0 818 {HB_SCRIPT_MALAYALAM, 0x0D10},
michael@0 819 {HB_SCRIPT_SINHALA, 0x0D90},
michael@0 820 {HB_SCRIPT_THAI, 0x0E01},
michael@0 821 {HB_SCRIPT_LAO, 0x0E81},
michael@0 822 {HB_SCRIPT_TIBETAN, 0x0F00},
michael@0 823 {HB_SCRIPT_MYANMAR, 0x1000},
michael@0 824 {HB_SCRIPT_GEORGIAN, 0x10A0},
michael@0 825 {HB_SCRIPT_ETHIOPIC, 0x1200},
michael@0 826 {HB_SCRIPT_CHEROKEE, 0x13A0},
michael@0 827 {HB_SCRIPT_OGHAM, 0x1680},
michael@0 828 {HB_SCRIPT_RUNIC, 0x16A0},
michael@0 829 {HB_SCRIPT_KHMER, 0x1780},
michael@0 830 {HB_SCRIPT_TAI_LE, 0x1950},
michael@0 831 {HB_SCRIPT_NEW_TAI_LUE, 0x1980},
michael@0 832 {HB_SCRIPT_TAI_THAM, 0x1A20},
michael@0 833 {HB_SCRIPT_CHAM, 0xAA00},
michael@0 834 };
michael@0 835
michael@0 836 // returns 0 for "Not Found"
michael@0 837 static SkUnichar getUnicodeFromHBScript(hb_script_t script) {
michael@0 838 SkUnichar unichar = 0;
michael@0 839 int numSupportedFonts = sizeof(HB_UnicodeMappingArray) / sizeof(HB_UnicodeMapping);
michael@0 840 for (int i = 0; i < numSupportedFonts; i++) {
michael@0 841 if (script == HB_UnicodeMappingArray[i].script) {
michael@0 842 unichar = HB_UnicodeMappingArray[i].unicode;
michael@0 843 break;
michael@0 844 }
michael@0 845 }
michael@0 846 return unichar;
michael@0 847 }
michael@0 848
michael@0 849 struct TypefaceLookupStruct {
michael@0 850 hb_script_t script;
michael@0 851 SkTypeface::Style style;
michael@0 852 SkPaintOptionsAndroid::FontVariant fontVariant;
michael@0 853 SkTypeface* typeface;
michael@0 854 };
michael@0 855
michael@0 856 SK_DECLARE_STATIC_MUTEX(gTypefaceTableMutex); // This is the mutex for gTypefaceTable
michael@0 857 static SkTDArray<TypefaceLookupStruct> gTypefaceTable; // This is protected by gTypefaceTableMutex
michael@0 858
michael@0 859 static int typefaceLookupCompare(const TypefaceLookupStruct& first,
michael@0 860 const TypefaceLookupStruct& second) {
michael@0 861 if (first.script != second.script) {
michael@0 862 return (first.script > second.script) ? 1 : -1;
michael@0 863 }
michael@0 864 if (first.style != second.style) {
michael@0 865 return (first.style > second.style) ? 1 : -1;
michael@0 866 }
michael@0 867 if (first.fontVariant != second.fontVariant) {
michael@0 868 return (first.fontVariant > second.fontVariant) ? 1 : -1;
michael@0 869 }
michael@0 870 return 0;
michael@0 871 }
michael@0 872
michael@0 873 SkTypeface* SkCreateTypefaceForScript(hb_script_t script, SkTypeface::Style style,
michael@0 874 SkPaintOptionsAndroid::FontVariant fontVariant) {
michael@0 875 SkAutoMutexAcquire ac(gTypefaceTableMutex);
michael@0 876
michael@0 877 TypefaceLookupStruct key;
michael@0 878 key.script = script;
michael@0 879 key.style = style;
michael@0 880 key.fontVariant = fontVariant;
michael@0 881
michael@0 882 int index = SkTSearch<TypefaceLookupStruct>(
michael@0 883 (const TypefaceLookupStruct*) gTypefaceTable.begin(),
michael@0 884 gTypefaceTable.count(), key, sizeof(TypefaceLookupStruct),
michael@0 885 typefaceLookupCompare);
michael@0 886
michael@0 887 SkTypeface* retTypeface = NULL;
michael@0 888 if (index >= 0) {
michael@0 889 retTypeface = gTypefaceTable[index].typeface;
michael@0 890 }
michael@0 891 else {
michael@0 892 SkUnichar unichar = getUnicodeFromHBScript(script);
michael@0 893 if (!unichar) {
michael@0 894 return NULL;
michael@0 895 }
michael@0 896
michael@0 897 SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
michael@0 898 retTypeface = fontConfig->getTypefaceForChar(unichar, style, fontVariant);
michael@0 899
michael@0 900 // add to the lookup table
michael@0 901 key.typeface = retTypeface;
michael@0 902 *gTypefaceTable.insert(~index) = key;
michael@0 903 }
michael@0 904
michael@0 905 // we ref(), the caller is expected to unref when they are done
michael@0 906 return SkSafeRef(retTypeface);
michael@0 907 }
michael@0 908
michael@0 909 #endif
michael@0 910
michael@0 911 ///////////////////////////////////////////////////////////////////////////////
michael@0 912
michael@0 913 SkFontMgr* SkFontMgr::Factory() {
michael@0 914 return NULL;
michael@0 915 }

mercurial