Loading core/java/android/text/StaticLayout.java +106 −17 Original line number Diff line number Diff line Loading @@ -161,9 +161,6 @@ public class StaticLayout extends Layout { float spacingadd, boolean includepad, boolean trackpad, float ellipsizedWidth, TextUtils.TruncateAt ellipsize) { int[] breakOpp = null; final String localeLanguageTag = paint.getTextLocale().toLanguageTag(); mLineCount = 0; int v = 0; Loading @@ -178,6 +175,8 @@ public class StaticLayout extends Layout { if (source instanceof Spanned) spanned = (Spanned) source; int DEFAULT_DIR = DIR_LEFT_TO_RIGHT; // XXX int paraEnd; for (int paraStart = bufStart; paraStart <= bufEnd; paraStart = paraEnd) { paraEnd = TextUtils.indexOf(source, CHAR_NEW_LINE, paraStart, bufEnd); Loading Loading @@ -244,9 +243,6 @@ public class StaticLayout extends Layout { int dir = measured.mDir; boolean easy = measured.mEasy; breakOpp = nLineBreakOpportunities(localeLanguageTag, chs, paraEnd - paraStart, breakOpp); int breakOppIndex = 0; int width = firstWidth; float w = 0; Loading Loading @@ -359,12 +355,15 @@ public class StaticLayout extends Layout { if (fmBottom > fitBottom) fitBottom = fmBottom; while (breakOpp[breakOppIndex] != -1 && breakOpp[breakOppIndex] < j - paraStart + 1) { breakOppIndex++; } boolean isLineBreak = breakOppIndex < breakOpp.length && breakOpp[breakOppIndex] == j - paraStart + 1; // From the Unicode Line Breaking Algorithm (at least approximately) boolean isLineBreak = isSpaceOrTab || // / is class SY and - is class HY, except when followed by a digit ((c == CHAR_SLASH || c == CHAR_HYPHEN) && (j + 1 >= spanEnd || !Character.isDigit(chs[j + 1 - paraStart]))) || // Ideographs are class ID: breakpoints when adjacent, except for NS // (non-starters), which can be broken after but not before (c >= CHAR_FIRST_CJK && isIdeographic(c, true) && j + 1 < spanEnd && isIdeographic(chs[j + 1 - paraStart], false)); if (isLineBreak) { okWidth = w; Loading Loading @@ -492,6 +491,97 @@ public class StaticLayout extends Layout { } } /** * Returns true if the specified character is one of those specified * as being Ideographic (class ID) by the Unicode Line Breaking Algorithm * (http://www.unicode.org/unicode/reports/tr14/), and is therefore OK * to break between a pair of. * * @param includeNonStarters also return true for category NS * (non-starters), which can be broken * after but not before. */ private static final boolean isIdeographic(char c, boolean includeNonStarters) { if (c >= '\u2E80' && c <= '\u2FFF') { return true; // CJK, KANGXI RADICALS, DESCRIPTION SYMBOLS } if (c == '\u3000') { return true; // IDEOGRAPHIC SPACE } if (c >= '\u3040' && c <= '\u309F') { if (!includeNonStarters) { switch (c) { case '\u3041': // # HIRAGANA LETTER SMALL A case '\u3043': // # HIRAGANA LETTER SMALL I case '\u3045': // # HIRAGANA LETTER SMALL U case '\u3047': // # HIRAGANA LETTER SMALL E case '\u3049': // # HIRAGANA LETTER SMALL O case '\u3063': // # HIRAGANA LETTER SMALL TU case '\u3083': // # HIRAGANA LETTER SMALL YA case '\u3085': // # HIRAGANA LETTER SMALL YU case '\u3087': // # HIRAGANA LETTER SMALL YO case '\u308E': // # HIRAGANA LETTER SMALL WA case '\u3095': // # HIRAGANA LETTER SMALL KA case '\u3096': // # HIRAGANA LETTER SMALL KE case '\u309B': // # KATAKANA-HIRAGANA VOICED SOUND MARK case '\u309C': // # KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK case '\u309D': // # HIRAGANA ITERATION MARK case '\u309E': // # HIRAGANA VOICED ITERATION MARK return false; } } return true; // Hiragana (except small characters) } if (c >= '\u30A0' && c <= '\u30FF') { if (!includeNonStarters) { switch (c) { case '\u30A0': // # KATAKANA-HIRAGANA DOUBLE HYPHEN case '\u30A1': // # KATAKANA LETTER SMALL A case '\u30A3': // # KATAKANA LETTER SMALL I case '\u30A5': // # KATAKANA LETTER SMALL U case '\u30A7': // # KATAKANA LETTER SMALL E case '\u30A9': // # KATAKANA LETTER SMALL O case '\u30C3': // # KATAKANA LETTER SMALL TU case '\u30E3': // # KATAKANA LETTER SMALL YA case '\u30E5': // # KATAKANA LETTER SMALL YU case '\u30E7': // # KATAKANA LETTER SMALL YO case '\u30EE': // # KATAKANA LETTER SMALL WA case '\u30F5': // # KATAKANA LETTER SMALL KA case '\u30F6': // # KATAKANA LETTER SMALL KE case '\u30FB': // # KATAKANA MIDDLE DOT case '\u30FC': // # KATAKANA-HIRAGANA PROLONGED SOUND MARK case '\u30FD': // # KATAKANA ITERATION MARK case '\u30FE': // # KATAKANA VOICED ITERATION MARK return false; } } return true; // Katakana (except small characters) } if (c >= '\u3400' && c <= '\u4DB5') { return true; // CJK UNIFIED IDEOGRAPHS EXTENSION A } if (c >= '\u4E00' && c <= '\u9FBB') { return true; // CJK UNIFIED IDEOGRAPHS } if (c >= '\uF900' && c <= '\uFAD9') { return true; // CJK COMPATIBILITY IDEOGRAPHS } if (c >= '\uA000' && c <= '\uA48F') { return true; // YI SYLLABLES } if (c >= '\uA490' && c <= '\uA4CF') { return true; // YI RADICALS } if (c >= '\uFE62' && c <= '\uFE66') { return true; // SMALL PLUS SIGN to SMALL EQUALS SIGN } if (c >= '\uFF10' && c <= '\uFF19') { return true; // WIDE DIGITS } return false; } private int out(CharSequence text, int start, int end, int above, int below, int top, int bottom, int v, float spacingmult, float spacingadd, Loading Loading @@ -840,11 +930,6 @@ public class StaticLayout extends Layout { mMeasured = MeasuredText.recycle(mMeasured); } // returns an array with terminal sentinel value -1 to indicate end // this is so that arrays can be recycled instead of allocating new arrays // every time private static native int[] nLineBreakOpportunities(String locale, char[] text, int length, int[] recycle); private int mLineCount; private int mTopPadding, mBottomPadding; private int mColumns; Loading @@ -870,9 +955,13 @@ public class StaticLayout extends Layout { private static final int TAB_INCREMENT = 20; // same as Layout, but that's private private static final char CHAR_FIRST_CJK = '\u2E80'; private static final char CHAR_NEW_LINE = '\n'; private static final char CHAR_TAB = '\t'; private static final char CHAR_SPACE = ' '; private static final char CHAR_SLASH = '/'; private static final char CHAR_HYPHEN = '-'; private static final char CHAR_ZWSP = '\u200B'; private static final double EXTRA_ROUNDING = 0.5; Loading core/jni/Android.mk +0 −1 Original line number Diff line number Diff line Loading @@ -62,7 +62,6 @@ LOCAL_SRC_FILES:= \ android_view_VelocityTracker.cpp \ android_text_AndroidCharacter.cpp \ android_text_AndroidBidi.cpp \ android_text_StaticLayout.cpp \ android_os_Debug.cpp \ android_os_MemoryFile.cpp \ android_os_MessageQueue.cpp \ Loading core/jni/AndroidRuntime.cpp +0 −2 Original line number Diff line number Diff line Loading @@ -148,7 +148,6 @@ extern int register_android_net_NetworkUtils(JNIEnv* env); extern int register_android_net_TrafficStats(JNIEnv* env); extern int register_android_net_wifi_WifiNative(JNIEnv* env); extern int register_android_text_AndroidCharacter(JNIEnv *env); extern int register_android_text_StaticLayout(JNIEnv *env); extern int register_android_text_AndroidBidi(JNIEnv *env); extern int register_android_opengl_classes(JNIEnv *env); extern int register_android_server_NetworkManagementSocketTagger(JNIEnv* env); Loading Loading @@ -1223,7 +1222,6 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_content_XmlBlock), REG_JNI(register_android_emoji_EmojiFactory), REG_JNI(register_android_text_AndroidCharacter), REG_JNI(register_android_text_StaticLayout), REG_JNI(register_android_text_AndroidBidi), REG_JNI(register_android_view_InputDevice), REG_JNI(register_android_view_KeyCharacterMap), Loading core/jni/android_text_StaticLayout.cppdeleted 100644 → 0 +0 −110 Original line number Diff line number Diff line /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "StaticLayout" #include "ScopedIcuLocale.h" #include "unicode/locid.h" #include "unicode/brkiter.h" #include "utils/misc.h" #include "utils/Log.h" #include "ScopedPrimitiveArray.h" #include "JNIHelp.h" #include <android_runtime/AndroidRuntime.h> #include <vector> namespace android { class ScopedBreakIterator { public: ScopedBreakIterator(JNIEnv* env, BreakIterator* breakIterator, jcharArray inputText, jint length) : mBreakIterator(breakIterator), mChars(env, inputText) { UErrorCode status = U_ZERO_ERROR; mUText = utext_openUChars(NULL, mChars.get(), length, &status); if (mUText == NULL) { return; } mBreakIterator->setText(mUText, status); } inline BreakIterator* operator->() { return mBreakIterator; } ~ScopedBreakIterator() { utext_close(mUText); delete mBreakIterator; } private: BreakIterator* mBreakIterator; ScopedCharArrayRO mChars; UText* mUText; // disable copying and assignment ScopedBreakIterator(const ScopedBreakIterator&); void operator=(const ScopedBreakIterator&); }; static jintArray nLineBreakOpportunities(JNIEnv* env, jclass, jstring javaLocaleName, jcharArray inputText, jint length, jintArray recycle) { jintArray ret; std::vector<jint> breaks(16); ScopedIcuLocale icuLocale(env, javaLocaleName); if (icuLocale.valid()) { UErrorCode status = U_ZERO_ERROR; BreakIterator* it = BreakIterator::createLineInstance(icuLocale.locale(), status); if (!U_SUCCESS(status) || it == NULL) { if (it) { delete it; } } else { ScopedBreakIterator breakIterator(env, it, inputText, length); for (int loc = breakIterator->first(); loc != BreakIterator::DONE; loc = breakIterator->next()) { breaks.push_back(loc); } } } breaks.push_back(-1); // sentinel terminal value if (recycle != NULL && env->GetArrayLength(recycle) >= breaks.size()) { ret = recycle; } else { ret = env->NewIntArray(breaks.size()); } if (ret != NULL) { env->SetIntArrayRegion(ret, 0, breaks.size(), &breaks.front()); } return ret; } static JNINativeMethod gMethods[] = { {"nLineBreakOpportunities", "(Ljava/lang/String;[CI[I)[I", (void*) nLineBreakOpportunities} }; int register_android_text_StaticLayout(JNIEnv* env) { return AndroidRuntime::registerNativeMethods(env, "android/text/StaticLayout", gMethods, NELEM(gMethods)); } } Loading
core/java/android/text/StaticLayout.java +106 −17 Original line number Diff line number Diff line Loading @@ -161,9 +161,6 @@ public class StaticLayout extends Layout { float spacingadd, boolean includepad, boolean trackpad, float ellipsizedWidth, TextUtils.TruncateAt ellipsize) { int[] breakOpp = null; final String localeLanguageTag = paint.getTextLocale().toLanguageTag(); mLineCount = 0; int v = 0; Loading @@ -178,6 +175,8 @@ public class StaticLayout extends Layout { if (source instanceof Spanned) spanned = (Spanned) source; int DEFAULT_DIR = DIR_LEFT_TO_RIGHT; // XXX int paraEnd; for (int paraStart = bufStart; paraStart <= bufEnd; paraStart = paraEnd) { paraEnd = TextUtils.indexOf(source, CHAR_NEW_LINE, paraStart, bufEnd); Loading Loading @@ -244,9 +243,6 @@ public class StaticLayout extends Layout { int dir = measured.mDir; boolean easy = measured.mEasy; breakOpp = nLineBreakOpportunities(localeLanguageTag, chs, paraEnd - paraStart, breakOpp); int breakOppIndex = 0; int width = firstWidth; float w = 0; Loading Loading @@ -359,12 +355,15 @@ public class StaticLayout extends Layout { if (fmBottom > fitBottom) fitBottom = fmBottom; while (breakOpp[breakOppIndex] != -1 && breakOpp[breakOppIndex] < j - paraStart + 1) { breakOppIndex++; } boolean isLineBreak = breakOppIndex < breakOpp.length && breakOpp[breakOppIndex] == j - paraStart + 1; // From the Unicode Line Breaking Algorithm (at least approximately) boolean isLineBreak = isSpaceOrTab || // / is class SY and - is class HY, except when followed by a digit ((c == CHAR_SLASH || c == CHAR_HYPHEN) && (j + 1 >= spanEnd || !Character.isDigit(chs[j + 1 - paraStart]))) || // Ideographs are class ID: breakpoints when adjacent, except for NS // (non-starters), which can be broken after but not before (c >= CHAR_FIRST_CJK && isIdeographic(c, true) && j + 1 < spanEnd && isIdeographic(chs[j + 1 - paraStart], false)); if (isLineBreak) { okWidth = w; Loading Loading @@ -492,6 +491,97 @@ public class StaticLayout extends Layout { } } /** * Returns true if the specified character is one of those specified * as being Ideographic (class ID) by the Unicode Line Breaking Algorithm * (http://www.unicode.org/unicode/reports/tr14/), and is therefore OK * to break between a pair of. * * @param includeNonStarters also return true for category NS * (non-starters), which can be broken * after but not before. */ private static final boolean isIdeographic(char c, boolean includeNonStarters) { if (c >= '\u2E80' && c <= '\u2FFF') { return true; // CJK, KANGXI RADICALS, DESCRIPTION SYMBOLS } if (c == '\u3000') { return true; // IDEOGRAPHIC SPACE } if (c >= '\u3040' && c <= '\u309F') { if (!includeNonStarters) { switch (c) { case '\u3041': // # HIRAGANA LETTER SMALL A case '\u3043': // # HIRAGANA LETTER SMALL I case '\u3045': // # HIRAGANA LETTER SMALL U case '\u3047': // # HIRAGANA LETTER SMALL E case '\u3049': // # HIRAGANA LETTER SMALL O case '\u3063': // # HIRAGANA LETTER SMALL TU case '\u3083': // # HIRAGANA LETTER SMALL YA case '\u3085': // # HIRAGANA LETTER SMALL YU case '\u3087': // # HIRAGANA LETTER SMALL YO case '\u308E': // # HIRAGANA LETTER SMALL WA case '\u3095': // # HIRAGANA LETTER SMALL KA case '\u3096': // # HIRAGANA LETTER SMALL KE case '\u309B': // # KATAKANA-HIRAGANA VOICED SOUND MARK case '\u309C': // # KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK case '\u309D': // # HIRAGANA ITERATION MARK case '\u309E': // # HIRAGANA VOICED ITERATION MARK return false; } } return true; // Hiragana (except small characters) } if (c >= '\u30A0' && c <= '\u30FF') { if (!includeNonStarters) { switch (c) { case '\u30A0': // # KATAKANA-HIRAGANA DOUBLE HYPHEN case '\u30A1': // # KATAKANA LETTER SMALL A case '\u30A3': // # KATAKANA LETTER SMALL I case '\u30A5': // # KATAKANA LETTER SMALL U case '\u30A7': // # KATAKANA LETTER SMALL E case '\u30A9': // # KATAKANA LETTER SMALL O case '\u30C3': // # KATAKANA LETTER SMALL TU case '\u30E3': // # KATAKANA LETTER SMALL YA case '\u30E5': // # KATAKANA LETTER SMALL YU case '\u30E7': // # KATAKANA LETTER SMALL YO case '\u30EE': // # KATAKANA LETTER SMALL WA case '\u30F5': // # KATAKANA LETTER SMALL KA case '\u30F6': // # KATAKANA LETTER SMALL KE case '\u30FB': // # KATAKANA MIDDLE DOT case '\u30FC': // # KATAKANA-HIRAGANA PROLONGED SOUND MARK case '\u30FD': // # KATAKANA ITERATION MARK case '\u30FE': // # KATAKANA VOICED ITERATION MARK return false; } } return true; // Katakana (except small characters) } if (c >= '\u3400' && c <= '\u4DB5') { return true; // CJK UNIFIED IDEOGRAPHS EXTENSION A } if (c >= '\u4E00' && c <= '\u9FBB') { return true; // CJK UNIFIED IDEOGRAPHS } if (c >= '\uF900' && c <= '\uFAD9') { return true; // CJK COMPATIBILITY IDEOGRAPHS } if (c >= '\uA000' && c <= '\uA48F') { return true; // YI SYLLABLES } if (c >= '\uA490' && c <= '\uA4CF') { return true; // YI RADICALS } if (c >= '\uFE62' && c <= '\uFE66') { return true; // SMALL PLUS SIGN to SMALL EQUALS SIGN } if (c >= '\uFF10' && c <= '\uFF19') { return true; // WIDE DIGITS } return false; } private int out(CharSequence text, int start, int end, int above, int below, int top, int bottom, int v, float spacingmult, float spacingadd, Loading Loading @@ -840,11 +930,6 @@ public class StaticLayout extends Layout { mMeasured = MeasuredText.recycle(mMeasured); } // returns an array with terminal sentinel value -1 to indicate end // this is so that arrays can be recycled instead of allocating new arrays // every time private static native int[] nLineBreakOpportunities(String locale, char[] text, int length, int[] recycle); private int mLineCount; private int mTopPadding, mBottomPadding; private int mColumns; Loading @@ -870,9 +955,13 @@ public class StaticLayout extends Layout { private static final int TAB_INCREMENT = 20; // same as Layout, but that's private private static final char CHAR_FIRST_CJK = '\u2E80'; private static final char CHAR_NEW_LINE = '\n'; private static final char CHAR_TAB = '\t'; private static final char CHAR_SPACE = ' '; private static final char CHAR_SLASH = '/'; private static final char CHAR_HYPHEN = '-'; private static final char CHAR_ZWSP = '\u200B'; private static final double EXTRA_ROUNDING = 0.5; Loading
core/jni/Android.mk +0 −1 Original line number Diff line number Diff line Loading @@ -62,7 +62,6 @@ LOCAL_SRC_FILES:= \ android_view_VelocityTracker.cpp \ android_text_AndroidCharacter.cpp \ android_text_AndroidBidi.cpp \ android_text_StaticLayout.cpp \ android_os_Debug.cpp \ android_os_MemoryFile.cpp \ android_os_MessageQueue.cpp \ Loading
core/jni/AndroidRuntime.cpp +0 −2 Original line number Diff line number Diff line Loading @@ -148,7 +148,6 @@ extern int register_android_net_NetworkUtils(JNIEnv* env); extern int register_android_net_TrafficStats(JNIEnv* env); extern int register_android_net_wifi_WifiNative(JNIEnv* env); extern int register_android_text_AndroidCharacter(JNIEnv *env); extern int register_android_text_StaticLayout(JNIEnv *env); extern int register_android_text_AndroidBidi(JNIEnv *env); extern int register_android_opengl_classes(JNIEnv *env); extern int register_android_server_NetworkManagementSocketTagger(JNIEnv* env); Loading Loading @@ -1223,7 +1222,6 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_content_XmlBlock), REG_JNI(register_android_emoji_EmojiFactory), REG_JNI(register_android_text_AndroidCharacter), REG_JNI(register_android_text_StaticLayout), REG_JNI(register_android_text_AndroidBidi), REG_JNI(register_android_view_InputDevice), REG_JNI(register_android_view_KeyCharacterMap), Loading
core/jni/android_text_StaticLayout.cppdeleted 100644 → 0 +0 −110 Original line number Diff line number Diff line /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "StaticLayout" #include "ScopedIcuLocale.h" #include "unicode/locid.h" #include "unicode/brkiter.h" #include "utils/misc.h" #include "utils/Log.h" #include "ScopedPrimitiveArray.h" #include "JNIHelp.h" #include <android_runtime/AndroidRuntime.h> #include <vector> namespace android { class ScopedBreakIterator { public: ScopedBreakIterator(JNIEnv* env, BreakIterator* breakIterator, jcharArray inputText, jint length) : mBreakIterator(breakIterator), mChars(env, inputText) { UErrorCode status = U_ZERO_ERROR; mUText = utext_openUChars(NULL, mChars.get(), length, &status); if (mUText == NULL) { return; } mBreakIterator->setText(mUText, status); } inline BreakIterator* operator->() { return mBreakIterator; } ~ScopedBreakIterator() { utext_close(mUText); delete mBreakIterator; } private: BreakIterator* mBreakIterator; ScopedCharArrayRO mChars; UText* mUText; // disable copying and assignment ScopedBreakIterator(const ScopedBreakIterator&); void operator=(const ScopedBreakIterator&); }; static jintArray nLineBreakOpportunities(JNIEnv* env, jclass, jstring javaLocaleName, jcharArray inputText, jint length, jintArray recycle) { jintArray ret; std::vector<jint> breaks(16); ScopedIcuLocale icuLocale(env, javaLocaleName); if (icuLocale.valid()) { UErrorCode status = U_ZERO_ERROR; BreakIterator* it = BreakIterator::createLineInstance(icuLocale.locale(), status); if (!U_SUCCESS(status) || it == NULL) { if (it) { delete it; } } else { ScopedBreakIterator breakIterator(env, it, inputText, length); for (int loc = breakIterator->first(); loc != BreakIterator::DONE; loc = breakIterator->next()) { breaks.push_back(loc); } } } breaks.push_back(-1); // sentinel terminal value if (recycle != NULL && env->GetArrayLength(recycle) >= breaks.size()) { ret = recycle; } else { ret = env->NewIntArray(breaks.size()); } if (ret != NULL) { env->SetIntArrayRegion(ret, 0, breaks.size(), &breaks.front()); } return ret; } static JNINativeMethod gMethods[] = { {"nLineBreakOpportunities", "(Ljava/lang/String;[CI[I)[I", (void*) nLineBreakOpportunities} }; int register_android_text_StaticLayout(JNIEnv* env) { return AndroidRuntime::registerNativeMethods(env, "android/text/StaticLayout", gMethods, NELEM(gMethods)); } }