diff --git a/core/jni/android/graphics/MinikinUtils.cpp b/core/jni/android/graphics/MinikinUtils.cpp index 9b774b3cfc530..0597d3f37a717 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 9c11dd1538719..654d148e2029b 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 7a34bc291ee4c..cb6e622ccced2 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 d5a0972d35e31..bd513ae60823c 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 35182f9d05a6a..90522f71a845a 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,