From bb9a51768d2d9dddbe2394b99a00544a3d144fac Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Sat, 13 Feb 2010 00:07:38 -0800 Subject: [PATCH] Add API to access ICU's East Asian Width Currently there is no way for an application built against the API to access East Asian Width data from ICU. This adds an API for applications to use to access it for correct drawing of international characters. Change-Id: Iab50698ee555ae2ca8ab4b242cc14aa6e0dc3b48 --- api/current.xml | 98 ++++++++++++++++++++ core/java/android/text/AndroidCharacter.java | 39 ++++++++ core/jni/android_text_AndroidCharacter.cpp | 65 ++++++++++++- 3 files changed, 199 insertions(+), 3 deletions(-) diff --git a/api/current.xml b/api/current.xml index 91344d6f6cbe0..9c663fed93a57 100644 --- a/api/current.xml +++ b/api/current.xml @@ -147852,6 +147852,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + count bytes of dest with the * directionalities from the first count chars of src. @@ -30,6 +37,38 @@ public class AndroidCharacter */ public native static void getDirectionalities(char[] src, byte[] dest, int count); + + /** + * Calculate the East Asian Width of a character according to + * Unicode TR#11. The return + * will be one of {@link #EAST_ASIAN_WIDTH_NEUTRAL}, + * {@link #EAST_ASIAN_WIDTH_AMBIGUOUS}, {@link #EAST_ASIAN_WIDTH_HALF_WIDTH}, + * {@link #EAST_ASIAN_WIDTH_FULL_WIDTH}, {@link #EAST_ASIAN_WIDTH_NARROW}, + * or {@link #EAST_ASIAN_WIDTH_WIDE}. + * + * @param input the character to measure + * @return the East Asian Width for input + */ + public native static int getEastAsianWidth(char input); + + /** + * Fill the first count bytes of dest with the + * East Asian Width from the first count chars of + * src. East Asian Width is calculated based on + * Unicode TR#11. Each entry + * in dest> will be one of {@link #EAST_ASIAN_WIDTH_NEUTRAL}, + * {@link #EAST_ASIAN_WIDTH_AMBIGUOUS}, {@link #EAST_ASIAN_WIDTH_HALF_WIDTH}, + * {@link #EAST_ASIAN_WIDTH_FULL_WIDTH}, {@link #EAST_ASIAN_WIDTH_NARROW}, + * or {@link #EAST_ASIAN_WIDTH_WIDE}. + * + * @param src character array of input to measure + * @param start first character in array to measure + * @param count maximum number of characters to measure + * @param dest byte array of results for each character in src + */ + public native static void getEastAsianWidths(char[] src, int start, + int count, byte[] dest); + /** * Replace the specified slice of text with the chars' * right-to-left mirrors (if any), returning true if any diff --git a/core/jni/android_text_AndroidCharacter.cpp b/core/jni/android_text_AndroidCharacter.cpp index 05d7b73c47ada..1353478f39f46 100644 --- a/core/jni/android_text_AndroidCharacter.cpp +++ b/core/jni/android_text_AndroidCharacter.cpp @@ -23,7 +23,8 @@ #include "utils/Log.h" #include "unicode/uchar.h" -#define DIRECTIONALITY_UNDEFINED (-1) +#define PROPERTY_UNDEFINED (-1) + // ICU => JDK mapping static int directionality_map[U_CHAR_DIRECTION_COUNT] = { 0, // U_LEFT_TO_RIGHT (0) => DIRECTIONALITY_LEFT_TO_RIGHT (0) @@ -79,7 +80,7 @@ static void getDirectionalities(JNIEnv* env, jobject obj, jcharArray srcArray, j (src[i + 1] & 0x3FF); int dir = u_charDirection(c); if (dir < 0 || dir >= U_CHAR_DIRECTION_COUNT) - dir = DIRECTIONALITY_UNDEFINED; + dir = PROPERTY_UNDEFINED; else dir = directionality_map[dir]; @@ -89,7 +90,7 @@ static void getDirectionalities(JNIEnv* env, jobject obj, jcharArray srcArray, j int c = src[i]; int dir = u_charDirection(c); if (dir < 0 || dir >= U_CHAR_DIRECTION_COUNT) - dest[i] = DIRECTIONALITY_UNDEFINED; + dest[i] = PROPERTY_UNDEFINED; else dest[i] = directionality_map[dir]; } @@ -100,6 +101,60 @@ DIRECTION_END: env->ReleaseByteArrayElements(destArray, dest, JNI_ABORT); } +static jint getEastAsianWidth(JNIEnv* env, jobject obj, jchar input) +{ + int width = u_getIntPropertyValue(input, UCHAR_EAST_ASIAN_WIDTH); + if (width < 0 || width >= U_EA_COUNT) + width = PROPERTY_UNDEFINED; + + return width; +} + +static void getEastAsianWidths(JNIEnv* env, jobject obj, jcharArray srcArray, + int start, int count, jbyteArray destArray) +{ + jchar* src = env->GetCharArrayElements(srcArray, NULL); + jbyte* dest = env->GetByteArrayElements(destArray, NULL); + if (src == NULL || dest == NULL) { + jniThrowException(env, "java/lang/NullPointerException", NULL); + goto EA_END; + } + + if (start < 0 || start > start + count + || env->GetArrayLength(srcArray) < (start + count) + || env->GetArrayLength(destArray) < count) { + jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL); + goto EA_END; + } + + for (int i = 0; i < count; i++) { + const int srci = start + i; + if (src[srci] >= 0xD800 && src[srci] <= 0xDBFF && + i + 1 < count && + src[srci + 1] >= 0xDC00 && src[srci + 1] <= 0xDFFF) { + int c = 0x00010000 + ((src[srci] - 0xD800) << 10) + + (src[srci + 1] & 0x3FF); + int width = u_getIntPropertyValue(c, UCHAR_EAST_ASIAN_WIDTH); + if (width < 0 || width >= U_EA_COUNT) + width = PROPERTY_UNDEFINED; + + dest[i++] = width; + dest[i] = width; + } else { + int c = src[srci]; + int width = u_getIntPropertyValue(c, UCHAR_EAST_ASIAN_WIDTH); + if (width < 0 || width >= U_EA_COUNT) + width = PROPERTY_UNDEFINED; + + dest[i] = width; + } + } + +EA_END: + env->ReleaseCharArrayElements(srcArray, src, JNI_ABORT); + env->ReleaseByteArrayElements(destArray, dest, JNI_ABORT); +} + static jboolean mirror(JNIEnv* env, jobject obj, jcharArray charArray, int start, int count) { jchar* data = env->GetCharArrayElements(charArray, NULL); @@ -140,6 +195,10 @@ static jchar getMirror(JNIEnv* env, jobject obj, jchar c) static JNINativeMethod gMethods[] = { { "getDirectionalities", "([C[BI)V", (void*) getDirectionalities }, + { "getEastAsianWidth", "(C)I", + (void*) getEastAsianWidth }, + { "getEastAsianWidths", "([CII[B)V", + (void*) getEastAsianWidths }, { "mirror", "([CII)Z", (void*) mirror }, { "getMirror", "(C)C",