aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk1
-rw-r--r--ThirdPartyProject.prop9
-rw-r--r--include/core/SkPaint.h4
-rw-r--r--include/core/SkScalerContext.h14
-rw-r--r--include/ports/SkTypeface_android.h26
-rw-r--r--src/core/SkGlyphCache.h2
-rw-r--r--src/images/SkImageDecoder_libwebp.cpp100
-rw-r--r--src/ports/SkFontHost_android.cpp135
8 files changed, 219 insertions, 72 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/SkPaint.h b/include/core/SkPaint.h
index 0ec6698..30ff663 100644
--- a/include/core/SkPaint.h
+++ b/include/core/SkPaint.h
@@ -861,10 +861,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&);
diff --git a/include/core/SkScalerContext.h b/include/core/SkScalerContext.h
index 29679d6..9bcf601 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
@@ -299,6 +300,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..3471a94 100644
--- a/include/ports/SkTypeface_android.h
+++ b/include/ports/SkTypeface_android.h
@@ -10,8 +10,6 @@
#define SkTypeface_android_DEFINED
#include "SkTypeface.h"
-#include "SkPaint.h"
-#include "../harfbuzz/src/harfbuzz-shaper.h"
enum FallbackScripts {
kArabic_FallbackScript,
@@ -31,8 +29,28 @@ enum FallbackScripts {
kFallbackScriptNumber
};
+#define SkTypeface_ValidScript(s) (s >= 0 && s < kFallbackScriptNumber)
-SK_API SkTypeface* SkCreateTypefaceForScript(HB_Script script, SkTypeface::Style style,
- SkPaint::FontVariant fontVariant) { return NULL; }
+/**
+ * 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 script id.
+ * @return reference to the matching typeface. Caller must call
+ * unref() when they are done.
+ */
+SK_API SkTypeface* SkCreateTypefaceForScript(FallbackScripts script);
+
+/**
+ * Return the string representation for the fallback script on Android.
+ * If the script is not valid, returns null.
+ */
+SK_API const char* SkGetFallbackScriptID(FallbackScripts script);
+
+/**
+ * Return the fallback script enum for the ID on Android.
+ * If the ID is not valid, or can not map to a fallback
+ * script, returns kFallbackScriptNumber.
+ */
+SK_API FallbackScripts SkGetFallbackScriptFromID(const char* id);
#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/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/SkFontHost_android.cpp b/src/ports/SkFontHost_android.cpp
index 2c58079..afd0ebe 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"
+
//#define SkDEBUGF(args ) SkDebugf args
@@ -958,3 +961,135 @@ SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
stream->unref();
return face;
}
+
+///////////////////////////////////////////////////////////////////////////////
+// Function from SkTypeface_android.h
+///////////////////////////////////////////////////////////////////////////////
+
+struct FBScriptInfo {
+ const FallbackScripts fScript;
+ const char* fScriptID;
+ const SkTypeface::Style fStyle;
+ const SkUnichar fChar; // representative character for that script type
+ SkFontID fFontID;
+};
+
+#define SK_DEFINE_SCRIPT_ENTRY(script, style, unichar) \
+ { script, #script, style, unichar, 0 }
+
+static FBScriptInfo gFBScriptInfo[] = {
+ SK_DEFINE_SCRIPT_ENTRY(kArabic_FallbackScript, SkTypeface::kNormal, 0x0600),
+ SK_DEFINE_SCRIPT_ENTRY(kArmenian_FallbackScript, SkTypeface::kNormal, 0x0531),
+ SK_DEFINE_SCRIPT_ENTRY(kBengali_FallbackScript, SkTypeface::kNormal, 0x0981),
+ SK_DEFINE_SCRIPT_ENTRY(kDevanagari_FallbackScript, SkTypeface::kNormal, 0x0901),
+ SK_DEFINE_SCRIPT_ENTRY(kEthiopic_FallbackScript, SkTypeface::kNormal, 0x1200),
+ SK_DEFINE_SCRIPT_ENTRY(kGeorgian_FallbackScript, SkTypeface::kNormal, 0x10A0),
+ SK_DEFINE_SCRIPT_ENTRY(kHebrewRegular_FallbackScript, SkTypeface::kNormal, 0x0591),
+ SK_DEFINE_SCRIPT_ENTRY(kHebrewBold_FallbackScript, SkTypeface::kBold, 0x0591),
+ SK_DEFINE_SCRIPT_ENTRY(kKannada_FallbackScript, SkTypeface::kNormal, 0x0C90),
+ SK_DEFINE_SCRIPT_ENTRY(kMalayalam_FallbackScript, SkTypeface::kNormal, 0x0D10),
+ SK_DEFINE_SCRIPT_ENTRY(kTamilRegular_FallbackScript, SkTypeface::kNormal, 0x0B82),
+ SK_DEFINE_SCRIPT_ENTRY(kTamilBold_FallbackScript, SkTypeface::kBold, 0x0B82),
+ SK_DEFINE_SCRIPT_ENTRY(kThai_FallbackScript, SkTypeface::kNormal, 0x0E01),
+ SK_DEFINE_SCRIPT_ENTRY(kTelugu_FallbackScript, SkTypeface::kNormal, 0x0C10),
+};
+
+static bool gFBScriptInitialized = false;
+static const int gFBScriptInfoCount = sizeof(gFBScriptInfo) / sizeof(FBScriptInfo);
+
+// ensure that if any value is added to the public enum it is also added here
+SK_COMPILE_ASSERT(gFBScriptInfoCount == kFallbackScriptNumber, FBScript_count_mismatch);
+
+
+// this function can't be called if the gFamilyHeadAndNameListMutex is already locked
+static SkFontID findFontIDForChar(SkUnichar uni, SkTypeface::Style style) {
+ gFamilyHeadAndNameListMutex.acquire();
+ SkTypeface* face = findBestFaceLocked(gDefaultFamily, style);
+ gFamilyHeadAndNameListMutex.release();
+ if (!face) {
+ return 0;
+ }
+
+ SkPaint paint;
+ paint.setTypeface(face);
+ paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+
+ SkAutoGlyphCache autoCache(paint, NULL);
+ SkGlyphCache* cache = autoCache.getCache();
+ SkFontID fontID = 0;
+
+ SkScalerContext* ctx = cache->getScalerContext();
+ if (ctx) {
+ return ctx->findTypefaceIdForChar(uni);
+ }
+ return 0;
+}
+
+// this function can't be called if the gFamilyHeadAndNameListMutex is already locked
+static void initFBScriptInfo() {
+ if (gFBScriptInitialized) {
+ return;
+ }
+
+ // ensure the system fonts are loaded
+ gFamilyHeadAndNameListMutex.acquire();
+ loadSystemFontsLocked();
+ gFamilyHeadAndNameListMutex.release();
+
+ for (int i = 0; i < gFBScriptInfoCount; i++) {
+ FBScriptInfo& scriptInfo = gFBScriptInfo[i];
+ // selects the best available style for the desired font. However, if
+ // bold is requested and no bold font exists for the typeface containing
+ // the character the next best style is chosen (e.g. normal).
+ scriptInfo.fFontID = findFontIDForChar(scriptInfo.fChar, scriptInfo.fStyle);
+ SkDEBUGF(("gFBScriptInfo[%s] --> %d", scriptInfo.fScriptID, scriptInfo.fFontID));
+ }
+ // mark the value as initialized so we don't repeat our work unnecessarily
+ gFBScriptInitialized = true;
+}
+
+SkTypeface* SkCreateTypefaceForScript(FallbackScripts script) {
+ if (!SkTypeface_ValidScript(script)) {
+ return NULL;
+ }
+
+ // ensure that our table is populated
+ initFBScriptInfo();
+
+ FBScriptInfo& scriptInfo = gFBScriptInfo[script];
+
+ // ensure the element with that index actually maps to the correct script
+ SkASSERT(scriptInfo.fScript == script);
+
+ // if a suitable script could not be found then return NULL
+ if (scriptInfo.fFontID == 0) {
+ return NULL;
+ }
+
+ SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex);
+
+ // retrieve the typeface the corresponds to this fontID
+ SkTypeface* tf = findFromUniqueIDLocked(scriptInfo.fFontID);
+ // we ref(), since the semantic is to return a new instance
+ tf->ref();
+ return tf;
+}
+
+const char* SkGetFallbackScriptID(FallbackScripts script) {
+ for (int i = 0; i < gFBScriptInfoCount; i++) {
+ if (gFBScriptInfo[i].fScript == script) {
+ return gFBScriptInfo[i].fScriptID;
+ }
+ }
+ return NULL;
+}
+
+FallbackScripts SkGetFallbackScriptFromID(const char* id) {
+ for (int i = 0; i < gFBScriptInfoCount; i++) {
+ if (strcmp(gFBScriptInfo[i].fScriptID, id) == 0) {
+ return gFBScriptInfo[i].fScript;
+ }
+ }
+ return kFallbackScriptNumber; // Use kFallbackScriptNumber as an invalid value.
+}
+