Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cfc607cf authored by Seigo Nonaka's avatar Seigo Nonaka
Browse files

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
parent 39a275b3
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -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
+14 −14
Original line number Diff line number Diff line
@@ -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},
+5 −5
Original line number Diff line number Diff line
@@ -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;
};
+6 −5
Original line number Diff line number Diff line
@@ -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<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;
}
+32 −4
Original line number Diff line number Diff line
@@ -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,