michael@0: From 0d730a94e9f6676d5cde45f955fe025a4549817e Mon Sep 17 00:00:00 2001 michael@0: From: George Wright michael@0: Date: Thu, 23 Aug 2012 16:45:38 -0400 michael@0: Subject: [PATCH 4/9] Bug 777614 - Re-apply bug 719872 - Fix crash on Android michael@0: by reverting to older FontHost r=nrc michael@0: michael@0: --- michael@0: gfx/skia/src/ports/SkFontHost_android_old.cpp | 664 ++++++++++++++++++++++++++ michael@0: 1 file changed, 664 insertions(+) michael@0: create mode 100644 gfx/skia/src/ports/SkFontHost_android_old.cpp michael@0: michael@0: diff --git a/gfx/skia/src/ports/SkFontHost_android_old.cpp b/gfx/skia/src/ports/SkFontHost_android_old.cpp michael@0: new file mode 100644 michael@0: index 0000000..b5c4f3c michael@0: --- /dev/null michael@0: +++ b/gfx/skia/src/ports/SkFontHost_android_old.cpp michael@0: @@ -0,0 +1,664 @@ michael@0: + michael@0: +/* michael@0: + * Copyright 2006 The Android Open Source Project michael@0: + * michael@0: + * Use of this source code is governed by a BSD-style license that can be michael@0: + * found in the LICENSE file. michael@0: + */ michael@0: + michael@0: + michael@0: +#include "SkFontHost.h" michael@0: +#include "SkDescriptor.h" michael@0: +#include "SkMMapStream.h" michael@0: +#include "SkPaint.h" michael@0: +#include "SkString.h" michael@0: +#include "SkStream.h" michael@0: +#include "SkThread.h" michael@0: +#include "SkTSearch.h" michael@0: +#include michael@0: + michael@0: +#define FONT_CACHE_MEMORY_BUDGET (768 * 1024) michael@0: + michael@0: +#ifndef SK_FONT_FILE_PREFIX michael@0: + #define SK_FONT_FILE_PREFIX "/fonts/" michael@0: +#endif michael@0: + michael@0: +bool find_name_and_attributes(SkStream* stream, SkString* name, SkTypeface::Style* style, michael@0: + bool* isFixedWidth); michael@0: + michael@0: +static void GetFullPathForSysFonts(SkString* full, const char name[]) { michael@0: + full->set(getenv("ANDROID_ROOT")); michael@0: + full->append(SK_FONT_FILE_PREFIX); michael@0: + full->append(name); michael@0: +} michael@0: + michael@0: +/////////////////////////////////////////////////////////////////////////////// michael@0: + michael@0: +struct FamilyRec; michael@0: + michael@0: +/* This guy holds a mapping of a name -> family, used for looking up fonts. michael@0: + Since it is stored in a stretchy array that doesn't preserve object michael@0: + semantics, we don't use constructor/destructors, but just have explicit michael@0: + helpers to manage our internal bookkeeping. michael@0: +*/ michael@0: +struct NameFamilyPair { michael@0: + const char* fName; // we own this michael@0: + FamilyRec* fFamily; // we don't own this, we just reference it michael@0: + michael@0: + void construct(const char name[], FamilyRec* family) { michael@0: + fName = strdup(name); michael@0: + fFamily = family; // we don't own this, so just record the referene michael@0: + } michael@0: + michael@0: + void destruct() { michael@0: + free((char*)fName); michael@0: + // we don't own family, so just ignore our reference michael@0: + } michael@0: +}; michael@0: + michael@0: +// we use atomic_inc to grow this for each typeface we create michael@0: +static int32_t gUniqueFontID; michael@0: + michael@0: +// this is the mutex that protects these globals michael@0: +static SkMutex gFamilyMutex; michael@0: +static FamilyRec* gFamilyHead; michael@0: +static SkTDArray gNameList; michael@0: + michael@0: +struct FamilyRec { michael@0: + FamilyRec* fNext; michael@0: + SkTypeface* fFaces[4]; michael@0: + michael@0: + FamilyRec() michael@0: + { michael@0: + fNext = gFamilyHead; michael@0: + memset(fFaces, 0, sizeof(fFaces)); michael@0: + gFamilyHead = this; michael@0: + } michael@0: +}; michael@0: + michael@0: +static SkTypeface* find_best_face(const FamilyRec* family, michael@0: + SkTypeface::Style style) { michael@0: + SkTypeface* const* faces = family->fFaces; michael@0: + michael@0: + if (faces[style] != NULL) { // exact match michael@0: + return faces[style]; michael@0: + } michael@0: + // look for a matching bold michael@0: + style = (SkTypeface::Style)(style ^ SkTypeface::kItalic); michael@0: + if (faces[style] != NULL) { michael@0: + return faces[style]; michael@0: + } michael@0: + // look for the plain michael@0: + if (faces[SkTypeface::kNormal] != NULL) { michael@0: + return faces[SkTypeface::kNormal]; michael@0: + } michael@0: + // look for anything michael@0: + for (int i = 0; i < 4; i++) { michael@0: + if (faces[i] != NULL) { michael@0: + return faces[i]; michael@0: + } michael@0: + } michael@0: + // should never get here, since the faces list should not be empty michael@0: + SkASSERT(!"faces list is empty"); michael@0: + return NULL; michael@0: +} michael@0: + michael@0: +static FamilyRec* find_family(const SkTypeface* member) { michael@0: + FamilyRec* curr = gFamilyHead; michael@0: + while (curr != NULL) { michael@0: + for (int i = 0; i < 4; i++) { michael@0: + if (curr->fFaces[i] == member) { michael@0: + return curr; michael@0: + } michael@0: + } michael@0: + curr = curr->fNext; michael@0: + } michael@0: + return NULL; michael@0: +} michael@0: + michael@0: +/* Returns the matching typeface, or NULL. If a typeface is found, its refcnt michael@0: + is not modified. michael@0: + */ michael@0: +static SkTypeface* find_from_uniqueID(uint32_t uniqueID) { michael@0: + FamilyRec* curr = gFamilyHead; michael@0: + while (curr != NULL) { michael@0: + for (int i = 0; i < 4; i++) { michael@0: + SkTypeface* face = curr->fFaces[i]; michael@0: + if (face != NULL && face->uniqueID() == uniqueID) { michael@0: + return face; michael@0: + } michael@0: + } michael@0: + curr = curr->fNext; michael@0: + } michael@0: + return NULL; michael@0: +} michael@0: + michael@0: +/* Remove reference to this face from its family. If the resulting family michael@0: + is empty (has no faces), return that family, otherwise return NULL michael@0: +*/ michael@0: +static FamilyRec* remove_from_family(const SkTypeface* face) { michael@0: + FamilyRec* family = find_family(face); michael@0: + SkASSERT(family->fFaces[face->style()] == face); michael@0: + family->fFaces[face->style()] = NULL; michael@0: + michael@0: + for (int i = 0; i < 4; i++) { michael@0: + if (family->fFaces[i] != NULL) { // family is non-empty michael@0: + return NULL; michael@0: + } michael@0: + } michael@0: + return family; // return the empty family michael@0: +} michael@0: + michael@0: +// maybe we should make FamilyRec be doubly-linked michael@0: +static void detach_and_delete_family(FamilyRec* family) { michael@0: + FamilyRec* curr = gFamilyHead; michael@0: + FamilyRec* prev = NULL; michael@0: + michael@0: + while (curr != NULL) { michael@0: + FamilyRec* next = curr->fNext; michael@0: + if (curr == family) { michael@0: + if (prev == NULL) { michael@0: + gFamilyHead = next; michael@0: + } else { michael@0: + prev->fNext = next; michael@0: + } michael@0: + SkDELETE(family); michael@0: + return; michael@0: + } michael@0: + prev = curr; michael@0: + curr = next; michael@0: + } michael@0: + SkASSERT(!"Yikes, couldn't find family in our list to remove/delete"); michael@0: +} michael@0: + michael@0: +static SkTypeface* find_typeface(const char name[], SkTypeface::Style style) { michael@0: + NameFamilyPair* list = gNameList.begin(); michael@0: + int count = gNameList.count(); michael@0: + michael@0: + int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0])); michael@0: + michael@0: + if (index >= 0) { michael@0: + return find_best_face(list[index].fFamily, style); michael@0: + } michael@0: + return NULL; michael@0: +} michael@0: + michael@0: +static SkTypeface* find_typeface(const SkTypeface* familyMember, michael@0: + SkTypeface::Style style) { michael@0: + const FamilyRec* family = find_family(familyMember); michael@0: + return family ? find_best_face(family, style) : NULL; michael@0: +} michael@0: + michael@0: +static void add_name(const char name[], FamilyRec* family) { michael@0: + SkAutoAsciiToLC tolc(name); michael@0: + name = tolc.lc(); michael@0: + michael@0: + NameFamilyPair* list = gNameList.begin(); michael@0: + int count = gNameList.count(); michael@0: + michael@0: + int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0])); michael@0: + michael@0: + if (index < 0) { michael@0: + list = gNameList.insert(~index); michael@0: + list->construct(name, family); michael@0: + } michael@0: +} michael@0: + michael@0: +static void remove_from_names(FamilyRec* emptyFamily) michael@0: +{ michael@0: +#ifdef SK_DEBUG michael@0: + for (int i = 0; i < 4; i++) { michael@0: + SkASSERT(emptyFamily->fFaces[i] == NULL); michael@0: + } michael@0: +#endif michael@0: + michael@0: + SkTDArray& list = gNameList; michael@0: + michael@0: + // must go backwards when removing michael@0: + for (int i = list.count() - 1; i >= 0; --i) { michael@0: + NameFamilyPair* pair = &list[i]; michael@0: + if (pair->fFamily == emptyFamily) { michael@0: + pair->destruct(); michael@0: + list.remove(i); michael@0: + } michael@0: + } michael@0: +} michael@0: + michael@0: +/////////////////////////////////////////////////////////////////////////////// michael@0: + michael@0: +class FamilyTypeface : public SkTypeface { michael@0: +public: michael@0: + FamilyTypeface(Style style, bool sysFont, SkTypeface* familyMember, michael@0: + bool isFixedWidth) michael@0: + : SkTypeface(style, sk_atomic_inc(&gUniqueFontID) + 1, isFixedWidth) { michael@0: + fIsSysFont = sysFont; michael@0: + michael@0: + SkAutoMutexAcquire ac(gFamilyMutex); michael@0: + michael@0: + FamilyRec* rec = NULL; michael@0: + if (familyMember) { michael@0: + rec = find_family(familyMember); michael@0: + SkASSERT(rec); michael@0: + } else { michael@0: + rec = SkNEW(FamilyRec); michael@0: + } michael@0: + rec->fFaces[style] = this; michael@0: + } michael@0: + michael@0: + virtual ~FamilyTypeface() { michael@0: + SkAutoMutexAcquire ac(gFamilyMutex); michael@0: + michael@0: + // remove us from our family. If the family is now empty, we return michael@0: + // that and then remove that family from the name list michael@0: + FamilyRec* family = remove_from_family(this); michael@0: + if (NULL != family) { michael@0: + remove_from_names(family); michael@0: + detach_and_delete_family(family); michael@0: + } michael@0: + } michael@0: + michael@0: + bool isSysFont() const { return fIsSysFont; } michael@0: + michael@0: + virtual SkStream* openStream() = 0; michael@0: + virtual const char* getUniqueString() const = 0; michael@0: + virtual const char* getFilePath() const = 0; michael@0: + michael@0: +private: michael@0: + bool fIsSysFont; michael@0: + michael@0: + typedef SkTypeface INHERITED; michael@0: +}; michael@0: + michael@0: +/////////////////////////////////////////////////////////////////////////////// michael@0: + michael@0: +class StreamTypeface : public FamilyTypeface { michael@0: +public: michael@0: + StreamTypeface(Style style, bool sysFont, SkTypeface* familyMember, michael@0: + SkStream* stream, bool isFixedWidth) michael@0: + : INHERITED(style, sysFont, familyMember, isFixedWidth) { michael@0: + SkASSERT(stream); michael@0: + stream->ref(); michael@0: + fStream = stream; michael@0: + } michael@0: + virtual ~StreamTypeface() { michael@0: + fStream->unref(); michael@0: + } michael@0: + michael@0: + // overrides michael@0: + virtual SkStream* openStream() { michael@0: + // we just ref our existing stream, since the caller will call unref() michael@0: + // when they are through michael@0: + fStream->ref(); michael@0: + // must rewind each time, since the caller assumes a "new" stream michael@0: + fStream->rewind(); michael@0: + return fStream; michael@0: + } michael@0: + virtual const char* getUniqueString() const { return NULL; } michael@0: + virtual const char* getFilePath() const { return NULL; } michael@0: + michael@0: +private: michael@0: + SkStream* fStream; michael@0: + michael@0: + typedef FamilyTypeface INHERITED; michael@0: +}; michael@0: + michael@0: +class FileTypeface : public FamilyTypeface { michael@0: +public: michael@0: + FileTypeface(Style style, bool sysFont, SkTypeface* familyMember, michael@0: + const char path[], bool isFixedWidth) michael@0: + : INHERITED(style, sysFont, familyMember, isFixedWidth) { michael@0: + SkString fullpath; michael@0: + michael@0: + if (sysFont) { michael@0: + GetFullPathForSysFonts(&fullpath, path); michael@0: + path = fullpath.c_str(); michael@0: + } michael@0: + fPath.set(path); michael@0: + } michael@0: + michael@0: + // overrides michael@0: + virtual SkStream* openStream() { michael@0: + SkStream* stream = SkNEW_ARGS(SkMMAPStream, (fPath.c_str())); michael@0: + michael@0: + // check for failure michael@0: + if (stream->getLength() <= 0) { michael@0: + SkDELETE(stream); michael@0: + // maybe MMAP isn't supported. try FILE michael@0: + stream = SkNEW_ARGS(SkFILEStream, (fPath.c_str())); michael@0: + if (stream->getLength() <= 0) { michael@0: + SkDELETE(stream); michael@0: + stream = NULL; michael@0: + } michael@0: + } michael@0: + return stream; michael@0: + } michael@0: + virtual const char* getUniqueString() const { michael@0: + const char* str = strrchr(fPath.c_str(), '/'); michael@0: + if (str) { michael@0: + str += 1; // skip the '/' michael@0: + } michael@0: + return str; michael@0: + } michael@0: + virtual const char* getFilePath() const { michael@0: + return fPath.c_str(); michael@0: + } michael@0: + michael@0: +private: michael@0: + SkString fPath; michael@0: + michael@0: + typedef FamilyTypeface INHERITED; michael@0: +}; michael@0: + michael@0: +/////////////////////////////////////////////////////////////////////////////// michael@0: +/////////////////////////////////////////////////////////////////////////////// michael@0: + michael@0: +static bool get_name_and_style(const char path[], SkString* name, michael@0: + SkTypeface::Style* style, michael@0: + bool* isFixedWidth, bool isExpected) { michael@0: + SkString fullpath; michael@0: + GetFullPathForSysFonts(&fullpath, path); michael@0: + michael@0: + SkMMAPStream stream(fullpath.c_str()); michael@0: + if (stream.getLength() > 0) { michael@0: + find_name_and_attributes(&stream, name, style, isFixedWidth); michael@0: + return true; michael@0: + } michael@0: + else { michael@0: + SkFILEStream stream(fullpath.c_str()); michael@0: + if (stream.getLength() > 0) { michael@0: + find_name_and_attributes(&stream, name, style, isFixedWidth); michael@0: + return true; michael@0: + } michael@0: + } michael@0: + michael@0: + if (isExpected) { michael@0: + SkDebugf("---- failed to open <%s> as a font\n", fullpath.c_str()); michael@0: + } michael@0: + return false; michael@0: +} michael@0: + michael@0: +// used to record our notion of the pre-existing fonts michael@0: +struct FontInitRec { michael@0: + const char* fFileName; michael@0: + const char* const* fNames; // null-terminated list michael@0: +}; michael@0: + michael@0: +static const char* gSansNames[] = { michael@0: + "sans-serif", "arial", "helvetica", "tahoma", "verdana", NULL michael@0: +}; michael@0: + michael@0: +static const char* gSerifNames[] = { michael@0: + "serif", "times", "times new roman", "palatino", "georgia", "baskerville", michael@0: + "goudy", "fantasy", "cursive", "ITC Stone Serif", NULL michael@0: +}; michael@0: + michael@0: +static const char* gMonoNames[] = { michael@0: + "monospace", "courier", "courier new", "monaco", NULL michael@0: +}; michael@0: + michael@0: +// deliberately empty, but we use the address to identify fallback fonts michael@0: +static const char* gFBNames[] = { NULL }; michael@0: + michael@0: +/* Fonts must be grouped by family, with the first font in a family having the michael@0: + list of names (even if that list is empty), and the following members having michael@0: + null for the list. The names list must be NULL-terminated michael@0: +*/ michael@0: +static const FontInitRec gSystemFonts[] = { michael@0: + { "DroidSans.ttf", gSansNames }, michael@0: + { "DroidSans-Bold.ttf", NULL }, michael@0: + { "DroidSerif-Regular.ttf", gSerifNames }, michael@0: + { "DroidSerif-Bold.ttf", NULL }, michael@0: + { "DroidSerif-Italic.ttf", NULL }, michael@0: + { "DroidSerif-BoldItalic.ttf", NULL }, michael@0: + { "DroidSansMono.ttf", gMonoNames }, michael@0: + /* These are optional, and can be ignored if not found in the file system. michael@0: + These are appended to gFallbackFonts[] as they are seen, so we list michael@0: + them in the order we want them to be accessed by NextLogicalFont(). michael@0: + */ michael@0: + { "DroidSansArabic.ttf", gFBNames }, michael@0: + { "DroidSansHebrew.ttf", gFBNames }, michael@0: + { "DroidSansThai.ttf", gFBNames }, michael@0: + { "MTLmr3m.ttf", gFBNames }, // Motoya Japanese Font michael@0: + { "MTLc3m.ttf", gFBNames }, // Motoya Japanese Font michael@0: + { "DroidSansJapanese.ttf", gFBNames }, michael@0: + { "DroidSansFallback.ttf", gFBNames } michael@0: +}; michael@0: + michael@0: +#define DEFAULT_NAMES gSansNames michael@0: + michael@0: +// these globals are assigned (once) by load_system_fonts() michael@0: +static FamilyRec* gDefaultFamily; michael@0: +static SkTypeface* gDefaultNormal; michael@0: + michael@0: +/* This is sized conservatively, assuming that it will never be a size issue. michael@0: + It will be initialized in load_system_fonts(), and will be filled with the michael@0: + fontIDs that can be used for fallback consideration, in sorted order (sorted michael@0: + meaning element[0] should be used first, then element[1], etc. When we hit michael@0: + a fontID==0 in the array, the list is done, hence our allocation size is michael@0: + +1 the total number of possible system fonts. Also see NextLogicalFont(). michael@0: + */ michael@0: +static uint32_t gFallbackFonts[SK_ARRAY_COUNT(gSystemFonts)+1]; michael@0: + michael@0: +/* Called once (ensured by the sentinel check at the beginning of our body). michael@0: + Initializes all the globals, and register the system fonts. michael@0: + */ michael@0: +static void load_system_fonts() { michael@0: + // check if we've already be called michael@0: + if (NULL != gDefaultNormal) { michael@0: + return; michael@0: + } michael@0: + michael@0: + const FontInitRec* rec = gSystemFonts; michael@0: + SkTypeface* firstInFamily = NULL; michael@0: + int fallbackCount = 0; michael@0: + michael@0: + for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) { michael@0: + // if we're the first in a new family, clear firstInFamily michael@0: + if (rec[i].fNames != NULL) { michael@0: + firstInFamily = NULL; michael@0: + } michael@0: + michael@0: + bool isFixedWidth; michael@0: + SkString name; michael@0: + SkTypeface::Style style; michael@0: + michael@0: + // we expect all the fonts, except the "fallback" fonts michael@0: + bool isExpected = (rec[i].fNames != gFBNames); michael@0: + if (!get_name_and_style(rec[i].fFileName, &name, &style, michael@0: + &isFixedWidth, isExpected)) { michael@0: + continue; michael@0: + } michael@0: + michael@0: + SkTypeface* tf = SkNEW_ARGS(FileTypeface, michael@0: + (style, michael@0: + true, // system-font (cannot delete) michael@0: + firstInFamily, // what family to join michael@0: + rec[i].fFileName, michael@0: + isFixedWidth) // filename michael@0: + ); michael@0: + michael@0: + if (rec[i].fNames != NULL) { michael@0: + // see if this is one of our fallback fonts michael@0: + if (rec[i].fNames == gFBNames) { michael@0: + // SkDebugf("---- adding %s as fallback[%d] fontID %d\n", michael@0: + // rec[i].fFileName, fallbackCount, tf->uniqueID()); michael@0: + gFallbackFonts[fallbackCount++] = tf->uniqueID(); michael@0: + } michael@0: + michael@0: + firstInFamily = tf; michael@0: + FamilyRec* family = find_family(tf); michael@0: + const char* const* names = rec[i].fNames; michael@0: + michael@0: + // record the default family if this is it michael@0: + if (names == DEFAULT_NAMES) { michael@0: + gDefaultFamily = family; michael@0: + } michael@0: + // add the names to map to this family michael@0: + while (*names) { michael@0: + add_name(*names, family); michael@0: + names += 1; michael@0: + } michael@0: + } michael@0: + } michael@0: + michael@0: + // do this after all fonts are loaded. This is our default font, and it michael@0: + // acts as a sentinel so we only execute load_system_fonts() once michael@0: + gDefaultNormal = find_best_face(gDefaultFamily, SkTypeface::kNormal); michael@0: + // now terminate our fallback list with the sentinel value michael@0: + gFallbackFonts[fallbackCount] = 0; michael@0: +} michael@0: + michael@0: +/////////////////////////////////////////////////////////////////////////////// michael@0: + michael@0: +void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) { michael@0: + const char* name = ((FamilyTypeface*)face)->getUniqueString(); michael@0: + michael@0: + stream->write8((uint8_t)face->style()); michael@0: + michael@0: + if (NULL == name || 0 == *name) { michael@0: + stream->writePackedUInt(0); michael@0: +// SkDebugf("--- fonthost serialize null\n"); michael@0: + } else { michael@0: + uint32_t len = strlen(name); michael@0: + stream->writePackedUInt(len); michael@0: + stream->write(name, len); michael@0: +// SkDebugf("--- fonthost serialize <%s> %d\n", name, face->style()); michael@0: + } michael@0: +} michael@0: + michael@0: +SkTypeface* SkFontHost::Deserialize(SkStream* stream) { michael@0: + load_system_fonts(); michael@0: + michael@0: + int style = stream->readU8(); michael@0: + michael@0: + int len = stream->readPackedUInt(); michael@0: + if (len > 0) { michael@0: + SkString str; michael@0: + str.resize(len); michael@0: + stream->read(str.writable_str(), len); michael@0: + michael@0: + const FontInitRec* rec = gSystemFonts; michael@0: + for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) { michael@0: + if (strcmp(rec[i].fFileName, str.c_str()) == 0) { michael@0: + // backup until we hit the fNames michael@0: + for (int j = i; j >= 0; --j) { michael@0: + if (rec[j].fNames != NULL) { michael@0: + return SkFontHost::CreateTypeface(NULL, michael@0: + rec[j].fNames[0], (SkTypeface::Style)style); michael@0: + } michael@0: + } michael@0: + } michael@0: + } michael@0: + } michael@0: + return NULL; michael@0: +} michael@0: + michael@0: +/////////////////////////////////////////////////////////////////////////////// michael@0: + michael@0: +SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, michael@0: + const char familyName[], michael@0: + SkTypeface::Style style) { michael@0: + load_system_fonts(); michael@0: + michael@0: + SkAutoMutexAcquire ac(gFamilyMutex); michael@0: + michael@0: + // clip to legal style bits michael@0: + style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic); michael@0: + michael@0: + SkTypeface* tf = NULL; michael@0: + michael@0: + if (NULL != familyFace) { michael@0: + tf = find_typeface(familyFace, style); michael@0: + } else if (NULL != familyName) { michael@0: +// SkDebugf("======= familyName <%s>\n", familyName); michael@0: + tf = find_typeface(familyName, style); michael@0: + } michael@0: + michael@0: + if (NULL == tf) { michael@0: + tf = find_best_face(gDefaultFamily, style); michael@0: + } michael@0: + michael@0: + // we ref(), since the symantic is to return a new instance michael@0: + tf->ref(); michael@0: + return tf; michael@0: +} michael@0: + michael@0: +SkStream* SkFontHost::OpenStream(uint32_t fontID) { michael@0: + SkAutoMutexAcquire ac(gFamilyMutex); michael@0: + michael@0: + FamilyTypeface* tf = (FamilyTypeface*)find_from_uniqueID(fontID); michael@0: + SkStream* stream = tf ? tf->openStream() : NULL; michael@0: + michael@0: + if (stream && stream->getLength() == 0) { michael@0: + stream->unref(); michael@0: + stream = NULL; michael@0: + } michael@0: + return stream; michael@0: +} michael@0: + michael@0: +size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length, michael@0: + int32_t* index) { michael@0: + SkAutoMutexAcquire ac(gFamilyMutex); michael@0: + michael@0: + FamilyTypeface* tf = (FamilyTypeface*)find_from_uniqueID(fontID); michael@0: + const char* src = tf ? tf->getFilePath() : NULL; michael@0: + michael@0: + if (src) { michael@0: + size_t size = strlen(src); michael@0: + if (path) { michael@0: + memcpy(path, src, SkMin32(size, length)); michael@0: + } michael@0: + if (index) { michael@0: + *index = 0; // we don't have collections (yet) michael@0: + } michael@0: + return size; michael@0: + } else { michael@0: + return 0; michael@0: + } michael@0: +} michael@0: + michael@0: +SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) { michael@0: + load_system_fonts(); michael@0: + michael@0: + /* First see if fontID is already one of our fallbacks. If so, return michael@0: + its successor. If fontID is not in our list, then return the first one michael@0: + in our list. Note: list is zero-terminated, and returning zero means michael@0: + we have no more fonts to use for fallbacks. michael@0: + */ michael@0: + const uint32_t* list = gFallbackFonts; michael@0: + for (int i = 0; list[i] != 0; i++) { michael@0: + if (list[i] == currFontID) { michael@0: + return list[i+1]; michael@0: + } michael@0: + } michael@0: + return list[0]; michael@0: +} michael@0: + michael@0: +/////////////////////////////////////////////////////////////////////////////// michael@0: + michael@0: +SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) { michael@0: + if (NULL == stream || stream->getLength() <= 0) { michael@0: + return NULL; michael@0: + } michael@0: + michael@0: + bool isFixedWidth; michael@0: + SkString name; michael@0: + SkTypeface::Style style; michael@0: + find_name_and_attributes(stream, &name, &style, &isFixedWidth); michael@0: + michael@0: + if (!name.isEmpty()) { michael@0: + return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream, isFixedWidth)); michael@0: + } else { michael@0: + return NULL; michael@0: + } michael@0: +} michael@0: + michael@0: +SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) { michael@0: + SkStream* stream = SkNEW_ARGS(SkMMAPStream, (path)); michael@0: + SkTypeface* face = SkFontHost::CreateTypefaceFromStream(stream); michael@0: + // since we created the stream, we let go of our ref() here michael@0: + stream->unref(); michael@0: + return face; michael@0: +} michael@0: + michael@0: +/////////////////////////////////////////////////////////////////////////////// michael@0: -- michael@0: 1.7.11.4 michael@0: