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

Commit dae8e94c authored by Doug Felt's avatar Doug Felt
Browse files

Add support for accessing native bidi implementation via jni.

Include a simple test to verify that the bidi code works.
parent a09bb0d2
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]));
            }