Home | History | Annotate | Download | only in jni
      1 /* //device/libs/android_runtime/android_text_AndroidCharacter.cpp
      2 **
      3 ** Copyright 2006, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 
     18 #define LOG_TAG "AndroidUnicode"
     19 
     20 #include <jni.h>
     21 #include <android_runtime/AndroidRuntime.h>
     22 #include "utils/misc.h"
     23 #include "utils/Log.h"
     24 #include "unicode/uchar.h"
     25 
     26 #define PROPERTY_UNDEFINED (-1)
     27 
     28 // ICU => JDK mapping
     29 static int directionality_map[U_CHAR_DIRECTION_COUNT] = {
     30     0, // U_LEFT_TO_RIGHT (0) => DIRECTIONALITY_LEFT_TO_RIGHT (0)
     31     1, // U_RIGHT_TO_LEFT (1) => DIRECTIONALITY_RIGHT_TO_LEFT (1)
     32     3, // U_EUROPEAN_NUMBER (2) => DIRECTIONALITY_EUROPEAN_NUMBER (3)
     33     4, // U_EUROPEAN_NUMBER_SEPARATOR (3) => DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR (4)
     34     5, // U_EUROPEAN_NUMBER_TERMINATOR (4) => DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR (5)
     35     6, // U_ARABIC_NUMBER (5) => DIRECTIONALITY_ARABIC_NUMBER (6)
     36     7, // U_COMMON_NUMBER_SEPARATOR (6) => DIRECTIONALITY_COMMON_NUMBER_SEPARATOR (7)
     37     10, // U_BLOCK_SEPARATOR (7) => DIRECTIONALITY_PARAGRAPH_SEPARATOR (10)
     38     11, // U_SEGMENT_SEPARATOR (8) => DIRECTIONALITY_SEGMENT_SEPARATOR (11)
     39     12, // U_WHITE_SPACE_NEUTRAL (9) => DIRECTIONALITY_WHITESPACE (12)
     40     13, // U_OTHER_NEUTRAL (10) => DIRECTIONALITY_OTHER_NEUTRALS (13)
     41     14, // U_LEFT_TO_RIGHT_EMBEDDING (11) => DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING (14)
     42     15, // U_LEFT_TO_RIGHT_OVERRIDE (12) => DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE (15)
     43     2, // U_RIGHT_TO_LEFT_ARABIC (13) => DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC (2)
     44     16, // U_RIGHT_TO_LEFT_EMBEDDING (14) => DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING (16)
     45     17, // U_RIGHT_TO_LEFT_OVERRIDE (15) => DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE (17)
     46     18, // U_POP_DIRECTIONAL_FORMAT (16) => DIRECTIONALITY_POP_DIRECTIONAL_FORMAT (18)
     47     8, // U_DIR_NON_SPACING_MARK (17) => DIRECTIONALITY_NONSPACING_MARK (8)
     48     9, // U_BOUNDARY_NEUTRAL (18) => DIRECTIONALITY_BOUNDARY_NEUTRAL (9)
     49 };
     50 
     51 namespace android {
     52 
     53 static void jniThrowException(JNIEnv* env, const char* exc, const char* msg = NULL)
     54 {
     55     jclass excClazz = env->FindClass(exc);
     56     LOG_ASSERT(excClazz, "Unable to find class %s", exc);
     57 
     58     env->ThrowNew(excClazz, msg);
     59 }
     60 
     61 static void getDirectionalities(JNIEnv* env, jobject obj, jcharArray srcArray, jbyteArray destArray, int count)
     62 {
     63     jchar* src = env->GetCharArrayElements(srcArray, NULL);
     64     jbyte* dest = env->GetByteArrayElements(destArray, NULL);
     65     if (src == NULL || dest == NULL) {
     66         jniThrowException(env, "java/lang/NullPointerException", NULL);
     67         goto DIRECTION_END;
     68     }
     69 
     70     if (env->GetArrayLength(srcArray) < count || env->GetArrayLength(destArray) < count) {
     71         jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
     72         goto DIRECTION_END;
     73     }
     74 
     75     for (int i = 0; i < count; i++) {
     76         if (src[i] >= 0xD800 && src[i] <= 0xDBFF &&
     77             i + 1 < count &&
     78             src[i + 1] >= 0xDC00 && src[i + 1] <= 0xDFFF) {
     79             int c = 0x00010000 + ((src[i] - 0xD800) << 10) +
     80                                  (src[i + 1] & 0x3FF);
     81             int dir = u_charDirection(c);
     82             if (dir < 0 || dir >= U_CHAR_DIRECTION_COUNT)
     83                 dir = PROPERTY_UNDEFINED;
     84             else
     85                 dir = directionality_map[dir];
     86 
     87             dest[i++] = dir;
     88             dest[i] = dir;
     89         } else {
     90             int c = src[i];
     91             int dir = u_charDirection(c);
     92             if (dir < 0 || dir >= U_CHAR_DIRECTION_COUNT)
     93                 dest[i] = PROPERTY_UNDEFINED;
     94             else
     95                 dest[i] = directionality_map[dir];
     96         }
     97     }
     98 
     99 DIRECTION_END:
    100     env->ReleaseCharArrayElements(srcArray, src, JNI_ABORT);
    101     env->ReleaseByteArrayElements(destArray, dest, JNI_ABORT);
    102 }
    103 
    104 static jint getEastAsianWidth(JNIEnv* env, jobject obj, jchar input)
    105 {
    106     int width = u_getIntPropertyValue(input, UCHAR_EAST_ASIAN_WIDTH);
    107     if (width < 0 || width >= U_EA_COUNT)
    108         width = PROPERTY_UNDEFINED;
    109 
    110     return width;
    111 }
    112 
    113 static void getEastAsianWidths(JNIEnv* env, jobject obj, jcharArray srcArray,
    114                                int start, int count, jbyteArray destArray)
    115 {
    116     jchar* src = env->GetCharArrayElements(srcArray, NULL);
    117     jbyte* dest = env->GetByteArrayElements(destArray, NULL);
    118     if (src == NULL || dest == NULL) {
    119         jniThrowException(env, "java/lang/NullPointerException", NULL);
    120         goto EA_END;
    121     }
    122 
    123     if (start < 0 || start > start + count
    124             || env->GetArrayLength(srcArray) < (start + count)
    125             || env->GetArrayLength(destArray) < count) {
    126         jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
    127         goto EA_END;
    128     }
    129 
    130     for (int i = 0; i < count; i++) {
    131         const int srci = start + i;
    132         if (src[srci] >= 0xD800 && src[srci] <= 0xDBFF &&
    133             i + 1 < count &&
    134             src[srci + 1] >= 0xDC00 && src[srci + 1] <= 0xDFFF) {
    135             int c = 0x00010000 + ((src[srci] - 0xD800) << 10) +
    136                                  (src[srci + 1] & 0x3FF);
    137             int width = u_getIntPropertyValue(c, UCHAR_EAST_ASIAN_WIDTH);
    138             if (width < 0 || width >= U_EA_COUNT)
    139                 width = PROPERTY_UNDEFINED;
    140 
    141             dest[i++] = width;
    142             dest[i] = width;
    143         } else {
    144             int c = src[srci];
    145             int width = u_getIntPropertyValue(c, UCHAR_EAST_ASIAN_WIDTH);
    146             if (width < 0 || width >= U_EA_COUNT)
    147                 width = PROPERTY_UNDEFINED;
    148 
    149             dest[i] = width;
    150         }
    151     }
    152 
    153 EA_END:
    154     env->ReleaseCharArrayElements(srcArray, src, JNI_ABORT);
    155     env->ReleaseByteArrayElements(destArray, dest, JNI_ABORT);
    156 }
    157 
    158 static jboolean mirror(JNIEnv* env, jobject obj, jcharArray charArray, int start, int count)
    159 {
    160     jchar* data = env->GetCharArrayElements(charArray, NULL);
    161     bool ret = false;
    162 
    163     if (data == NULL) {
    164         jniThrowException(env, "java/lang/NullPointerException", NULL);
    165         goto MIRROR_END;
    166     }
    167 
    168     if (start < 0 || start > start + count
    169             || env->GetArrayLength(charArray) < start + count) {
    170         jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
    171         goto MIRROR_END;
    172     }
    173 
    174     for (int i = start; i < start + count; i++) {
    175         // XXX this thinks it knows that surrogates are never mirrored
    176 
    177         int c1 = data[i];
    178         int c2 = u_charMirror(c1);
    179 
    180         if (c1 != c2) {
    181             data[i] = c2;
    182             ret = true;
    183         }
    184     }
    185 
    186 MIRROR_END:
    187     env->ReleaseCharArrayElements(charArray, data, JNI_ABORT);
    188 	return ret;
    189 }
    190 
    191 static jchar getMirror(JNIEnv* env, jobject obj, jchar c)
    192 {
    193     return u_charMirror(c);
    194 }
    195 
    196 static JNINativeMethod gMethods[] = {
    197 	{ "getDirectionalities", "([C[BI)V",
    198         (void*) getDirectionalities },
    199 	{ "getEastAsianWidth", "(C)I",
    200         (void*) getEastAsianWidth },
    201 	{ "getEastAsianWidths", "([CII[B)V",
    202         (void*) getEastAsianWidths },
    203 	{ "mirror", "([CII)Z",
    204         (void*) mirror },
    205 	{ "getMirror", "(C)C",
    206         (void*) getMirror }
    207 };
    208 
    209 int register_android_text_AndroidCharacter(JNIEnv* env)
    210 {
    211     jclass clazz = env->FindClass("android/text/AndroidCharacter");
    212     LOG_ASSERT(clazz, "Cannot find android/text/AndroidCharacter");
    213 
    214     return AndroidRuntime::registerNativeMethods(env, "android/text/AndroidCharacter",
    215             gMethods, NELEM(gMethods));
    216 }
    217 
    218 }
    219