mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-05 16:46:26 +00:00
685 lines
22 KiB
Diff
685 lines
22 KiB
Diff
From 0d730a94e9f6676d5cde45f955fe025a4549817e Mon Sep 17 00:00:00 2001
|
|
From: George Wright <gw@gwright.org.uk>
|
|
Date: Thu, 23 Aug 2012 16:45:38 -0400
|
|
Subject: [PATCH 4/9] Bug 777614 - Re-apply bug 719872 - Fix crash on Android
|
|
by reverting to older FontHost r=nrc
|
|
|
|
---
|
|
gfx/skia/src/ports/SkFontHost_android_old.cpp | 664 ++++++++++++++++++++++++++
|
|
1 file changed, 664 insertions(+)
|
|
create mode 100644 gfx/skia/src/ports/SkFontHost_android_old.cpp
|
|
|
|
diff --git a/gfx/skia/src/ports/SkFontHost_android_old.cpp b/gfx/skia/src/ports/SkFontHost_android_old.cpp
|
|
new file mode 100644
|
|
index 0000000..b5c4f3c
|
|
--- /dev/null
|
|
+++ b/gfx/skia/src/ports/SkFontHost_android_old.cpp
|
|
@@ -0,0 +1,664 @@
|
|
+
|
|
+/*
|
|
+ * Copyright 2006 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 "SkMMapStream.h"
|
|
+#include "SkPaint.h"
|
|
+#include "SkString.h"
|
|
+#include "SkStream.h"
|
|
+#include "SkThread.h"
|
|
+#include "SkTSearch.h"
|
|
+#include <stdio.h>
|
|
+
|
|
+#define FONT_CACHE_MEMORY_BUDGET (768 * 1024)
|
|
+
|
|
+#ifndef SK_FONT_FILE_PREFIX
|
|
+ #define SK_FONT_FILE_PREFIX "/fonts/"
|
|
+#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(getenv("ANDROID_ROOT"));
|
|
+ full->append(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
|
|
+static SkMutex gFamilyMutex;
|
|
+static FamilyRec* gFamilyHead;
|
|
+static SkTDArray<NameFamilyPair> 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
|
|
+ SkASSERT(!"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;
|
|
+ }
|
|
+ SkASSERT(!"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<NameFamilyPair>& 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,
|
|
+ bool isFixedWidth)
|
|
+ : SkTypeface(style, sk_atomic_inc(&gUniqueFontID) + 1, isFixedWidth) {
|
|
+ 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;
|
|
+
|
|
+private:
|
|
+ bool fIsSysFont;
|
|
+
|
|
+ typedef SkTypeface INHERITED;
|
|
+};
|
|
+
|
|
+///////////////////////////////////////////////////////////////////////////////
|
|
+
|
|
+class StreamTypeface : public FamilyTypeface {
|
|
+public:
|
|
+ StreamTypeface(Style style, bool sysFont, SkTypeface* familyMember,
|
|
+ SkStream* stream, bool isFixedWidth)
|
|
+ : INHERITED(style, sysFont, familyMember, isFixedWidth) {
|
|
+ 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();
|
|
+ // must rewind each time, since the caller assumes a "new" stream
|
|
+ fStream->rewind();
|
|
+ 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[], bool isFixedWidth)
|
|
+ : INHERITED(style, sysFont, familyMember, isFixedWidth) {
|
|
+ SkString fullpath;
|
|
+
|
|
+ if (sysFont) {
|
|
+ GetFullPathForSysFonts(&fullpath, path);
|
|
+ path = fullpath.c_str();
|
|
+ }
|
|
+ fPath.set(path);
|
|
+ }
|
|
+
|
|
+ // overrides
|
|
+ virtual SkStream* openStream() {
|
|
+ SkStream* stream = SkNEW_ARGS(SkMMAPStream, (fPath.c_str()));
|
|
+
|
|
+ // check for failure
|
|
+ if (stream->getLength() <= 0) {
|
|
+ SkDELETE(stream);
|
|
+ // maybe MMAP isn't supported. try FILE
|
|
+ stream = SkNEW_ARGS(SkFILEStream, (fPath.c_str()));
|
|
+ if (stream->getLength() <= 0) {
|
|
+ SkDELETE(stream);
|
|
+ stream = NULL;
|
|
+ }
|
|
+ }
|
|
+ return stream;
|
|
+ }
|
|
+ virtual const char* getUniqueString() const {
|
|
+ const char* str = strrchr(fPath.c_str(), '/');
|
|
+ if (str) {
|
|
+ str += 1; // skip the '/'
|
|
+ }
|
|
+ return str;
|
|
+ }
|
|
+ virtual const char* getFilePath() const {
|
|
+ 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* isFixedWidth, bool isExpected) {
|
|
+ SkString fullpath;
|
|
+ GetFullPathForSysFonts(&fullpath, path);
|
|
+
|
|
+ SkMMAPStream stream(fullpath.c_str());
|
|
+ if (stream.getLength() > 0) {
|
|
+ find_name_and_attributes(&stream, name, style, isFixedWidth);
|
|
+ return true;
|
|
+ }
|
|
+ else {
|
|
+ SkFILEStream stream(fullpath.c_str());
|
|
+ if (stream.getLength() > 0) {
|
|
+ find_name_and_attributes(&stream, name, style, isFixedWidth);
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ 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[] = {
|
|
+ { "DroidSans.ttf", gSansNames },
|
|
+ { "DroidSans-Bold.ttf", NULL },
|
|
+ { "DroidSerif-Regular.ttf", gSerifNames },
|
|
+ { "DroidSerif-Bold.ttf", NULL },
|
|
+ { "DroidSerif-Italic.ttf", NULL },
|
|
+ { "DroidSerif-BoldItalic.ttf", NULL },
|
|
+ { "DroidSansMono.ttf", gMonoNames },
|
|
+ /* These are optional, and can be ignored if not found in the file system.
|
|
+ These are appended to gFallbackFonts[] as they are seen, so we list
|
|
+ them in the order we want them to be accessed by NextLogicalFont().
|
|
+ */
|
|
+ { "DroidSansArabic.ttf", gFBNames },
|
|
+ { "DroidSansHebrew.ttf", gFBNames },
|
|
+ { "DroidSansThai.ttf", gFBNames },
|
|
+ { "MTLmr3m.ttf", gFBNames }, // Motoya Japanese Font
|
|
+ { "MTLc3m.ttf", gFBNames }, // Motoya Japanese Font
|
|
+ { "DroidSansJapanese.ttf", gFBNames },
|
|
+ { "DroidSansFallback.ttf", gFBNames }
|
|
+};
|
|
+
|
|
+#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 NextLogicalFont().
|
|
+ */
|
|
+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;
|
|
+ }
|
|
+
|
|
+ bool isFixedWidth;
|
|
+ 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,
|
|
+ &isFixedWidth, isExpected)) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ SkTypeface* tf = SkNEW_ARGS(FileTypeface,
|
|
+ (style,
|
|
+ true, // system-font (cannot delete)
|
|
+ firstInFamily, // what family to join
|
|
+ rec[i].fFileName,
|
|
+ isFixedWidth) // 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;
|
|
+}
|
|
+
|
|
+size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
|
|
+ int32_t* index) {
|
|
+ SkAutoMutexAcquire ac(gFamilyMutex);
|
|
+
|
|
+ FamilyTypeface* tf = (FamilyTypeface*)find_from_uniqueID(fontID);
|
|
+ const char* src = tf ? tf->getFilePath() : NULL;
|
|
+
|
|
+ if (src) {
|
|
+ size_t size = strlen(src);
|
|
+ if (path) {
|
|
+ memcpy(path, src, SkMin32(size, length));
|
|
+ }
|
|
+ if (index) {
|
|
+ *index = 0; // we don't have collections (yet)
|
|
+ }
|
|
+ return size;
|
|
+ } else {
|
|
+ return 0;
|
|
+ }
|
|
+}
|
|
+
|
|
+SkFontID SkFontHost::NextLogicalFont(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 list[i+1];
|
|
+ }
|
|
+ }
|
|
+ return list[0];
|
|
+}
|
|
+
|
|
+///////////////////////////////////////////////////////////////////////////////
|
|
+
|
|
+SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
|
|
+ if (NULL == stream || stream->getLength() <= 0) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ bool isFixedWidth;
|
|
+ SkString name;
|
|
+ SkTypeface::Style style;
|
|
+ find_name_and_attributes(stream, &name, &style, &isFixedWidth);
|
|
+
|
|
+ if (!name.isEmpty()) {
|
|
+ return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream, isFixedWidth));
|
|
+ } else {
|
|
+ return NULL;
|
|
+ }
|
|
+}
|
|
+
|
|
+SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
|
|
+ SkStream* stream = SkNEW_ARGS(SkMMAPStream, (path));
|
|
+ SkTypeface* face = SkFontHost::CreateTypefaceFromStream(stream);
|
|
+ // since we created the stream, we let go of our ref() here
|
|
+ stream->unref();
|
|
+ return face;
|
|
+}
|
|
+
|
|
+///////////////////////////////////////////////////////////////////////////////
|
|
--
|
|
1.7.11.4
|
|
|