blob: 6bc650a01c2d68a98cb16eb6fbccb7cc4ba568d1 [file] [log] [blame]
/*
* 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.
*/
#include "AndroidSystemNatives.h"
#include <JNIHelp.h>
#include "ErrorCode.h"
#include "unicode/ubidi.h"
#include <stdlib.h>
#include <string.h>
struct BiDiData {
BiDiData(UBiDi* biDi) : mBiDi(biDi), embeddingLevels(NULL) {
}
~BiDiData() {
ubidi_close(mBiDi);
delete[] embeddingLevels;
}
UBiDi* mBiDi;
jbyte* embeddingLevels;
};
static BiDiData* biDiData(jlong ptr) {
return reinterpret_cast<BiDiData*>(static_cast<uintptr_t>(ptr));
}
static jlong BidiWrapper_ubidi_open(JNIEnv* env, jclass) {
return reinterpret_cast<uintptr_t>(new BiDiData(ubidi_open()));
}
static void BidiWrapper_ubidi_close(JNIEnv* env, 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);
jbyte* oldEmbeddingLevels = data->embeddingLevels;
// Copy the new embedding levels from the Java heap to the native heap.
if (newEmbeddingLevels != NULL) {
data->embeddingLevels = new jbyte[length];
env->GetByteArrayRegion(newEmbeddingLevels, 0, length, data->embeddingLevels);
} else {
data->embeddingLevels = NULL;
}
UErrorCode err = U_ZERO_ERROR;
jchar* _text = env->GetCharArrayElements(text, NULL);
ubidi_setPara(data->mBiDi, _text, length, paraLevel, (UBiDiLevel*) data->embeddingLevels, &err);
env->ReleaseCharArrayElements(text, _text, 0);
delete[] oldEmbeddingLevels;
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)) {
return 0;
}
BiDiData* lineData = new BiDiData(sized);
BiDiData* data = biDiData(ptr);
ubidi_setLine(data->mBiDi, start, limit, lineData->mBiDi, &err);
icu4jni_error(env, err);
return reinterpret_cast<uintptr_t>(lineData);
}
static jint BidiWrapper_ubidi_getDirection(JNIEnv * env, jclass clazz, jlong ptr) {
return ubidi_getDirection(biDiData(ptr)->mBiDi);
}
static jint BidiWrapper_ubidi_getLength(JNIEnv* env, jclass, jlong ptr) {
return ubidi_getLength(biDiData(ptr)->mBiDi);
}
static jbyte BidiWrapper_ubidi_getParaLevel(JNIEnv* env, jclass, jlong ptr) {
return ubidi_getParaLevel(biDiData(ptr)->mBiDi);
}
static jbyteArray BidiWrapper_ubidi_getLevels(JNIEnv* env, jclass, jlong ptr) {
BiDiData* data = biDiData(ptr);
UErrorCode err = U_ZERO_ERROR;
const UBiDiLevel* levels = ubidi_getLevels(data->mBiDi, &err);
if (icu4jni_error(env, err)) {
return NULL;
}
int len = ubidi_getLength(data->mBiDi);
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) {
BiDiData* data = biDiData(ptr);
UErrorCode err = U_ZERO_ERROR;
int count = ubidi_countRuns(data->mBiDi, &err);
icu4jni_error(env, err);
return count;
}
static jobjectArray BidiWrapper_ubidi_getRuns(JNIEnv* env, jclass, jlong ptr) {
BiDiData* data = biDiData(ptr);
UErrorCode err = U_ZERO_ERROR;
int runCount = ubidi_countRuns(data->mBiDi, &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(data->mBiDi, 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) {
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);
jintArray result = env->NewIntArray(length);
env->SetIntArrayRegion(result, 0, length, local_indexMap);
delete[] local_indexMap;
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));
}