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

Commit 277903f8 authored by Eric Fischer's avatar Eric Fischer Committed by Android (Google) Code Review
Browse files

Merge "Add support for accessing native bidi implementation via jni."

parents 7964d1f7 dae8e94c
Loading
Loading
Loading
Loading
+48 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 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.
 */

package android.text;

/**
 * Access the ICU bidi implementation.
 * @hide
 */
/* package */ class AndroidBidi {

    public static int bidi(int dir, char[] chs, byte[] chInfo, int n, boolean haveInfo) {
        if (chs == null || chInfo == null) {
            throw new NullPointerException();
        }

        if (n < 0 || chs.length < n || chInfo.length < n) {
            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;
        }

        int result = runBidi(dir, chs, chInfo, n, haveInfo);
        result = (result & 0x1) == 0 ? Layout.DIR_LEFT_TO_RIGHT : Layout.DIR_RIGHT_TO_LEFT;
        return result;
    }

    private native static int runBidi(int dir, char[] chs, byte[] chInfo, int n, boolean haveInfo);
}
 No newline at end of file
+1 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ LOCAL_SRC_FILES:= \
	android_view_Surface.cpp \
	android_view_ViewRoot.cpp \
	android_text_AndroidCharacter.cpp \
	android_text_AndroidBidi.cpp \
	android_text_KeyCharacterMap.cpp \
	android_os_Debug.cpp \
	android_os_FileUtils.cpp \
+2 −0
Original line number Diff line number Diff line
@@ -142,6 +142,7 @@ extern int register_android_net_NetworkUtils(JNIEnv* env);
extern int register_android_net_wifi_WifiManager(JNIEnv* env);
extern int register_android_security_Md5MessageDigest(JNIEnv *env);
extern int register_android_text_AndroidCharacter(JNIEnv *env);
extern int register_android_text_AndroidBidi(JNIEnv *env);
extern int register_android_text_KeyCharacterMap(JNIEnv *env);
extern int register_android_opengl_classes(JNIEnv *env);
extern int register_android_bluetooth_HeadsetBase(JNIEnv* env);
@@ -1184,6 +1185,7 @@ static const RegJNIRec gRegJNI[] = {
    REG_JNI(register_android_emoji_EmojiFactory),
    REG_JNI(register_android_security_Md5MessageDigest),
    REG_JNI(register_android_text_AndroidCharacter),
    REG_JNI(register_android_text_AndroidBidi),
    REG_JNI(register_android_text_KeyCharacterMap),
    REG_JNI(register_android_os_Process),
    REG_JNI(register_android_os_Binder),
+81 −0
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 <jni.h>
#include <android_runtime/AndroidRuntime.h>
#include "utils/misc.h"
#include "utils/Log.h"
#include "unicode/ubidi.h"

namespace android {
    
static void jniThrowException(JNIEnv* env, const char* exc, const char* msg = NULL)
{
    jclass excClazz = env->FindClass(exc);
    LOG_ASSERT(excClazz, "Unable to find class %s", exc);

    env->ThrowNew(excClazz, msg);
}

static jint runBidi(JNIEnv* env, jobject obj, jint dir, jcharArray chsArray, 
                    jbyteArray infoArray, int 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);
            ubidi_setPara(bidi, 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 JNINativeMethod gMethods[] = {
        { "runBidi", "(I[C[BIZ)I",
        (void*) runBidi }
};

int register_android_text_AndroidBidi(JNIEnv* env)
{
    jclass clazz = env->FindClass("android/text/AndroidBidi");
    LOG_ASSERT(clazz, "Cannot find android/text/AndroidBidi");
    
    return AndroidRuntime::registerNativeMethods(env, "android/text/AndroidBidi",
            gMethods, NELEM(gMethods));
}

}
+32 −1
Original line number Diff line number Diff line
@@ -88,7 +88,38 @@ public class StaticLayoutBidiTest extends TestCase {
        int resultDir = StaticLayout.bidi(dir, chs, chInfo, n, false);
        
        {
            StringBuilder sb = new StringBuilder("xdirs:");
            StringBuilder sb = new StringBuilder("info:");
            for (int i = 0; i < n; ++i) {
                sb.append(" ").append(String.valueOf(chInfo[i]));
            }
            Log.i("BIDI", sb.toString());
        }
        
        char[] resultLevelChars = new char[n];
        for (int i = 0; i < n; ++i) {
            resultLevelChars[i] = (char)('0' + chInfo[i]);
        }
        String resultLevels = new String(resultLevelChars);
        assertEquals("direction", expectedDir, resultDir);
        assertEquals("levels", expectedLevels, resultLevels);
    }
    
    @SmallTest
    public void testNativeBidi() {
        // native bidi returns levels, not simply directions
        expectNativeBidi(REQ_DL,  ALEF + BET + GIMEL + " abc", "1111222", R);
    }
    
    private void expectNativeBidi(int dir, String text, 
            String expectedLevels, int expectedDir) {
        char[] chs = text.toCharArray();
        int n = chs.length;
        byte[] chInfo = new byte[n];
        
        int resultDir = AndroidBidi.bidi(dir, chs, chInfo, n, false);
        
        {
            StringBuilder sb = new StringBuilder("info:");
            for (int i = 0; i < n; ++i) {
                sb.append(" ").append(String.valueOf(chInfo[i]));
            }