mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 22:32:46 +00:00
531 lines
19 KiB
Diff
531 lines
19 KiB
Diff
# HG changeset patch
|
|
# Parent 9ee29e4aace683ddf6cf8ddb2893cd34fcfc772c
|
|
# User James Willcox <jwillcox@mozilla.com>
|
|
diff --git a/gfx/skia/Makefile.in b/gfx/skia/Makefile.in
|
|
--- a/gfx/skia/Makefile.in
|
|
+++ b/gfx/skia/Makefile.in
|
|
@@ -305,21 +305,20 @@ CPPSRCS += \
|
|
SkFontHost_mac_coretext.cpp \
|
|
SkTime_Unix.cpp \
|
|
$(NULL)
|
|
endif
|
|
|
|
ifeq (android,$(MOZ_WIDGET_TOOLKIT))
|
|
CPPSRCS += \
|
|
SkFontHost_FreeType.cpp \
|
|
SkFontHost_android.cpp \
|
|
SkFontHost_gamma.cpp \
|
|
- FontHostConfiguration_android.cpp \
|
|
SkMMapStream.cpp \
|
|
SkTime_Unix.cpp \
|
|
$(NULL)
|
|
|
|
DEFINES += -DSK_BUILD_FOR_ANDROID_NDK
|
|
OS_CXXFLAGS += $(CAIRO_FT_CFLAGS)
|
|
endif
|
|
|
|
ifeq (gtk2,$(MOZ_WIDGET_TOOLKIT))
|
|
CPPSRCS += \
|
|
diff --git a/gfx/skia/src/ports/SkFontHost_android.cpp b/gfx/skia/src/ports/SkFontHost_android.cpp
|
|
--- a/gfx/skia/src/ports/SkFontHost_android.cpp
|
|
+++ b/gfx/skia/src/ports/SkFontHost_android.cpp
|
|
@@ -1,38 +1,31 @@
|
|
+
|
|
/*
|
|
-**
|
|
-** Copyright 2006, The Android Open Source Project
|
|
-**
|
|
-** Licensed under the Apache License, Version 2.0 (the "License");
|
|
-** you may not use this file except in compliance with the License.
|
|
-** You may obtain a copy of the License at
|
|
-**
|
|
-** http://www.apache.org/licenses/LICENSE-2.0
|
|
-**
|
|
-** Unless required by applicable law or agreed to in writing, software
|
|
-** distributed under the License is distributed on an "AS IS" BASIS,
|
|
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
-** See the License for the specific language governing permissions and
|
|
-** limitations under the License.
|
|
-*/
|
|
+ * 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 "FontHostConfiguration_android.h"
|
|
#include <stdio.h>
|
|
|
|
+#define FONT_CACHE_MEMORY_BUDGET (768 * 1024)
|
|
+
|
|
#ifndef SK_FONT_FILE_PREFIX
|
|
#define SK_FONT_FILE_PREFIX "/fonts/"
|
|
#endif
|
|
|
|
SkTypeface::Style find_name_and_attributes(SkStream* stream, SkString* name,
|
|
bool* isFixedWidth);
|
|
|
|
static void GetFullPathForSysFonts(SkString* full, const char name[]) {
|
|
full->set(getenv("ANDROID_ROOT"));
|
|
full->append(SK_FONT_FILE_PREFIX);
|
|
@@ -99,21 +92,21 @@ static SkTypeface* find_best_face(const
|
|
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");
|
|
+ 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;
|
|
}
|
|
@@ -138,31 +131,27 @@ static SkTypeface* find_from_uniqueID(ui
|
|
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);
|
|
- if (family) {
|
|
- SkASSERT(family->fFaces[face->style()] == face);
|
|
- family->fFaces[face->style()] = NULL;
|
|
+ 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;
|
|
- }
|
|
+ for (int i = 0; i < 4; i++) {
|
|
+ if (family->fFaces[i] != NULL) { // family is non-empty
|
|
+ return NULL;
|
|
}
|
|
- } else {
|
|
-// SkDebugf("remove_from_family(%p) face not found", face);
|
|
}
|
|
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) {
|
|
@@ -172,21 +161,21 @@ static void detach_and_delete_family(Fam
|
|
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");
|
|
+ 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);
|
|
@@ -387,111 +376,90 @@ static bool get_name_and_style(const cha
|
|
}
|
|
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 }
|
|
+};
|
|
|
|
-/* Fonts are 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 FontInitRec *gSystemFonts;
|
|
-static size_t gNumSystemFonts = 0;
|
|
-
|
|
-#define SYSTEM_FONTS_FILE "/system/etc/system_fonts.cfg"
|
|
+#define DEFAULT_NAMES gSansNames
|
|
|
|
// these globals are assigned (once) by load_system_fonts()
|
|
static FamilyRec* gDefaultFamily;
|
|
static SkTypeface* gDefaultNormal;
|
|
-static char** gDefaultNames = NULL;
|
|
-static uint32_t *gFallbackFonts;
|
|
|
|
-/* Load info from a configuration file that populates the system/fallback font structures
|
|
-*/
|
|
-static void load_font_info() {
|
|
-// load_font_info_xml("/system/etc/system_fonts.xml");
|
|
- SkTDArray<FontFamily*> fontFamilies;
|
|
- getFontFamilies(fontFamilies);
|
|
-
|
|
- SkTDArray<FontInitRec> fontInfo;
|
|
- bool firstInFamily = false;
|
|
- for (int i = 0; i < fontFamilies.count(); ++i) {
|
|
- FontFamily *family = fontFamilies[i];
|
|
- firstInFamily = true;
|
|
- for (int j = 0; j < family->fFileNames.count(); ++j) {
|
|
- FontInitRec fontInfoRecord;
|
|
- fontInfoRecord.fFileName = family->fFileNames[j];
|
|
- if (j == 0) {
|
|
- if (family->fNames.count() == 0) {
|
|
- // Fallback font
|
|
- fontInfoRecord.fNames = (char **)gFBNames;
|
|
- } else {
|
|
- SkTDArray<const char*> names = family->fNames;
|
|
- const char **nameList = (const char**)
|
|
- malloc((names.count() + 1) * sizeof(char*));
|
|
- if (nameList == NULL) {
|
|
- // shouldn't get here
|
|
- break;
|
|
- }
|
|
- if (gDefaultNames == NULL) {
|
|
- gDefaultNames = (char**) nameList;
|
|
- }
|
|
- for (int i = 0; i < names.count(); ++i) {
|
|
- nameList[i] = names[i];
|
|
- }
|
|
- nameList[names.count()] = NULL;
|
|
- fontInfoRecord.fNames = nameList;
|
|
- }
|
|
- } else {
|
|
- fontInfoRecord.fNames = NULL;
|
|
- }
|
|
- *fontInfo.append() = fontInfoRecord;
|
|
- }
|
|
- }
|
|
- gNumSystemFonts = fontInfo.count();
|
|
- gSystemFonts = (FontInitRec*) malloc(gNumSystemFonts * sizeof(FontInitRec));
|
|
- gFallbackFonts = (uint32_t*) malloc((gNumSystemFonts + 1) * sizeof(uint32_t));
|
|
- if (gSystemFonts == NULL) {
|
|
- // shouldn't get here
|
|
- gNumSystemFonts = 0;
|
|
- }
|
|
- for (size_t i = 0; i < gNumSystemFonts; ++i) {
|
|
- gSystemFonts[i].fFileName = fontInfo[i].fFileName;
|
|
- gSystemFonts[i].fNames = fontInfo[i].fNames;
|
|
- }
|
|
- fontFamilies.deleteAll();
|
|
-}
|
|
+/* 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;
|
|
}
|
|
|
|
- load_font_info();
|
|
-
|
|
const FontInitRec* rec = gSystemFonts;
|
|
SkTypeface* firstInFamily = NULL;
|
|
int fallbackCount = 0;
|
|
|
|
- for (size_t i = 0; i < gNumSystemFonts; i++) {
|
|
+ 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
|
|
@@ -515,120 +483,75 @@ static void load_system_fonts() {
|
|
// 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 == gDefaultNames) {
|
|
+ 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) {
|
|
- // lookup and record if the font is custom (i.e. not a system font)
|
|
- bool isCustomFont = !((FamilyTypeface*)face)->isSysFont();
|
|
- stream->writeBool(isCustomFont);
|
|
+ const char* name = ((FamilyTypeface*)face)->getUniqueString();
|
|
|
|
- if (isCustomFont) {
|
|
- SkStream* fontStream = ((FamilyTypeface*)face)->openStream();
|
|
+ stream->write8((uint8_t)face->style());
|
|
|
|
- // store the length of the custom font
|
|
- uint32_t len = fontStream->getLength();
|
|
- stream->write32(len);
|
|
-
|
|
- // store the entire font in the serialized stream
|
|
- void* fontData = malloc(len);
|
|
-
|
|
- fontStream->read(fontData, len);
|
|
- stream->write(fontData, len);
|
|
-
|
|
- fontStream->unref();
|
|
- free(fontData);
|
|
-// SkDebugf("--- fonthost custom serialize %d %d\n", face->style(), len);
|
|
-
|
|
+ if (NULL == name || 0 == *name) {
|
|
+ stream->writePackedUInt(0);
|
|
+// SkDebugf("--- fonthost serialize null\n");
|
|
} else {
|
|
- 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());
|
|
- }
|
|
+ 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();
|
|
|
|
- // check if the font is a custom or system font
|
|
- bool isCustomFont = stream->readBool();
|
|
+ int style = stream->readU8();
|
|
|
|
- if (isCustomFont) {
|
|
+ int len = stream->readPackedUInt();
|
|
+ if (len > 0) {
|
|
+ SkString str;
|
|
+ str.resize(len);
|
|
+ stream->read(str.writable_str(), len);
|
|
|
|
- // read the length of the custom font from the stream
|
|
- uint32_t len = stream->readU32();
|
|
-
|
|
- // generate a new stream to store the custom typeface
|
|
- SkMemoryStream* fontStream = new SkMemoryStream(len);
|
|
- stream->read((void*)fontStream->getMemoryBase(), len);
|
|
-
|
|
- SkTypeface* face = CreateTypefaceFromStream(fontStream);
|
|
-
|
|
- fontStream->unref();
|
|
-
|
|
-// SkDebugf("--- fonthost custom deserialize %d %d\n", face->style(), len);
|
|
- return face;
|
|
-
|
|
- } else {
|
|
- 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 < gNumSystemFonts; 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], NULL, 0,
|
|
- (SkTypeface::Style)style);
|
|
- }
|
|
+ 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], NULL, 0, (SkTypeface::Style)style);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
@@ -697,49 +620,32 @@ size_t SkFontHost::GetFileName(SkFontID
|
|
}
|
|
return size;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
|
|
load_system_fonts();
|
|
|
|
- const SkTypeface* origTypeface = find_from_uniqueID(origFontID);
|
|
- const SkTypeface* currTypeface = find_from_uniqueID(currFontID);
|
|
-
|
|
- SkASSERT(origTypeface != 0);
|
|
- SkASSERT(currTypeface != 0);
|
|
-
|
|
- // Our fallback list always stores the id of the plain in each fallback
|
|
- // family, so we transform currFontID to its plain equivalent.
|
|
- currFontID = find_typeface(currTypeface, SkTypeface::kNormal)->uniqueID();
|
|
-
|
|
/* 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) {
|
|
- if (list[i+1] == 0)
|
|
- return 0;
|
|
- const SkTypeface* nextTypeface = find_from_uniqueID(list[i+1]);
|
|
- return find_typeface(nextTypeface, origTypeface->style())->uniqueID();
|
|
+ return list[i+1];
|
|
}
|
|
}
|
|
-
|
|
- // If we get here, currFontID was not a fallback, so we start at the
|
|
- // beginning of our list.
|
|
- const SkTypeface* firstTypeface = find_from_uniqueID(list[0]);
|
|
- return find_typeface(firstTypeface, origTypeface->style())->uniqueID();
|
|
+ return list[0];
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
|
|
if (NULL == stream || stream->getLength() <= 0) {
|
|
return NULL;
|
|
}
|
|
|
|
bool isFixedWidth;
|
|
@@ -754,10 +660,11 @@ SkTypeface* SkFontHost::CreateTypefaceFr
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
+///////////////////////////////////////////////////////////////////////////////
|