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