merge in ics-release history after reset to master
diff --git a/Android.mk b/Android.mk
index 3f65320..8a8ed78 100644
--- a/Android.mk
+++ b/Android.mk
@@ -89,6 +89,7 @@
src/images/SkCreateRLEPixelRef.cpp \
src/images/SkImageDecoder_Factory.cpp \
src/images/SkImageEncoder_Factory.cpp \
+ src/ports/FontHostConfiguration_android.cpp \
src/ports/SkFontHost_android.cpp \
src/ports/SkFontHost_gamma.cpp \
src/ports/SkFontHost_FreeType.cpp \
@@ -221,7 +222,8 @@
libemoji \
libjpeg \
libutils \
- libz
+ libz \
+ libexpat
LOCAL_STATIC_LIBRARIES := \
libft2 \
@@ -243,7 +245,8 @@
external/giflib \
external/jpeg \
external/webp/include \
- frameworks/opt/emoji
+ frameworks/opt/emoji \
+ external/expat/lib
ifeq ($(NO_FALLBACK_FONT),true)
LOCAL_CFLAGS += -DNO_FALLBACK_FONT
diff --git a/src/images/SkImageDecoder_libwebp.cpp b/src/images/SkImageDecoder_libwebp.cpp
index 6f8dfcc..51f8a46 100644
--- a/src/images/SkImageDecoder_libwebp.cpp
+++ b/src/images/SkImageDecoder_libwebp.cpp
@@ -38,9 +38,6 @@
#include "webp/encode.h"
}
-/* If defined, work around missing padding byte in content generated by webpconv */
-#define WEBPCONV_MISSING_PADDING 1
-
#ifdef ANDROID
#include <cutils/properties.h>
@@ -59,24 +56,6 @@
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
-// An helper to extract a integer (little endian) from byte array. This is
-// called only once per decoding, so no real need to optimize it in any way
-static uint32_t getint32l(unsigned char *in) {
- int result;
- unsigned char *buffer = (unsigned char*) in;
-
- if (buffer == NULL) {
- return 0;
- }
-
- result = buffer[3];
- result = (result << 8) + buffer[2];
- result = (result << 8) + buffer[1];
- result = (result << 8) + buffer[0];
-
- return result;
-}
-
static const size_t WEBP_VP8_HEADER_SIZE = 30;
static const size_t WEBP_IDECODE_BUFFER_SZ = (1 << 16);
@@ -152,288 +131,6 @@
return false; // must always return false
}
-typedef struct {
- SkBitmap* image;
- SkStream* stream;
-} WEBPImage;
-
-// WebP library embeds its own YUV to RGB converter. However, High-level API doesn't take benefit
-// of (U,v) clipped values being valid for up to 4 pixels, and so there is a significant improvement
-// in performance in handling this on our own.
-// TODO: use architecture-optimized (eventually hardware-accelerated) YUV converters
-#define YUV_HALF (1 << (YUV_FIX - 1))
-#define YUV_FIX 16 // fixed-point precision
-#define YUV_RANGE_MIN (-227) // min value of r/g/b output
-#define YUV_RANGE_MAX (256 + 226) // max value of r/g/b output
-static int16_t VP8kVToR[256], VP8kUToB[256];
-static int32_t VP8kVToG[256], VP8kUToG[256];
-static uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN];
-
-static void yuv_init_tables() {
- int i;
-
- for (i = 0; i < 256; ++i) {
- VP8kVToR[i] = (89858 * (i - 128) + YUV_HALF) >> YUV_FIX;
- VP8kUToG[i] = -22014 * (i - 128) + YUV_HALF;
- VP8kVToG[i] = -45773 * (i - 128);
- VP8kUToB[i] = (113618 * (i - 128) + YUV_HALF) >> YUV_FIX;
- }
- for (i = YUV_RANGE_MIN; i < YUV_RANGE_MAX; ++i) {
- const int k = ((i - 16) * 76283 + YUV_HALF) >> YUV_FIX;
- VP8kClip[i - YUV_RANGE_MIN] = (k < 0) ? 0 : (k > 255) ? 255 : k;
- }
-}
-
-// Static global mutex to protect Webp initialization
-static SkMutex gYUVMutex;
-static bool gYUVReady = false;
-
-static bool yuv_init() {
- if (!gYUVReady) {
- gYUVMutex.acquire();
- if (!gYUVReady) {
- yuv_init_tables();
- gYUVReady = true;
- }
- gYUVMutex.release();
- }
-
- return gYUVReady;
-}
-
-#define PutRGBA(p,r,g,b) (((SkPMColor*) (p))[0] = SkPackARGB32(0xff,(r),(g),(b)))
-#define PutRGB565(p,r,g,b) (((SkPMColor16*) (p))[0] = SkPackRGB16((r)>>3,(g)>>2,(b)>>3))
-#define PutRGBA4444(p,r,g,b) (((SkPMColor16*) (p))[0] = SkPackARGB4444(0xf,(r)>>4,(g)>>4,(b)>>4))
-
-#define CRGBA(p,y,roff,goff,boff) PutRGBA(p, \
- VP8kClip[(y) + (roff) - YUV_RANGE_MIN], \
- VP8kClip[(y) + (goff) - YUV_RANGE_MIN], \
- VP8kClip[(y) + (boff) - YUV_RANGE_MIN])
-#define CRGB565(p,y,roff,goff,boff) PutRGB565(p, \
- VP8kClip[(y) + (roff) - YUV_RANGE_MIN], \
- VP8kClip[(y) + (goff) - YUV_RANGE_MIN], \
- VP8kClip[(y) + (boff) - YUV_RANGE_MIN])
-#define CRGBA4444(p,y,roff,goff,boff) PutRGBA4444(p, \
- VP8kClip[(y) + (roff) - YUV_RANGE_MIN], \
- VP8kClip[(y) + (goff) - YUV_RANGE_MIN], \
- VP8kClip[(y) + (boff) - YUV_RANGE_MIN])
-
-static int block_put(const VP8Io* io) {
- WEBPImage *p = (WEBPImage*) io->opaque;
- SkBitmap* decodedBitmap = p->image;
-
- const int w = io->width;
- const int mb_h = io->mb_h;
-
- const uint8_t *y, *y2, *u, *v;
- const uint8_t *py, *py2, *pu, *pv;
-
- uint8_t* pout;
- uint8_t* pout2;
-
- int i, j;
- const int ystride2 = io->y_stride * 2;
- int bpp;
- SkBitmap::Config config = decodedBitmap->config();
-
- //SkASSERT(!(io->mb_y & 1));
-
- y = io->y;
- u = io->u;
- v = io->v;
-
- switch (config) {
- case SkBitmap::kARGB_8888_Config:
- bpp = 4;
- break;
- case SkBitmap::kRGB_565_Config:
- bpp = 2;
- break;
- case SkBitmap::kARGB_4444_Config:
- bpp = 2;
- break;
- default:
- // Unsupported config
- return 0;
- }
-
- for (j = 0; j < mb_h;) {
- pout = decodedBitmap->getAddr8(0, io->mb_y + j);
- if (j + 1 < mb_h) {
- y2 = y + io->y_stride;
- pout2 = decodedBitmap->getAddr8(0, io->mb_y + j + 1);
- } else {
- y2 = NULL;
- pout2 = NULL;
- }
-
- // Copy YUV into target buffer
- py = y;
- pu = u;
- pv = v;
-
- py2 = y2;
-
- // Leave test for config out of inner loop. This implies some redundancy in code,
- // but help in supporting several configs without degrading performance.
- // As a reminder, one must *NOT* put py increment into parameters (i.e. *py++) in the hope to
- // improve performance or code readability. Since it is used as argument of a macro which uses it
- // several times in its expression, so this would end up in having it too much incremented
- switch (config) {
- case SkBitmap::kARGB_8888_Config:
- for (i = 0; i < w; i += 2) {
- // U and V are common for up to 4 pixels
- const int r_off = VP8kVToR[*pv];
- const int g_off = (VP8kVToG[*pv] + VP8kUToG[*pu]) >> YUV_FIX;
- const int b_off = VP8kUToB[*pu];
-
- CRGBA(pout, *py, r_off, g_off, b_off);
- pout += bpp;
- py++;
-
- // Width shouldn't be odd, so this should always be true
- if (i + 1 < w) {
- CRGBA(pout, *py, r_off, g_off, b_off);
- pout += bpp;
- py++;
- }
-
- if (pout2) {
- CRGBA(pout2, *py2, r_off, g_off, b_off);
- pout2 += bpp;
- py2++;
-
- // Width shouldn't be odd, so this should always be true
- if (i + 1 < w) {
- CRGBA(pout2, *py2, r_off, g_off, b_off);
- pout2 += bpp;
- py2++;
- }
- }
-
- pu++;
- pv++;
- }
- break;
- case SkBitmap::kRGB_565_Config:
- for (i = 0; i < w; i += 2) {
- // U and V are common for up to 4 pixels
- const int r_off = VP8kVToR[*pv];
- const int g_off = (VP8kVToG[*pv] + VP8kUToG[*pu]) >> YUV_FIX;
- const int b_off = VP8kUToB[*pu];
-
- CRGB565(pout, *py, r_off, g_off, b_off);
- pout += bpp;
- py++;
-
- // Width shouldn't be odd, so this should always be true
- if (i + 1 < w) {
- CRGB565(pout, *py, r_off, g_off, b_off);
- pout += bpp;
- py++;
- }
-
- if (pout2) {
- CRGB565(pout2, *py2, r_off, g_off, b_off);
- pout2 += bpp;
- py2++;
-
- // Width shouldn't be odd, so this should always be true
- if (i + 1 < w) {
- CRGB565(pout2, *py2, r_off, g_off, b_off);
- pout2 += bpp;
- py2++;
- }
- }
-
- pu++;
- pv++;
- }
- break;
- case SkBitmap::kARGB_4444_Config:
- for (i = 0; i < w; i += 2) {
- // U and V are common for up to 4 pixels
- const int r_off = VP8kVToR[*pv];
- const int g_off = (VP8kVToG[*pv] + VP8kUToG[*pu]) >> YUV_FIX;
- const int b_off = VP8kUToB[*pu];
-
- CRGBA4444(pout, *py, r_off, g_off, b_off);
- pout += bpp;
- py++;
-
- // Width shouldn't be odd, so this should always be true
- if (i + 1 < w) {
- CRGBA4444(pout, *py, r_off, g_off, b_off);
- pout += bpp;
- py++;
- }
-
- if (pout2) {
- CRGBA4444(pout2, *py2, r_off, g_off, b_off);
- pout2 += bpp;
- py2++;
-
- // Width shouldn't be odd, so this should always be true
- if (i + 1 < w) {
- CRGBA4444(pout2, *py2, r_off, g_off, b_off);
- pout2 += bpp;
- py2++;
- }
- }
-
- pu++;
- pv++;
- }
- break;
- default:
- // Unsupported config (can't happen, but prevents compiler warning)
- SkASSERT(0);
- break;
- }
-
- if (y2) {
- // Scanned and populated two rows
- y += ystride2;
- y2 += ystride2;
- j += 2;
- } else {
- // Skip to next row
- y += io->y_stride;
- j++;
- }
-
- u += io->uv_stride;
- v += io->uv_stride;
- }
-
- return 1;
-}
-
-static int block_setup(VP8Io* io) {
- yuv_init();
- return 1;
-}
-
-static void block_teardown(const VP8Io* io) {
-}
-
-static bool webp_init_custom_io(WebPIDecoder* idec, SkBitmap* decodedBitmap) {
- if (idec == NULL) {
- return false;
- }
-
- WEBPImage pSrc;
- // Custom Put callback need reference to target image.
- pSrc.image = decodedBitmap;
-
- if (!WebPISetIOHooks(idec, block_put, block_setup, block_teardown,
- (void*)&pSrc)) {
- return false;
- }
-
- return true;
-}
-
// Incremental WebP image decoding. Reads input buffer of 64K size iteratively
// and decodes this block to appropriate color-space as per config object.
static bool webp_idecode(SkStream* stream, SkBitmap* decodedBitmap) {
@@ -442,13 +139,32 @@
stream->rewind();
const uint32_t contentSize = stream->getLength();
- WebPIDecoder* idec = WebPINew(MODE_YUV);
- if (idec == NULL) {
+ WEBP_CSP_MODE mode = MODE_LAST;
+ SkBitmap::Config config = decodedBitmap->config();
+ if (config == SkBitmap::kARGB_8888_Config) {
+ mode = MODE_RGBA;
+ } else if (config == SkBitmap::kARGB_4444_Config) {
+ mode = MODE_RGBA_4444;
+ } else if (config == SkBitmap::kRGB_565_Config) {
+ mode = MODE_RGB_565;
+ } else {
+ return false;
+ }
+
+ WebPDecoderConfig decode_config;
+ if (WebPInitDecoderConfig(&decode_config) == 0) {
return false;
}
- if (!webp_init_custom_io(idec, decodedBitmap)) {
- WebPIDelete(idec);
+ decode_config.output.colorspace = mode;
+ decode_config.output.u.RGBA.rgba = (uint8_t*)decodedBitmap->getPixels();
+ decode_config.output.u.RGBA.stride = decodedBitmap->rowBytes();
+ decode_config.output.u.RGBA.size = decodedBitmap->getSize();
+ decode_config.output.is_external_memory = 1;
+
+ WebPIDecoder* idec = WebPIDecode(NULL, NULL, &decode_config);
+ if (idec == NULL) {
+ WebPFreeDecBuffer(&decode_config.output);
return false;
}
@@ -460,6 +176,7 @@
unsigned char* input = (uint8_t*)srcStorage.get();
if (input == NULL) {
WebPIDelete(idec);
+ WebPFreeDecBuffer(&decode_config.output);
return false;
}
@@ -483,6 +200,7 @@
}
srcStorage.free();
WebPIDelete(idec);
+ WebPFreeDecBuffer(&decode_config.output);
if (bytes_remaining > 0) {
return false;
@@ -509,7 +227,6 @@
}
}
-
if (!this->chooseFromOneChoice(config, origWidth, origHeight)) {
return false;
}
diff --git a/src/ports/FontHostConfiguration_android.cpp b/src/ports/FontHostConfiguration_android.cpp
new file mode 100644
index 0000000..78f1de4
--- /dev/null
+++ b/src/ports/FontHostConfiguration_android.cpp
@@ -0,0 +1,192 @@
+/* libs/graphics/ports/FontHostConfiguration_android.cpp
+**
+** Copyright 2011, 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.
+*/
+
+#include "FontHostConfiguration_android.h"
+#include <expat.h>
+#include "SkTDArray.h"
+
+#define SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml"
+#define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml"
+#define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml"
+
+
+// These defines are used to determine the kind of tag that we're currently populating with data.
+// We only care about the sibling tags nameset and fileset for now.
+#define NO_TAG 0
+#define NAMESET_TAG 1
+#define FILESET_TAG 2
+
+/**
+ * The FamilyData structure is passed around by the parser so that each handler can read these
+ * variables that are relevant to the current parsing.
+ */
+struct FamilyData {
+ FamilyData(XML_Parser *parserRef, SkTDArray<FontFamily*> &familiesRef) :
+ parser(parserRef), families(familiesRef), currentTag(NO_TAG) {};
+
+ XML_Parser *parser; // The expat parser doing the work
+ SkTDArray<FontFamily*> &families; // The array that each family is put into as it is parsed
+ FontFamily *currentFamily; // The current family being created
+ int currentTag; // A flag to indicate whether we're in nameset/fileset tags
+};
+
+/**
+ * Handler for arbitrary text. This is used to parse the text inside each name or file tag. The
+ * resulting strings are put into the fNames or fFileNames arrays.
+ */
+void textHandler(void *data, const char *s, int len) {
+ FamilyData *familyData = (FamilyData*) data;
+ // Make sure we're in the right state to store this name information
+ if (familyData->currentFamily &&
+ (familyData->currentTag == NAMESET_TAG || familyData->currentTag == FILESET_TAG)) {
+ // Malloc new buffer to store the string
+ char *buff;
+ buff = (char*) malloc((len + 1) * sizeof(char));
+ strncpy(buff, s, len);
+ buff[len] = '\0';
+ switch (familyData->currentTag) {
+ case NAMESET_TAG:
+ *(familyData->currentFamily->fNames.append()) = buff;
+ break;
+ case FILESET_TAG:
+ *(familyData->currentFamily->fFileNames.append()) = buff;
+ break;
+ default:
+ // Noop - don't care about any text that's not in the Fonts or Names list
+ break;
+ }
+ }
+}
+
+/**
+ * Handler for the start of a tag. The only tags we expect are family, nameset, fileset, name,
+ * and file.
+ */
+void startElementHandler(void *data, const char *tag, const char **atts) {
+ FamilyData *familyData = (FamilyData*) data;
+ int len = strlen(tag);
+ if (strncmp(tag, "family", len)== 0) {
+ familyData->currentFamily = new FontFamily();
+ familyData->currentFamily->order = -1;
+ // The Family tag has an optional "order" attribute with an integer value >= 0
+ // If this attribute does not exist, the default value is -1
+ for (int i = 0; atts[i] != NULL; i += 2) {
+ const char* attribute = atts[i];
+ const char* valueString = atts[i+1];
+ int value;
+ int len = sscanf(valueString, "%d", &value);
+ if (len > 0) {
+ familyData->currentFamily->order = value;
+ }
+ }
+ } else if (len == 7 && strncmp(tag, "nameset", len)== 0) {
+ familyData->currentTag = NAMESET_TAG;
+ } else if (len == 7 && strncmp(tag, "fileset", len) == 0) {
+ familyData->currentTag = FILESET_TAG;
+ } else if ((strncmp(tag, "name", len) == 0 && familyData->currentTag == NAMESET_TAG) ||
+ (strncmp(tag, "file", len) == 0 && familyData->currentTag == FILESET_TAG)) {
+ // If it's a Name, parse the text inside
+ XML_SetCharacterDataHandler(*familyData->parser, textHandler);
+ }
+}
+
+/**
+ * Handler for the end of tags. We only care about family, nameset, fileset, name, and file.
+ */
+void endElementHandler(void *data, const char *tag) {
+ FamilyData *familyData = (FamilyData*) data;
+ int len = strlen(tag);
+ if (strncmp(tag, "family", len)== 0) {
+ // Done parsing a Family - store the created currentFamily in the families array
+ *familyData->families.append() = familyData->currentFamily;
+ familyData->currentFamily = NULL;
+ } else if (len == 7 && strncmp(tag, "nameset", len)== 0) {
+ familyData->currentTag = NO_TAG;
+ } else if (len == 7 && strncmp(tag, "fileset", len)== 0) {
+ familyData->currentTag = NO_TAG;
+ } else if ((strncmp(tag, "name", len) == 0 && familyData->currentTag == NAMESET_TAG) ||
+ (strncmp(tag, "file", len) == 0 && familyData->currentTag == FILESET_TAG)) {
+ // Disable the arbitrary text handler installed to load Name data
+ XML_SetCharacterDataHandler(*familyData->parser, NULL);
+ }
+}
+
+/**
+ * This function parses the given filename and stores the results in the given families array.
+ */
+void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &families) {
+ XML_Parser parser = XML_ParserCreate(NULL);
+ FamilyData *familyData = new FamilyData(&parser, families);
+ XML_SetUserData(parser, familyData);
+ XML_SetElementHandler(parser, startElementHandler, endElementHandler);
+ FILE *file = fopen(filename, "r");
+ if (file == NULL) {
+ // Some of the files we attempt to parse (in particular, /vendor/etc/fallback_fonts.xml)
+ // are optional - failure here is okay because one of these optional files may not exist.
+ return;
+ }
+ char buffer[512];
+ bool done = false;
+ while (!done) {
+ fgets(buffer, sizeof(buffer), file);
+ int len = strlen(buffer);
+ if (feof(file) != 0) {
+ done = true;
+ }
+ XML_Parse(parser, buffer, len, done);
+ }
+}
+
+/**
+ * Loads data on font families from various expected configuration files. The resulting data
+ * is returned in the given fontFamilies array.
+ */
+void getFontFamilies(SkTDArray<FontFamily*> &fontFamilies) {
+
+ SkTDArray<FontFamily*> fallbackFonts;
+ SkTDArray<FontFamily*> vendorFonts;
+ parseConfigFile(SYSTEM_FONTS_FILE, fontFamilies);
+ parseConfigFile(FALLBACK_FONTS_FILE, fallbackFonts);
+ parseConfigFile(VENDOR_FONTS_FILE, vendorFonts);
+
+ // This loop inserts the vendor fallback fonts in the correct order in the overall
+ // fallbacks list.
+ int currentOrder = -1;
+ for (int i = 0; i < vendorFonts.count(); ++i) {
+ FontFamily* family = vendorFonts[i];
+ int order = family->order;
+ if (order < 0) {
+ if (currentOrder < 0) {
+ // Default case - just add it to the end of the fallback list
+ *fallbackFonts.append() = family;
+ } else {
+ // no order specified on this font, but we're incrementing the order
+ // based on an earlier order insertion request
+ *fallbackFonts.insert(currentOrder++) = family;
+ }
+ } else {
+ // Add the font into the fallback list in the specified order. Set currentOrder
+ // for correct placement of other fonts in the vendor list.
+ *fallbackFonts.insert(order) = family;
+ currentOrder = order + 1;
+ }
+ }
+ // Append all fallback fonts to system fonts
+ for (int i = 0; i < fallbackFonts.count(); ++i) {
+ *fontFamilies.append() = fallbackFonts[i];
+ }
+}
diff --git a/src/ports/FontHostConfiguration_android.h b/src/ports/FontHostConfiguration_android.h
new file mode 100644
index 0000000..57a0126
--- /dev/null
+++ b/src/ports/FontHostConfiguration_android.h
@@ -0,0 +1,41 @@
+/* libs/graphics/ports/FontHostConfiguration_android.h
+**
+** Copyright 2011, 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.
+*/
+#ifndef FONTHOSTCONFIGURATION_ANDROID_H_
+#define FONTHOSTCONFIGURATION_ANDROID_H_
+
+#include "SkTDArray.h"
+
+/**
+ * The FontFamily data structure is created during parsing and handed back to Skia to fold
+ * into its representation of font families. fNames is the list of font names that alias to a
+ * font family. fFileNames is the list of font filenames for the family. Order is the priority
+ * order for the font. This is used internally to determine the order in which to place fallback
+ * fonts as they are read from the configuration files.
+ */
+struct FontFamily {
+ SkTDArray<const char*> fNames;
+ SkTDArray<const char*> fFileNames;
+ int order;
+};
+
+/**
+ * Parses all system font configuration files and returns the results in an array of FontFamily
+ * structures.
+ */
+void getFontFamilies(SkTDArray<FontFamily*> &fontFamilies);
+
+#endif /* FONTHOSTCONFIGURATION_ANDROID_H_ */
diff --git a/src/ports/SkFontHost_android.cpp b/src/ports/SkFontHost_android.cpp
index 7d17544..76d9961 100644
--- a/src/ports/SkFontHost_android.cpp
+++ b/src/ports/SkFontHost_android.cpp
@@ -23,6 +23,7 @@
#include "SkStream.h"
#include "SkThread.h"
#include "SkTSearch.h"
+#include "FontHostConfiguration_android.h"
#include <stdio.h>
#define FONT_CACHE_MEMORY_BUDGET (768 * 1024)
@@ -395,64 +396,80 @@
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-Regular.ttf",gFBNames },
- { "DroidSansHebrew-Bold.ttf", NULL },
- { "DroidSansThai.ttf", gFBNames },
- { "MTLmr3m.ttf", gFBNames }, // Motoya Japanese Font
- { "MTLc3m.ttf", gFBNames }, // Motoya Japanese Font
- { "DroidSansJapanese.ttf", gFBNames },
- { "DroidSansEthiopic-Regular.ttf",gFBNames },
- { "DroidSansEthiopic-Bold.ttf", NULL },
- { "DroidSansFallback.ttf", gFBNames }
-};
-#define DEFAULT_NAMES gSansNames
+/* 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"
// these globals are assigned (once) by load_system_fonts()
static FamilyRec* gDefaultFamily;
static SkTypeface* gDefaultNormal;
+static char** gDefaultNames = NULL;
+static uint32_t *gFallbackFonts;
-/* 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];
+/* 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();
+}
/* Called once (ensured by the sentinel check at the beginning of our body).
Initializes all the globals, and register the system fonts.
@@ -463,11 +480,13 @@
return;
}
+ load_font_info();
+
const FontInitRec* rec = gSystemFonts;
SkTypeface* firstInFamily = NULL;
int fallbackCount = 0;
- for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
+ for (size_t i = 0; i < gNumSystemFonts; i++) {
// if we're the first in a new family, clear firstInFamily
if (rec[i].fNames != NULL) {
firstInFamily = NULL;
@@ -505,7 +524,7 @@
const char* const* names = rec[i].fNames;
// record the default family if this is it
- if (names == DEFAULT_NAMES) {
+ if (names == gDefaultNames) {
gDefaultFamily = family;
}
// add the names to map to this family
@@ -553,7 +572,7 @@
stream->read(str.writable_str(), len);
const FontInitRec* rec = gSystemFonts;
- for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
+ 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) {