Merge "Replace JNI portion of AndroidBidi with calls to ICU4J"
This commit is contained in:
committed by
Android (Google) Code Review
commit
a5511eb648
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
@@ -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),
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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:");
|
||||
|
||||
Reference in New Issue
Block a user