| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #define LOG_TAG "BidiWrapper" |
| |
| #include <JNIHelp.h> |
| #include "ErrorCode.h" |
| #include "UniquePtr.h" |
| #include "unicode/ubidi.h" |
| #include <stdlib.h> |
| #include <string.h> |
| |
| struct BiDiData { |
| BiDiData(UBiDi* biDi) : mBiDi(biDi), mEmbeddingLevels(NULL) { |
| } |
| |
| ~BiDiData() { |
| ubidi_close(mBiDi); |
| } |
| |
| UBiDiLevel* embeddingLevels() { |
| return reinterpret_cast<UBiDiLevel*>(&mEmbeddingLevels[0]); |
| } |
| |
| void setEmbeddingLevels(jbyte* newEmbeddingLevels) { |
| mEmbeddingLevels.reset(newEmbeddingLevels); |
| } |
| |
| UBiDi* uBiDi() { |
| return mBiDi; |
| } |
| |
| private: |
| UBiDi* mBiDi; |
| UniquePtr<jbyte[]> mEmbeddingLevels; |
| |
| // Disallow copy and assignment. |
| BiDiData(const BiDiData&); |
| void operator=(const BiDiData&); |
| }; |
| |
| static BiDiData* biDiData(jlong ptr) { |
| return reinterpret_cast<BiDiData*>(static_cast<uintptr_t>(ptr)); |
| } |
| |
| static UBiDi* uBiDi(jlong ptr) { |
| return reinterpret_cast<BiDiData*>(static_cast<uintptr_t>(ptr))->uBiDi(); |
| } |
| |
| static jlong BidiWrapper_ubidi_open(JNIEnv*, jclass) { |
| return reinterpret_cast<uintptr_t>(new BiDiData(ubidi_open())); |
| } |
| |
| static void BidiWrapper_ubidi_close(JNIEnv*, jclass, jlong ptr) { |
| delete biDiData(ptr); |
| } |
| |
| static void BidiWrapper_ubidi_setPara(JNIEnv* env, jclass, jlong ptr, jcharArray text, jint length, jbyte paraLevel, jbyteArray newEmbeddingLevels) { |
| BiDiData* data = biDiData(ptr); |
| // Copy the new embedding levels from the Java heap to the native heap. |
| if (newEmbeddingLevels != NULL) { |
| jbyte* dst; |
| data->setEmbeddingLevels(dst = new jbyte[length]); |
| env->GetByteArrayRegion(newEmbeddingLevels, 0, length, dst); |
| } else { |
| data->setEmbeddingLevels(NULL); |
| } |
| UErrorCode err = U_ZERO_ERROR; |
| jchar* chars = env->GetCharArrayElements(text, NULL); |
| ubidi_setPara(data->uBiDi(), chars, length, paraLevel, data->embeddingLevels(), &err); |
| env->ReleaseCharArrayElements(text, chars, 0); |
| icu4jni_error(env, err); |
| } |
| |
| static jlong BidiWrapper_ubidi_setLine(JNIEnv* env, jclass, jlong ptr, jint start, jint limit) { |
| UErrorCode err = U_ZERO_ERROR; |
| UBiDi* sized = ubidi_openSized(limit - start, 0, &err); |
| if (icu4jni_error(env, err) != FALSE) { |
| return 0; |
| } |
| UniquePtr<BiDiData> lineData(new BiDiData(sized)); |
| ubidi_setLine(uBiDi(ptr), start, limit, lineData->uBiDi(), &err); |
| icu4jni_error(env, err); |
| return reinterpret_cast<uintptr_t>(lineData.release()); |
| } |
| |
| static jint BidiWrapper_ubidi_getDirection(JNIEnv*, jclass, jlong ptr) { |
| return ubidi_getDirection(uBiDi(ptr)); |
| } |
| |
| static jint BidiWrapper_ubidi_getLength(JNIEnv*, jclass, jlong ptr) { |
| return ubidi_getLength(uBiDi(ptr)); |
| } |
| |
| static jbyte BidiWrapper_ubidi_getParaLevel(JNIEnv*, jclass, jlong ptr) { |
| return ubidi_getParaLevel(uBiDi(ptr)); |
| } |
| |
| static jbyteArray BidiWrapper_ubidi_getLevels(JNIEnv* env, jclass, jlong ptr) { |
| UErrorCode err = U_ZERO_ERROR; |
| const UBiDiLevel* levels = ubidi_getLevels(uBiDi(ptr), &err); |
| if (icu4jni_error(env, err)) { |
| return NULL; |
| } |
| int len = ubidi_getLength(uBiDi(ptr)); |
| jbyteArray result = env->NewByteArray(len); |
| env->SetByteArrayRegion(result, 0, len, reinterpret_cast<const jbyte*>(levels)); |
| return result; |
| } |
| |
| static jint BidiWrapper_ubidi_countRuns(JNIEnv* env, jclass, jlong ptr) { |
| UErrorCode err = U_ZERO_ERROR; |
| int count = ubidi_countRuns(uBiDi(ptr), &err); |
| icu4jni_error(env, err); |
| return count; |
| } |
| |
| static jobjectArray BidiWrapper_ubidi_getRuns(JNIEnv* env, jclass, jlong ptr) { |
| UBiDi* ubidi = uBiDi(ptr); |
| UErrorCode err = U_ZERO_ERROR; |
| int runCount = ubidi_countRuns(ubidi, &err); |
| if (icu4jni_error(env, err)) { |
| return NULL; |
| } |
| jclass bidiRunClass = env->FindClass("org/apache/harmony/text/BidiRun"); |
| jmethodID bidiRunConstructor = env->GetMethodID(bidiRunClass, "<init>", "(III)V"); |
| jobjectArray runs = env->NewObjectArray(runCount, bidiRunClass, NULL); |
| UBiDiLevel level = 0; |
| int start = 0; |
| int limit = 0; |
| for (int i = 0; i < runCount; ++i) { |
| ubidi_getLogicalRun(ubidi, start, &limit, &level); |
| jobject run = env->NewObject(bidiRunClass, bidiRunConstructor, start, limit, level); |
| env->SetObjectArrayElement(runs, i, run); |
| start = limit; |
| } |
| return runs; |
| } |
| |
| static jintArray BidiWrapper_ubidi_reorderVisual(JNIEnv* env, jclass, jbyteArray levels, jint length) { |
| UniquePtr<int[]> local_indexMap(new int[length]); |
| jbyte* local_levelBytes = env->GetByteArrayElements(levels, NULL); |
| UBiDiLevel* local_levels = reinterpret_cast<UBiDiLevel*>(local_levelBytes); |
| ubidi_reorderVisual(local_levels, length, &local_indexMap[0]); |
| jintArray result = env->NewIntArray(length); |
| env->SetIntArrayRegion(result, 0, length, &local_indexMap[0]); |
| env->ReleaseByteArrayElements(levels, local_levelBytes, 0); |
| return result; |
| } |
| |
| static JNINativeMethod gMethods[] = { |
| { "ubidi_close", "(J)V", (void*) BidiWrapper_ubidi_close }, |
| { "ubidi_countRuns", "(J)I", (void*) BidiWrapper_ubidi_countRuns }, |
| { "ubidi_getDirection", "(J)I", (void*) BidiWrapper_ubidi_getDirection }, |
| { "ubidi_getLength", "(J)I", (void*) BidiWrapper_ubidi_getLength }, |
| { "ubidi_getLevels", "(J)[B", (void*) BidiWrapper_ubidi_getLevels }, |
| { "ubidi_getParaLevel", "(J)B", (void*) BidiWrapper_ubidi_getParaLevel }, |
| { "ubidi_getRuns", "(J)[Lorg/apache/harmony/text/BidiRun;", (void*) BidiWrapper_ubidi_getRuns }, |
| { "ubidi_open", "()J", (void*) BidiWrapper_ubidi_open }, |
| { "ubidi_reorderVisual", "([BI)[I", (void*) BidiWrapper_ubidi_reorderVisual }, |
| { "ubidi_setLine", "(JII)J", (void*) BidiWrapper_ubidi_setLine }, |
| { "ubidi_setPara", "(J[CIB[B)V", (void*) BidiWrapper_ubidi_setPara }, |
| }; |
| int register_org_apache_harmony_text_BidiWrapper(JNIEnv* env) { |
| return jniRegisterNativeMethods(env, "org/apache/harmony/text/BidiWrapper", |
| gMethods, NELEM(gMethods)); |
| } |