OSDN Git Service

Introduce cache mechanism for LocaleList.
authorSeigo Nonaka <nona@google.com>
Wed, 2 Dec 2015 01:53:18 +0000 (10:53 +0900)
committerSeigo Nonaka <nona@google.com>
Tue, 8 Dec 2015 00:50:20 +0000 (16:50 -0800)
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
core/jni/android/graphics/Paint.cpp
core/jni/android/graphics/Paint.h
core/jni/android/graphics/PaintImpl.cpp
graphics/java/android/graphics/Paint.java

index 9b774b3..0597d3f 100644 (file)
@@ -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
index 9c11dd1..654d148 100644 (file)
@@ -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<Paint*>(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<Paint*>(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},
index 7a34bc2..cb6e622 100644 (file)
@@ -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;
 };
index d5a0972..bd513ae 100644 (file)
 
 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<const SkPaint&>(a) == static_cast<const SkPaint&>(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;
 }
index 35182f9..90522f7 100644 (file)
@@ -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<String, Integer> 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,