aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk1
-rw-r--r--ThirdPartyProject.prop9
-rw-r--r--include/core/SkFontHost.h9
-rw-r--r--include/core/SkPaint.h24
-rw-r--r--include/core/SkScalerContext.h18
-rw-r--r--include/ports/SkTypeface_android.h31
-rw-r--r--src/core/SkGlyphCache.h2
-rw-r--r--src/core/SkPaint.cpp16
-rw-r--r--src/core/SkScalerContext.cpp8
-rw-r--r--src/images/SkImageDecoder_libwebp.cpp100
-rw-r--r--src/ports/FontHostConfiguration_android.cpp53
-rw-r--r--src/ports/FontHostConfiguration_android.h17
-rw-r--r--src/ports/SkFontHost_FreeType.cpp4
-rw-r--r--src/ports/SkFontHost_android.cpp231
14 files changed, 396 insertions, 127 deletions
diff --git a/Android.mk b/Android.mk
index 08cf6f8..846c157 100644
--- a/Android.mk
+++ b/Android.mk
@@ -295,6 +295,7 @@ LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/include/config \
$(LOCAL_PATH)/include/effects \
$(LOCAL_PATH)/include/images \
+ $(LOCAL_PATH)/include/ports \
$(LOCAL_PATH)/include/utils \
$(LOCAL_PATH)/include/xml \
external/freetype/include \
diff --git a/ThirdPartyProject.prop b/ThirdPartyProject.prop
deleted file mode 100644
index 6bd7584..0000000
--- a/ThirdPartyProject.prop
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright 2010 Google Inc. All Rights Reserved.
-#Fri Jul 16 10:03:09 PDT 2010
-currentVersion=Unknown
-version=Unknown
-isNative=true
-name=skia
-keywords=skia
-onDevice=true
-homepage=http\://code.google.com/p/skia/
diff --git a/include/core/SkFontHost.h b/include/core/SkFontHost.h
index 25c9ecb..ace08d8 100644
--- a/include/core/SkFontHost.h
+++ b/include/core/SkFontHost.h
@@ -154,6 +154,15 @@ public:
*/
static SkFontID NextLogicalFont(SkFontID currFontID, SkFontID origFontID);
+#ifdef SK_BUILD_FOR_ANDROID
+ /*
+ * This Android-only version of NextLogicalFont allows us to pass in an
+ * entire Rec structure so that a caller can change fallback behavior
+ */
+ static SkFontID NextLogicalFont(const SkScalerContext::Rec& rec);
+#endif
+
+
///////////////////////////////////////////////////////////////////////////
/** Given a filled-out rec, the fonthost may decide to modify it to reflect
diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h
index 0ec6698..1715013 100644
--- a/include/core/SkPaint.h
+++ b/include/core/SkPaint.h
@@ -665,6 +665,25 @@ public:
@param locale set the paint's locale value for drawing text.
*/
void setTextLocale(const SkString& locale);
+
+
+ enum FontVariant {
+ kDefault_Variant, // Currently setting yourself to Default gives you Compact Variant
+ kCompact_Variant,
+ kElegant_Variant,
+ kLast_Variant = kElegant_Variant,
+ };
+
+ /** Return the font variant
+ @return the font variant used by this paint object
+ */
+ FontVariant getFontVariant() const { return fFontVariant; }
+
+
+ /** Set the font variant
+ @param fontVariant set the paint's font variant for choosing fonts
+ */
+ void setFontVariant(FontVariant fontVariant);
#endif
/** Return the paint's text size.
@@ -861,10 +880,6 @@ public:
SkPath* path) const;
#ifdef SK_BUILD_FOR_ANDROID
-
- enum FontVariant {
- kElegant_Variant,
- };
const SkGlyph& getUnicharMetrics(SkUnichar);
const SkGlyph& getGlyphMetrics(uint16_t);
const void* findImage(const SkGlyph&);
@@ -910,6 +925,7 @@ private:
unsigned fHinting : 2;
#ifdef SK_BUILD_FOR_ANDROID
SkString fTextLocale;
+ FontVariant fFontVariant;
#endif
SkDrawCacheProc getDrawCacheProc() const;
diff --git a/include/core/SkScalerContext.h b/include/core/SkScalerContext.h
index 29679d6..33c3c3d 100644
--- a/include/core/SkScalerContext.h
+++ b/include/core/SkScalerContext.h
@@ -15,6 +15,7 @@
#include "SkPaint.h"
#include "SkPath.h"
#include "SkPoint.h"
+#include "SkTypeface.h"
//#define SK_USE_COLOR_LUMINANCE
@@ -209,6 +210,9 @@ public:
#ifdef SK_USE_COLOR_LUMINANCE
uint32_t fLumBits;
#endif
+#ifdef SK_BUILD_FOR_ANDROID
+ SkPaint::FontVariant fFontVariant;
+#endif
uint8_t fMaskFormat;
uint8_t fStrokeJoin;
uint16_t fFlags;
@@ -233,7 +237,6 @@ public:
SkMask::Format getFormat() const {
return static_cast<SkMask::Format>(fMaskFormat);
}
-
#ifdef SK_USE_COLOR_LUMINANCE
SkColor getLuminanceColor() const {
return fLumBits;
@@ -299,6 +302,19 @@ public:
SkPaint::FontMetrics* mY);
#ifdef SK_BUILD_FOR_ANDROID
+ // This function must be public for SkTypeface_android.h, but should not be
+ // called by other callers
+ SkFontID findTypefaceIdForChar(SkUnichar uni) {
+ SkScalerContext* ctx = this;
+ while (NULL != ctx) {
+ if (ctx->generateCharToGlyph(uni)) {
+ return ctx->fRec.fFontID;
+ }
+ ctx = ctx->getNextContext();
+ }
+ return 0;
+ }
+
unsigned getBaseGlyphCount(SkUnichar charCode);
#endif
diff --git a/include/ports/SkTypeface_android.h b/include/ports/SkTypeface_android.h
index 0023879..c3eb3d1 100644
--- a/include/ports/SkTypeface_android.h
+++ b/include/ports/SkTypeface_android.h
@@ -11,28 +11,19 @@
#include "SkTypeface.h"
#include "SkPaint.h"
-#include "../harfbuzz/src/harfbuzz-shaper.h"
-
-enum FallbackScripts {
- kArabic_FallbackScript,
- kArmenian_FallbackScript,
- kBengali_FallbackScript,
- kDevanagari_FallbackScript,
- kEthiopic_FallbackScript,
- kGeorgian_FallbackScript,
- kHebrewRegular_FallbackScript,
- kHebrewBold_FallbackScript,
- kKannada_FallbackScript,
- kMalayalam_FallbackScript,
- kTamilRegular_FallbackScript,
- kTamilBold_FallbackScript,
- kThai_FallbackScript,
- kTelugu_FallbackScript,
- kFallbackScriptNumber
-};
+#include "../harfbuzz/src/harfbuzz-shaper.h"
+/**
+ * Return a new typeface for a fallback script. If the script is
+ * not valid, or can not map to a font, returns null.
+ * @param script The harfbuzz script id.
+ * @param style The font style, for example bold
+ * @param elegant true if we want the web friendly elegant version of the font
+ * @return reference to the matching typeface. Caller must call
+ * unref() when they are done.
+ */
SK_API SkTypeface* SkCreateTypefaceForScript(HB_Script script, SkTypeface::Style style,
- SkPaint::FontVariant fontVariant) { return NULL; }
+ SkPaint::FontVariant fontVariant = SkPaint::kDefault_Variant);
#endif
diff --git a/src/core/SkGlyphCache.h b/src/core/SkGlyphCache.h
index 2895c54..23f3c55 100644
--- a/src/core/SkGlyphCache.h
+++ b/src/core/SkGlyphCache.h
@@ -123,6 +123,8 @@ public:
// call the proc)
void removeAuxProc(void (*auxProc)(void*));
+ SkScalerContext* getScalerContext() const { return fScalerContext; }
+
/** Call proc on all cache entries, stopping early if proc returns true.
The proc should not create or delete caches, since it could produce
deadlock.
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp
index e1932a7..412ab2b 100644
--- a/src/core/SkPaint.cpp
+++ b/src/core/SkPaint.cpp
@@ -72,6 +72,7 @@ SkPaint::SkPaint() {
fHinting = SkPaintDefaults_Hinting;
#ifdef SK_BUILD_FOR_ANDROID
new(&fTextLocale) SkString();
+ fFontVariant = kDefault_Variant;
fGenerationID = 0;
#endif
}
@@ -372,6 +373,18 @@ void SkPaint::setTextLocale(const SkString& locale) {
GEN_ID_INC;
}
}
+
+void SkPaint::setFontVariant(FontVariant fontVariant) {
+ if ((unsigned)fontVariant <= kLast_Variant) {
+ GEN_ID_INC_EVAL((unsigned)fontVariant != fFontVariant);
+ fFontVariant = fontVariant;
+ } else {
+#ifdef SK_REPORT_API_RANGE_CHECK
+ SkDebugf("SkPaint::setFontVariant(%d) out of range\n", fontVariant);
+#endif
+ }
+}
+
#endif
///////////////////////////////////////////////////////////////////////////////
@@ -1561,6 +1574,9 @@ void SkScalerContext::MakeRec(const SkPaint& paint,
#else
rec->setLuminanceBits(computeLuminance(paint));
#endif
+#ifdef SK_BUILD_FOR_ANDROID
+ rec->fFontVariant = paint.getFontVariant();
+#endif //SK_BUILD_FOR_ANDROID
/* Allow the fonthost to modify our rec before we use it as a key into the
cache. This way if we're asking for something that they will ignore,
diff --git a/src/core/SkScalerContext.cpp b/src/core/SkScalerContext.cpp
index 2921b1e..e33ad7a 100644
--- a/src/core/SkScalerContext.cpp
+++ b/src/core/SkScalerContext.cpp
@@ -118,7 +118,13 @@ static SkScalerContext* allocNextContext(const SkScalerContext::Rec& rec) {
// fonthost will determine the next possible font to search, based
// on the current font in fRec. It will return NULL if ctx is our
// last font that can be searched (i.e. ultimate fallback font)
- uint32_t newFontID = SkFontHost::NextLogicalFont(rec.fFontID, rec.fOrigFontID);
+#ifdef SK_BUILD_FOR_ANDROID
+ // On Android, pass entire rec structure so that clients can change fallback behavior
+ uint32_t newFontID = SkFontHost::NextLogicalFont(rec);
+#else
+ uint32_t newFontID = SkFontHost::NextLogicalFont(rec.fFontID, rec.fOrigFontID);
+#endif
+
if (0 == newFontID) {
return NULL;
}
diff --git a/src/images/SkImageDecoder_libwebp.cpp b/src/images/SkImageDecoder_libwebp.cpp
index 3e416cc..b2aea24 100644
--- a/src/images/SkImageDecoder_libwebp.cpp
+++ b/src/images/SkImageDecoder_libwebp.cpp
@@ -56,20 +56,29 @@ static const char KEY_MEM_CAP[] = "ro.media.dec.webp.memcap";
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
-static const size_t WEBP_VP8_HEADER_SIZE = 30;
+static const size_t WEBP_VP8_HEADER_SIZE = 64;
static const size_t WEBP_IDECODE_BUFFER_SZ = (1 << 16);
// Parse headers of RIFF container, and check for valid Webp (VP8) content.
-static bool webp_parse_header(SkStream* stream, int* width, int* height) {
+static bool webp_parse_header(SkStream* stream, int* width, int* height,
+ int* alpha) {
unsigned char buffer[WEBP_VP8_HEADER_SIZE];
+ const uint32_t contentSize = stream->getLength();
const size_t len = stream->read(buffer, WEBP_VP8_HEADER_SIZE);
- if (len != WEBP_VP8_HEADER_SIZE) {
+ const uint32_t read_bytes = (contentSize < WEBP_VP8_HEADER_SIZE) ?
+ contentSize : WEBP_VP8_HEADER_SIZE;
+ if (len != read_bytes) {
return false; // can't read enough
}
- if (WebPGetInfo(buffer, WEBP_VP8_HEADER_SIZE, width, height) == 0) {
+ WebPBitstreamFeatures features;
+ VP8StatusCode status = WebPGetFeatures(buffer, read_bytes, &features);
+ if (status != VP8_STATUS_OK) {
return false; // Invalid WebP file.
}
+ *width = features.width;
+ *height = features.height;
+ *alpha = features.has_alpha;
// sanity check for image size that's about to be decoded.
{
@@ -102,6 +111,7 @@ private:
SkStream *inputStream;
int origWidth;
int origHeight;
+ int hasAlpha;
};
//////////////////////////////////////////////////////////////////////////
@@ -160,10 +170,8 @@ static bool webp_idecode(SkStream* stream, WebPDecoderConfig& config) {
stream->rewind();
const uint32_t contentSize = stream->getLength();
- uint32_t read_buffer_size = contentSize;
- if (read_buffer_size > WEBP_IDECODE_BUFFER_SZ) {
- read_buffer_size = WEBP_IDECODE_BUFFER_SZ;
- }
+ const uint32_t read_buffer_size = (contentSize < WEBP_IDECODE_BUFFER_SZ) ?
+ contentSize : WEBP_IDECODE_BUFFER_SZ;
SkAutoMalloc srcStorage(read_buffer_size);
unsigned char* input = (uint8_t*)srcStorage.get();
if (input == NULL) {
@@ -175,8 +183,8 @@ static bool webp_idecode(SkStream* stream, WebPDecoderConfig& config) {
uint32_t bytes_remaining = contentSize;
while (bytes_remaining > 0) {
const uint32_t bytes_to_read =
- (bytes_remaining > WEBP_IDECODE_BUFFER_SZ) ?
- WEBP_IDECODE_BUFFER_SZ : bytes_remaining;
+ (bytes_remaining < WEBP_IDECODE_BUFFER_SZ) ?
+ bytes_remaining : WEBP_IDECODE_BUFFER_SZ;
const size_t bytes_read = stream->read(input, bytes_to_read);
if (bytes_read == 0) {
@@ -201,9 +209,9 @@ static bool webp_idecode(SkStream* stream, WebPDecoderConfig& config) {
}
}
-static bool webp_get_config_resize_crop(WebPDecoderConfig& config,
- SkBitmap* decodedBitmap,
- SkIRect region) {
+static bool webp_get_config_resize(WebPDecoderConfig& config,
+ SkBitmap* decodedBitmap,
+ int width, int height) {
WEBP_CSP_MODE mode = webp_decode_mode(decodedBitmap);
if (mode == MODE_LAST) {
return false;
@@ -219,14 +227,8 @@ static bool webp_get_config_resize_crop(WebPDecoderConfig& config,
config.output.u.RGBA.size = decodedBitmap->getSize();
config.output.is_external_memory = 1;
- config.options.use_cropping = 1;
- config.options.crop_left = region.fLeft;
- config.options.crop_top = region.fTop;
- config.options.crop_width = region.width();
- config.options.crop_height = region.height();
-
- if (region.width() != decodedBitmap->width() ||
- region.height() != decodedBitmap->height()) {
+ if (width != decodedBitmap->width() ||
+ height != decodedBitmap->height()) {
config.options.use_scaling = 1;
config.options.scaled_width = decodedBitmap->width();
config.options.scaled_height = decodedBitmap->height();
@@ -235,37 +237,24 @@ static bool webp_get_config_resize_crop(WebPDecoderConfig& config,
return true;
}
-static bool webp_get_config_resize(WebPDecoderConfig& config,
- SkBitmap* decodedBitmap, int origWidth,
- int origHeight) {
- WEBP_CSP_MODE mode = webp_decode_mode(decodedBitmap);
- if (mode == MODE_LAST) {
- return false;
- }
-
- if (WebPInitDecoderConfig(&config) == 0) {
- return false;
- }
+static bool webp_get_config_resize_crop(WebPDecoderConfig& config,
+ SkBitmap* decodedBitmap,
+ SkIRect region) {
- config.output.colorspace = mode;
- config.output.u.RGBA.rgba = (uint8_t*)decodedBitmap->getPixels();
- config.output.u.RGBA.stride = decodedBitmap->rowBytes();
- config.output.u.RGBA.size = decodedBitmap->getSize();
- config.output.is_external_memory = 1;
+ if (!webp_get_config_resize(config, decodedBitmap,
+ region.width(), region.height())) return false;
- if (origWidth != decodedBitmap->width() ||
- origHeight != decodedBitmap->height()) {
- config.options.use_scaling = 1;
- config.options.scaled_width = decodedBitmap->width();
- config.options.scaled_height = decodedBitmap->height();
- }
+ config.options.use_cropping = 1;
+ config.options.crop_left = region.fLeft;
+ config.options.crop_top = region.fTop;
+ config.options.crop_width = region.width();
+ config.options.crop_height = region.height();
return true;
}
bool SkWEBPImageDecoder::setDecodeConfig(SkBitmap* decodedBitmap,
int width, int height) {
- bool hasAlpha = false;
SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, hasAlpha);
// YUV converter supports output in RGB565, RGBA4444 and RGBA8888 formats.
@@ -286,16 +275,15 @@ bool SkWEBPImageDecoder::setDecodeConfig(SkBitmap* decodedBitmap,
decodedBitmap->setConfig(config, width, height, 0);
- // Current WEBP specification has no support for alpha layer.
- decodedBitmap->setIsOpaque(true);
+ decodedBitmap->setIsOpaque(!hasAlpha);
return true;
}
bool SkWEBPImageDecoder::onBuildTileIndex(SkStream* stream,
int *width, int *height) {
- int origWidth, origHeight;
- if (!webp_parse_header(stream, &origWidth, &origHeight)) {
+ int origWidth, origHeight, hasAlpha;
+ if (!webp_parse_header(stream, &origWidth, &origHeight, &hasAlpha)) {
return false;
}
@@ -306,11 +294,12 @@ bool SkWEBPImageDecoder::onBuildTileIndex(SkStream* stream,
this->inputStream = stream;
this->origWidth = origWidth;
this->origHeight = origHeight;
+ this->hasAlpha = hasAlpha;
return true;
}
-static bool isConfigCompatiable(SkBitmap* bitmap) {
+static bool isConfigCompatible(SkBitmap* bitmap) {
SkBitmap::Config config = bitmap->config();
return config == SkBitmap::kARGB_4444_Config ||
config == SkBitmap::kRGB_565_Config ||
@@ -338,9 +327,9 @@ bool SkWEBPImageDecoder::onDecodeRegion(SkBitmap* decodedBitmap,
// 3. bitmap's size is same as the required region (after sampled)
bool directDecode = (rect == region) &&
(decodedBitmap->isNull() ||
- isConfigCompatiable(decodedBitmap) &&
+ (isConfigCompatible(decodedBitmap) &&
(decodedBitmap->width() == width) &&
- (decodedBitmap->height() == height));
+ (decodedBitmap->height() == height)));
SkTScopedPtr<SkBitmap> adb;
SkBitmap *bitmap = decodedBitmap;
@@ -394,10 +383,11 @@ bool SkWEBPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap,
AutoTimeMillis atm("WEBP Decode");
#endif
- int origWidth, origHeight;
- if (!webp_parse_header(stream, &origWidth, &origHeight)) {
+ int origWidth, origHeight, hasAlpha;
+ if (!webp_parse_header(stream, &origWidth, &origHeight, &hasAlpha)) {
return false;
}
+ this->hasAlpha = hasAlpha;
const int sampleSize = this->getSampleSize();
SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize);
@@ -568,8 +558,8 @@ bool SkWEBPImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bm,
#include "SkTRegistry.h"
static SkImageDecoder* DFactory(SkStream* stream) {
- int width, height;
- if (!webp_parse_header(stream, &width, &height)) {
+ int width, height, hasAlpha;
+ if (!webp_parse_header(stream, &width, &height, &hasAlpha)) {
return false;
}
diff --git a/src/ports/FontHostConfiguration_android.cpp b/src/ports/FontHostConfiguration_android.cpp
index d1164c8..9296769 100644
--- a/src/ports/FontHostConfiguration_android.cpp
+++ b/src/ports/FontHostConfiguration_android.cpp
@@ -18,6 +18,7 @@
#include "FontHostConfiguration_android.h"
#include "SkString.h"
#include "SkTDArray.h"
+#include "SkTypeface.h"
#include <expat.h>
#if !defined(SK_BUILD_FOR_ANDROID_NDK)
#include <cutils/properties.h>
@@ -46,12 +47,13 @@ struct FamilyData {
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
+ FontFileInfo *currentFontInfo; // The current fontInfo 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.
+ * or file tag. The resulting strings are put into the fNames or FontFileInfo arrays.
*/
void textHandler(void *data, const char *s, int len) {
FamilyData *familyData = (FamilyData*) data;
@@ -68,7 +70,9 @@ void textHandler(void *data, const char *s, int len) {
*(familyData->currentFamily->fNames.append()) = buff;
break;
case FILESET_TAG:
- *(familyData->currentFamily->fFileNames.append()) = buff;
+ if (familyData->currentFontInfo) {
+ familyData->currentFontInfo->fFileName = buff;
+ }
break;
default:
// Noop - don't care about any text that's not in the Fonts or Names list
@@ -78,6 +82,39 @@ void textHandler(void *data, const char *s, int len) {
}
/**
+ * Handler for font files. This processes the attributes for language and variants
+ * then lets textHandler handle the actual file name
+ */
+void fontFileElementHandler(FamilyData *familyData, const char **attributes) {
+ FontFileInfo* newFileInfo = new FontFileInfo();
+ if (attributes) {
+ int currentAttributeIndex = 0;
+ while (attributes[currentAttributeIndex]) {
+ const char* attributeName = attributes[currentAttributeIndex];
+ const char* attributeValue = attributes[currentAttributeIndex+1];
+ int nameLength = strlen(attributeName);
+ int valueLength = strlen(attributeValue);
+ if (strncmp(attributeName, "variant", nameLength) == 0) {
+ if (strncmp(attributeValue, "elegant", valueLength) == 0) {
+ newFileInfo->fVariant = SkPaint::kElegant_Variant;
+ } else if (strncmp(attributeValue, "compact", valueLength) == 0) {
+ newFileInfo->fVariant = SkPaint::kCompact_Variant;
+ }
+ } else if (strncmp(attributeName, "language", nameLength) == 0) {
+ if (strncmp(attributeValue, "ja", valueLength) == 0) {
+ newFileInfo->fLanguage = "ja";
+ } //else if (other languages)
+ }
+ //each element is a pair of attributeName/attributeValue string pairs
+ currentAttributeIndex += 2;
+ }
+ }
+ *(familyData->currentFamily->fFontFileArray.append()) = newFileInfo;
+ familyData->currentFontInfo = newFileInfo;
+ XML_SetCharacterDataHandler(*familyData->parser, textHandler);
+}
+
+/**
* Handler for the start of a tag. The only tags we expect are family, nameset,
* fileset, name, and file.
*/
@@ -98,14 +135,16 @@ void startElementHandler(void *data, const char *tag, const char **atts) {
familyData->currentFamily->order = value;
}
}
- } else if (len == 7 && strncmp(tag, "nameset", len)== 0) {
+ } 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)) {
+ } else if (strncmp(tag, "name", len) == 0 && familyData->currentTag == NAMESET_TAG) {
// If it's a Name, parse the text inside
XML_SetCharacterDataHandler(*familyData->parser, textHandler);
+ } else if (strncmp(tag, "file", len) == 0 && familyData->currentTag == FILESET_TAG) {
+ // If it's a file, parse the attributes, then parse the text inside
+ fontFileElementHandler(familyData, atts);
}
}
@@ -120,9 +159,9 @@ void endElementHandler(void *data, const char *tag) {
// 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) {
+ } else if (len == 7 && strncmp(tag, "nameset", len) == 0) {
familyData->currentTag = NO_TAG;
- } else if (len == 7 && strncmp(tag, "fileset", len)== 0) {
+ } 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)) {
diff --git a/src/ports/FontHostConfiguration_android.h b/src/ports/FontHostConfiguration_android.h
index 2441f0e..c8a70e3 100644
--- a/src/ports/FontHostConfiguration_android.h
+++ b/src/ports/FontHostConfiguration_android.h
@@ -18,18 +18,27 @@
#define FONTHOSTCONFIGURATION_ANDROID_H_
#include "SkTDArray.h"
+#include "SkPaint.h"
+
+struct FontFileInfo {
+ FontFileInfo() : fVariant(SkPaint::kDefault_Variant), fLanguage(NULL), fFileName(NULL) {}
+ const char* fFileName;
+ SkPaint::FontVariant fVariant;
+ const char* fLanguage; // We may eventually use a enum for this
+};
+
/**
* 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
+ * font names that alias to a font family. fontFileArray is the list of information
+ * about each file. 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;
+ SkTDArray<const char*> fNames;
+ SkTDArray<FontFileInfo*> fFontFileArray;
int order;
};
diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp
index fc60ef9..6aa2120 100644
--- a/src/ports/SkFontHost_FreeType.cpp
+++ b/src/ports/SkFontHost_FreeType.cpp
@@ -961,8 +961,8 @@ void SkScalerContext_FreeType::generateAdvance(SkGlyph* glyph) {
if (0 == error) {
glyph->fRsbDelta = 0;
glyph->fLsbDelta = 0;
- glyph->fAdvanceX = advance; // advance *2/3; //DEBUG
- glyph->fAdvanceY = 0;
+ glyph->fAdvanceX = SkFixedMul(fMatrix22.xx, advance); // advance *2/3; //DEBUG
+ glyph->fAdvanceY = -SkFixedMul(fMatrix22.yx, advance);
return;
}
}
diff --git a/src/ports/SkFontHost_android.cpp b/src/ports/SkFontHost_android.cpp
index 2c58079..38d1d06 100644
--- a/src/ports/SkFontHost_android.cpp
+++ b/src/ports/SkFontHost_android.cpp
@@ -27,6 +27,9 @@
#include "FontHostConfiguration_android.h"
#include <stdio.h>
#include <string.h>
+#include "SkGlyphCache.h"
+#include "SkTypeface_android.h"
+#include "SkTSearch.h"
//#define SkDEBUGF(args ) SkDebugf args
@@ -73,7 +76,7 @@ static SkTypeface* createTypefaceLocked(const SkTypeface* familyFace,
SkTypeface::Style style);
static SkStream* openStreamLocked(uint32_t fontID);
static size_t getFileNameLocked(SkFontID fontID, char path[], size_t length, int32_t* index);
-static SkFontID nextLogicalFontLocked(SkFontID currFontID, SkFontID origFontID);
+static SkFontID nextLogicalFontLocked(const SkScalerContext::Rec& rec);
static SkTypeface* createTypefaceFromStreamLocked(SkStream* stream);
///////////////////////////////////////////////////////////////////////////////
@@ -147,6 +150,12 @@ static SkTypeface* findBestFaceLocked(const FamilyRec* family,
return NULL;
}
+static SkTypeface* FindBestFace(const FamilyRec* family,
+ SkTypeface::Style style) {
+ SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
+ return findBestFaceLocked(family, style);
+}
+
static FamilyRec* findFamilyLocked(const SkTypeface* member) {
FamilyRec* curr = gFamilyHead;
while (curr != NULL) {
@@ -177,6 +186,14 @@ static SkTypeface* findFromUniqueIDLocked(uint32_t uniqueID) {
return NULL;
}
+/* Returns the matching typeface, or NULL. If a typeface is found, its refcnt
+ is not modified.
+ */
+static SkTypeface* FindFromUniqueID(uint32_t uniqueID) {
+ SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
+ return findFromUniqueIDLocked(uniqueID);
+}
+
/* Remove reference to this face from its family. If the resulting family
is empty (has no faces), return that family, otherwise return NULL
*/
@@ -394,8 +411,15 @@ private:
// used to record our notion of the pre-existing fonts
struct FontInitRec {
- const char* fFileName;
- const char* const* fNames; // null-terminated list
+ const char* fFileName;
+ const char* const* fNames; // null-terminated list
+ SkPaint::FontVariant fVariant;
+};
+
+//used to record information about the fallback fonts
+struct FallbackFontRec {
+ SkFontID fFontID;
+ SkPaint::FontVariant fVariant;
};
// deliberately empty, but we use the address to identify fallback fonts
@@ -407,7 +431,7 @@ static const char* gFBNames[] = { NULL };
null for the list. The names list must be NULL-terminated.
*/
static SkTDArray<FontInitRec> gSystemFonts;
-static SkTDArray<SkFontID> gFallbackFonts;
+static SkTDArray<FallbackFontRec> gFallbackFonts;
// these globals are assigned (once) by loadSystemFontsLocked()
static FamilyRec* gDefaultFamily = NULL;
@@ -490,8 +514,8 @@ static void loadFontInfoLocked() {
for (int i = 0; i < fontFamilies.count(); ++i) {
FontFamily *family = fontFamilies[i];
- for (int j = 0; j < family->fFileNames.count(); ++j) {
- const char* filename = family->fFileNames[j];
+ for (int j = 0; j < family->fFontFileArray.count(); ++j) {
+ const char* filename = family->fFontFileArray[j]->fFileName;
if (haveSystemFont(filename)) {
SkDebugf("---- system font and fallback font files specify a duplicate "
"font %s, skipping the second occurrence", filename);
@@ -500,6 +524,7 @@ static void loadFontInfoLocked() {
FontInitRec fontInfoRecord;
fontInfoRecord.fFileName = filename;
+ fontInfoRecord.fVariant = family->fFontFileArray[j]->fVariant;
if (j == 0) {
if (family->fNames.count() == 0) {
// Fallback font
@@ -592,7 +617,10 @@ static void initSystemFontsLocked() {
if (names == gFBNames) {
SkDEBUGF(("---- adding %s as fallback[%d] fontID %d\n",
gSystemFonts[i].fFileName, gFallbackFonts.count(), tf->uniqueID()));
- *gFallbackFonts.append() = tf->uniqueID();
+ FallbackFontRec newFallbackRec;
+ newFallbackRec.fFontID = tf->uniqueID();
+ newFallbackRec.fVariant = gSystemFonts[i].fVariant;
+ *gFallbackFonts.append() = newFallbackRec;
}
firstInFamily = tf;
@@ -631,7 +659,7 @@ static SkFontID findUniqueIDLocked(const char* filename) {
static int findFallbackFontIndex(SkFontID fontId) {
for (int i = 0; i < gFallbackFonts.count(); i++) {
- if (gFallbackFonts[i] == fontId) {
+ if (gFallbackFonts[i].fFontID == fontId) {
return i;
}
}
@@ -649,8 +677,8 @@ static void reloadFallbackFontsLocked() {
for (int i = 0; i < fallbackFamilies.count(); ++i) {
FontFamily *family = fallbackFamilies[i];
- for (int j = 0; j < family->fFileNames.count(); ++j) {
- const char* filename = family->fFileNames[j];
+ for (int j = 0; j < family->fFontFileArray.count(); ++j) {
+ const char* filename = family->fFontFileArray[j]->fFileName;
if (filename) {
if (!haveSystemFont(filename)) {
SkDebugf("---- skipping fallback font %s because it was not "
@@ -677,8 +705,10 @@ static void reloadFallbackFontsLocked() {
SkDEBUGF(("---- reload %s as fallback[%d] fontID %d\n",
filename, gFallbackFonts.count(), uniqueID));
-
- *gFallbackFonts.append() = uniqueID;
+ FallbackFontRec newFallbackFont;
+ newFallbackFont.fFontID = uniqueID;
+ newFallbackFont.fVariant = family->fFontFileArray[j]->fVariant;
+ *gFallbackFonts.append() = newFallbackFont;
break; // The fallback set contains only the first font of each family
}
}
@@ -883,16 +913,16 @@ static size_t getFileNameLocked(SkFontID fontID, char path[], size_t length, int
}
}
-SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
+SkFontID SkFontHost::NextLogicalFont(const SkScalerContext::Rec& rec) {
SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
- return nextLogicalFontLocked(currFontID, origFontID);
+ return nextLogicalFontLocked(rec);
}
-static SkFontID nextLogicalFontLocked(SkFontID currFontID, SkFontID origFontID) {
+static SkFontID nextLogicalFontLocked(const SkScalerContext::Rec& rec) {
loadSystemFontsLocked();
- const SkTypeface* origTypeface = findFromUniqueIDLocked(origFontID);
- const SkTypeface* currTypeface = findFromUniqueIDLocked(currFontID);
+ const SkTypeface* origTypeface = findFromUniqueIDLocked(rec.fOrigFontID);
+ const SkTypeface* currTypeface = findFromUniqueIDLocked(rec.fFontID);
SkASSERT(origTypeface != 0);
SkASSERT(currTypeface != 0);
@@ -908,17 +938,30 @@ static SkFontID nextLogicalFontLocked(SkFontID currFontID, SkFontID origFontID)
*/
int plainFallbackFontIndex = findFallbackFontIndex(plainFontID);
int nextFallbackFontIndex = plainFallbackFontIndex + 1;
- SkFontID nextFontID;
- if (nextFallbackFontIndex == gFallbackFonts.count()) {
- nextFontID = 0; // no more fallbacks
- } else {
- const SkTypeface* nextTypeface = findFromUniqueIDLocked(gFallbackFonts[nextFallbackFontIndex]);
- nextFontID = findTypefaceLocked(nextTypeface, origTypeface->style())->uniqueID();
+
+ // If a rec object is set to prefer "kDefault_Variant" it means they have no preference
+ // In this case, we set the value to "kCompact_Variant"
+ SkPaint::FontVariant recPreference = rec.fFontVariant;
+ if (recPreference == SkPaint::kDefault_Variant) {
+ recPreference = SkPaint::kCompact_Variant;
+ }
+ SkFontID nextFontID = 0;
+ while (nextFallbackFontIndex < gFallbackFonts.count()) {
+ bool normalFont =
+ (gFallbackFonts[nextFallbackFontIndex].fVariant == SkPaint::kDefault_Variant);
+ bool fontChosen = (gFallbackFonts[nextFallbackFontIndex].fVariant == recPreference);
+ if (normalFont || fontChosen) {
+ const SkTypeface* nextTypeface =
+ findFromUniqueIDLocked(gFallbackFonts[nextFallbackFontIndex].fFontID);
+ nextFontID = findTypefaceLocked(nextTypeface, origTypeface->style())->uniqueID();
+ break;
+ }
+ nextFallbackFontIndex++;
}
SkDEBUGF(("---- nextLogicalFont: currFontID=%d, origFontID=%d, plainFontID=%d, "
"plainFallbackFontIndex=%d, nextFallbackFontIndex=%d "
- "=> nextFontID=%d", currFontID, origFontID, plainFontID,
+ "=> nextFontID=%d", rec.fFontID, rec.fOrigFontID, plainFontID,
plainFallbackFontIndex, nextFallbackFontIndex, nextFontID));
return nextFontID;
}
@@ -958,3 +1001,143 @@ SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
stream->unref();
return face;
}
+
+///////////////////////////////////////////////////////////////////////////////
+// Function from SkTypeface_android.h
+///////////////////////////////////////////////////////////////////////////////
+
+static SkFontID findFontIDForChar(SkUnichar uni, SkTypeface::Style style,
+ SkPaint::FontVariant fontVariant) {
+ SkTypeface* face = FindBestFace(gDefaultFamily, style);
+ if (!face) {
+ return 0;
+ }
+
+ SkPaint paint;
+ paint.setTypeface(face);
+ paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+ paint.setFontVariant(fontVariant);
+
+ SkAutoGlyphCache autoCache(paint, NULL);
+ SkGlyphCache* cache = autoCache.getCache();
+ SkFontID fontID = 0;
+
+ SkScalerContext* ctx = cache->getScalerContext();
+ if (ctx) {
+ return ctx->findTypefaceIdForChar(uni);
+ }
+ return 0;
+}
+
+struct HB_UnicodeMapping {
+ HB_Script script;
+ const SkUnichar unicode;
+};
+
+/*
+ * The following scripts are not complex fonts and we do not expect them to be parsed by this table
+ * HB_Script_Common,
+ * HB_Script_Greek,
+ * HB_Script_Cyrillic,
+ * HB_Script_Hangul
+ * HB_Script_Inherited
+ */
+
+static HB_UnicodeMapping HB_UnicodeMappingArray[] {
+ {HB_Script_Armenian, 0x0531},
+ {HB_Script_Hebrew, 0x0591},
+ {HB_Script_Arabic, 0x0600},
+ {HB_Script_Syriac, 0x0710},
+ {HB_Script_Thaana, 0x0780},
+ {HB_Script_Nko, 0x07C0},
+ {HB_Script_Devanagari, 0x0901},
+ {HB_Script_Bengali, 0x0981},
+ {HB_Script_Gurmukhi, 0x0A10},
+ {HB_Script_Gujarati, 0x0A90},
+ {HB_Script_Oriya, 0x0B10},
+ {HB_Script_Tamil, 0x0B82},
+ {HB_Script_Telugu, 0x0C10},
+ {HB_Script_Kannada, 0x0C90},
+ {HB_Script_Malayalam, 0x0D10},
+ {HB_Script_Sinhala, 0x0D90},
+ {HB_Script_Thai, 0x0E01},
+ {HB_Script_Lao, 0x0E81},
+ {HB_Script_Tibetan, 0x0F00},
+ {HB_Script_Myanmar, 0x1000},
+ {HB_Script_Georgian, 0x10A0},
+ // we don't currently support HB_Script_Ethiopic, it is a placeholder for an upstream merge
+ //{HB_Script_Ethiopic, 0x1200},
+ {HB_Script_Ogham, 0x1680},
+ {HB_Script_Runic, 0x16A0},
+ {HB_Script_Khmer, 0x1780},
+};
+
+// returns 0 for "Not Found"
+static SkUnichar getUnicodeFromHBScript(HB_Script script) {
+ SkUnichar unichar = 0;
+ int numSupportedFonts = sizeof(HB_UnicodeMappingArray) / sizeof(HB_UnicodeMapping);
+ for (int i = 0; i < numSupportedFonts; i++) {
+ if (script == HB_UnicodeMappingArray[i].script) {
+ unichar = HB_UnicodeMappingArray[i].unicode;
+ break;
+ }
+ }
+ return unichar;
+}
+
+struct TypefaceLookupStruct {
+ HB_Script script;
+ SkTypeface::Style style;
+ SkPaint::FontVariant fontVariant;
+ SkTypeface* typeface;
+};
+
+SK_DECLARE_STATIC_MUTEX(gTypefaceTableMutex); // This is the mutex for gTypefaceTable
+static SkTDArray<TypefaceLookupStruct> gTypefaceTable; // This is protected by gTypefaceTableMutex
+
+static int typefaceLookupCompare(const TypefaceLookupStruct& first,
+ const TypefaceLookupStruct& second) {
+ if (first.script != second.script) {
+ return (first.script > second.script) ? 1 : -1;
+ }
+ if (first.style != second.style) {
+ return (first.style > second.style) ? 1 : -1;
+ }
+ if (first.fontVariant != second.fontVariant) {
+ return (first.fontVariant > second.fontVariant) ? 1 : -1;
+ }
+ return 0;
+}
+
+SK_API SkTypeface* SkCreateTypefaceForScript(HB_Script script, SkTypeface::Style style,
+ SkPaint::FontVariant fontVariant) {
+ SkTypeface* retTypeface = NULL;
+
+ SkAutoMutexAcquire ac(gTypefaceTableMutex); // Note: NOT gFamilyHeadAndNameListMutex
+ TypefaceLookupStruct key;
+ key.script = script;
+ key.style = style;
+ key.fontVariant = fontVariant;
+ int index = SkTSearch<TypefaceLookupStruct>(
+ (const TypefaceLookupStruct*) gTypefaceTable.begin(),
+ gTypefaceTable.count(), key, sizeof(TypefaceLookupStruct),
+ &typefaceLookupCompare);
+ if (index >= 0) {
+ retTypeface = gTypefaceTable[index].typeface;
+ }
+ else {
+ SkUnichar unichar = getUnicodeFromHBScript(script);
+ if (!unichar) {
+ return NULL;
+ }
+ SkFontID newFontID = findFontIDForChar(unichar, style, fontVariant);
+ // retrieve the typeface that corresponds to this fontID
+ retTypeface = FindFromUniqueID(newFontID);
+ key.typeface = retTypeface;
+ index = ~index;
+ *gTypefaceTable.insert(index) = key;
+ }
+ // we ref(), the caller is expected to unref when they are done
+ SkSafeRef(retTypeface);
+ return retTypeface;
+}