diff options
| -rw-r--r-- | core/java/android/text/AndroidBidi.java | 62 | ||||
| -rw-r--r-- | core/java/android/text/MeasuredText.java | 6 | ||||
| -rw-r--r-- | core/jni/Android.bp | 1 | ||||
| -rw-r--r-- | core/jni/AndroidRuntime.cpp | 2 | ||||
| -rw-r--r-- | core/jni/android_text_AndroidBidi.cpp | 72 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/text/StaticLayoutBidiTest.java | 2 |
6 files changed, 52 insertions, 93 deletions
diff --git a/core/java/android/text/AndroidBidi.java b/core/java/android/text/AndroidBidi.java index bbe152321a38..179d545f8ccd 100644 --- a/core/java/android/text/AndroidBidi.java +++ b/core/java/android/text/AndroidBidi.java @@ -16,6 +16,11 @@ package android.text; +import android.icu.lang.UCharacter; +import android.icu.lang.UCharacterDirection; +import android.icu.lang.UProperty; +import android.icu.text.Bidi; +import android.icu.text.BidiClassifier; import android.text.Layout.Directions; import com.android.internal.annotations.VisibleForTesting; @@ -27,26 +32,57 @@ import com.android.internal.annotations.VisibleForTesting; @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public class AndroidBidi { - public static int bidi(int dir, char[] chs, byte[] chInfo, int n, boolean haveInfo) { + private static class EmojiBidiOverride extends BidiClassifier { + EmojiBidiOverride() { + super(null /* No persisting object needed */); + } + + // Tells ICU to use the standard Unicode value. + private static final int NO_OVERRIDE = + UCharacter.getIntPropertyMaxValue(UProperty.BIDI_CLASS) + 1; + + @Override + public int classify(int c) { + if (Emoji.isNewEmoji(c)) { + // All new emoji characters in Unicode 10.0 are of the bidi class ON. + return UCharacterDirection.OTHER_NEUTRAL; + } else { + return NO_OVERRIDE; + } + } + } + + private static final EmojiBidiOverride sEmojiBidiOverride = new EmojiBidiOverride(); + + /** + * Runs the bidi algorithm on input text. + */ + public static int bidi(int dir, char[] chs, byte[] chInfo) { if (chs == null || chInfo == null) { throw new NullPointerException(); } - if (n < 0 || chs.length < n || chInfo.length < n) { + final int length = chs.length; + if (chInfo.length < length) { throw new IndexOutOfBoundsException(); } - switch(dir) { - case Layout.DIR_REQUEST_LTR: dir = 0; break; - case Layout.DIR_REQUEST_RTL: dir = 1; break; - case Layout.DIR_REQUEST_DEFAULT_LTR: dir = -2; break; - case Layout.DIR_REQUEST_DEFAULT_RTL: dir = -1; break; - default: dir = 0; break; + final byte paraLevel; + switch (dir) { + case Layout.DIR_REQUEST_LTR: paraLevel = Bidi.LTR; break; + case Layout.DIR_REQUEST_RTL: paraLevel = Bidi.RTL; break; + case Layout.DIR_REQUEST_DEFAULT_LTR: paraLevel = Bidi.LEVEL_DEFAULT_LTR; break; + case Layout.DIR_REQUEST_DEFAULT_RTL: paraLevel = Bidi.LEVEL_DEFAULT_RTL; break; + default: paraLevel = Bidi.LTR; break; } - - int result = runBidi(dir, chs, chInfo, n, haveInfo); - result = (result & 0x1) == 0 ? Layout.DIR_LEFT_TO_RIGHT : Layout.DIR_RIGHT_TO_LEFT; - return result; + final Bidi icuBidi = new Bidi(length /* maxLength */, 0 /* maxRunCount */); + icuBidi.setCustomClassifier(sEmojiBidiOverride); + icuBidi.setPara(chs, paraLevel, null /* embeddingLevels */); + for (int i = 0; i < length; i++) { + chInfo[i] = icuBidi.getLevelAt(i); + } + final byte result = icuBidi.getParaLevel(); + return (result & 0x1) == 0 ? Layout.DIR_LEFT_TO_RIGHT : Layout.DIR_RIGHT_TO_LEFT; } /** @@ -178,6 +214,4 @@ public class AndroidBidi { } return new Directions(ld); } - - private native static int runBidi(int dir, char[] chs, byte[] chInfo, int n, boolean haveInfo); }
\ No newline at end of file diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java index b09ccc299b28..ffc44a72c357 100644 --- a/core/java/android/text/MeasuredText.java +++ b/core/java/android/text/MeasuredText.java @@ -106,8 +106,8 @@ class MeasuredText { if (mWidths == null || mWidths.length < len) { mWidths = ArrayUtils.newUnpaddedFloatArray(len); } - if (mChars == null || mChars.length < len) { - mChars = ArrayUtils.newUnpaddedCharArray(len); + if (mChars == null || mChars.length != len) { + mChars = new char[len]; } TextUtils.getChars(text, start, end, mChars, 0); @@ -151,7 +151,7 @@ class MeasuredText { boolean isRtl = textDir.isRtl(mChars, 0, len); bidiRequest = isRtl ? Layout.DIR_REQUEST_RTL : Layout.DIR_REQUEST_LTR; } - mDir = AndroidBidi.bidi(bidiRequest, mChars, mLevels, len, false); + mDir = AndroidBidi.bidi(bidiRequest, mChars, mLevels); mEasy = false; } } diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 256b920ee34a..3043810290f4 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -77,7 +77,6 @@ cc_library_shared { "android_view_ThreadedRenderer.cpp", "android_view_VelocityTracker.cpp", "android_text_AndroidCharacter.cpp", - "android_text_AndroidBidi.cpp", "android_text_Hyphenator.cpp", "android_text_StaticLayout.cpp", "android_os_Debug.cpp", diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index deb4d5ab9e8c..a04780e4bea9 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -175,7 +175,6 @@ extern int register_android_net_TrafficStats(JNIEnv* env); extern int register_android_text_AndroidCharacter(JNIEnv *env); extern int register_android_text_Hyphenator(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_ddm_DdmHandleNativeHeap(JNIEnv *env); extern int register_android_server_NetworkManagementSocketTagger(JNIEnv* env); @@ -1324,7 +1323,6 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_text_AndroidCharacter), REG_JNI(register_android_text_Hyphenator), REG_JNI(register_android_text_StaticLayout), - REG_JNI(register_android_text_AndroidBidi), REG_JNI(register_android_view_InputDevice), REG_JNI(register_android_view_KeyCharacterMap), REG_JNI(register_android_os_Process), diff --git a/core/jni/android_text_AndroidBidi.cpp b/core/jni/android_text_AndroidBidi.cpp deleted file mode 100644 index f72f0f0dc60a..000000000000 --- a/core/jni/android_text_AndroidBidi.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* //device/libs/android_runtime/android_text_AndroidBidi.cpp -** -** Copyright 2010, 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 "AndroidUnicode" - -#include <nativehelper/JNIHelp.h> -#include "core_jni_helpers.h" -#include "utils/misc.h" -#include "utils/Log.h" -#include "unicode/ubidi.h" -#include <minikin/Emoji.h> - -namespace android { - -static jint runBidi(JNIEnv* env, jobject obj, jint dir, jcharArray chsArray, - jbyteArray infoArray, jint n, jboolean haveInfo) -{ - // Parameters are checked on java side - // Failures from GetXXXArrayElements indicate a serious out-of-memory condition - // that we don't bother to report, we're probably dead anyway. - jint result = 0; - jchar* chs = env->GetCharArrayElements(chsArray, NULL); - if (chs != NULL) { - jbyte* info = env->GetByteArrayElements(infoArray, NULL); - if (info != NULL) { - UErrorCode status = U_ZERO_ERROR; - UBiDi* bidi = ubidi_openSized(n, 0, &status); - // Set callbacks to override bidi classes of new emoji - ubidi_setClassCallback( - bidi, minikin::emojiBidiOverride, nullptr, nullptr, nullptr, &status); - ubidi_setPara(bidi, reinterpret_cast<const UChar*>(chs), n, dir, NULL, &status); - if (U_SUCCESS(status)) { - for (int i = 0; i < n; ++i) { - info[i] = ubidi_getLevelAt(bidi, i); - } - result = ubidi_getParaLevel(bidi); - } else { - jniThrowException(env, "java/lang/RuntimeException", NULL); - } - ubidi_close(bidi); - - env->ReleaseByteArrayElements(infoArray, info, 0); - } - env->ReleaseCharArrayElements(chsArray, chs, JNI_ABORT); - } - return result; -} - -static const JNINativeMethod gMethods[] = { - { "runBidi", "(I[C[BIZ)I", (void*) runBidi } -}; - -int register_android_text_AndroidBidi(JNIEnv* env) -{ - return RegisterMethodsOrDie(env, "android/text/AndroidBidi", gMethods, NELEM(gMethods)); -} - -} diff --git a/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java b/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java index d16cce8b40b3..8092203033c2 100644 --- a/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java +++ b/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java @@ -96,7 +96,7 @@ public class StaticLayoutBidiTest { int n = chs.length; byte[] chInfo = new byte[n]; - int resultDir = AndroidBidi.bidi(dir, chs, chInfo, n, false); + int resultDir = AndroidBidi.bidi(dir, chs, chInfo); { StringBuilder sb = new StringBuilder("info:"); |