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