gfx/skia/trunk/src/ports/SkFontHost_android_old.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 2006 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
michael@0 10 #include "SkFontDescriptor.h"
michael@0 11 #include "SkFontHost.h"
michael@0 12 #include "SkFontHost_FreeType_common.h"
michael@0 13 #include "SkDescriptor.h"
michael@0 14 #include "SkStream.h"
michael@0 15 #include "SkPaint.h"
michael@0 16 #include "SkString.h"
michael@0 17 #include "SkStream.h"
michael@0 18 #include "SkThread.h"
michael@0 19 #include "SkTSearch.h"
michael@0 20 #include <stdio.h>
michael@0 21
michael@0 22 #define FONT_CACHE_MEMORY_BUDGET (768 * 1024)
michael@0 23
michael@0 24 #ifndef SK_FONT_FILE_PREFIX
michael@0 25 #define SK_FONT_FILE_PREFIX "/fonts/"
michael@0 26 #endif
michael@0 27
michael@0 28 bool find_name_and_attributes(SkStream* stream, SkString* name, SkTypeface::Style* style,
michael@0 29 bool* isFixedWidth);
michael@0 30
michael@0 31 static void GetFullPathForSysFonts(SkString* full, const char name[]) {
michael@0 32 full->set(getenv("ANDROID_ROOT"));
michael@0 33 full->append(SK_FONT_FILE_PREFIX);
michael@0 34 full->append(name);
michael@0 35 }
michael@0 36
michael@0 37 ///////////////////////////////////////////////////////////////////////////////
michael@0 38
michael@0 39 struct FamilyRec;
michael@0 40
michael@0 41 /* This guy holds a mapping of a name -> family, used for looking up fonts.
michael@0 42 Since it is stored in a stretchy array that doesn't preserve object
michael@0 43 semantics, we don't use constructor/destructors, but just have explicit
michael@0 44 helpers to manage our internal bookkeeping.
michael@0 45 */
michael@0 46 struct NameFamilyPair {
michael@0 47 const char* fName; // we own this
michael@0 48 FamilyRec* fFamily; // we don't own this, we just reference it
michael@0 49
michael@0 50 void construct(const char name[], FamilyRec* family) {
michael@0 51 fName = strdup(name);
michael@0 52 fFamily = family; // we don't own this, so just record the referene
michael@0 53 }
michael@0 54
michael@0 55 void destruct() {
michael@0 56 free((char*)fName);
michael@0 57 // we don't own family, so just ignore our reference
michael@0 58 }
michael@0 59 };
michael@0 60
michael@0 61 // we use atomic_inc to grow this for each typeface we create
michael@0 62 static int32_t gUniqueFontID;
michael@0 63
michael@0 64 // this is the mutex that protects these globals
michael@0 65 static SkMutex gFamilyMutex;
michael@0 66 static FamilyRec* gFamilyHead;
michael@0 67 static SkTDArray<NameFamilyPair> gNameList;
michael@0 68
michael@0 69 struct FamilyRec {
michael@0 70 FamilyRec* fNext;
michael@0 71 SkTypeface* fFaces[4];
michael@0 72
michael@0 73 FamilyRec()
michael@0 74 {
michael@0 75 fNext = gFamilyHead;
michael@0 76 memset(fFaces, 0, sizeof(fFaces));
michael@0 77 gFamilyHead = this;
michael@0 78 }
michael@0 79 };
michael@0 80
michael@0 81 static SkTypeface* find_best_face(const FamilyRec* family,
michael@0 82 SkTypeface::Style style) {
michael@0 83 SkTypeface* const* faces = family->fFaces;
michael@0 84
michael@0 85 if (faces[style] != NULL) { // exact match
michael@0 86 return faces[style];
michael@0 87 }
michael@0 88 // look for a matching bold
michael@0 89 style = (SkTypeface::Style)(style ^ SkTypeface::kItalic);
michael@0 90 if (faces[style] != NULL) {
michael@0 91 return faces[style];
michael@0 92 }
michael@0 93 // look for the plain
michael@0 94 if (faces[SkTypeface::kNormal] != NULL) {
michael@0 95 return faces[SkTypeface::kNormal];
michael@0 96 }
michael@0 97 // look for anything
michael@0 98 for (int i = 0; i < 4; i++) {
michael@0 99 if (faces[i] != NULL) {
michael@0 100 return faces[i];
michael@0 101 }
michael@0 102 }
michael@0 103 // should never get here, since the faces list should not be empty
michael@0 104 SkASSERT(!"faces list is empty");
michael@0 105 return NULL;
michael@0 106 }
michael@0 107
michael@0 108 static FamilyRec* find_family(const SkTypeface* member) {
michael@0 109 FamilyRec* curr = gFamilyHead;
michael@0 110 while (curr != NULL) {
michael@0 111 for (int i = 0; i < 4; i++) {
michael@0 112 if (curr->fFaces[i] == member) {
michael@0 113 return curr;
michael@0 114 }
michael@0 115 }
michael@0 116 curr = curr->fNext;
michael@0 117 }
michael@0 118 return NULL;
michael@0 119 }
michael@0 120
michael@0 121 /* Returns the matching typeface, or NULL. If a typeface is found, its refcnt
michael@0 122 is not modified.
michael@0 123 */
michael@0 124 static SkTypeface* find_from_uniqueID(uint32_t uniqueID) {
michael@0 125 FamilyRec* curr = gFamilyHead;
michael@0 126 while (curr != NULL) {
michael@0 127 for (int i = 0; i < 4; i++) {
michael@0 128 SkTypeface* face = curr->fFaces[i];
michael@0 129 if (face != NULL && face->uniqueID() == uniqueID) {
michael@0 130 return face;
michael@0 131 }
michael@0 132 }
michael@0 133 curr = curr->fNext;
michael@0 134 }
michael@0 135 return NULL;
michael@0 136 }
michael@0 137
michael@0 138 /* Remove reference to this face from its family. If the resulting family
michael@0 139 is empty (has no faces), return that family, otherwise return NULL
michael@0 140 */
michael@0 141 static FamilyRec* remove_from_family(const SkTypeface* face) {
michael@0 142 FamilyRec* family = find_family(face);
michael@0 143 SkASSERT(family->fFaces[face->style()] == face);
michael@0 144 family->fFaces[face->style()] = NULL;
michael@0 145
michael@0 146 for (int i = 0; i < 4; i++) {
michael@0 147 if (family->fFaces[i] != NULL) { // family is non-empty
michael@0 148 return NULL;
michael@0 149 }
michael@0 150 }
michael@0 151 return family; // return the empty family
michael@0 152 }
michael@0 153
michael@0 154 // maybe we should make FamilyRec be doubly-linked
michael@0 155 static void detach_and_delete_family(FamilyRec* family) {
michael@0 156 FamilyRec* curr = gFamilyHead;
michael@0 157 FamilyRec* prev = NULL;
michael@0 158
michael@0 159 while (curr != NULL) {
michael@0 160 FamilyRec* next = curr->fNext;
michael@0 161 if (curr == family) {
michael@0 162 if (prev == NULL) {
michael@0 163 gFamilyHead = next;
michael@0 164 } else {
michael@0 165 prev->fNext = next;
michael@0 166 }
michael@0 167 SkDELETE(family);
michael@0 168 return;
michael@0 169 }
michael@0 170 prev = curr;
michael@0 171 curr = next;
michael@0 172 }
michael@0 173 SkASSERT(!"Yikes, couldn't find family in our list to remove/delete");
michael@0 174 }
michael@0 175
michael@0 176 static SkTypeface* find_typeface(const char name[], SkTypeface::Style style) {
michael@0 177 NameFamilyPair* list = gNameList.begin();
michael@0 178 int count = gNameList.count();
michael@0 179
michael@0 180 int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
michael@0 181
michael@0 182 if (index >= 0) {
michael@0 183 return find_best_face(list[index].fFamily, style);
michael@0 184 }
michael@0 185 return NULL;
michael@0 186 }
michael@0 187
michael@0 188 static SkTypeface* find_typeface(const SkTypeface* familyMember,
michael@0 189 SkTypeface::Style style) {
michael@0 190 const FamilyRec* family = find_family(familyMember);
michael@0 191 return family ? find_best_face(family, style) : NULL;
michael@0 192 }
michael@0 193
michael@0 194 static void add_name(const char name[], FamilyRec* family) {
michael@0 195 SkAutoAsciiToLC tolc(name);
michael@0 196 name = tolc.lc();
michael@0 197
michael@0 198 NameFamilyPair* list = gNameList.begin();
michael@0 199 int count = gNameList.count();
michael@0 200
michael@0 201 int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
michael@0 202
michael@0 203 if (index < 0) {
michael@0 204 list = gNameList.insert(~index);
michael@0 205 list->construct(name, family);
michael@0 206 }
michael@0 207 }
michael@0 208
michael@0 209 static void remove_from_names(FamilyRec* emptyFamily)
michael@0 210 {
michael@0 211 #ifdef SK_DEBUG
michael@0 212 for (int i = 0; i < 4; i++) {
michael@0 213 SkASSERT(emptyFamily->fFaces[i] == NULL);
michael@0 214 }
michael@0 215 #endif
michael@0 216
michael@0 217 SkTDArray<NameFamilyPair>& list = gNameList;
michael@0 218
michael@0 219 // must go backwards when removing
michael@0 220 for (int i = list.count() - 1; i >= 0; --i) {
michael@0 221 NameFamilyPair* pair = &list[i];
michael@0 222 if (pair->fFamily == emptyFamily) {
michael@0 223 pair->destruct();
michael@0 224 list.remove(i);
michael@0 225 }
michael@0 226 }
michael@0 227 }
michael@0 228
michael@0 229 ///////////////////////////////////////////////////////////////////////////////
michael@0 230
michael@0 231 class FamilyTypeface : public SkTypeface_FreeType {
michael@0 232 public:
michael@0 233 FamilyTypeface(Style style, bool sysFont, SkTypeface* familyMember,
michael@0 234 bool isFixedWidth)
michael@0 235 : SkTypeface_FreeType(style, sk_atomic_inc(&gUniqueFontID) + 1, isFixedWidth) {
michael@0 236 fIsSysFont = sysFont;
michael@0 237
michael@0 238 SkAutoMutexAcquire ac(gFamilyMutex);
michael@0 239
michael@0 240 FamilyRec* rec = NULL;
michael@0 241 if (familyMember) {
michael@0 242 rec = find_family(familyMember);
michael@0 243 SkASSERT(rec);
michael@0 244 } else {
michael@0 245 rec = SkNEW(FamilyRec);
michael@0 246 }
michael@0 247 rec->fFaces[style] = this;
michael@0 248 }
michael@0 249
michael@0 250 virtual ~FamilyTypeface() {
michael@0 251 SkAutoMutexAcquire ac(gFamilyMutex);
michael@0 252
michael@0 253 // remove us from our family. If the family is now empty, we return
michael@0 254 // that and then remove that family from the name list
michael@0 255 FamilyRec* family = remove_from_family(this);
michael@0 256 if (NULL != family) {
michael@0 257 remove_from_names(family);
michael@0 258 detach_and_delete_family(family);
michael@0 259 }
michael@0 260 }
michael@0 261
michael@0 262 bool isSysFont() const { return fIsSysFont; }
michael@0 263
michael@0 264 virtual const char* getUniqueString() const = 0;
michael@0 265 virtual const char* getFilePath() const = 0;
michael@0 266
michael@0 267 protected:
michael@0 268 virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE;
michael@0 269
michael@0 270 private:
michael@0 271 bool fIsSysFont;
michael@0 272
michael@0 273 typedef SkTypeface INHERITED;
michael@0 274 };
michael@0 275
michael@0 276 ///////////////////////////////////////////////////////////////////////////////
michael@0 277
michael@0 278 class StreamTypeface : public FamilyTypeface {
michael@0 279 public:
michael@0 280 StreamTypeface(Style style, bool sysFont, SkTypeface* familyMember,
michael@0 281 SkStream* stream, bool isFixedWidth)
michael@0 282 : INHERITED(style, sysFont, familyMember, isFixedWidth) {
michael@0 283 SkASSERT(stream);
michael@0 284 stream->ref();
michael@0 285 fStream = stream;
michael@0 286 }
michael@0 287 virtual ~StreamTypeface() {
michael@0 288 fStream->unref();
michael@0 289 }
michael@0 290
michael@0 291 // overrides
michael@0 292 virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE {
michael@0 293 *ttcIndex = 0;
michael@0 294 // we just ref our existing stream, since the caller will call unref()
michael@0 295 // when they are through
michael@0 296 fStream->ref();
michael@0 297 // must rewind each time, since the caller assumes a "new" stream
michael@0 298 fStream->rewind();
michael@0 299 return fStream;
michael@0 300 }
michael@0 301 virtual const char* getUniqueString() const { return NULL; }
michael@0 302 virtual const char* getFilePath() const { return NULL; }
michael@0 303
michael@0 304 private:
michael@0 305 SkStream* fStream;
michael@0 306
michael@0 307 typedef FamilyTypeface INHERITED;
michael@0 308 };
michael@0 309
michael@0 310 class FileTypeface : public FamilyTypeface {
michael@0 311 public:
michael@0 312 FileTypeface(Style style, bool sysFont, SkTypeface* familyMember,
michael@0 313 const char path[], bool isFixedWidth)
michael@0 314 : INHERITED(style, sysFont, familyMember, isFixedWidth) {
michael@0 315 SkString fullpath;
michael@0 316
michael@0 317 if (sysFont) {
michael@0 318 GetFullPathForSysFonts(&fullpath, path);
michael@0 319 path = fullpath.c_str();
michael@0 320 }
michael@0 321 fPath.set(path);
michael@0 322 }
michael@0 323
michael@0 324 // overrides
michael@0 325 virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE {
michael@0 326 *ttcIndex = 0;
michael@0 327 SkStream* stream = SkNEW_ARGS(SkFILEStream, (fPath.c_str()));
michael@0 328
michael@0 329 // check for failure
michael@0 330 if (stream->getLength() <= 0) {
michael@0 331 SkDELETE(stream);
michael@0 332 stream = NULL;
michael@0 333 }
michael@0 334 return stream;
michael@0 335 }
michael@0 336 virtual const char* getUniqueString() const {
michael@0 337 const char* str = strrchr(fPath.c_str(), '/');
michael@0 338 if (str) {
michael@0 339 str += 1; // skip the '/'
michael@0 340 }
michael@0 341 return str;
michael@0 342 }
michael@0 343 virtual const char* getFilePath() const {
michael@0 344 return fPath.c_str();
michael@0 345 }
michael@0 346
michael@0 347 private:
michael@0 348 SkString fPath;
michael@0 349
michael@0 350 typedef FamilyTypeface INHERITED;
michael@0 351 };
michael@0 352
michael@0 353 ///////////////////////////////////////////////////////////////////////////////
michael@0 354 ///////////////////////////////////////////////////////////////////////////////
michael@0 355
michael@0 356 static bool get_name_and_style(const char path[], SkString* name,
michael@0 357 SkTypeface::Style* style,
michael@0 358 bool* isFixedWidth, bool isExpected) {
michael@0 359 SkString fullpath;
michael@0 360 GetFullPathForSysFonts(&fullpath, path);
michael@0 361
michael@0 362 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(fullpath.c_str()));
michael@0 363 if (stream.get()) {
michael@0 364 find_name_and_attributes(stream, name, style, isFixedWidth);
michael@0 365 return true;
michael@0 366 }
michael@0 367
michael@0 368 if (isExpected) {
michael@0 369 SkDebugf("---- failed to open <%s> as a font\n", fullpath.c_str());
michael@0 370 }
michael@0 371 return false;
michael@0 372 }
michael@0 373
michael@0 374 // used to record our notion of the pre-existing fonts
michael@0 375 struct FontInitRec {
michael@0 376 const char* fFileName;
michael@0 377 const char* const* fNames; // null-terminated list
michael@0 378 };
michael@0 379
michael@0 380 static const char* gSansNames[] = {
michael@0 381 "sans-serif", "arial", "helvetica", "tahoma", "verdana", NULL
michael@0 382 };
michael@0 383
michael@0 384 static const char* gSerifNames[] = {
michael@0 385 "serif", "times", "times new roman", "palatino", "georgia", "baskerville",
michael@0 386 "goudy", "fantasy", "cursive", "ITC Stone Serif", NULL
michael@0 387 };
michael@0 388
michael@0 389 static const char* gMonoNames[] = {
michael@0 390 "monospace", "courier", "courier new", "monaco", NULL
michael@0 391 };
michael@0 392
michael@0 393 // deliberately empty, but we use the address to identify fallback fonts
michael@0 394 static const char* gFBNames[] = { NULL };
michael@0 395
michael@0 396 /* Fonts must be grouped by family, with the first font in a family having the
michael@0 397 list of names (even if that list is empty), and the following members having
michael@0 398 null for the list. The names list must be NULL-terminated
michael@0 399 */
michael@0 400 static const FontInitRec gSystemFonts[] = {
michael@0 401 { "DroidSans.ttf", gSansNames },
michael@0 402 { "DroidSans-Bold.ttf", NULL },
michael@0 403 { "DroidSerif-Regular.ttf", gSerifNames },
michael@0 404 { "DroidSerif-Bold.ttf", NULL },
michael@0 405 { "DroidSerif-Italic.ttf", NULL },
michael@0 406 { "DroidSerif-BoldItalic.ttf", NULL },
michael@0 407 { "DroidSansMono.ttf", gMonoNames },
michael@0 408 /* These are optional, and can be ignored if not found in the file system.
michael@0 409 These are appended to gFallbackFonts[] as they are seen, so we list
michael@0 410 them in the order we want them to be accessed by NextLogicalFont().
michael@0 411 */
michael@0 412 { "DroidSansArabic.ttf", gFBNames },
michael@0 413 { "DroidSansHebrew.ttf", gFBNames },
michael@0 414 { "DroidSansThai.ttf", gFBNames },
michael@0 415 { "MTLmr3m.ttf", gFBNames }, // Motoya Japanese Font
michael@0 416 { "MTLc3m.ttf", gFBNames }, // Motoya Japanese Font
michael@0 417 { "DroidSansJapanese.ttf", gFBNames },
michael@0 418 { "DroidSansFallback.ttf", gFBNames }
michael@0 419 };
michael@0 420
michael@0 421 #define DEFAULT_NAMES gSansNames
michael@0 422
michael@0 423 // these globals are assigned (once) by load_system_fonts()
michael@0 424 static FamilyRec* gDefaultFamily;
michael@0 425 static SkTypeface* gDefaultNormal;
michael@0 426
michael@0 427 /* This is sized conservatively, assuming that it will never be a size issue.
michael@0 428 It will be initialized in load_system_fonts(), and will be filled with the
michael@0 429 fontIDs that can be used for fallback consideration, in sorted order (sorted
michael@0 430 meaning element[0] should be used first, then element[1], etc. When we hit
michael@0 431 a fontID==0 in the array, the list is done, hence our allocation size is
michael@0 432 +1 the total number of possible system fonts. Also see NextLogicalFont().
michael@0 433 */
michael@0 434 static uint32_t gFallbackFonts[SK_ARRAY_COUNT(gSystemFonts)+1];
michael@0 435
michael@0 436 /* Called once (ensured by the sentinel check at the beginning of our body).
michael@0 437 Initializes all the globals, and register the system fonts.
michael@0 438 */
michael@0 439 static void load_system_fonts() {
michael@0 440 // check if we've already be called
michael@0 441 if (NULL != gDefaultNormal) {
michael@0 442 return;
michael@0 443 }
michael@0 444
michael@0 445 const FontInitRec* rec = gSystemFonts;
michael@0 446 SkTypeface* firstInFamily = NULL;
michael@0 447 int fallbackCount = 0;
michael@0 448
michael@0 449 for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
michael@0 450 // if we're the first in a new family, clear firstInFamily
michael@0 451 if (rec[i].fNames != NULL) {
michael@0 452 firstInFamily = NULL;
michael@0 453 }
michael@0 454
michael@0 455 bool isFixedWidth;
michael@0 456 SkString name;
michael@0 457 SkTypeface::Style style;
michael@0 458
michael@0 459 // we expect all the fonts, except the "fallback" fonts
michael@0 460 bool isExpected = (rec[i].fNames != gFBNames);
michael@0 461 if (!get_name_and_style(rec[i].fFileName, &name, &style,
michael@0 462 &isFixedWidth, isExpected)) {
michael@0 463 continue;
michael@0 464 }
michael@0 465
michael@0 466 SkTypeface* tf = SkNEW_ARGS(FileTypeface,
michael@0 467 (style,
michael@0 468 true, // system-font (cannot delete)
michael@0 469 firstInFamily, // what family to join
michael@0 470 rec[i].fFileName,
michael@0 471 isFixedWidth) // filename
michael@0 472 );
michael@0 473
michael@0 474 if (rec[i].fNames != NULL) {
michael@0 475 // see if this is one of our fallback fonts
michael@0 476 if (rec[i].fNames == gFBNames) {
michael@0 477 // SkDebugf("---- adding %s as fallback[%d] fontID %d\n",
michael@0 478 // rec[i].fFileName, fallbackCount, tf->uniqueID());
michael@0 479 gFallbackFonts[fallbackCount++] = tf->uniqueID();
michael@0 480 }
michael@0 481
michael@0 482 firstInFamily = tf;
michael@0 483 FamilyRec* family = find_family(tf);
michael@0 484 const char* const* names = rec[i].fNames;
michael@0 485
michael@0 486 // record the default family if this is it
michael@0 487 if (names == DEFAULT_NAMES) {
michael@0 488 gDefaultFamily = family;
michael@0 489 }
michael@0 490 // add the names to map to this family
michael@0 491 while (*names) {
michael@0 492 add_name(*names, family);
michael@0 493 names += 1;
michael@0 494 }
michael@0 495 }
michael@0 496 }
michael@0 497
michael@0 498 // do this after all fonts are loaded. This is our default font, and it
michael@0 499 // acts as a sentinel so we only execute load_system_fonts() once
michael@0 500 gDefaultNormal = find_best_face(gDefaultFamily, SkTypeface::kNormal);
michael@0 501 // now terminate our fallback list with the sentinel value
michael@0 502 gFallbackFonts[fallbackCount] = 0;
michael@0 503 }
michael@0 504
michael@0 505 void FamilyTypeface::onGetFontDescriptor(SkFontDescriptor* desc,
michael@0 506 bool* isLocalStream) const {
michael@0 507 {
michael@0 508 SkAutoMutexAcquire ac(gFamilyMutex);
michael@0 509 //desc->setFamilyName(find_family_name(this));
michael@0 510 desc->setFontFileName(this->getUniqueString());
michael@0 511 }
michael@0 512 *isLocalStream = !this->isSysFont();
michael@0 513 }
michael@0 514
michael@0 515 ///////////////////////////////////////////////////////////////////////////////
michael@0 516
michael@0 517 SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
michael@0 518 const char familyName[],
michael@0 519 SkTypeface::Style style) {
michael@0 520 load_system_fonts();
michael@0 521
michael@0 522 SkAutoMutexAcquire ac(gFamilyMutex);
michael@0 523
michael@0 524 // clip to legal style bits
michael@0 525 style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
michael@0 526
michael@0 527 SkTypeface* tf = NULL;
michael@0 528
michael@0 529 if (NULL != familyFace) {
michael@0 530 tf = find_typeface(familyFace, style);
michael@0 531 } else if (NULL != familyName) {
michael@0 532 // SkDebugf("======= familyName <%s>\n", familyName);
michael@0 533 tf = find_typeface(familyName, style);
michael@0 534 }
michael@0 535
michael@0 536 if (NULL == tf) {
michael@0 537 tf = find_best_face(gDefaultFamily, style);
michael@0 538 }
michael@0 539
michael@0 540 // we ref(), since the symantic is to return a new instance
michael@0 541 tf->ref();
michael@0 542 return tf;
michael@0 543 }
michael@0 544
michael@0 545 SkTypeface* SkAndroidNextLogicalTypeface(SkFontID currFontID, SkFontID origFontID,
michael@0 546 const SkPaintOptionsAndroid& options) {
michael@0 547 load_system_fonts();
michael@0 548
michael@0 549 /* First see if fontID is already one of our fallbacks. If so, return
michael@0 550 its successor. If fontID is not in our list, then return the first one
michael@0 551 in our list. Note: list is zero-terminated, and returning zero means
michael@0 552 we have no more fonts to use for fallbacks.
michael@0 553 */
michael@0 554 const uint32_t* list = gFallbackFonts;
michael@0 555 for (int i = 0; list[i] != 0; i++) {
michael@0 556 if (list[i] == currFontID) {
michael@0 557 return find_from_uniqueID(list[i+1]);
michael@0 558 }
michael@0 559 }
michael@0 560 return find_from_uniqueID(list[0]);
michael@0 561 }
michael@0 562
michael@0 563 ///////////////////////////////////////////////////////////////////////////////
michael@0 564
michael@0 565 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
michael@0 566 if (NULL == stream || stream->getLength() <= 0) {
michael@0 567 return NULL;
michael@0 568 }
michael@0 569
michael@0 570 bool isFixedWidth;
michael@0 571 SkString name;
michael@0 572 SkTypeface::Style style;
michael@0 573 find_name_and_attributes(stream, &name, &style, &isFixedWidth);
michael@0 574
michael@0 575 if (!name.isEmpty()) {
michael@0 576 return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream, isFixedWidth));
michael@0 577 } else {
michael@0 578 return NULL;
michael@0 579 }
michael@0 580 }
michael@0 581
michael@0 582 SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
michael@0 583 SkStream* stream = SkNEW_ARGS(SkFILEStream, (path));
michael@0 584 SkTypeface* face = SkFontHost::CreateTypefaceFromStream(stream);
michael@0 585 // since we created the stream, we let go of our ref() here
michael@0 586 stream->unref();
michael@0 587 return face;
michael@0 588 }
michael@0 589

mercurial