• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  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 "NativeBidi"
19 
20 #include "ErrorCode.h"
21 #include "JNIHelp.h"
22 #include "JniConstants.h"
23 #include "ScopedPrimitiveArray.h"
24 #include "UniquePtr.h"
25 #include "unicode/ubidi.h"
26 
27 #include <stdlib.h>
28 #include <string.h>
29 
30 struct BiDiData {
BiDiDataBiDiData31     BiDiData(UBiDi* biDi) : mBiDi(biDi), mEmbeddingLevels(NULL) {
32     }
33 
~BiDiDataBiDiData34     ~BiDiData() {
35         ubidi_close(mBiDi);
36     }
37 
embeddingLevelsBiDiData38     UBiDiLevel* embeddingLevels() {
39         return reinterpret_cast<UBiDiLevel*>(&mEmbeddingLevels[0]);
40     }
41 
setEmbeddingLevelsBiDiData42     void setEmbeddingLevels(jbyte* newEmbeddingLevels) {
43         mEmbeddingLevels.reset(newEmbeddingLevels);
44     }
45 
uBiDiBiDiData46     UBiDi* uBiDi() {
47         return mBiDi;
48     }
49 
50 private:
51     UBiDi* mBiDi;
52     UniquePtr<jbyte[]> mEmbeddingLevels;
53 
54     // Disallow copy and assignment.
55     BiDiData(const BiDiData&);
56     void operator=(const BiDiData&);
57 };
58 
biDiData(jlong ptr)59 static BiDiData* biDiData(jlong ptr) {
60     return reinterpret_cast<BiDiData*>(static_cast<uintptr_t>(ptr));
61 }
62 
uBiDi(jlong ptr)63 static UBiDi* uBiDi(jlong ptr) {
64     return reinterpret_cast<BiDiData*>(static_cast<uintptr_t>(ptr))->uBiDi();
65 }
66 
NativeBidi_ubidi_open(JNIEnv *,jclass)67 static jlong NativeBidi_ubidi_open(JNIEnv*, jclass) {
68     return reinterpret_cast<uintptr_t>(new BiDiData(ubidi_open()));
69 }
70 
NativeBidi_ubidi_close(JNIEnv *,jclass,jlong ptr)71 static void NativeBidi_ubidi_close(JNIEnv*, jclass, jlong ptr) {
72     delete biDiData(ptr);
73 }
74 
NativeBidi_ubidi_setPara(JNIEnv * env,jclass,jlong ptr,jcharArray text,jint length,jint paraLevel,jbyteArray newEmbeddingLevels)75 static void NativeBidi_ubidi_setPara(JNIEnv* env, jclass, jlong ptr, jcharArray text, jint length, jint paraLevel, jbyteArray newEmbeddingLevels) {
76     BiDiData* data = biDiData(ptr);
77     // Copy the new embedding levels from the Java heap to the native heap.
78     if (newEmbeddingLevels != NULL) {
79         jbyte* dst;
80         data->setEmbeddingLevels(dst = new jbyte[length]);
81         env->GetByteArrayRegion(newEmbeddingLevels, 0, length, dst);
82     } else {
83         data->setEmbeddingLevels(NULL);
84     }
85     ScopedCharArrayRO chars(env, text);
86     if (chars.get() == NULL) {
87         return;
88     }
89     UErrorCode err = U_ZERO_ERROR;
90     ubidi_setPara(data->uBiDi(), chars.get(), length, paraLevel, data->embeddingLevels(), &err);
91     icu4jni_error(env, err);
92 }
93 
NativeBidi_ubidi_setLine(JNIEnv * env,jclass,jlong ptr,jint start,jint limit)94 static jlong NativeBidi_ubidi_setLine(JNIEnv* env, jclass, jlong ptr, jint start, jint limit) {
95     UErrorCode err = U_ZERO_ERROR;
96     UBiDi* sized = ubidi_openSized(limit - start, 0, &err);
97     if (icu4jni_error(env, err) != FALSE) {
98         return 0;
99     }
100     UniquePtr<BiDiData> lineData(new BiDiData(sized));
101     ubidi_setLine(uBiDi(ptr), start, limit, lineData->uBiDi(), &err);
102     icu4jni_error(env, err);
103     return reinterpret_cast<uintptr_t>(lineData.release());
104 }
105 
NativeBidi_ubidi_getDirection(JNIEnv *,jclass,jlong ptr)106 static jint NativeBidi_ubidi_getDirection(JNIEnv*, jclass, jlong ptr) {
107     return ubidi_getDirection(uBiDi(ptr));
108 }
109 
NativeBidi_ubidi_getLength(JNIEnv *,jclass,jlong ptr)110 static jint NativeBidi_ubidi_getLength(JNIEnv*, jclass, jlong ptr) {
111     return ubidi_getLength(uBiDi(ptr));
112 }
113 
NativeBidi_ubidi_getParaLevel(JNIEnv *,jclass,jlong ptr)114 static jbyte NativeBidi_ubidi_getParaLevel(JNIEnv*, jclass, jlong ptr) {
115     return ubidi_getParaLevel(uBiDi(ptr));
116 }
117 
NativeBidi_ubidi_getLevels(JNIEnv * env,jclass,jlong ptr)118 static jbyteArray NativeBidi_ubidi_getLevels(JNIEnv* env, jclass, jlong ptr) {
119     UErrorCode err = U_ZERO_ERROR;
120     const UBiDiLevel* levels = ubidi_getLevels(uBiDi(ptr), &err);
121     if (icu4jni_error(env, err)) {
122         return NULL;
123     }
124     int len = ubidi_getLength(uBiDi(ptr));
125     jbyteArray result = env->NewByteArray(len);
126     env->SetByteArrayRegion(result, 0, len, reinterpret_cast<const jbyte*>(levels));
127     return result;
128 }
129 
NativeBidi_ubidi_countRuns(JNIEnv * env,jclass,jlong ptr)130 static jint NativeBidi_ubidi_countRuns(JNIEnv* env, jclass, jlong ptr) {
131     UErrorCode err = U_ZERO_ERROR;
132     int count = ubidi_countRuns(uBiDi(ptr), &err);
133     icu4jni_error(env, err);
134     return count;
135 }
136 
NativeBidi_ubidi_getRuns(JNIEnv * env,jclass,jlong ptr)137 static jobjectArray NativeBidi_ubidi_getRuns(JNIEnv* env, jclass, jlong ptr) {
138     UBiDi* ubidi = uBiDi(ptr);
139     UErrorCode err = U_ZERO_ERROR;
140     int runCount = ubidi_countRuns(ubidi, &err);
141     if (icu4jni_error(env, err)) {
142         return NULL;
143     }
144     jmethodID bidiRunConstructor = env->GetMethodID(JniConstants::bidiRunClass, "<init>", "(III)V");
145     jobjectArray runs = env->NewObjectArray(runCount, JniConstants::bidiRunClass, NULL);
146     UBiDiLevel level = 0;
147     int start = 0;
148     int limit = 0;
149     for (int i = 0; i < runCount; ++i) {
150         ubidi_getLogicalRun(ubidi, start, &limit, &level);
151         jobject run = env->NewObject(JniConstants::bidiRunClass, bidiRunConstructor, start, limit, level);
152         env->SetObjectArrayElement(runs, i, run);
153         start = limit;
154     }
155     return runs;
156 }
157 
NativeBidi_ubidi_reorderVisual(JNIEnv * env,jclass,jbyteArray javaLevels,jint length)158 static jintArray NativeBidi_ubidi_reorderVisual(JNIEnv* env, jclass, jbyteArray javaLevels, jint length) {
159     ScopedByteArrayRO levelBytes(env, javaLevels);
160     if (levelBytes.get() == NULL) {
161         return NULL;
162     }
163 
164     const UBiDiLevel* levels = reinterpret_cast<const UBiDiLevel*>(levelBytes.get());
165 
166     UniquePtr<int[]> indexMap(new int[length]);
167     ubidi_reorderVisual(levels, length, &indexMap[0]);
168 
169     jintArray result = env->NewIntArray(length);
170     env->SetIntArrayRegion(result, 0, length, &indexMap[0]);
171     return result;
172 }
173 
174 static JNINativeMethod gMethods[] = {
175     NATIVE_METHOD(NativeBidi, ubidi_close, "(J)V"),
176     NATIVE_METHOD(NativeBidi, ubidi_countRuns, "(J)I"),
177     NATIVE_METHOD(NativeBidi, ubidi_getDirection, "(J)I"),
178     NATIVE_METHOD(NativeBidi, ubidi_getLength, "(J)I"),
179     NATIVE_METHOD(NativeBidi, ubidi_getLevels, "(J)[B"),
180     NATIVE_METHOD(NativeBidi, ubidi_getParaLevel, "(J)B"),
181     NATIVE_METHOD(NativeBidi, ubidi_getRuns, "(J)[Lorg/apache/harmony/text/BidiRun;"),
182     NATIVE_METHOD(NativeBidi, ubidi_open, "()J"),
183     NATIVE_METHOD(NativeBidi, ubidi_reorderVisual, "([BI)[I"),
184     NATIVE_METHOD(NativeBidi, ubidi_setLine, "(JII)J"),
185     NATIVE_METHOD(NativeBidi, ubidi_setPara, "(J[CII[B)V"),
186 };
register_org_apache_harmony_text_NativeBidi(JNIEnv * env)187 int register_org_apache_harmony_text_NativeBidi(JNIEnv* env) {
188     return jniRegisterNativeMethods(env, "org/apache/harmony/text/NativeBidi",
189             gMethods, NELEM(gMethods));
190 }
191