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",