From 2248d4e08fbbcfea7c2187f6e3eab45a9841db7b Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Queru Date: Wed, 2 May 2012 16:47:22 -0700 Subject: Tweaks for forward-compatibility Change-Id: I3c734d0f7961aada86977d3b7414ee489f3f6c05 --- include/utils/SkNWayCanvas.h | 2 +- src/core/SkCanvas.cpp | 12 ++++++++++++ src/utils/SkNWayCanvas.cpp | 6 +++++- tests/CanvasTest.cpp | 3 ++- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/include/utils/SkNWayCanvas.h b/include/utils/SkNWayCanvas.h index 69c1fcf..dbf4a58 100644 --- a/include/utils/SkNWayCanvas.h +++ b/include/utils/SkNWayCanvas.h @@ -13,7 +13,7 @@ class SkNWayCanvas : public SkCanvas { public: - SkNWayCanvas(); + SkNWayCanvas(int width, int height); virtual ~SkNWayCanvas(); void addCanvas(SkCanvas*); diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index aa92dd0..7861636 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -573,6 +573,9 @@ bool SkCanvas::readPixels(SkBitmap* bitmap, bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) { SkDevice* device = this->getDevice(); + if (!device) { + return false; + } SkIRect bounds; bounds.set(0, 0, device->width(), device->height()); @@ -1058,6 +1061,10 @@ static bool clipPathHelper(const SkCanvas* canvas, SkRasterClip* currClip, } } else { const SkDevice* device = canvas->getDevice(); + if (!device) { + return currClip->setEmpty(); + } + base.setRect(0, 0, device->width(), device->height()); if (SkRegion::kReplace_Op == op) { @@ -1114,6 +1121,11 @@ bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { void SkCanvas::validateClip() const { // construct clipRgn from the clipstack const SkDevice* device = this->getDevice(); + if (!device) { + SkASSERT(this->getTotalClip().isEmpty()); + return; + } + SkIRect ir; ir.set(0, 0, device->width(), device->height()); SkRasterClip tmpClip(ir); diff --git a/src/utils/SkNWayCanvas.cpp b/src/utils/SkNWayCanvas.cpp index 06cf32d..9f6ebc6 100644 --- a/src/utils/SkNWayCanvas.cpp +++ b/src/utils/SkNWayCanvas.cpp @@ -7,7 +7,11 @@ */ #include "SkNWayCanvas.h" -SkNWayCanvas::SkNWayCanvas() {} +SkNWayCanvas::SkNWayCanvas(int width, int height) { + SkBitmap bm; + bm.setConfig(SkBitmap::kNo_Config, width, height); + this->setBitmapDevice(bm); +} SkNWayCanvas::~SkNWayCanvas() { this->removeAll(); diff --git a/tests/CanvasTest.cpp b/tests/CanvasTest.cpp index 7cafda2..76573ed 100644 --- a/tests/CanvasTest.cpp +++ b/tests/CanvasTest.cpp @@ -691,7 +691,8 @@ static void TestNWayCanvasStateConsistency( SkDevice indirectDevice2(indirectStore2); SkCanvas indirectCanvas2(&indirectDevice2); - SkNWayCanvas nWayCanvas; + SkISize canvasSize = referenceCanvas.getDeviceSize(); + SkNWayCanvas nWayCanvas(canvasSize.width(), canvasSize.height()); nWayCanvas.addCanvas(&indirectCanvas1); nWayCanvas.addCanvas(&indirectCanvas2); -- cgit v1.1 From dc7d4843a1b47c431ec5b358e8d9807e309a735e Mon Sep 17 00:00:00 2001 From: Romain Guy Date: Mon, 14 May 2012 13:59:31 -0700 Subject: Add new utfToGlyphs API for GL renderer Bug #6408362 DO NOT MERGE Change-Id: I3103fb1249afc2845259a85caae849c8b3fb3980 --- include/core/SkPaint.h | 3 +++ src/core/SkPaint.cpp | 31 +++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h index 7be5ad2..30ff663 100644 --- a/include/core/SkPaint.h +++ b/include/core/SkPaint.h @@ -870,6 +870,9 @@ public: /** Returns the base glyph count for the strike associated with this paint */ unsigned getBaseGlyphCount(SkUnichar text) const; + + int utfToGlyphs(const void* text, TextEncoding encoding, + size_t byteLength, uint16_t glyphs[]) const; #endif // returns true if the paint's settings (e.g. xfermode + alpha) resolve to diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp index 82a1f57..07fe9b0 100644 --- a/src/core/SkPaint.cpp +++ b/src/core/SkPaint.cpp @@ -440,6 +440,37 @@ const void* SkPaint::findImage(const SkGlyph& glyph) { SkGlyphCache::AttachCache(cache); return image; } + +int SkPaint::utfToGlyphs(const void* textData, TextEncoding encoding, + size_t byteLength, uint16_t glyphs[]) const { + + SkAutoGlyphCache autoCache(*this, NULL); + SkGlyphCache* cache = autoCache.getCache(); + + const char* text = (const char*) textData; + const char* stop = text + byteLength; + uint16_t* gptr = glyphs; + + switch (encoding) { + case SkPaint::kUTF8_TextEncoding: + while (text < stop) { + *gptr++ = cache->unicharToGlyph(SkUTF8_NextUnichar(&text)); + } + break; + case SkPaint::kUTF16_TextEncoding: { + const uint16_t* text16 = (const uint16_t*)text; + const uint16_t* stop16 = (const uint16_t*)stop; + while (text16 < stop16) { + *gptr++ = cache->unicharToGlyph(SkUTF16_NextUnichar(&text16)); + } + break; + } + default: + SkDEBUGFAIL("unknown text encoding"); + } + return gptr - glyphs; +} + #endif int SkPaint::textToGlyphs(const void* textData, size_t byteLength, -- cgit v1.1 From f155f5c356828b086d98fb0a0a4f03da2b1a9858 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 15 May 2012 13:41:31 -0700 Subject: Remove obsolete ThirdPartyProject.prop file. Change-Id: Idfcfd2c29869e78833df93125f5fed2d1bffdb78 --- ThirdPartyProject.prop | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 ThirdPartyProject.prop 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/ -- cgit v1.1 From cde7dcc5111806870f94721561056e990a9211c8 Mon Sep 17 00:00:00 2001 From: Billy Hewlett Date: Mon, 4 Jun 2012 13:37:11 -0700 Subject: Fix hardcoded font path. Allow adding new font path thru Skia changes. Bug: 6609231 Change-Id: Ie37ada42e7e78ab78318f3ed76eb627bffaddb1a --- Android.mk | 1 + include/core/SkScalerContext.h | 14 ++++ include/ports/SkTypeface_android.h | 56 +++++++++++++++ src/core/SkGlyphCache.h | 2 + src/ports/SkFontHost_android.cpp | 135 +++++++++++++++++++++++++++++++++++++ 5 files changed, 208 insertions(+) create mode 100644 include/ports/SkTypeface_android.h diff --git a/Android.mk b/Android.mk index 0630d51..4bc95ed 100644 --- a/Android.mk +++ b/Android.mk @@ -291,6 +291,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/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 new file mode 100644 index 0000000..3471a94 --- /dev/null +++ b/include/ports/SkTypeface_android.h @@ -0,0 +1,56 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkTypeface_android_DEFINED +#define SkTypeface_android_DEFINED + +#include "SkTypeface.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 +}; + +#define SkTypeface_ValidScript(s) (s >= 0 && s < kFallbackScriptNumber) + +/** + * 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/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 #include +#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. +} + -- cgit v1.1 From 22c3eb1bb4ab1c58edb7b3dd159e5c1969136c51 Mon Sep 17 00:00:00 2001 From: Vikas Arora Date: Thu, 31 May 2012 11:29:48 +0530 Subject: Prepare Skia-Webp decoder for Alpha and lossless. Change the webp_parse_header to read appropriate header bytes (required for Alpha & lossless bit-stream); Replaced call WebPGetInfo with WebPGetFeatures to get hasAlpha information; Replaced hard-coded setIsOpaque(true) with setIsOpaque(!hasAlpha); Refactored code for setting decoder config; Change-Id: I8208233d1aaa0a213a35dd996a72e43f78901c89 --- src/images/SkImageDecoder_libwebp.cpp | 100 +++++++++++++++------------------- 1 file changed, 45 insertions(+), 55 deletions(-) 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 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; } -- cgit v1.1 From 10a5e44dc3b8f22e8c4e862cd81d220b7fd4edfa Mon Sep 17 00:00:00 2001 From: Billy Hewlett Date: Thu, 7 Jun 2012 15:23:06 -0700 Subject: Cherrypick change to skia Change-Id: I9845f8d042fb89fe0f4876f0021b9ec486ac3ef5 --- include/ports/SkTypeface_android.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 include/ports/SkTypeface_android.h diff --git a/include/ports/SkTypeface_android.h b/include/ports/SkTypeface_android.h new file mode 100644 index 0000000..1a02a55 --- /dev/null +++ b/include/ports/SkTypeface_android.h @@ -0,0 +1,34 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkTypeface_android_DEFINED +#define SkTypeface_android_DEFINED + +#include "SkTypeface.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 +}; + + +SK_API SkTypeface* SkCreateTypefaceForScript(FallbackScripts script) {return NULL; } +#endif -- cgit v1.1 From 79bf51281ffa537ddfbb54dededdad5aa9e466e8 Mon Sep 17 00:00:00 2001 From: Victoria Lease Date: Wed, 13 Jun 2012 10:23:10 -0700 Subject: Skia solution to fake-bold fallback fonts. This version of the fake-bold-for-fallback-fonts fix addresses the issue succinctly inside of Skia, with no need for Skia's clients to be aware of the issue. Attempts to draw a bold parent font flag the embolden flag in the associated SkScalerContext while leaving the SkPaint's fake bold flag unmodified. This depends upon change Icdd13f6b, which arranges for FreeType's FontHost to ignore redundant embolden requests. Bug: 6629786 Change-Id: I4132a232896f72f632caefd79add2f00c36a578a --- src/core/SkPaint.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp index 07fe9b0..e1932a7 100644 --- a/src/core/SkPaint.cpp +++ b/src/core/SkPaint.cpp @@ -1447,7 +1447,8 @@ void SkScalerContext::MakeRec(const SkPaint& paint, const SkMatrix* deviceMatrix, Rec* rec) { SkASSERT(deviceMatrix == NULL || !deviceMatrix->hasPerspective()); - rec->fOrigFontID = SkTypeface::UniqueID(paint.getTypeface()); + SkTypeface* typeface = paint.getTypeface(); + rec->fOrigFontID = SkTypeface::UniqueID(typeface); rec->fFontID = rec->fOrigFontID; rec->fTextSize = paint.getTextSize(); rec->fPreScaleX = paint.getTextScaleX(); @@ -1468,10 +1469,21 @@ void SkScalerContext::MakeRec(const SkPaint& paint, unsigned flags = 0; - if (paint.isFakeBoldText()) { #ifdef SK_USE_FREETYPE_EMBOLDEN + // It is possible that the SkTypeface used to draw glyphs has + // different properties than the SkTypeface set in the SkPaint. + // If we are asked to render bold text with a bold font, and are + // forced to fall back to a font with normal weight for some + // glyphs, we need to use fake bold to render those glyphs. In + // order to do that, we set SkScalerContext's "embolden" flag + // here if we are trying to draw bold text via any means, and + // ignore it at the glyph outline generation stage if the font + // actually being used is already bold. + if (paint.isFakeBoldText() || (typeface && typeface->isBold())) { flags |= SkScalerContext::kEmbolden_Flag; + } #else + if (paint.isFakeBoldText()) { SkScalar fakeBoldScale = SkScalarInterpFunc(paint.getTextSize(), kStdFakeBoldInterpKeys, kStdFakeBoldInterpValues, @@ -1484,8 +1496,8 @@ void SkScalerContext::MakeRec(const SkPaint& paint, } else { strokeWidth += extra; } -#endif } +#endif if (paint.isDevKernText()) { flags |= SkScalerContext::kDevKernText_Flag; -- cgit v1.1 From 421654d4bf3ca50e2247a7389851d2e8f4812564 Mon Sep 17 00:00:00 2001 From: Billy Hewlett Date: Mon, 11 Jun 2012 15:52:55 -0700 Subject: Use Elegant fonts for Webkit, Compact fonts for Textview Fonts can be marked with elegant or compact in fallback_fonts.xml. Webkit uses elegant fonts, Textview uses compact fonts (the default), unmarked fonts are used by both. Bug: 6649136 Change-Id: I6ab6173c2efc50eba8fcc488c89dfdd083fb9c06 --- include/core/SkFontHost.h | 9 + include/core/SkPaint.h | 20 +++ include/core/SkScalerContext.h | 4 +- include/ports/SkTypeface_android.h | 45 +---- src/core/SkPaint.cpp | 16 ++ src/core/SkScalerContext.cpp | 8 +- src/ports/FontHostConfiguration_android.cpp | 53 +++++- src/ports/FontHostConfiguration_android.h | 17 +- src/ports/SkFontHost_android.cpp | 266 +++++++++++++++------------- 9 files changed, 269 insertions(+), 169 deletions(-) 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 30ff663..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. @@ -906,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 9bcf601..33c3c3d 100644 --- a/include/core/SkScalerContext.h +++ b/include/core/SkScalerContext.h @@ -210,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; @@ -234,7 +237,6 @@ public: SkMask::Format getFormat() const { return static_cast(fMaskFormat); } - #ifdef SK_USE_COLOR_LUMINANCE SkColor getLuminanceColor() const { return fLumBits; diff --git a/include/ports/SkTypeface_android.h b/include/ports/SkTypeface_android.h index 3471a94..c3eb3d1 100644 --- a/include/ports/SkTypeface_android.h +++ b/include/ports/SkTypeface_android.h @@ -10,47 +10,20 @@ #define SkTypeface_android_DEFINED #include "SkTypeface.h" +#include "SkPaint.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 -}; - -#define SkTypeface_ValidScript(s) (s >= 0 && s < 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 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. + * @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 FallbackScripts SkGetFallbackScriptFromID(const char* id); +SK_API SkTypeface* SkCreateTypefaceForScript(HB_Script script, SkTypeface::Style style, + SkPaint::FontVariant fontVariant = SkPaint::kDefault_Variant); #endif 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/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 #if !defined(SK_BUILD_FOR_ANDROID_NDK) #include @@ -46,12 +47,13 @@ struct FamilyData { XML_Parser *parser; // The expat parser doing the work SkTDArray &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 fNames; - SkTDArray fFileNames; + SkTDArray fNames; + SkTDArray fFontFileArray; int order; }; diff --git a/src/ports/SkFontHost_android.cpp b/src/ports/SkFontHost_android.cpp index afd0ebe..0a9cced 100644 --- a/src/ports/SkFontHost_android.cpp +++ b/src/ports/SkFontHost_android.cpp @@ -29,7 +29,7 @@ #include #include "SkGlyphCache.h" #include "SkTypeface_android.h" - +#include "SkTSearch.h" //#define SkDEBUGF(args ) SkDebugf args @@ -76,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); /////////////////////////////////////////////////////////////////////////////// @@ -150,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) { @@ -180,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 */ @@ -397,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 @@ -410,7 +431,7 @@ static const char* gFBNames[] = { NULL }; null for the list. The names list must be NULL-terminated. */ static SkTDArray gSystemFonts; -static SkTDArray gFallbackFonts; +static SkTDArray gFallbackFonts; // these globals are assigned (once) by loadSystemFontsLocked() static FamilyRec* gDefaultFamily = NULL; @@ -493,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); @@ -503,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 @@ -595,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; @@ -634,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; } } @@ -652,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 " @@ -680,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 } } @@ -886,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); @@ -911,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; } @@ -966,46 +1006,9 @@ SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) { // 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(); +static SkFontID findFontIDForChar(SkUnichar uni, SkTypeface::Style style, + SkPaint::FontVariant fontVariant) { + SkTypeface* face = FindBestFace(gDefaultFamily, style); if (!face) { return 0; } @@ -1013,6 +1016,7 @@ static SkFontID findFontIDForChar(SkUnichar uni, SkTypeface::Style style) { SkPaint paint; paint.setTypeface(face); paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); + paint.setFontVariant(fontVariant); SkAutoGlyphCache autoCache(paint, NULL); SkGlyphCache* cache = autoCache.getCache(); @@ -1025,71 +1029,93 @@ static SkFontID findFontIDForChar(SkUnichar uni, SkTypeface::Style style) { return 0; } -// this function can't be called if the gFamilyHeadAndNameListMutex is already locked -static void initFBScriptInfo() { - if (gFBScriptInitialized) { - return; - } +struct HB_UnicodeMapping { + HB_Script script; + const SkUnichar unicode; +}; - // 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; -} +static HB_UnicodeMapping HB_UnicodeMappingArray[] { + {HB_Script_Arabic, 0x0600}, + {HB_Script_Armenian, 0x0531}, + {HB_Script_Bengali, 0x0981}, + {HB_Script_Devanagari, 0x0901}, + // we don't currently support HB_Script_Ethiopic, it is a placeholder for an upstream merge + //{HB_Script_Ethiopic, 0x1200}, + {HB_Script_Georgian, 0x10A0}, + {HB_Script_Hebrew, 0x0591}, + {HB_Script_Kannada, 0x0C90}, + {HB_Script_Malayalam, 0x0D10}, + {HB_Script_Tamil, 0x0B82}, + {HB_Script_Thai, 0x0E01}, + {HB_Script_Telugu, 0x0C10}, +}; -SkTypeface* SkCreateTypefaceForScript(FallbackScripts script) { - if (!SkTypeface_ValidScript(script)) { - return NULL; +// 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; +} - // ensure that our table is populated - initFBScriptInfo(); - - FBScriptInfo& scriptInfo = gFBScriptInfo[script]; +struct TypefaceLookupStruct { + HB_Script script; + SkTypeface::Style style; + SkPaint::FontVariant fontVariant; + SkTypeface* typeface; +}; - // ensure the element with that index actually maps to the correct script - SkASSERT(scriptInfo.fScript == script); +SK_DECLARE_STATIC_MUTEX(gTypefaceTableMutex); // This is the mutex for gTypefaceTable +static SkTDArray gTypefaceTable; // This is protected by gTypefaceTableMutex - // if a suitable script could not be found then return NULL - if (scriptInfo.fFontID == 0) { - return NULL; +static int typefaceLookupCompare(const TypefaceLookupStruct& first, + const TypefaceLookupStruct& second) { + if (first.script != second.script) { + return (first.script > second.script) ? 1 : -1; } - - 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; - } + if (first.style != second.style) { + return (first.style > second.style) ? 1 : -1; } - return NULL; + if (first.fontVariant != second.fontVariant) { + return (first.fontVariant > second.fontVariant) ? 1 : -1; + } + return 0; } -FallbackScripts SkGetFallbackScriptFromID(const char* id) { - for (int i = 0; i < gFBScriptInfoCount; i++) { - if (strcmp(gFBScriptInfo[i].fScriptID, id) == 0) { - return gFBScriptInfo[i].fScript; +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( + (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); + // we ref(), since the semantic is to return a new instance + retTypeface->ref(); + key.typeface = retTypeface; + index = ~index; + *gTypefaceTable.insert(index) = key; } - return kFallbackScriptNumber; // Use kFallbackScriptNumber as an invalid value. + return retTypeface; } - -- cgit v1.1 From 8c1c7cfacd82a174c65fcbf839d7037e3692aee8 Mon Sep 17 00:00:00 2001 From: Billy Hewlett Date: Wed, 20 Jun 2012 17:56:31 -0700 Subject: Cherrypick change to skia Change-Id: I7514b6931a11a0a79ec3abd4068f72998fcdf99d --- include/core/SkPaint.h | 4 ++++ include/ports/SkTypeface_android.h | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h index 31bc30b..22d003e 100644 --- a/include/core/SkPaint.h +++ b/include/core/SkPaint.h @@ -848,6 +848,10 @@ 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/ports/SkTypeface_android.h b/include/ports/SkTypeface_android.h index 1a02a55..0023879 100644 --- a/include/ports/SkTypeface_android.h +++ b/include/ports/SkTypeface_android.h @@ -10,6 +10,8 @@ #define SkTypeface_android_DEFINED #include "SkTypeface.h" +#include "SkPaint.h" +#include "../harfbuzz/src/harfbuzz-shaper.h" enum FallbackScripts { kArabic_FallbackScript, @@ -30,5 +32,7 @@ enum FallbackScripts { }; -SK_API SkTypeface* SkCreateTypefaceForScript(FallbackScripts script) {return NULL; } +SK_API SkTypeface* SkCreateTypefaceForScript(HB_Script script, SkTypeface::Style style, + SkPaint::FontVariant fontVariant) { return NULL; } + #endif -- cgit v1.1 From 81957ccb58db76c172e195dc3e31eba85d3e4ac9 Mon Sep 17 00:00:00 2001 From: Billy Hewlett Date: Thu, 21 Jun 2012 09:45:15 -0700 Subject: Revert "Use Elegant fonts for Webkit, Compact fonts for Textview" This reverts commit 421654d4bf3ca50e2247a7389851d2e8f4812564 --- include/core/SkFontHost.h | 9 - include/core/SkPaint.h | 20 --- include/core/SkScalerContext.h | 4 +- include/ports/SkTypeface_android.h | 45 ++++- src/core/SkPaint.cpp | 16 -- src/core/SkScalerContext.cpp | 8 +- src/ports/FontHostConfiguration_android.cpp | 53 +----- src/ports/FontHostConfiguration_android.h | 17 +- src/ports/SkFontHost_android.cpp | 266 +++++++++++++--------------- 9 files changed, 169 insertions(+), 269 deletions(-) diff --git a/include/core/SkFontHost.h b/include/core/SkFontHost.h index ace08d8..25c9ecb 100644 --- a/include/core/SkFontHost.h +++ b/include/core/SkFontHost.h @@ -154,15 +154,6 @@ 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 1715013..30ff663 100644 --- a/include/core/SkPaint.h +++ b/include/core/SkPaint.h @@ -665,25 +665,6 @@ 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. @@ -925,7 +906,6 @@ 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 33c3c3d..9bcf601 100644 --- a/include/core/SkScalerContext.h +++ b/include/core/SkScalerContext.h @@ -210,9 +210,6 @@ 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; @@ -237,6 +234,7 @@ public: SkMask::Format getFormat() const { return static_cast(fMaskFormat); } + #ifdef SK_USE_COLOR_LUMINANCE SkColor getLuminanceColor() const { return fLumBits; diff --git a/include/ports/SkTypeface_android.h b/include/ports/SkTypeface_android.h index c3eb3d1..3471a94 100644 --- a/include/ports/SkTypeface_android.h +++ b/include/ports/SkTypeface_android.h @@ -10,20 +10,47 @@ #define SkTypeface_android_DEFINED #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 +}; + +#define SkTypeface_ValidScript(s) (s >= 0 && s < kFallbackScriptNumber) /** * 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. + * @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 SkTypeface* SkCreateTypefaceForScript(HB_Script script, SkTypeface::Style style, - SkPaint::FontVariant fontVariant = SkPaint::kDefault_Variant); +SK_API FallbackScripts SkGetFallbackScriptFromID(const char* id); #endif diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp index 412ab2b..e1932a7 100644 --- a/src/core/SkPaint.cpp +++ b/src/core/SkPaint.cpp @@ -72,7 +72,6 @@ SkPaint::SkPaint() { fHinting = SkPaintDefaults_Hinting; #ifdef SK_BUILD_FOR_ANDROID new(&fTextLocale) SkString(); - fFontVariant = kDefault_Variant; fGenerationID = 0; #endif } @@ -373,18 +372,6 @@ 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 /////////////////////////////////////////////////////////////////////////////// @@ -1574,9 +1561,6 @@ 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 e33ad7a..2921b1e 100644 --- a/src/core/SkScalerContext.cpp +++ b/src/core/SkScalerContext.cpp @@ -118,13 +118,7 @@ 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) -#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 - + uint32_t newFontID = SkFontHost::NextLogicalFont(rec.fFontID, rec.fOrigFontID); if (0 == newFontID) { return NULL; } diff --git a/src/ports/FontHostConfiguration_android.cpp b/src/ports/FontHostConfiguration_android.cpp index 9296769..d1164c8 100644 --- a/src/ports/FontHostConfiguration_android.cpp +++ b/src/ports/FontHostConfiguration_android.cpp @@ -18,7 +18,6 @@ #include "FontHostConfiguration_android.h" #include "SkString.h" #include "SkTDArray.h" -#include "SkTypeface.h" #include #if !defined(SK_BUILD_FOR_ANDROID_NDK) #include @@ -47,13 +46,12 @@ struct FamilyData { XML_Parser *parser; // The expat parser doing the work SkTDArray &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 FontFileInfo arrays. + * 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; @@ -70,9 +68,7 @@ void textHandler(void *data, const char *s, int len) { *(familyData->currentFamily->fNames.append()) = buff; break; case FILESET_TAG: - if (familyData->currentFontInfo) { - familyData->currentFontInfo->fFileName = buff; - } + *(familyData->currentFamily->fFileNames.append()) = buff; break; default: // Noop - don't care about any text that's not in the Fonts or Names list @@ -82,39 +78,6 @@ 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. */ @@ -135,16 +98,14 @@ 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) { + } 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); - } 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); } } @@ -159,9 +120,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 c8a70e3..2441f0e 100644 --- a/src/ports/FontHostConfiguration_android.h +++ b/src/ports/FontHostConfiguration_android.h @@ -18,27 +18,18 @@ #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. fontFileArray is the list of information - * about each file. Order is the priority order for the font. This is + * 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 fNames; - SkTDArray fFontFileArray; + SkTDArray fNames; + SkTDArray fFileNames; int order; }; diff --git a/src/ports/SkFontHost_android.cpp b/src/ports/SkFontHost_android.cpp index 0a9cced..afd0ebe 100644 --- a/src/ports/SkFontHost_android.cpp +++ b/src/ports/SkFontHost_android.cpp @@ -29,7 +29,7 @@ #include #include "SkGlyphCache.h" #include "SkTypeface_android.h" -#include "SkTSearch.h" + //#define SkDEBUGF(args ) SkDebugf args @@ -76,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(const SkScalerContext::Rec& rec); +static SkFontID nextLogicalFontLocked(SkFontID currFontID, SkFontID origFontID); static SkTypeface* createTypefaceFromStreamLocked(SkStream* stream); /////////////////////////////////////////////////////////////////////////////// @@ -150,12 +150,6 @@ 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) { @@ -186,14 +180,6 @@ 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 */ @@ -411,15 +397,8 @@ private: // used to record our notion of the pre-existing fonts struct FontInitRec { - 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; + const char* fFileName; + const char* const* fNames; // null-terminated list }; // deliberately empty, but we use the address to identify fallback fonts @@ -431,7 +410,7 @@ static const char* gFBNames[] = { NULL }; null for the list. The names list must be NULL-terminated. */ static SkTDArray gSystemFonts; -static SkTDArray gFallbackFonts; +static SkTDArray gFallbackFonts; // these globals are assigned (once) by loadSystemFontsLocked() static FamilyRec* gDefaultFamily = NULL; @@ -514,8 +493,8 @@ static void loadFontInfoLocked() { for (int i = 0; i < fontFamilies.count(); ++i) { FontFamily *family = fontFamilies[i]; - for (int j = 0; j < family->fFontFileArray.count(); ++j) { - const char* filename = family->fFontFileArray[j]->fFileName; + for (int j = 0; j < family->fFileNames.count(); ++j) { + const char* filename = family->fFileNames[j]; if (haveSystemFont(filename)) { SkDebugf("---- system font and fallback font files specify a duplicate " "font %s, skipping the second occurrence", filename); @@ -524,7 +503,6 @@ static void loadFontInfoLocked() { FontInitRec fontInfoRecord; fontInfoRecord.fFileName = filename; - fontInfoRecord.fVariant = family->fFontFileArray[j]->fVariant; if (j == 0) { if (family->fNames.count() == 0) { // Fallback font @@ -617,10 +595,7 @@ static void initSystemFontsLocked() { if (names == gFBNames) { SkDEBUGF(("---- adding %s as fallback[%d] fontID %d\n", gSystemFonts[i].fFileName, gFallbackFonts.count(), tf->uniqueID())); - FallbackFontRec newFallbackRec; - newFallbackRec.fFontID = tf->uniqueID(); - newFallbackRec.fVariant = gSystemFonts[i].fVariant; - *gFallbackFonts.append() = newFallbackRec; + *gFallbackFonts.append() = tf->uniqueID(); } firstInFamily = tf; @@ -659,7 +634,7 @@ static SkFontID findUniqueIDLocked(const char* filename) { static int findFallbackFontIndex(SkFontID fontId) { for (int i = 0; i < gFallbackFonts.count(); i++) { - if (gFallbackFonts[i].fFontID == fontId) { + if (gFallbackFonts[i] == fontId) { return i; } } @@ -677,8 +652,8 @@ static void reloadFallbackFontsLocked() { for (int i = 0; i < fallbackFamilies.count(); ++i) { FontFamily *family = fallbackFamilies[i]; - for (int j = 0; j < family->fFontFileArray.count(); ++j) { - const char* filename = family->fFontFileArray[j]->fFileName; + for (int j = 0; j < family->fFileNames.count(); ++j) { + const char* filename = family->fFileNames[j]; if (filename) { if (!haveSystemFont(filename)) { SkDebugf("---- skipping fallback font %s because it was not " @@ -705,10 +680,8 @@ static void reloadFallbackFontsLocked() { SkDEBUGF(("---- reload %s as fallback[%d] fontID %d\n", filename, gFallbackFonts.count(), uniqueID)); - FallbackFontRec newFallbackFont; - newFallbackFont.fFontID = uniqueID; - newFallbackFont.fVariant = family->fFontFileArray[j]->fVariant; - *gFallbackFonts.append() = newFallbackFont; + + *gFallbackFonts.append() = uniqueID; break; // The fallback set contains only the first font of each family } } @@ -913,16 +886,16 @@ static size_t getFileNameLocked(SkFontID fontID, char path[], size_t length, int } } -SkFontID SkFontHost::NextLogicalFont(const SkScalerContext::Rec& rec) { +SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) { SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex); - return nextLogicalFontLocked(rec); + return nextLogicalFontLocked(currFontID, origFontID); } -static SkFontID nextLogicalFontLocked(const SkScalerContext::Rec& rec) { +static SkFontID nextLogicalFontLocked(SkFontID currFontID, SkFontID origFontID) { loadSystemFontsLocked(); - const SkTypeface* origTypeface = findFromUniqueIDLocked(rec.fOrigFontID); - const SkTypeface* currTypeface = findFromUniqueIDLocked(rec.fFontID); + const SkTypeface* origTypeface = findFromUniqueIDLocked(origFontID); + const SkTypeface* currTypeface = findFromUniqueIDLocked(currFontID); SkASSERT(origTypeface != 0); SkASSERT(currTypeface != 0); @@ -938,30 +911,17 @@ static SkFontID nextLogicalFontLocked(const SkScalerContext::Rec& rec) { */ int plainFallbackFontIndex = findFallbackFontIndex(plainFontID); int nextFallbackFontIndex = plainFallbackFontIndex + 1; - - // 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++; + SkFontID nextFontID; + if (nextFallbackFontIndex == gFallbackFonts.count()) { + nextFontID = 0; // no more fallbacks + } else { + const SkTypeface* nextTypeface = findFromUniqueIDLocked(gFallbackFonts[nextFallbackFontIndex]); + nextFontID = findTypefaceLocked(nextTypeface, origTypeface->style())->uniqueID(); } SkDEBUGF(("---- nextLogicalFont: currFontID=%d, origFontID=%d, plainFontID=%d, " "plainFallbackFontIndex=%d, nextFallbackFontIndex=%d " - "=> nextFontID=%d", rec.fFontID, rec.fOrigFontID, plainFontID, + "=> nextFontID=%d", currFontID, origFontID, plainFontID, plainFallbackFontIndex, nextFallbackFontIndex, nextFontID)); return nextFontID; } @@ -1006,9 +966,46 @@ SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) { // Function from SkTypeface_android.h /////////////////////////////////////////////////////////////////////////////// -static SkFontID findFontIDForChar(SkUnichar uni, SkTypeface::Style style, - SkPaint::FontVariant fontVariant) { - SkTypeface* face = FindBestFace(gDefaultFamily, style); +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; } @@ -1016,7 +1013,6 @@ static SkFontID findFontIDForChar(SkUnichar uni, SkTypeface::Style style, SkPaint paint; paint.setTypeface(face); paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); - paint.setFontVariant(fontVariant); SkAutoGlyphCache autoCache(paint, NULL); SkGlyphCache* cache = autoCache.getCache(); @@ -1029,93 +1025,71 @@ static SkFontID findFontIDForChar(SkUnichar uni, SkTypeface::Style style, return 0; } -struct HB_UnicodeMapping { - HB_Script script; - const SkUnichar unicode; -}; - -static HB_UnicodeMapping HB_UnicodeMappingArray[] { - {HB_Script_Arabic, 0x0600}, - {HB_Script_Armenian, 0x0531}, - {HB_Script_Bengali, 0x0981}, - {HB_Script_Devanagari, 0x0901}, - // we don't currently support HB_Script_Ethiopic, it is a placeholder for an upstream merge - //{HB_Script_Ethiopic, 0x1200}, - {HB_Script_Georgian, 0x10A0}, - {HB_Script_Hebrew, 0x0591}, - {HB_Script_Kannada, 0x0C90}, - {HB_Script_Malayalam, 0x0D10}, - {HB_Script_Tamil, 0x0B82}, - {HB_Script_Thai, 0x0E01}, - {HB_Script_Telugu, 0x0C10}, -}; +// this function can't be called if the gFamilyHeadAndNameListMutex is already locked +static void initFBScriptInfo() { + if (gFBScriptInitialized) { + return; + } -// 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; - } + // 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)); } - return unichar; + // mark the value as initialized so we don't repeat our work unnecessarily + gFBScriptInitialized = true; } -struct TypefaceLookupStruct { - HB_Script script; - SkTypeface::Style style; - SkPaint::FontVariant fontVariant; - SkTypeface* typeface; -}; +SkTypeface* SkCreateTypefaceForScript(FallbackScripts script) { + if (!SkTypeface_ValidScript(script)) { + return NULL; + } -SK_DECLARE_STATIC_MUTEX(gTypefaceTableMutex); // This is the mutex for gTypefaceTable -static SkTDArray gTypefaceTable; // This is protected by gTypefaceTableMutex + // ensure that our table is populated + initFBScriptInfo(); -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; + 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; } - return 0; + + 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; } -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( - (const TypefaceLookupStruct*) gTypefaceTable.begin(), - gTypefaceTable.count(), key, sizeof(TypefaceLookupStruct), - &typefaceLookupCompare); - if (index >= 0) { - retTypeface = gTypefaceTable[index].typeface; +const char* SkGetFallbackScriptID(FallbackScripts script) { + for (int i = 0; i < gFBScriptInfoCount; i++) { + if (gFBScriptInfo[i].fScript == script) { + return gFBScriptInfo[i].fScriptID; + } } - else { - SkUnichar unichar = getUnicodeFromHBScript(script); - if (!unichar) { - return NULL; + 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; } - SkFontID newFontID = findFontIDForChar(unichar, style, fontVariant); - // retrieve the typeface that corresponds to this fontID - retTypeface = FindFromUniqueID(newFontID); - // we ref(), since the semantic is to return a new instance - retTypeface->ref(); - key.typeface = retTypeface; - index = ~index; - *gTypefaceTable.insert(index) = key; } - return retTypeface; + return kFallbackScriptNumber; // Use kFallbackScriptNumber as an invalid value. } + -- cgit v1.1 From 212ef7a5d592a11522f73d858bf98f5201631b70 Mon Sep 17 00:00:00 2001 From: Billy Hewlett Date: Thu, 21 Jun 2012 09:58:17 -0700 Subject: Revert "Revert "Use Elegant fonts for Webkit, Compact fonts for Textview"" This reverts commit 81957ccb58db76c172e195dc3e31eba85d3e4ac9 --- include/core/SkFontHost.h | 9 + include/core/SkPaint.h | 20 +++ include/core/SkScalerContext.h | 4 +- include/ports/SkTypeface_android.h | 45 +---- src/core/SkPaint.cpp | 16 ++ src/core/SkScalerContext.cpp | 8 +- src/ports/FontHostConfiguration_android.cpp | 53 +++++- src/ports/FontHostConfiguration_android.h | 17 +- src/ports/SkFontHost_android.cpp | 266 +++++++++++++++------------- 9 files changed, 269 insertions(+), 169 deletions(-) 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 30ff663..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. @@ -906,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 9bcf601..33c3c3d 100644 --- a/include/core/SkScalerContext.h +++ b/include/core/SkScalerContext.h @@ -210,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; @@ -234,7 +237,6 @@ public: SkMask::Format getFormat() const { return static_cast(fMaskFormat); } - #ifdef SK_USE_COLOR_LUMINANCE SkColor getLuminanceColor() const { return fLumBits; diff --git a/include/ports/SkTypeface_android.h b/include/ports/SkTypeface_android.h index 3471a94..c3eb3d1 100644 --- a/include/ports/SkTypeface_android.h +++ b/include/ports/SkTypeface_android.h @@ -10,47 +10,20 @@ #define SkTypeface_android_DEFINED #include "SkTypeface.h" +#include "SkPaint.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 -}; - -#define SkTypeface_ValidScript(s) (s >= 0 && s < 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 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. + * @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 FallbackScripts SkGetFallbackScriptFromID(const char* id); +SK_API SkTypeface* SkCreateTypefaceForScript(HB_Script script, SkTypeface::Style style, + SkPaint::FontVariant fontVariant = SkPaint::kDefault_Variant); #endif 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/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 #if !defined(SK_BUILD_FOR_ANDROID_NDK) #include @@ -46,12 +47,13 @@ struct FamilyData { XML_Parser *parser; // The expat parser doing the work SkTDArray &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 fNames; - SkTDArray fFileNames; + SkTDArray fNames; + SkTDArray fFontFileArray; int order; }; diff --git a/src/ports/SkFontHost_android.cpp b/src/ports/SkFontHost_android.cpp index afd0ebe..0a9cced 100644 --- a/src/ports/SkFontHost_android.cpp +++ b/src/ports/SkFontHost_android.cpp @@ -29,7 +29,7 @@ #include #include "SkGlyphCache.h" #include "SkTypeface_android.h" - +#include "SkTSearch.h" //#define SkDEBUGF(args ) SkDebugf args @@ -76,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); /////////////////////////////////////////////////////////////////////////////// @@ -150,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) { @@ -180,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 */ @@ -397,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 @@ -410,7 +431,7 @@ static const char* gFBNames[] = { NULL }; null for the list. The names list must be NULL-terminated. */ static SkTDArray gSystemFonts; -static SkTDArray gFallbackFonts; +static SkTDArray gFallbackFonts; // these globals are assigned (once) by loadSystemFontsLocked() static FamilyRec* gDefaultFamily = NULL; @@ -493,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); @@ -503,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 @@ -595,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; @@ -634,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; } } @@ -652,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 " @@ -680,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 } } @@ -886,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); @@ -911,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; } @@ -966,46 +1006,9 @@ SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) { // 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(); +static SkFontID findFontIDForChar(SkUnichar uni, SkTypeface::Style style, + SkPaint::FontVariant fontVariant) { + SkTypeface* face = FindBestFace(gDefaultFamily, style); if (!face) { return 0; } @@ -1013,6 +1016,7 @@ static SkFontID findFontIDForChar(SkUnichar uni, SkTypeface::Style style) { SkPaint paint; paint.setTypeface(face); paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); + paint.setFontVariant(fontVariant); SkAutoGlyphCache autoCache(paint, NULL); SkGlyphCache* cache = autoCache.getCache(); @@ -1025,71 +1029,93 @@ static SkFontID findFontIDForChar(SkUnichar uni, SkTypeface::Style style) { return 0; } -// this function can't be called if the gFamilyHeadAndNameListMutex is already locked -static void initFBScriptInfo() { - if (gFBScriptInitialized) { - return; - } +struct HB_UnicodeMapping { + HB_Script script; + const SkUnichar unicode; +}; - // 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; -} +static HB_UnicodeMapping HB_UnicodeMappingArray[] { + {HB_Script_Arabic, 0x0600}, + {HB_Script_Armenian, 0x0531}, + {HB_Script_Bengali, 0x0981}, + {HB_Script_Devanagari, 0x0901}, + // we don't currently support HB_Script_Ethiopic, it is a placeholder for an upstream merge + //{HB_Script_Ethiopic, 0x1200}, + {HB_Script_Georgian, 0x10A0}, + {HB_Script_Hebrew, 0x0591}, + {HB_Script_Kannada, 0x0C90}, + {HB_Script_Malayalam, 0x0D10}, + {HB_Script_Tamil, 0x0B82}, + {HB_Script_Thai, 0x0E01}, + {HB_Script_Telugu, 0x0C10}, +}; -SkTypeface* SkCreateTypefaceForScript(FallbackScripts script) { - if (!SkTypeface_ValidScript(script)) { - return NULL; +// 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; +} - // ensure that our table is populated - initFBScriptInfo(); - - FBScriptInfo& scriptInfo = gFBScriptInfo[script]; +struct TypefaceLookupStruct { + HB_Script script; + SkTypeface::Style style; + SkPaint::FontVariant fontVariant; + SkTypeface* typeface; +}; - // ensure the element with that index actually maps to the correct script - SkASSERT(scriptInfo.fScript == script); +SK_DECLARE_STATIC_MUTEX(gTypefaceTableMutex); // This is the mutex for gTypefaceTable +static SkTDArray gTypefaceTable; // This is protected by gTypefaceTableMutex - // if a suitable script could not be found then return NULL - if (scriptInfo.fFontID == 0) { - return NULL; +static int typefaceLookupCompare(const TypefaceLookupStruct& first, + const TypefaceLookupStruct& second) { + if (first.script != second.script) { + return (first.script > second.script) ? 1 : -1; } - - 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; - } + if (first.style != second.style) { + return (first.style > second.style) ? 1 : -1; } - return NULL; + if (first.fontVariant != second.fontVariant) { + return (first.fontVariant > second.fontVariant) ? 1 : -1; + } + return 0; } -FallbackScripts SkGetFallbackScriptFromID(const char* id) { - for (int i = 0; i < gFBScriptInfoCount; i++) { - if (strcmp(gFBScriptInfo[i].fScriptID, id) == 0) { - return gFBScriptInfo[i].fScript; +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( + (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); + // we ref(), since the semantic is to return a new instance + retTypeface->ref(); + key.typeface = retTypeface; + index = ~index; + *gTypefaceTable.insert(index) = key; } - return kFallbackScriptNumber; // Use kFallbackScriptNumber as an invalid value. + return retTypeface; } - -- cgit v1.1 From 669f287c3eec9ca1755d8d27ba1b5e17464b714a Mon Sep 17 00:00:00 2001 From: Billy Hewlett Date: Tue, 26 Jun 2012 13:27:55 -0700 Subject: Cleanup ref counts for SkCreateTypefaceForScript After this checkin, SkCreateTypefaceForScript refs each typeface that it creates before it returns it. Additionally, all supported harfbuzz codepoints are added to the unicode mapping array. This patch also fixes a test crash (see bug) Bug:6756432 Change-Id: Ida3276b76e745b817f9e63be54945e411516dd03 --- src/ports/SkFontHost_android.cpp | 42 ++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/src/ports/SkFontHost_android.cpp b/src/ports/SkFontHost_android.cpp index 0a9cced..38d1d06 100644 --- a/src/ports/SkFontHost_android.cpp +++ b/src/ports/SkFontHost_android.cpp @@ -1034,20 +1034,42 @@ struct HB_UnicodeMapping { 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_Arabic, 0x0600}, {HB_Script_Armenian, 0x0531}, - {HB_Script_Bengali, 0x0981}, - {HB_Script_Devanagari, 0x0901}, - // we don't currently support HB_Script_Ethiopic, it is a placeholder for an upstream merge - //{HB_Script_Ethiopic, 0x1200}, - {HB_Script_Georgian, 0x10A0}, {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_Tamil, 0x0B82}, + {HB_Script_Sinhala, 0x0D90}, {HB_Script_Thai, 0x0E01}, - {HB_Script_Telugu, 0x0C10}, + {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" @@ -1111,11 +1133,11 @@ SK_API SkTypeface* SkCreateTypefaceForScript(HB_Script script, SkTypeface::Style SkFontID newFontID = findFontIDForChar(unichar, style, fontVariant); // retrieve the typeface that corresponds to this fontID retTypeface = FindFromUniqueID(newFontID); - // we ref(), since the semantic is to return a new instance - retTypeface->ref(); 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; } -- cgit v1.1 From b4fad178c792687c50683880bcfaf507d54b30ca Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Tue, 17 Jul 2012 15:36:33 -0700 Subject: Accurately calculate advances in general case. Fixes bug 6833339. The advance values computed by generateAdvance() were inconsistent with those computed by generateMetrics, because the fMatrix22 was being applied in the latter but not former case. Since fMatrix22.xx is 1.0 almost all the time (the exception is only when skew and scale are both applied), failures were rare. This patch is an alternative to ag/#/c/207887, in that they both fix the problem, but in different ways. That patch made fMatrix22.xx equal to 1.0 in almost all cases, while this one gives correct advance values for arbitrary fMatrix22 values. Change-Id: Iedfa36e884e3e3e2f078a5d4edfc82004a54e895 --- src/ports/SkFontHost_FreeType.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp index 621c94a..da00d51 100644 --- a/src/ports/SkFontHost_FreeType.cpp +++ b/src/ports/SkFontHost_FreeType.cpp @@ -951,8 +951,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; } } -- cgit v1.1 From d1280a29424e20a876a4995ff1446d57aac0289d Mon Sep 17 00:00:00 2001 From: Victoria Lease Date: Thu, 26 Jul 2012 15:50:40 -0700 Subject: Reduce embolden effect. Certain CJK glyphs become essentially unreadable when emboldened at sizes used by common apps like News/Weather. Reducing embolden strength slightly makes these glyphs much more readable without sacrificing bold/normal weight differentiation. Bug: 6712857 Change-Id: Iec1c478171e33751be1cddbaae6a8ec30bb6cbab --- src/ports/SkFontHost_FreeType.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp index da00d51..6aa2120 100644 --- a/src/ports/SkFontHost_FreeType.cpp +++ b/src/ports/SkFontHost_FreeType.cpp @@ -63,6 +63,16 @@ #define SK_GAMMA_EXPONENT 2.2 #endif +// hand-tuned value to reduce outline embolden strength +#ifndef SK_OUTLINE_EMBOLDEN_DIVISOR + #ifdef SK_BUILD_FOR_ANDROID + #define SK_OUTLINE_EMBOLDEN_DIVISOR 34 + #else + #define SK_OUTLINE_EMBOLDEN_DIVISOR 24 + #endif +#endif + + #ifdef SK_DEBUG #define SkASSERT_CONTINUE(pred) \ do { \ @@ -892,7 +902,7 @@ FT_Error SkScalerContext_FreeType::setupSize() { void SkScalerContext_FreeType::emboldenOutline(FT_Outline* outline) { FT_Pos strength; strength = FT_MulFix(fFace->units_per_EM, fFace->size->metrics.y_scale) - / 24; + / SK_OUTLINE_EMBOLDEN_DIVISOR; FT_Outline_Embolden(outline, strength); } -- cgit v1.1 From e454fde2aeb9f50cae4ae6d3237aac6553540ff5 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Fri, 27 Jul 2012 12:42:04 -0700 Subject: Fix bug 6888377: crash in GetUnitsPerEm on locale change The underlying problem is that no SkScalerContext objects existed at the time shapeFontRun is called immediately after a locale change from en to ja (apparently the dumping of the cache caused all these to be deallocated), so gFTLibrary was null (and the call tio ref_ft_face assumes that it's initialized). There's a pattern for calls which might not necessarily be called from a scaler context (GetAdvancedTypefaceMetrics is one such), to explicitly check for an uninitialized library, and create one for the length of the call if so. This patch changes GetUnitsPerEm to follow this pattern. Change-Id: I19a4b6fa49fad0aeacc04bf971101aacca6bc94f --- src/ports/SkFontHost_FreeType.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp index da00d51..eb05959 100644 --- a/src/ports/SkFontHost_FreeType.cpp +++ b/src/ports/SkFontHost_FreeType.cpp @@ -685,6 +685,13 @@ void SkFontHost::FilterRec(SkScalerContext::Rec* rec) { #ifdef SK_BUILD_FOR_ANDROID uint32_t SkFontHost::GetUnitsPerEm(SkFontID fontID) { SkAutoMutexAcquire ac(gFTMutex); + FT_Library libInit = NULL; + if (gFTCount == 0) { + if (!InitFreetype()) + sk_throw(); + libInit = gFTLibrary; + } + SkAutoTCallIProc ftLib(libInit); SkFaceRec *rec = ref_ft_face(fontID); uint16_t unitsPerEm = 0; -- cgit v1.1 From d8f575c86838a8f546c90692bfea0bbe30a92dbe Mon Sep 17 00:00:00 2001 From: Zhongjun Chen Date: Tue, 22 May 2012 19:16:44 +0800 Subject: [Skia]: fix TOMBSTONE issue when browsing JPEG image and exiting Gallery When browsing JPEG image and then exiting Gallery, the TOMBSTONE issue occour. This is because JPEG Decode method still access a pointer which has been deleted. This patch can fix it. Change-Id: I3ac3e4b8f37d352a70676abb6d151961e873e459 Author: Zhongjun Chen Signed-off-by: Zhongjun Chen Singed-off-by: Shuo Gao Signed-off-by: Bruce Beare Signed-off-by: Jack Ren Author-tracking-BZ: 37479 --- src/images/SkImageDecoder_libjpeg.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/images/SkImageDecoder_libjpeg.cpp b/src/images/SkImageDecoder_libjpeg.cpp index fbb6887..33f222c 100644 --- a/src/images/SkImageDecoder_libjpeg.cpp +++ b/src/images/SkImageDecoder_libjpeg.cpp @@ -48,9 +48,9 @@ public: SkJPEGImageIndex() {} virtual ~SkJPEGImageIndex() { jpeg_destroy_huffman_index(index); - delete cinfo->src; jpeg_finish_decompress(cinfo); jpeg_destroy_decompress(cinfo); + delete cinfo->src; free(cinfo); } jpeg_decompress_struct *cinfo; -- cgit v1.1 From 99180756367573f1d741a5104ed401c5a7308ae9 Mon Sep 17 00:00:00 2001 From: Derek Sollenberger Date: Thu, 16 Aug 2012 15:08:47 -0400 Subject: Ensure SkCanvas will have a device by default. bug: 6987261 Change-Id: I8cb5b6da2347a1fa88a13aa3548312a7773831e5 --- src/core/SkCanvas.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 7861636..0e26728 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -425,7 +425,8 @@ SkCanvas::SkCanvas() : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) { inc_canvas(); - this->init(NULL); + SkBitmap bitmap; + this->init(SkNEW_ARGS(SkDevice, (bitmap)))->unref(); } SkCanvas::SkCanvas(SkDevice* device) -- cgit v1.1 From fd3c420022d5f842fe8be5c21300e0d01463a5ad Mon Sep 17 00:00:00 2001 From: Victoria Lease Date: Fri, 17 Aug 2012 14:59:02 -0700 Subject: Forward-compatibility stubs Change-Id: I9c5bf5ce38827ced91d8912a1fa49adbd14a46b8 --- Android.mk | 1 + include/core/SkLanguage.h | 70 +++++++++++++++++++++++++++++++++++++++++++++++ include/core/SkPaint.h | 9 ++++++ src/core/SkLanguage.cpp | 54 ++++++++++++++++++++++++++++++++++++ src/core/SkPaint.cpp | 4 +++ 5 files changed, 138 insertions(+) create mode 100644 include/core/SkLanguage.h create mode 100644 src/core/SkLanguage.cpp diff --git a/Android.mk b/Android.mk index 08cf6f8..613a90f 100644 --- a/Android.mk +++ b/Android.mk @@ -108,6 +108,7 @@ LOCAL_SRC_FILES:= \ src/core/SkGeometry.cpp \ src/core/SkGlyphCache.cpp \ src/core/SkGraphics.cpp \ + src/core/SkLanguage.cpp \ src/core/SkLineClipper.cpp \ src/core/SkMallocPixelRef.cpp \ src/core/SkMask.cpp \ diff --git a/include/core/SkLanguage.h b/include/core/SkLanguage.h new file mode 100644 index 0000000..923008e --- /dev/null +++ b/include/core/SkLanguage.h @@ -0,0 +1,70 @@ + +/* + * Copyright 2012 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. + */ + + +#ifndef SkLanguage_DEFINED +#define SkLanguage_DEFINED + +#include "SkTypes.h" + +#ifdef SK_BUILD_FOR_ANDROID + +#include "SkString.h" + +struct SkLanguageInfo { + SkLanguageInfo(const char* tag) : fTag(tag) { } + SkString fTag; //! BCP 47 language identifier +}; + +/** \class SkLanguage + + The SkLanguage class represents a human written language, and is used by + text draw operations to determine which glyph to draw when drawing + characters with variants (ie Han-derived characters). +*/ +class SkLanguage { +public: + SkLanguage() : fInfo(getInfo("")) { } + SkLanguage(const char* tag) : fInfo(getInfo(tag)) { } + SkLanguage(const SkLanguage& b) : fInfo(b.fInfo) { } + + /** Gets a BCP 47 language identifier for this SkLanguage. + @return a BCP 47 language identifier representing this language + */ + const SkString& getTag() const { return fInfo->fTag; } + + /** Performs BCP 47 fallback to return an SkLanguage one step more general. + @return an SkLanguage one step more general + */ + SkLanguage getParent() const; + + bool operator==(const SkLanguage& b) const { + return fInfo == b.fInfo; + } + bool operator!=(const SkLanguage& b) const { + return fInfo != b.fInfo; + } + bool operator<(const SkLanguage& b) const { + return fInfo < b.fInfo; + } + bool operator>(const SkLanguage& b) const { + return fInfo > b.fInfo; + } + SkLanguage& operator=(const SkLanguage& b) { + fInfo = b.fInfo; + return *this; + } + +private: + const SkLanguageInfo* fInfo; + + static const SkLanguageInfo* getInfo(const char* tag); +}; + +#endif // #ifdef SK_BUILD_FOR_ANDROID +#endif // #ifndef SkLanguage_DEFINED diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h index 0ec6698..9e12ece 100644 --- a/include/core/SkPaint.h +++ b/include/core/SkPaint.h @@ -15,6 +15,10 @@ #include "SkXfermode.h" #include "SkString.h" +#ifdef SK_BUILD_FOR_ANDROID +#include "SkLanguage.h" +#endif + class SkAutoGlyphCache; class SkColorFilter; class SkDescriptor; @@ -665,6 +669,11 @@ public: @param locale set the paint's locale value for drawing text. */ void setTextLocale(const SkString& locale); + + /** Set the paint's language value used for drawing text. + @param language set the paint's language value for drawing text. + */ + void setLanguage(const SkLanguage& language); #endif /** Return the paint's text size. diff --git a/src/core/SkLanguage.cpp b/src/core/SkLanguage.cpp new file mode 100644 index 0000000..3b8ba3c --- /dev/null +++ b/src/core/SkLanguage.cpp @@ -0,0 +1,54 @@ + +/* + * Copyright 2012 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 "SkLanguage.h" + +#ifdef SK_BUILD_FOR_ANDROID // currently only for Android + +#include "SkTDict.h" +#include "SkThread.h" +#include + +SkLanguage SkLanguage::getParent() const { + SkASSERT(fInfo != NULL); + SkASSERT(fInfo->fTag != NULL); + const char* tag = fInfo->fTag.c_str(); + SkASSERT(tag != NULL); + + // strip off the rightmost "-.*" + char* parentTagEnd = strrchr(tag, '-'); + if (parentTagEnd == NULL) { + return SkLanguage(""); + } + size_t parentTagLen = parentTagEnd - tag; + char parentTag[parentTagLen + 1]; + strncpy(parentTag, tag, parentTagLen); + parentTag[parentTagLen] = '\0'; + return SkLanguage(parentTag); +} + +SK_DECLARE_STATIC_MUTEX(gGetInfoMutex); +const SkLanguageInfo* SkLanguage::getInfo(const char* tag) { + SkAutoMutexAcquire lock(gGetInfoMutex); + + static const size_t kDictSize = 128; + static SkTDict tagToInfo(kDictSize); + + // try a lookup + SkLanguageInfo* info; + if (tagToInfo.find(tag, &info)) { + return info; + } + + // no match - add this language + info = new SkLanguageInfo(tag); + tagToInfo.set(tag, info); + return info; +} + +#endif diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp index e1932a7..fc5e57c 100644 --- a/src/core/SkPaint.cpp +++ b/src/core/SkPaint.cpp @@ -372,6 +372,10 @@ void SkPaint::setTextLocale(const SkString& locale) { GEN_ID_INC; } } + +void SkPaint::setLanguage(const SkLanguage& language) { + setTextLocale(SkString(language.getTag())); +} #endif /////////////////////////////////////////////////////////////////////////////// -- cgit v1.1 From 725b3e03acb91dc69296554932624b36612bd189 Mon Sep 17 00:00:00 2001 From: Billy Hewlett Date: Tue, 3 Jul 2012 17:03:55 -0700 Subject: DO NOT MERGE Han Preference Cherry-pick Id8c91ae0be6cad8a7ef77a0cd5803676290986c1 from master. During font initialization, create a seperate fallback list for each locale. At runtime, use the fallbacklist associated with the locale set in the paint object. Fallback files are associated with locales in fallback_fonts.xml. Multiple files can be associated with the same locale, ordering within that langauge and apart from that language in the fallback order is preserved. This changelist also includes some refactoring, notably of the functions that call getNextContext(). Change-Id: I121f0e491a522c4a8558a0066b2d8969fb8a3667 --- Android.mk | 1 + include/core/SkLanguage.h | 70 +++++++ include/core/SkPaint.h | 19 +- include/core/SkScalerContext.h | 18 +- src/core/SkLanguage.cpp | 54 +++++ src/core/SkPaint.cpp | 26 ++- src/core/SkScalerContext.cpp | 58 +++--- src/ports/FontHostConfiguration_android.cpp | 75 +------ src/ports/FontHostConfiguration_android.h | 18 +- src/ports/SkFontHost_android.cpp | 300 ++++++++++++++++++---------- 10 files changed, 407 insertions(+), 232 deletions(-) create mode 100644 include/core/SkLanguage.h create mode 100644 src/core/SkLanguage.cpp diff --git a/Android.mk b/Android.mk index 846c157..c240d69 100644 --- a/Android.mk +++ b/Android.mk @@ -108,6 +108,7 @@ LOCAL_SRC_FILES:= \ src/core/SkGeometry.cpp \ src/core/SkGlyphCache.cpp \ src/core/SkGraphics.cpp \ + src/core/SkLanguage.cpp \ src/core/SkLineClipper.cpp \ src/core/SkMallocPixelRef.cpp \ src/core/SkMask.cpp \ diff --git a/include/core/SkLanguage.h b/include/core/SkLanguage.h new file mode 100644 index 0000000..923008e --- /dev/null +++ b/include/core/SkLanguage.h @@ -0,0 +1,70 @@ + +/* + * Copyright 2012 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. + */ + + +#ifndef SkLanguage_DEFINED +#define SkLanguage_DEFINED + +#include "SkTypes.h" + +#ifdef SK_BUILD_FOR_ANDROID + +#include "SkString.h" + +struct SkLanguageInfo { + SkLanguageInfo(const char* tag) : fTag(tag) { } + SkString fTag; //! BCP 47 language identifier +}; + +/** \class SkLanguage + + The SkLanguage class represents a human written language, and is used by + text draw operations to determine which glyph to draw when drawing + characters with variants (ie Han-derived characters). +*/ +class SkLanguage { +public: + SkLanguage() : fInfo(getInfo("")) { } + SkLanguage(const char* tag) : fInfo(getInfo(tag)) { } + SkLanguage(const SkLanguage& b) : fInfo(b.fInfo) { } + + /** Gets a BCP 47 language identifier for this SkLanguage. + @return a BCP 47 language identifier representing this language + */ + const SkString& getTag() const { return fInfo->fTag; } + + /** Performs BCP 47 fallback to return an SkLanguage one step more general. + @return an SkLanguage one step more general + */ + SkLanguage getParent() const; + + bool operator==(const SkLanguage& b) const { + return fInfo == b.fInfo; + } + bool operator!=(const SkLanguage& b) const { + return fInfo != b.fInfo; + } + bool operator<(const SkLanguage& b) const { + return fInfo < b.fInfo; + } + bool operator>(const SkLanguage& b) const { + return fInfo > b.fInfo; + } + SkLanguage& operator=(const SkLanguage& b) { + fInfo = b.fInfo; + return *this; + } + +private: + const SkLanguageInfo* fInfo; + + static const SkLanguageInfo* getInfo(const char* tag); +}; + +#endif // #ifdef SK_BUILD_FOR_ANDROID +#endif // #ifndef SkLanguage_DEFINED diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h index 1715013..d2233f0 100644 --- a/include/core/SkPaint.h +++ b/include/core/SkPaint.h @@ -10,11 +10,16 @@ #ifndef SkPaint_DEFINED #define SkPaint_DEFINED +#include "SkTypes.h" #include "SkColor.h" #include "SkDrawLooper.h" #include "SkXfermode.h" #include "SkString.h" +#ifdef SK_BUILD_FOR_ANDROID +#include "SkLanguage.h" +#endif + class SkAutoGlyphCache; class SkColorFilter; class SkDescriptor; @@ -656,15 +661,15 @@ public: void setTextAlign(Align align); #ifdef SK_BUILD_FOR_ANDROID - /** Return the paint's text locale value. - @return the paint's text locale value used for drawing text. + /** Return the paint's language value used for drawing text. + @return the paint's language value used for drawing text. */ - const SkString& getTextLocale() const { return fTextLocale; } + const SkLanguage& getLanguage() const { return fLanguage; } - /** Set the paint's text locale. - @param locale set the paint's locale value for drawing text. + /** Set the paint's language value used for drawing text. + @param language set the paint's language value for drawing text. */ - void setTextLocale(const SkString& locale); + void setLanguage(const SkLanguage& language); enum FontVariant { @@ -924,7 +929,7 @@ private: unsigned fTextEncoding : 2; // 3 values unsigned fHinting : 2; #ifdef SK_BUILD_FOR_ANDROID - SkString fTextLocale; + SkLanguage fLanguage; FontVariant fFontVariant; #endif diff --git a/include/core/SkScalerContext.h b/include/core/SkScalerContext.h index 33c3c3d..4a0c70d 100644 --- a/include/core/SkScalerContext.h +++ b/include/core/SkScalerContext.h @@ -17,6 +17,10 @@ #include "SkPoint.h" #include "SkTypeface.h" +#ifdef SK_BUILD_FOR_ANDROID +#include "SkLanguage.h" +#endif + //#define SK_USE_COLOR_LUMINANCE class SkDescriptor; @@ -211,6 +215,7 @@ public: uint32_t fLumBits; #endif #ifdef SK_BUILD_FOR_ANDROID + SkLanguage fLanguage; SkPaint::FontVariant fFontVariant; #endif uint8_t fMaskFormat; @@ -304,16 +309,7 @@ public: #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; - } + SkFontID findTypefaceIdForChar(SkUnichar uni); unsigned getBaseGlyphCount(SkUnichar charCode); #endif @@ -341,6 +337,8 @@ protected: void forceGenerateImageFromPath() { fGenerateImageFromPath = true; } private: + SkScalerContext* getContextFromChar(SkUnichar uni, unsigned& glyphID); + SkPathEffect* fPathEffect; SkMaskFilter* fMaskFilter; SkRasterizer* fRasterizer; diff --git a/src/core/SkLanguage.cpp b/src/core/SkLanguage.cpp new file mode 100644 index 0000000..3b8ba3c --- /dev/null +++ b/src/core/SkLanguage.cpp @@ -0,0 +1,54 @@ + +/* + * Copyright 2012 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 "SkLanguage.h" + +#ifdef SK_BUILD_FOR_ANDROID // currently only for Android + +#include "SkTDict.h" +#include "SkThread.h" +#include + +SkLanguage SkLanguage::getParent() const { + SkASSERT(fInfo != NULL); + SkASSERT(fInfo->fTag != NULL); + const char* tag = fInfo->fTag.c_str(); + SkASSERT(tag != NULL); + + // strip off the rightmost "-.*" + char* parentTagEnd = strrchr(tag, '-'); + if (parentTagEnd == NULL) { + return SkLanguage(""); + } + size_t parentTagLen = parentTagEnd - tag; + char parentTag[parentTagLen + 1]; + strncpy(parentTag, tag, parentTagLen); + parentTag[parentTagLen] = '\0'; + return SkLanguage(parentTag); +} + +SK_DECLARE_STATIC_MUTEX(gGetInfoMutex); +const SkLanguageInfo* SkLanguage::getInfo(const char* tag) { + SkAutoMutexAcquire lock(gGetInfoMutex); + + static const size_t kDictSize = 128; + static SkTDict tagToInfo(kDictSize); + + // try a lookup + SkLanguageInfo* info; + if (tagToInfo.find(tag, &info)) { + return info; + } + + // no match - add this language + info = new SkLanguageInfo(tag); + tagToInfo.set(tag, info); + return info; +} + +#endif diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp index 412ab2b..35b5b38 100644 --- a/src/core/SkPaint.cpp +++ b/src/core/SkPaint.cpp @@ -32,6 +32,7 @@ //#define SK_REPORT_API_RANGE_CHECK #ifdef SK_BUILD_FOR_ANDROID +#include "SkLanguage.h" #define GEN_ID_INC fGenerationID++ #define GEN_ID_INC_EVAL(expression) if (expression) { fGenerationID++; } #else @@ -71,7 +72,7 @@ SkPaint::SkPaint() { fTextEncoding = kUTF8_TextEncoding; fHinting = SkPaintDefaults_Hinting; #ifdef SK_BUILD_FOR_ANDROID - new(&fTextLocale) SkString(); + fLanguage = SkLanguage(); fFontVariant = kDefault_Variant; fGenerationID = 0; #endif @@ -89,9 +90,6 @@ SkPaint::SkPaint(const SkPaint& src) { SkSafeRef(fRasterizer); SkSafeRef(fLooper); SkSafeRef(fImageFilter); -#ifdef SK_BUILD_FOR_ANDROID - new(&fTextLocale) SkString(src.fTextLocale); -#endif } SkPaint::~SkPaint() { @@ -130,12 +128,10 @@ SkPaint& SkPaint::operator=(const SkPaint& src) { SkSafeUnref(fImageFilter); #ifdef SK_BUILD_FOR_ANDROID - fTextLocale.~SkString(); uint32_t oldGenerationID = fGenerationID; #endif memcpy(this, &src, sizeof(src)); #ifdef SK_BUILD_FOR_ANDROID - new(&fTextLocale) SkString(src.fTextLocale); fGenerationID = oldGenerationID + 1; #endif @@ -367,9 +363,9 @@ void SkPaint::setTextEncoding(TextEncoding encoding) { } #ifdef SK_BUILD_FOR_ANDROID -void SkPaint::setTextLocale(const SkString& locale) { - if(!fTextLocale.equals(locale)) { - fTextLocale.set(locale); +void SkPaint::setLanguage(const SkLanguage& language) { + if(fLanguage != language) { + fLanguage = language; GEN_ID_INC; } } @@ -1575,6 +1571,7 @@ void SkScalerContext::MakeRec(const SkPaint& paint, rec->setLuminanceBits(computeLuminance(paint)); #endif #ifdef SK_BUILD_FOR_ANDROID + rec->fLanguage = paint.getLanguage(); rec->fFontVariant = paint.getFontVariant(); #endif //SK_BUILD_FOR_ANDROID @@ -1852,6 +1849,12 @@ void SkPaint::flatten(SkFlattenableWriteBuffer& buffer) const { *ptr++ = pack_4(this->getStrokeCap(), this->getStrokeJoin(), this->getStyle(), this->getTextEncoding()); +#ifdef SK_BUILD_FOR_ANDROID + buffer.writeInt(this->getFontVariant()); + const SkString& langTag = this->getLanguage().getTag(); + buffer.writeString(langTag.c_str(), langTag.size()); +#endif + // now we're done with ptr and the (pre)reserved space. If we need to write // additional fields, use the buffer directly if (flatFlags & kHasTypeface_FlatFlag) { @@ -1906,6 +1909,11 @@ void SkPaint::unflatten(SkFlattenableReadBuffer& buffer) { this->setStyle(static_cast