From cfc607cf57d453f977c9c4bf09b41ac481c4bbec Mon Sep 17 00:00:00 2001 From: Seigo Nonaka Date: Wed, 2 Dec 2015 10:53:18 +0900 Subject: [PATCH] Introduce cache mechanism for LocaleList. Setting the LocaleList to the native Paint object is not a lightweight operation since it needs to propagate a string object to the native code which then needs to parse it for making minikin language list. To avoid performance regressions, cache the minikin language ID in android.graphics.Paint and send the LocaleList with cached ID instead of a string the next time native code is called. BUG: 25122318 Change-Id: Ib5ce8bcff8a1c0a2b1a1c3d1868ea8be5a0e642f --- core/jni/android/graphics/MinikinUtils.cpp | 5 ++--- core/jni/android/graphics/Paint.cpp | 28 +++++++++++------------ core/jni/android/graphics/Paint.h | 10 ++++----- core/jni/android/graphics/PaintImpl.cpp | 11 ++++----- graphics/java/android/graphics/Paint.java | 36 ++++++++++++++++++++++++++---- 5 files changed, 59 insertions(+), 31 deletions(-) diff --git a/core/jni/android/graphics/MinikinUtils.cpp b/core/jni/android/graphics/MinikinUtils.cpp index 9b774b3cfc53..0597d3f37a71 100644 --- a/core/jni/android/graphics/MinikinUtils.cpp +++ b/core/jni/android/graphics/MinikinUtils.cpp @@ -33,11 +33,10 @@ FontStyle MinikinUtils::prepareMinikinPaint(MinikinPaint* minikinPaint, FontColl FontStyle resolved = resolvedFace->fStyle; /* Prepare minikin FontStyle */ - const std::string& langs = paint->getTextLocales(); - FontLanguages minikinLangs(langs.c_str(), langs.size()); FontVariant minikinVariant = (paint->getFontVariant() == VARIANT_ELEGANT) ? VARIANT_ELEGANT : VARIANT_COMPACT; - FontStyle minikinStyle(minikinLangs, minikinVariant, resolved.getWeight(), resolved.getItalic()); + const uint32_t langListId = paint->getMinikinLangListId(); + FontStyle minikinStyle(langListId, minikinVariant, resolved.getWeight(), resolved.getItalic()); /* Prepare minikin Paint */ // Note: it would be nice to handle fractional size values (it would improve smooth zoom diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp index 9c11dd153871..654d148e2029 100644 --- a/core/jni/android/graphics/Paint.cpp +++ b/core/jni/android/graphics/Paint.cpp @@ -71,13 +71,6 @@ static void defaultSettingsForAndroid(Paint* paint) { paint->setTextEncoding(Paint::kGlyphID_TextEncoding); } -struct LocalesCacheEntry { - std::string javaLocales; - std::string languageTags; -}; - -static thread_local LocalesCacheEntry sSingleEntryLocalesCache; - namespace PaintGlue { enum MoveOpt { AFTER, AT_OR_AFTER, BEFORE, AT_OR_BEFORE, AT @@ -402,15 +395,20 @@ namespace PaintGlue { } } - static void setTextLocales(JNIEnv* env, jobject clazz, jlong objHandle, jstring locales) { + static jint setTextLocales(JNIEnv* env, jobject clazz, jlong objHandle, jstring locales) { Paint* obj = reinterpret_cast(objHandle); ScopedUtfChars localesChars(env, locales); - if (sSingleEntryLocalesCache.javaLocales != localesChars.c_str()) { - sSingleEntryLocalesCache.javaLocales = localesChars.c_str(); - toLanguageTags(&sSingleEntryLocalesCache.languageTags, localesChars.c_str()); - } + std::string buf; + toLanguageTags(&buf, localesChars.c_str()); + jint minikinLangListId = FontStyle::registerLanguageList(buf); + obj->setMinikinLangListId(minikinLangListId); + return minikinLangListId; + } - obj->setTextLocales(sSingleEntryLocalesCache.languageTags); + static void setTextLocalesByMinikinLangListId(JNIEnv* env, jobject clazz, jlong objHandle, + jint minikinLangListId) { + Paint* obj = reinterpret_cast(objHandle); + obj->setMinikinLangListId(minikinLangListId); } static jboolean isElegantTextHeight(JNIEnv* env, jobject, jlong paintHandle) { @@ -991,7 +989,9 @@ static const JNINativeMethod methods[] = { {"nSetRasterizer","!(JJ)J", (void*) PaintGlue::setRasterizer}, {"nGetTextAlign","!(J)I", (void*) PaintGlue::getTextAlign}, {"nSetTextAlign","!(JI)V", (void*) PaintGlue::setTextAlign}, - {"nSetTextLocales","!(JLjava/lang/String;)V", (void*) PaintGlue::setTextLocales}, + {"nSetTextLocales","!(JLjava/lang/String;)I", (void*) PaintGlue::setTextLocales}, + {"nSetTextLocalesByMinikinLangListId","!(JI)V", + (void*) PaintGlue::setTextLocalesByMinikinLangListId}, {"nIsElegantTextHeight","!(J)Z", (void*) PaintGlue::isElegantTextHeight}, {"nSetElegantTextHeight","!(JZ)V", (void*) PaintGlue::setElegantTextHeight}, {"nGetTextSize","!(J)F", (void*) PaintGlue::getTextSize}, diff --git a/core/jni/android/graphics/Paint.h b/core/jni/android/graphics/Paint.h index 7a34bc291ee4..cb6e622ccced 100644 --- a/core/jni/android/graphics/Paint.h +++ b/core/jni/android/graphics/Paint.h @@ -53,12 +53,12 @@ public: return mFontFeatureSettings; } - void setTextLocales(const std::string &textLocales) { - mTextLocales = textLocales; + void setMinikinLangListId(uint32_t minikinLangListId) { + mMinikinLangListId = minikinLangListId; } - const std::string& getTextLocales() const { - return mTextLocales; + uint32_t getMinikinLangListId() const { + return mMinikinLangListId; } void setFontVariant(FontVariant variant) { @@ -80,7 +80,7 @@ public: private: float mLetterSpacing = 0; std::string mFontFeatureSettings; - std::string mTextLocales; + uint32_t mMinikinLangListId; FontVariant mFontVariant; uint32_t mHyphenEdit = 0; }; diff --git a/core/jni/android/graphics/PaintImpl.cpp b/core/jni/android/graphics/PaintImpl.cpp index d5a0972d35e3..bd513ae60823 100644 --- a/core/jni/android/graphics/PaintImpl.cpp +++ b/core/jni/android/graphics/PaintImpl.cpp @@ -22,13 +22,14 @@ namespace android { -Paint::Paint() : SkPaint(), - mLetterSpacing(0), mFontFeatureSettings(), mTextLocales(), mFontVariant(VARIANT_DEFAULT) { +Paint::Paint() : + SkPaint(), mLetterSpacing(0), mFontFeatureSettings(), mMinikinLangListId(0), + mFontVariant(VARIANT_DEFAULT) { } Paint::Paint(const Paint& paint) : SkPaint(paint), mLetterSpacing(paint.mLetterSpacing), mFontFeatureSettings(paint.mFontFeatureSettings), - mTextLocales(paint.mTextLocales), mFontVariant(paint.mFontVariant), + mMinikinLangListId(paint.mMinikinLangListId), mFontVariant(paint.mFontVariant), mHyphenEdit(paint.mHyphenEdit) { } @@ -39,7 +40,7 @@ Paint& Paint::operator=(const Paint& other) { SkPaint::operator=(other); mLetterSpacing = other.mLetterSpacing; mFontFeatureSettings = other.mFontFeatureSettings; - mTextLocales = other.mTextLocales; + mMinikinLangListId = other.mMinikinLangListId; mFontVariant = other.mFontVariant; mHyphenEdit = other.mHyphenEdit; return *this; @@ -49,7 +50,7 @@ bool operator==(const Paint& a, const Paint& b) { return static_cast(a) == static_cast(b) && a.mLetterSpacing == b.mLetterSpacing && a.mFontFeatureSettings == b.mFontFeatureSettings - && a.mTextLocales == b.mTextLocales + && a.mMinikinLangListId == b.mMinikinLangListId && a.mFontVariant == b.mFontVariant && a.mHyphenEdit == b.mHyphenEdit; } diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 35182f9d05a6..90522f71a845 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -25,6 +25,9 @@ import android.text.SpannedString; import android.text.TextUtils; import android.util.LocaleList; +import com.android.internal.annotations.GuardedBy; + +import java.util.HashMap; import java.util.Locale; /** @@ -56,6 +59,16 @@ public class Paint { private LocaleList mLocales; private String mFontFeatureSettings; + private static final Object sCacheLock = new Object(); + + /** + * Cache for the Minikin language list ID. + * + * A map from a string representation of the LocaleList to Minikin's language list ID. + */ + @GuardedBy("sCacheLock") + private static final HashMap sMinikinLangListIdCache = new HashMap<>(); + /** * @hide */ @@ -1335,7 +1348,7 @@ public class Paint { return; } mLocales = new LocaleList(locale); - nSetTextLocales(mNativePaint, locale.toString()); + syncTextLocalesWithMinikin(); } /** @@ -1372,7 +1385,21 @@ public class Paint { } if (locales.equals(mLocales)) return; mLocales = locales; - nSetTextLocales(mNativePaint, locales.toLanguageTags()); + syncTextLocalesWithMinikin(); + } + + private void syncTextLocalesWithMinikin() { + final String languageTags = mLocales.toLanguageTags(); + final Integer minikinLangListId; + synchronized (sCacheLock) { + minikinLangListId = sMinikinLangListIdCache.get(languageTags); + if (minikinLangListId == null) { + final int newID = nSetTextLocales(mNativePaint, languageTags); + sMinikinLangListIdCache.put(languageTags, newID); + return; + } + } + nSetTextLocalesByMinikinLangListId(mNativePaint, minikinLangListId.intValue()); } /** @@ -2714,8 +2741,9 @@ public class Paint { private static native void nSetTextAlign(long paintPtr, int align); - private static native void nSetTextLocales(long paintPtr, - String locales); + private static native int nSetTextLocales(long paintPtr, String locales); + private static native void nSetTextLocalesByMinikinLangListId(long paintPtr, + int mMinikinLangListId); private static native float nGetTextAdvances(long paintPtr, long typefacePtr, char[] text, int index, int count, int contextIndex, int contextCount, -- 2.11.0