diff --git a/src/ports/SkFontHost_simple.cpp b/src/ports/SkFontHost_simple.cpp deleted file mode 100644 index c1208d04e4..0000000000 --- a/src/ports/SkFontHost_simple.cpp +++ /dev/null @@ -1,598 +0,0 @@ - -/* - * Copyright 2011 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkFontHost.h" -#include "SkDescriptor.h" -#include "SkPaint.h" -#include "SkString.h" -#include "SkStream.h" -#include "SkThread.h" -#include "SkTSearch.h" -#include - -#ifdef SK_BUILD_FOR_MAC - #define SK_FONT_FILE_PREFIX "/Library/Fonts/" -#else - #define SK_FONT_FILE_PREFIX "/skimages/" -#endif - -bool find_name_and_attributes(SkStream* stream, SkString* name, - SkTypeface::Style* style, bool* isFixedWidth); - -static void GetFullPathForSysFonts(SkString* full, const char name[]) { - full->set(SK_FONT_FILE_PREFIX); - full->append(name); -} - -/////////////////////////////////////////////////////////////////////////////// - -struct FamilyRec; - -/* This guy holds a mapping of a name -> family, used for looking up fonts. - Since it is stored in a stretchy array that doesn't preserve object - semantics, we don't use constructor/destructors, but just have explicit - helpers to manage our internal bookkeeping. -*/ -struct NameFamilyPair { - const char* fName; // we own this - FamilyRec* fFamily; // we don't own this, we just reference it - - void construct(const char name[], FamilyRec* family) { - fName = strdup(name); - fFamily = family; // we don't own this, so just record the referene - } - - void destruct() { - free((char*)fName); - // we don't own family, so just ignore our reference - } -}; - -// we use atomic_inc to grow this for each typeface we create -static int32_t gUniqueFontID; - -// this is the mutex that protects these globals -SK_DECLARE_STATIC_MUTEX(gFamilyMutex); -static FamilyRec* gFamilyHead; -static SkTDArray gNameList; - -struct FamilyRec { - FamilyRec* fNext; - SkTypeface* fFaces[4]; - - FamilyRec() - { - fNext = gFamilyHead; - memset(fFaces, 0, sizeof(fFaces)); - gFamilyHead = this; - } -}; - -static SkTypeface* find_best_face(const FamilyRec* family, - SkTypeface::Style style) { - SkTypeface* const* faces = family->fFaces; - - if (faces[style] != NULL) { // exact match - return faces[style]; - } - // look for a matching bold - style = (SkTypeface::Style)(style ^ SkTypeface::kItalic); - if (faces[style] != NULL) { - return faces[style]; - } - // look for the plain - if (faces[SkTypeface::kNormal] != NULL) { - return faces[SkTypeface::kNormal]; - } - // look for anything - for (int i = 0; i < 4; i++) { - if (faces[i] != NULL) { - return faces[i]; - } - } - // should never get here, since the faces list should not be empty - SkDEBUGFAIL("faces list is empty"); - return NULL; -} - -static FamilyRec* find_family(const SkTypeface* member) { - FamilyRec* curr = gFamilyHead; - while (curr != NULL) { - for (int i = 0; i < 4; i++) { - if (curr->fFaces[i] == member) { - return curr; - } - } - curr = curr->fNext; - } - return NULL; -} - -/* Returns the matching typeface, or NULL. If a typeface is found, its refcnt - is not modified. - */ -static SkTypeface* find_from_uniqueID(uint32_t uniqueID) { - FamilyRec* curr = gFamilyHead; - while (curr != NULL) { - for (int i = 0; i < 4; i++) { - SkTypeface* face = curr->fFaces[i]; - if (face != NULL && face->uniqueID() == uniqueID) { - return face; - } - } - curr = curr->fNext; - } - return NULL; -} - -/* Remove reference to this face from its family. If the resulting family - is empty (has no faces), return that family, otherwise return NULL -*/ -static FamilyRec* remove_from_family(const SkTypeface* face) { - FamilyRec* family = find_family(face); - SkASSERT(family->fFaces[face->style()] == face); - family->fFaces[face->style()] = NULL; - - for (int i = 0; i < 4; i++) { - if (family->fFaces[i] != NULL) { // family is non-empty - return NULL; - } - } - return family; // return the empty family -} - -// maybe we should make FamilyRec be doubly-linked -static void detach_and_delete_family(FamilyRec* family) { - FamilyRec* curr = gFamilyHead; - FamilyRec* prev = NULL; - - while (curr != NULL) { - FamilyRec* next = curr->fNext; - if (curr == family) { - if (prev == NULL) { - gFamilyHead = next; - } else { - prev->fNext = next; - } - SkDELETE(family); - return; - } - prev = curr; - curr = next; - } - SkDEBUGFAIL("Yikes, couldn't find family in our list to remove/delete"); -} - -static SkTypeface* find_typeface(const char name[], SkTypeface::Style style) { - NameFamilyPair* list = gNameList.begin(); - int count = gNameList.count(); - - int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0])); - - if (index >= 0) { - return find_best_face(list[index].fFamily, style); - } - return NULL; -} - -static SkTypeface* find_typeface(const SkTypeface* familyMember, - SkTypeface::Style style) { - const FamilyRec* family = find_family(familyMember); - return family ? find_best_face(family, style) : NULL; -} - -static void add_name(const char name[], FamilyRec* family) { - SkAutoAsciiToLC tolc(name); - name = tolc.lc(); - - NameFamilyPair* list = gNameList.begin(); - int count = gNameList.count(); - - int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0])); - - if (index < 0) { - list = gNameList.insert(~index); - list->construct(name, family); - } -} - -static void remove_from_names(FamilyRec* emptyFamily) -{ -#ifdef SK_DEBUG - for (int i = 0; i < 4; i++) { - SkASSERT(emptyFamily->fFaces[i] == NULL); - } -#endif - - SkTDArray& list = gNameList; - - // must go backwards when removing - for (int i = list.count() - 1; i >= 0; --i) { - NameFamilyPair* pair = &list[i]; - if (pair->fFamily == emptyFamily) { - pair->destruct(); - list.remove(i); - } - } -} - -/////////////////////////////////////////////////////////////////////////////// - -class FamilyTypeface : public SkTypeface { -public: - FamilyTypeface(Style style, bool sysFont, SkTypeface* familyMember) - : SkTypeface(style, sk_atomic_inc(&gUniqueFontID) + 1) { - fIsSysFont = sysFont; - - SkAutoMutexAcquire ac(gFamilyMutex); - - FamilyRec* rec = NULL; - if (familyMember) { - rec = find_family(familyMember); - SkASSERT(rec); - } else { - rec = SkNEW(FamilyRec); - } - rec->fFaces[style] = this; - } - - virtual ~FamilyTypeface() { - SkAutoMutexAcquire ac(gFamilyMutex); - - // remove us from our family. If the family is now empty, we return - // that and then remove that family from the name list - FamilyRec* family = remove_from_family(this); - if (NULL != family) { - remove_from_names(family); - detach_and_delete_family(family); - } - } - - bool isSysFont() const { return fIsSysFont; } - - virtual SkStream* openStream() = 0; - virtual const char* getUniqueString() const = 0; - virtual const char* getFilePath() const = 0; - -protected: - virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics( - SkAdvancedTypefaceMetrics::PerGlyphInfo, - const uint32_t*, - uint32_t) const SK_OVERRIDE { - return NULL; - } - -private: - bool fIsSysFont; - - typedef SkTypeface INHERITED; -}; - -/////////////////////////////////////////////////////////////////////////////// - -class StreamTypeface : public FamilyTypeface { -public: - StreamTypeface(Style style, bool sysFont, SkTypeface* familyMember, - SkStream* stream) - : INHERITED(style, sysFont, familyMember) { - SkASSERT(stream); - stream->ref(); - fStream = stream; - } - virtual ~StreamTypeface() { - fStream->unref(); - } - - // overrides - virtual SkStream* openStream() { - // we just ref our existing stream, since the caller will call unref() - // when they are through - fStream->ref(); - return fStream; - } - virtual const char* getUniqueString() const { return NULL; } - virtual const char* getFilePath() const { return NULL; } - -private: - SkStream* fStream; - - typedef FamilyTypeface INHERITED; -}; - -class FileTypeface : public FamilyTypeface { -public: - FileTypeface(Style style, bool sysFont, SkTypeface* familyMember, - const char path[]) - : INHERITED(style, sysFont, familyMember) { - SkString fullpath; - - if (sysFont) { - GetFullPathForSysFonts(&fullpath, path); - path = fullpath.c_str(); - } - fPath.set(path); - } - - virtual SkStream* openStream() SK_OVERRIDE { - return SkStream::NewFromFile(fPath.c_str()); - } - - virtual const char* getUniqueString() const SK_OVERRIDE { - const char* str = strrchr(fPath.c_str(), '/'); - if (str) { - str += 1; // skip the '/' - } - return str; - } - virtual const char* getFilePath() const SK_OVERRIDE { - return fPath.c_str(); - } - -private: - SkString fPath; - - typedef FamilyTypeface INHERITED; -}; - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -static bool get_name_and_style(const char path[], SkString* name, - SkTypeface::Style* style, bool isExpected) { - SkString fullpath; - GetFullPathForSysFonts(&fullpath, path); - - SkAutoTUnref stream(SkStream::NewFromFile(fullpath.c_str())); - if (stream.get()) { - return find_name_and_attributes(&stream, name, style, NULL); - } else { - if (isExpected) { - SkDebugf("---- failed to open <%s> as a font\n", fullpath.c_str()); - } - return false; - } -} - -// used to record our notion of the pre-existing fonts -struct FontInitRec { - const char* fFileName; - const char* const* fNames; // null-terminated list -}; - -static const char* gSansNames[] = { - "sans-serif", "arial", "helvetica", "tahoma", "verdana", NULL -}; - -static const char* gSerifNames[] = { - "serif", "times", "times new roman", "palatino", "georgia", "baskerville", - "goudy", "fantasy", "cursive", "ITC Stone Serif", NULL -}; - -static const char* gMonoNames[] = { - "monospace", "courier", "courier new", "monaco", NULL -}; - -// deliberately empty, but we use the address to identify fallback fonts -static const char* gFBNames[] = { NULL }; - -/* Fonts must be grouped by family, with the first font in a family having the - list of names (even if that list is empty), and the following members having - null for the list. The names list must be NULL-terminated -*/ -static const FontInitRec gSystemFonts[] = { - { "Arial.ttf", gSansNames }, - { "Times.ttf", gSerifNames }, - { "samplefont.ttf", gSansNames }, -}; - -#define DEFAULT_NAMES gSansNames - -// these globals are assigned (once) by load_system_fonts() -static FamilyRec* gDefaultFamily; -static SkTypeface* gDefaultNormal; - -/* This is sized conservatively, assuming that it will never be a size issue. - It will be initialized in load_system_fonts(), and will be filled with the - fontIDs that can be used for fallback consideration, in sorted order (sorted - meaning element[0] should be used first, then element[1], etc. When we hit - a fontID==0 in the array, the list is done, hence our allocation size is - +1 the total number of possible system fonts. Also see NextLogicalTypeface(). - */ -static uint32_t gFallbackFonts[SK_ARRAY_COUNT(gSystemFonts)+1]; - -/* Called once (ensured by the sentinel check at the beginning of our body). - Initializes all the globals, and register the system fonts. - */ -static void load_system_fonts() { - // check if we've already be called - if (NULL != gDefaultNormal) { - return; - } - - const FontInitRec* rec = gSystemFonts; - SkTypeface* firstInFamily = NULL; - int fallbackCount = 0; - - for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) { - // if we're the first in a new family, clear firstInFamily - if (rec[i].fNames != NULL) { - firstInFamily = NULL; - } - - SkString name; - SkTypeface::Style style; - - // we expect all the fonts, except the "fallback" fonts - bool isExpected = (rec[i].fNames != gFBNames); - if (!get_name_and_style(rec[i].fFileName, &name, &style, isExpected)) { - continue; - } - - SkTypeface* tf = SkNEW_ARGS(FileTypeface, - (style, - true, // system-font (cannot delete) - firstInFamily, // what family to join - rec[i].fFileName) // filename - ); - - if (rec[i].fNames != NULL) { - // see if this is one of our fallback fonts - if (rec[i].fNames == gFBNames) { - // SkDebugf("---- adding %s as fallback[%d] fontID %d\n", - // rec[i].fFileName, fallbackCount, tf->uniqueID()); - gFallbackFonts[fallbackCount++] = tf->uniqueID(); - } - - firstInFamily = tf; - FamilyRec* family = find_family(tf); - const char* const* names = rec[i].fNames; - - // record the default family if this is it - if (names == DEFAULT_NAMES) { - gDefaultFamily = family; - } - // add the names to map to this family - while (*names) { - add_name(*names, family); - names += 1; - } - } - } - - // do this after all fonts are loaded. This is our default font, and it - // acts as a sentinel so we only execute load_system_fonts() once - gDefaultNormal = find_best_face(gDefaultFamily, SkTypeface::kNormal); - // now terminate our fallback list with the sentinel value - gFallbackFonts[fallbackCount] = 0; -} - -/////////////////////////////////////////////////////////////////////////////// - -void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) { - const char* name = ((FamilyTypeface*)face)->getUniqueString(); - - stream->write8((uint8_t)face->style()); - - if (NULL == name || 0 == *name) { - stream->writePackedUInt(0); -// SkDebugf("--- fonthost serialize null\n"); - } else { - uint32_t len = strlen(name); - stream->writePackedUInt(len); - stream->write(name, len); -// SkDebugf("--- fonthost serialize <%s> %d\n", name, face->style()); - } -} - -SkTypeface* SkFontHost::Deserialize(SkStream* stream) { - load_system_fonts(); - - int style = stream->readU8(); - - int len = stream->readPackedUInt(); - if (len > 0) { - SkString str; - str.resize(len); - stream->read(str.writable_str(), len); - - const FontInitRec* rec = gSystemFonts; - for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) { - if (strcmp(rec[i].fFileName, str.c_str()) == 0) { - // backup until we hit the fNames - for (int j = i; j >= 0; --j) { - if (rec[j].fNames != NULL) { - return SkFontHost::CreateTypeface(NULL, - rec[j].fNames[0], (SkTypeface::Style)style); - } - } - } - } - } - return NULL; -} - -/////////////////////////////////////////////////////////////////////////////// - -SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, - const char familyName[], - SkTypeface::Style style) { - load_system_fonts(); - - SkAutoMutexAcquire ac(gFamilyMutex); - - // clip to legal style bits - style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic); - - SkTypeface* tf = NULL; - - if (NULL != familyFace) { - tf = find_typeface(familyFace, style); - } else if (NULL != familyName) { -// SkDebugf("======= familyName <%s>\n", familyName); - tf = find_typeface(familyName, style); - } - - if (NULL == tf) { - tf = find_best_face(gDefaultFamily, style); - } - - // we ref(), since the symantic is to return a new instance - tf->ref(); - return tf; -} - -SkStream* SkFontHost::OpenStream(uint32_t fontID) { - SkAutoMutexAcquire ac(gFamilyMutex); - - FamilyTypeface* tf = (FamilyTypeface*)find_from_uniqueID(fontID); - SkStream* stream = tf ? tf->openStream() : NULL; - - if (stream && stream->getLength() == 0) { - stream->unref(); - stream = NULL; - } - return stream; -} - -SkTypeface* SkFontHost::NextLogicalTypeface(SkFontID currFontID, SkFontID origFontID) { - load_system_fonts(); - - /* First see if fontID is already one of our fallbacks. If so, return - its successor. If fontID is not in our list, then return the first one - in our list. Note: list is zero-terminated, and returning zero means - we have no more fonts to use for fallbacks. - */ - const uint32_t* list = gFallbackFonts; - for (int i = 0; list[i] != 0; i++) { - if (list[i] == currFontID) { - return SkSafeRef(find_from_uniqueID(list[i+1])); - } - } - return SkSafeRef(list[0]); -} - -/////////////////////////////////////////////////////////////////////////////// - -SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) { - if (NULL == stream || stream->getLength() <= 0) { - return NULL; - } - - SkTypeface::Style style; - if (find_name_and_attributes(stream, NULL, &style, NULL)) { - return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream)); - } else { - return NULL; - } -} - -SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) { - SkAutoTUnref stream(SkStream::NewFromFile(path)); - return stream.get() ? SkFontHost::CreateTypefaceFromStream(stream) : NULL; -}