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