Loading core/java/android/text/AndroidBidi.java +48 −14 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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(); } final byte paraLevel; 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; 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; } /** Loading Loading @@ -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 core/java/android/text/MeasuredText.java +3 −3 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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; } } Loading core/jni/Android.bp +0 −1 Original line number Diff line number Diff line Loading @@ -87,7 +87,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", Loading core/jni/AndroidRuntime.cpp +0 −2 Original line number Diff line number Diff line Loading @@ -177,7 +177,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); Loading Loading @@ -1335,7 +1334,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), Loading core/jni/android_text_AndroidBidi.cppdeleted 100644 → 0 +0 −72 Original line number Diff line number Diff line /* //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)); } } Loading
core/java/android/text/AndroidBidi.java +48 −14 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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(); } final byte paraLevel; 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; 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; } /** Loading Loading @@ -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
core/java/android/text/MeasuredText.java +3 −3 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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; } } Loading
core/jni/Android.bp +0 −1 Original line number Diff line number Diff line Loading @@ -87,7 +87,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", Loading
core/jni/AndroidRuntime.cpp +0 −2 Original line number Diff line number Diff line Loading @@ -177,7 +177,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); Loading Loading @@ -1335,7 +1334,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), Loading
core/jni/android_text_AndroidBidi.cppdeleted 100644 → 0 +0 −72 Original line number Diff line number Diff line /* //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)); } }