Loading core/java/android/util/LocaleList.java +20 −10 Original line number Diff line number Diff line Loading @@ -37,6 +37,11 @@ import java.util.Locale; */ public final class LocaleList { private final Locale[] mList; // This is a comma-separated list of the locales in the LocaleList created at construction time, // basically the result of running each locale's toLanguageTag() method and concatenating them // with commas in between. private final String mStringRepresentation; private static final Locale[] sEmptyList = new Locale[0]; private static final LocaleList sEmptyLocaleList = new LocaleList(); Loading Loading @@ -95,15 +100,9 @@ public final class LocaleList { return sb.toString(); } @NonNull public String toLanguageTags() { StringBuilder sb = new StringBuilder(); for (int i = 0; i < mList.length; ++i) { sb.append(mList[i].toLanguageTag()); if (i < mList.length - 1) { sb.append(','); } } return sb.toString(); return mStringRepresentation; } /** Loading @@ -112,6 +111,7 @@ public final class LocaleList { */ public LocaleList() { mList = sEmptyList; mStringRepresentation = ""; } /** Loading @@ -121,9 +121,11 @@ public final class LocaleList { public LocaleList(@Nullable Locale locale) { if (locale == null) { mList = sEmptyList; mStringRepresentation = ""; } else { mList = new Locale[1]; mList[0] = (Locale) locale.clone(); mStringRepresentation = locale.toLanguageTag(); } } Loading @@ -134,9 +136,11 @@ public final class LocaleList { public LocaleList(@Nullable Locale[] list) { if (list == null || list.length == 0) { mList = sEmptyList; mStringRepresentation = ""; } else { final Locale[] localeList = new Locale[list.length]; final HashSet<Locale> seenLocales = new HashSet<Locale>(); final StringBuilder sb = new StringBuilder(); for (int i = 0; i < list.length; ++i) { final Locale l = list[i]; if (l == null) { Loading @@ -144,11 +148,17 @@ public final class LocaleList { } else if (seenLocales.contains(l)) { throw new IllegalArgumentException(); } else { seenLocales.add(l); localeList[i] = (Locale) l.clone(); final Locale localeClone = (Locale) l.clone(); localeList[i] = localeClone; sb.append(localeClone.toLanguageTag()); if (i < list.length - 1) { sb.append(','); } seenLocales.add(localeClone); } } mList = localeList; mStringRepresentation = sb.toString(); } } Loading core/jni/android/graphics/MinikinUtils.cpp +3 −3 Original line number Diff line number Diff line Loading @@ -33,11 +33,11 @@ FontStyle MinikinUtils::prepareMinikinPaint(MinikinPaint* minikinPaint, FontColl FontStyle resolved = resolvedFace->fStyle; /* Prepare minikin FontStyle */ const std::string& lang = paint->getTextLocale(); FontLanguage minikinLang(lang.c_str(), lang.size()); 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(minikinLang, minikinVariant, resolved.getWeight(), resolved.getItalic()); FontStyle minikinStyle(minikinLangs, minikinVariant, resolved.getWeight(), resolved.getItalic()); /* Prepare minikin Paint */ // Note: it would be nice to handle fractional size values (it would improve smooth zoom Loading core/jni/android/graphics/Paint.cpp +56 −18 Original line number Diff line number Diff line Loading @@ -43,12 +43,10 @@ #include "Paint.h" #include "TypefaceImpl.h" #include <vector> #include <cassert> #include <cstring> #include <memory> // temporary for debugging #include <Caches.h> #include <utils/Log.h> #include <vector> namespace android { Loading @@ -71,12 +69,12 @@ static void defaultSettingsForAndroid(Paint* paint) { paint->setTextEncoding(Paint::kGlyphID_TextEncoding); } struct LocaleCacheEntry { std::string javaLocale; std::string languageTag; struct LocalesCacheEntry { std::string javaLocales; std::string languageTags; }; static thread_local LocaleCacheEntry sSingleEntryLocaleCache; static thread_local LocalesCacheEntry sSingleEntryLocalesCache; namespace PaintGlue { enum MoveOpt { Loading Loading @@ -360,17 +358,57 @@ namespace PaintGlue { output[0] = '\0'; } static void setTextLocale(JNIEnv* env, jobject clazz, jlong objHandle, jstring locale) { Paint* obj = reinterpret_cast<Paint*>(objHandle); ScopedUtfChars localeChars(env, locale); if (sSingleEntryLocaleCache.javaLocale != localeChars.c_str()) { sSingleEntryLocaleCache.javaLocale = localeChars.c_str(); static void toLanguageTags(std::string* output, const char* locales) { if (output == NULL) { return; } if (locales == NULL) { output->clear(); return; } char langTag[ULOC_FULLNAME_CAPACITY]; toLanguageTag(langTag, ULOC_FULLNAME_CAPACITY, localeChars.c_str()); sSingleEntryLocaleCache.languageTag = langTag; const char* commaLoc = strchr(locales, ','); if (commaLoc == NULL) { assert(locales[0] != '\0'); // the string should not be empty toLanguageTag(langTag, ULOC_FULLNAME_CAPACITY, locales); *output = langTag; return; } size_t len = strlen(locales); char locale[len]; output->clear(); output->reserve(len); const char* lastStart = locales; do { assert(lastStart > commaLoc); // the substring should not be empty strncpy(locale, lastStart, commaLoc - lastStart); locale[commaLoc - lastStart] = '\0'; toLanguageTag(langTag, ULOC_FULLNAME_CAPACITY, locale); if (langTag[0] != '\0') { output->append(langTag); output->push_back(','); } lastStart = commaLoc + 1; commaLoc = strchr(lastStart, ','); } while (commaLoc != NULL); assert(lastStart[0] != '\0'); // the final substring should not be empty toLanguageTag(langTag, ULOC_FULLNAME_CAPACITY, lastStart); if (langTag[0] != '\0') { output->append(langTag); } } static void 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()); } obj->setTextLocale(sSingleEntryLocaleCache.languageTag); obj->setTextLocales(sSingleEntryLocalesCache.languageTags); } static jboolean isElegantTextHeight(JNIEnv* env, jobject, jlong paintHandle) { Loading Loading @@ -952,7 +990,7 @@ static const JNINativeMethod methods[] = { {"nSetRasterizer","!(JJ)J", (void*) PaintGlue::setRasterizer}, {"nGetTextAlign","!(J)I", (void*) PaintGlue::getTextAlign}, {"nSetTextAlign","!(JI)V", (void*) PaintGlue::setTextAlign}, {"nSetTextLocale","!(JLjava/lang/String;)V", (void*) PaintGlue::setTextLocale}, {"nSetTextLocales","!(JLjava/lang/String;)V", (void*) PaintGlue::setTextLocales}, {"nIsElegantTextHeight","!(J)Z", (void*) PaintGlue::isElegantTextHeight}, {"nSetElegantTextHeight","!(JZ)V", (void*) PaintGlue::setElegantTextHeight}, {"nGetTextSize","!(J)F", (void*) PaintGlue::getTextSize}, Loading core/jni/android/graphics/Paint.h +5 −5 Original line number Diff line number Diff line Loading @@ -53,12 +53,12 @@ public: return mFontFeatureSettings; } void setTextLocale(const std::string &textLocale) { mTextLocale = textLocale; void setTextLocales(const std::string &textLocales) { mTextLocales = textLocales; } const std::string& getTextLocale() const { return mTextLocale; const std::string& getTextLocales() const { return mTextLocales; } void setFontVariant(FontVariant variant) { Loading @@ -80,7 +80,7 @@ public: private: float mLetterSpacing = 0; std::string mFontFeatureSettings; std::string mTextLocale; std::string mTextLocales; FontVariant mFontVariant; uint32_t mHyphenEdit = 0; }; Loading core/jni/android/graphics/PaintImpl.cpp +4 −4 Original line number Diff line number Diff line Loading @@ -23,12 +23,12 @@ namespace android { Paint::Paint() : SkPaint(), mLetterSpacing(0), mFontFeatureSettings(), mTextLocale(), mFontVariant(VARIANT_DEFAULT) { mLetterSpacing(0), mFontFeatureSettings(), mTextLocales(), mFontVariant(VARIANT_DEFAULT) { } Paint::Paint(const Paint& paint) : SkPaint(paint), mLetterSpacing(paint.mLetterSpacing), mFontFeatureSettings(paint.mFontFeatureSettings), mTextLocale(paint.mTextLocale), mFontVariant(paint.mFontVariant), mTextLocales(paint.mTextLocales), mFontVariant(paint.mFontVariant), mHyphenEdit(paint.mHyphenEdit) { } Loading @@ -39,7 +39,7 @@ Paint& Paint::operator=(const Paint& other) { SkPaint::operator=(other); mLetterSpacing = other.mLetterSpacing; mFontFeatureSettings = other.mFontFeatureSettings; mTextLocale = other.mTextLocale; mTextLocales = other.mTextLocales; mFontVariant = other.mFontVariant; mHyphenEdit = other.mHyphenEdit; return *this; Loading @@ -49,7 +49,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.mTextLocale == b.mTextLocale && a.mTextLocales == b.mTextLocales && a.mFontVariant == b.mFontVariant && a.mHyphenEdit == b.mHyphenEdit; } Loading Loading
core/java/android/util/LocaleList.java +20 −10 Original line number Diff line number Diff line Loading @@ -37,6 +37,11 @@ import java.util.Locale; */ public final class LocaleList { private final Locale[] mList; // This is a comma-separated list of the locales in the LocaleList created at construction time, // basically the result of running each locale's toLanguageTag() method and concatenating them // with commas in between. private final String mStringRepresentation; private static final Locale[] sEmptyList = new Locale[0]; private static final LocaleList sEmptyLocaleList = new LocaleList(); Loading Loading @@ -95,15 +100,9 @@ public final class LocaleList { return sb.toString(); } @NonNull public String toLanguageTags() { StringBuilder sb = new StringBuilder(); for (int i = 0; i < mList.length; ++i) { sb.append(mList[i].toLanguageTag()); if (i < mList.length - 1) { sb.append(','); } } return sb.toString(); return mStringRepresentation; } /** Loading @@ -112,6 +111,7 @@ public final class LocaleList { */ public LocaleList() { mList = sEmptyList; mStringRepresentation = ""; } /** Loading @@ -121,9 +121,11 @@ public final class LocaleList { public LocaleList(@Nullable Locale locale) { if (locale == null) { mList = sEmptyList; mStringRepresentation = ""; } else { mList = new Locale[1]; mList[0] = (Locale) locale.clone(); mStringRepresentation = locale.toLanguageTag(); } } Loading @@ -134,9 +136,11 @@ public final class LocaleList { public LocaleList(@Nullable Locale[] list) { if (list == null || list.length == 0) { mList = sEmptyList; mStringRepresentation = ""; } else { final Locale[] localeList = new Locale[list.length]; final HashSet<Locale> seenLocales = new HashSet<Locale>(); final StringBuilder sb = new StringBuilder(); for (int i = 0; i < list.length; ++i) { final Locale l = list[i]; if (l == null) { Loading @@ -144,11 +148,17 @@ public final class LocaleList { } else if (seenLocales.contains(l)) { throw new IllegalArgumentException(); } else { seenLocales.add(l); localeList[i] = (Locale) l.clone(); final Locale localeClone = (Locale) l.clone(); localeList[i] = localeClone; sb.append(localeClone.toLanguageTag()); if (i < list.length - 1) { sb.append(','); } seenLocales.add(localeClone); } } mList = localeList; mStringRepresentation = sb.toString(); } } Loading
core/jni/android/graphics/MinikinUtils.cpp +3 −3 Original line number Diff line number Diff line Loading @@ -33,11 +33,11 @@ FontStyle MinikinUtils::prepareMinikinPaint(MinikinPaint* minikinPaint, FontColl FontStyle resolved = resolvedFace->fStyle; /* Prepare minikin FontStyle */ const std::string& lang = paint->getTextLocale(); FontLanguage minikinLang(lang.c_str(), lang.size()); 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(minikinLang, minikinVariant, resolved.getWeight(), resolved.getItalic()); FontStyle minikinStyle(minikinLangs, minikinVariant, resolved.getWeight(), resolved.getItalic()); /* Prepare minikin Paint */ // Note: it would be nice to handle fractional size values (it would improve smooth zoom Loading
core/jni/android/graphics/Paint.cpp +56 −18 Original line number Diff line number Diff line Loading @@ -43,12 +43,10 @@ #include "Paint.h" #include "TypefaceImpl.h" #include <vector> #include <cassert> #include <cstring> #include <memory> // temporary for debugging #include <Caches.h> #include <utils/Log.h> #include <vector> namespace android { Loading @@ -71,12 +69,12 @@ static void defaultSettingsForAndroid(Paint* paint) { paint->setTextEncoding(Paint::kGlyphID_TextEncoding); } struct LocaleCacheEntry { std::string javaLocale; std::string languageTag; struct LocalesCacheEntry { std::string javaLocales; std::string languageTags; }; static thread_local LocaleCacheEntry sSingleEntryLocaleCache; static thread_local LocalesCacheEntry sSingleEntryLocalesCache; namespace PaintGlue { enum MoveOpt { Loading Loading @@ -360,17 +358,57 @@ namespace PaintGlue { output[0] = '\0'; } static void setTextLocale(JNIEnv* env, jobject clazz, jlong objHandle, jstring locale) { Paint* obj = reinterpret_cast<Paint*>(objHandle); ScopedUtfChars localeChars(env, locale); if (sSingleEntryLocaleCache.javaLocale != localeChars.c_str()) { sSingleEntryLocaleCache.javaLocale = localeChars.c_str(); static void toLanguageTags(std::string* output, const char* locales) { if (output == NULL) { return; } if (locales == NULL) { output->clear(); return; } char langTag[ULOC_FULLNAME_CAPACITY]; toLanguageTag(langTag, ULOC_FULLNAME_CAPACITY, localeChars.c_str()); sSingleEntryLocaleCache.languageTag = langTag; const char* commaLoc = strchr(locales, ','); if (commaLoc == NULL) { assert(locales[0] != '\0'); // the string should not be empty toLanguageTag(langTag, ULOC_FULLNAME_CAPACITY, locales); *output = langTag; return; } size_t len = strlen(locales); char locale[len]; output->clear(); output->reserve(len); const char* lastStart = locales; do { assert(lastStart > commaLoc); // the substring should not be empty strncpy(locale, lastStart, commaLoc - lastStart); locale[commaLoc - lastStart] = '\0'; toLanguageTag(langTag, ULOC_FULLNAME_CAPACITY, locale); if (langTag[0] != '\0') { output->append(langTag); output->push_back(','); } lastStart = commaLoc + 1; commaLoc = strchr(lastStart, ','); } while (commaLoc != NULL); assert(lastStart[0] != '\0'); // the final substring should not be empty toLanguageTag(langTag, ULOC_FULLNAME_CAPACITY, lastStart); if (langTag[0] != '\0') { output->append(langTag); } } static void 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()); } obj->setTextLocale(sSingleEntryLocaleCache.languageTag); obj->setTextLocales(sSingleEntryLocalesCache.languageTags); } static jboolean isElegantTextHeight(JNIEnv* env, jobject, jlong paintHandle) { Loading Loading @@ -952,7 +990,7 @@ static const JNINativeMethod methods[] = { {"nSetRasterizer","!(JJ)J", (void*) PaintGlue::setRasterizer}, {"nGetTextAlign","!(J)I", (void*) PaintGlue::getTextAlign}, {"nSetTextAlign","!(JI)V", (void*) PaintGlue::setTextAlign}, {"nSetTextLocale","!(JLjava/lang/String;)V", (void*) PaintGlue::setTextLocale}, {"nSetTextLocales","!(JLjava/lang/String;)V", (void*) PaintGlue::setTextLocales}, {"nIsElegantTextHeight","!(J)Z", (void*) PaintGlue::isElegantTextHeight}, {"nSetElegantTextHeight","!(JZ)V", (void*) PaintGlue::setElegantTextHeight}, {"nGetTextSize","!(J)F", (void*) PaintGlue::getTextSize}, Loading
core/jni/android/graphics/Paint.h +5 −5 Original line number Diff line number Diff line Loading @@ -53,12 +53,12 @@ public: return mFontFeatureSettings; } void setTextLocale(const std::string &textLocale) { mTextLocale = textLocale; void setTextLocales(const std::string &textLocales) { mTextLocales = textLocales; } const std::string& getTextLocale() const { return mTextLocale; const std::string& getTextLocales() const { return mTextLocales; } void setFontVariant(FontVariant variant) { Loading @@ -80,7 +80,7 @@ public: private: float mLetterSpacing = 0; std::string mFontFeatureSettings; std::string mTextLocale; std::string mTextLocales; FontVariant mFontVariant; uint32_t mHyphenEdit = 0; }; Loading
core/jni/android/graphics/PaintImpl.cpp +4 −4 Original line number Diff line number Diff line Loading @@ -23,12 +23,12 @@ namespace android { Paint::Paint() : SkPaint(), mLetterSpacing(0), mFontFeatureSettings(), mTextLocale(), mFontVariant(VARIANT_DEFAULT) { mLetterSpacing(0), mFontFeatureSettings(), mTextLocales(), mFontVariant(VARIANT_DEFAULT) { } Paint::Paint(const Paint& paint) : SkPaint(paint), mLetterSpacing(paint.mLetterSpacing), mFontFeatureSettings(paint.mFontFeatureSettings), mTextLocale(paint.mTextLocale), mFontVariant(paint.mFontVariant), mTextLocales(paint.mTextLocales), mFontVariant(paint.mFontVariant), mHyphenEdit(paint.mHyphenEdit) { } Loading @@ -39,7 +39,7 @@ Paint& Paint::operator=(const Paint& other) { SkPaint::operator=(other); mLetterSpacing = other.mLetterSpacing; mFontFeatureSettings = other.mFontFeatureSettings; mTextLocale = other.mTextLocale; mTextLocales = other.mTextLocales; mFontVariant = other.mFontVariant; mHyphenEdit = other.mHyphenEdit; return *this; Loading @@ -49,7 +49,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.mTextLocale == b.mTextLocale && a.mTextLocales == b.mTextLocales && a.mFontVariant == b.mFontVariant && a.mHyphenEdit == b.mHyphenEdit; } Loading