Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a5511eb6 authored by Roozbeh Pournader's avatar Roozbeh Pournader Committed by Android (Google) Code Review
Browse files

Merge "Replace JNI portion of AndroidBidi with calls to ICU4J"

parents c2e67f4b a15fd848
Loading
Loading
Loading
Loading
+48 −14
Original line number Diff line number Diff line
@@ -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();
        }

        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;
    }

    /**
@@ -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
+3 −3
Original line number Diff line number Diff line
@@ -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;
        }
    }
+0 −1
Original line number Diff line number Diff line
@@ -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",
+0 −2
Original line number Diff line number Diff line
@@ -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),
+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