diff --git a/lib/java/jni/include/JniHelper.h b/lib/java/jni/include/JniHelper.h index 73dddab..2cbde14 100644 --- a/lib/java/jni/include/JniHelper.h +++ b/lib/java/jni/include/JniHelper.h @@ -1,9 +1,22 @@ #include +#define STRINGIFY(s) _STRINGIFY(s) +#define _STRINGIFY(s) #s + inline jlong get_handle(JNIEnv *env, jobject instance) { jclass cls = env->FindClass("alphaTab/alphaSkia/AlphaSkiaNative"); + if (!cls) + { + env->ThrowNew(env->FindClass("java/lang/IllegalStateException"), "Could not find class alphaTab.alphaSkia.AlphaSkiaNative"); + return 0; + } jfieldID handleFieldId = env->GetFieldID(cls, "handle", "J"); + if (!handleFieldId) + { + env->ThrowNew(env->FindClass("java/lang/IllegalStateException"), "Could not find field handle in class alphaTab.alphaSkia.AlphaSkiaNative"); + return 0; + } return env->GetLongField(instance, handleFieldId); } inline void set_handle(JNIEnv *env, jobject instance, jlong handle) @@ -12,3 +25,23 @@ inline void set_handle(JNIEnv *env, jobject instance, jlong handle) jfieldID handleFieldId = env->GetFieldID(cls, "handle", "J"); env->SetLongField(instance, handleFieldId, handle); } + +#define CHECK_HANDLE_RETURN(handle, returnValue) \ + if (!handle) \ + { \ + if (!env->ExceptionCheck()) \ + { \ + env->ThrowNew(env->FindClass("java/lang/IllegalArgumentException"), "Invalid object handle (" STRINGIFY(handle) ")"); \ + } \ + return returnValue; \ + } + +#define CHECK_HANDLE(handle) \ + if (!handle) \ + { \ + if (!env->ExceptionCheck()) \ + { \ + env->ThrowNew(env->FindClass("java/lang/IllegalArgumentException"), "Invalid object handle (" STRINGIFY(handle) ")"); \ + } \ + return; \ + } \ No newline at end of file diff --git a/lib/java/jni/src/AlphaSkiaCanvas.cpp b/lib/java/jni/src/AlphaSkiaCanvas.cpp index bc117a7..33bc85c 100644 --- a/lib/java/jni/src/AlphaSkiaCanvas.cpp +++ b/lib/java/jni/src/AlphaSkiaCanvas.cpp @@ -7,30 +7,40 @@ extern "C" JNIEXPORT jint JNICALL Java_alphaTab_alphaSkia_AlphaSkiaCanvas_getColor(JNIEnv *env, jobject instance) { alphaskia_canvas_t canvas = reinterpret_cast(get_handle(env, instance)); + CHECK_HANDLE_RETURN(canvas, 0) + return static_cast(alphaskia_canvas_get_color(canvas)); } JNIEXPORT void JNICALL Java_alphaTab_alphaSkia_AlphaSkiaCanvas_setColor(JNIEnv *env, jobject instance, jint color) { alphaskia_canvas_t canvas = reinterpret_cast(get_handle(env, instance)); + CHECK_HANDLE(canvas) + alphaskia_canvas_set_color(canvas, static_cast(color)); } JNIEXPORT jfloat JNICALL Java_alphaTab_alphaSkia_AlphaSkiaCanvas_getLineWidth(JNIEnv *env, jobject instance) { alphaskia_canvas_t canvas = reinterpret_cast(get_handle(env, instance)); + CHECK_HANDLE_RETURN(canvas, 0.0f) + return static_cast(alphaskia_canvas_get_line_width(canvas)); } JNIEXPORT void JNICALL Java_alphaTab_alphaSkia_AlphaSkiaCanvas_setLineWidth(JNIEnv *env, jobject instance, jfloat line_width) { alphaskia_canvas_t canvas = reinterpret_cast(get_handle(env, instance)); + CHECK_HANDLE(canvas) + alphaskia_canvas_set_line_width(canvas, static_cast(line_width)); } JNIEXPORT void JNICALL Java_alphaTab_alphaSkia_AlphaSkiaCanvas_close(JNIEnv *env, jobject instance) { alphaskia_canvas_t canvas = reinterpret_cast(get_handle(env, instance)); + CHECK_HANDLE(canvas) + alphaskia_canvas_free(canvas); set_handle(env, instance, 0); } @@ -38,19 +48,33 @@ extern "C" JNIEXPORT void JNICALL Java_alphaTab_alphaSkia_AlphaSkiaCanvas_beginRender(JNIEnv *env, jobject instance, jint width, jint height, jfloat renderScale) { alphaskia_canvas_t canvas = reinterpret_cast(get_handle(env, instance)); + CHECK_HANDLE(canvas) alphaskia_canvas_begin_render(canvas, width, height, static_cast(renderScale)); } JNIEXPORT void JNICALL Java_alphaTab_alphaSkia_AlphaSkiaCanvas_drawImage(JNIEnv *env, jobject instance, jobject image, jfloat x, jfloat y, jfloat w, jfloat h) { alphaskia_canvas_t canvas = reinterpret_cast(get_handle(env, instance)); + CHECK_HANDLE(canvas) + alphaskia_image_t nativeImage = reinterpret_cast(get_handle(env, image)); + if (!canvas) + { + if (!env->ExceptionCheck()) + { + env->ThrowNew(env->FindClass("java/lang/IllegalArgumentException"), "Invalid object handle"); + } + return; + } + alphaskia_canvas_draw_image(canvas, nativeImage, static_cast(x), static_cast(y), static_cast(w), static_cast(h)); } JNIEXPORT jobject JNICALL Java_alphaTab_alphaSkia_AlphaSkiaCanvas_endRender(JNIEnv *env, jobject instance) { alphaskia_canvas_t canvas = reinterpret_cast(get_handle(env, instance)); + CHECK_HANDLE_RETURN(canvas, nullptr) + alphaskia_image_t image = alphaskia_canvas_end_render(canvas); jclass cls = env->FindClass("alphaTab/alphaSkia/AlphaSkiaImage"); @@ -61,79 +85,120 @@ extern "C" JNIEXPORT void JNICALL Java_alphaTab_alphaSkia_AlphaSkiaCanvas_fillRect(JNIEnv *env, jobject instance, jfloat x, jfloat y, jfloat w, jfloat h) { alphaskia_canvas_t canvas = reinterpret_cast(get_handle(env, instance)); + CHECK_HANDLE(canvas) + alphaskia_canvas_fill_rect(canvas, x, y, w, h); } JNIEXPORT void JNICALL Java_alphaTab_alphaSkia_AlphaSkiaCanvas_strokeRect(JNIEnv *env, jobject instance, jfloat x, jfloat y, jfloat w, jfloat h) { alphaskia_canvas_t canvas = reinterpret_cast(get_handle(env, instance)); + CHECK_HANDLE(canvas) alphaskia_canvas_stroke_rect(canvas, x, y, w, h); } JNIEXPORT void JNICALL Java_alphaTab_alphaSkia_AlphaSkiaCanvas_beginPath(JNIEnv *env, jobject instance) { alphaskia_canvas_t canvas = reinterpret_cast(get_handle(env, instance)); + CHECK_HANDLE(canvas) + alphaskia_canvas_begin_path(canvas); } JNIEXPORT void JNICALL Java_alphaTab_alphaSkia_AlphaSkiaCanvas_closePath(JNIEnv *env, jobject instance) { alphaskia_canvas_t canvas = reinterpret_cast(get_handle(env, instance)); + CHECK_HANDLE(canvas) + alphaskia_canvas_close_path(canvas); } JNIEXPORT void JNICALL Java_alphaTab_alphaSkia_AlphaSkiaCanvas_moveTo(JNIEnv *env, jobject instance, jfloat x, jfloat y) { alphaskia_canvas_t canvas = reinterpret_cast(get_handle(env, instance)); + CHECK_HANDLE(canvas) + alphaskia_canvas_move_to(canvas, x, y); } JNIEXPORT void JNICALL Java_alphaTab_alphaSkia_AlphaSkiaCanvas_lineTo(JNIEnv *env, jobject instance, jfloat x, jfloat y) { alphaskia_canvas_t canvas = reinterpret_cast(get_handle(env, instance)); + CHECK_HANDLE(canvas) + alphaskia_canvas_line_to(canvas, x, y); } JNIEXPORT void JNICALL Java_alphaTab_alphaSkia_AlphaSkiaCanvas_quadraticCurveTo(JNIEnv *env, jobject instance, jfloat cpx, jfloat cpy, jfloat x, jfloat y) { alphaskia_canvas_t canvas = reinterpret_cast(get_handle(env, instance)); + CHECK_HANDLE(canvas) + alphaskia_canvas_quadratic_curve_to(canvas, cpx, cpy, x, y); } JNIEXPORT void JNICALL Java_alphaTab_alphaSkia_AlphaSkiaCanvas_bezierCurveTo(JNIEnv *env, jobject instance, jfloat cp1x, jfloat cp1y, jfloat cp2x, jfloat cp2y, jfloat x, jfloat y) { alphaskia_canvas_t canvas = reinterpret_cast(get_handle(env, instance)); + CHECK_HANDLE(canvas) + alphaskia_canvas_bezier_curve_to(canvas, cp1x, cp1y, cp2x, cp2y, x, y); } JNIEXPORT void JNICALL Java_alphaTab_alphaSkia_AlphaSkiaCanvas_fillCircle(JNIEnv *env, jobject instance, jfloat x, jfloat y, jfloat r) { alphaskia_canvas_t canvas = reinterpret_cast(get_handle(env, instance)); + CHECK_HANDLE(canvas) + alphaskia_canvas_fill_circle(canvas, x, y, r); } JNIEXPORT void JNICALL Java_alphaTab_alphaSkia_AlphaSkiaCanvas_strokeCircle(JNIEnv *env, jobject instance, jfloat x, jfloat y, jfloat r) { alphaskia_canvas_t canvas = reinterpret_cast(get_handle(env, instance)); + CHECK_HANDLE(canvas) + alphaskia_canvas_stroke_circle(canvas, x, y, r); } JNIEXPORT void JNICALL Java_alphaTab_alphaSkia_AlphaSkiaCanvas_fill(JNIEnv *env, jobject instance) { alphaskia_canvas_t canvas = reinterpret_cast(get_handle(env, instance)); + CHECK_HANDLE(canvas) + alphaskia_canvas_fill(canvas); } JNIEXPORT void JNICALL Java_alphaTab_alphaSkia_AlphaSkiaCanvas_stroke(JNIEnv *env, jobject instance) { alphaskia_canvas_t canvas = reinterpret_cast(get_handle(env, instance)); + CHECK_HANDLE(canvas) + alphaskia_canvas_stroke(canvas); } JNIEXPORT void JNICALL Java_alphaTab_alphaSkia_AlphaSkiaCanvas_fillText(JNIEnv *env, jobject instance, jstring str, jobject typeface, jfloat font_size, jfloat x, jfloat y, jobject text_align, jobject baseline) { alphaskia_canvas_t canvas = reinterpret_cast(get_handle(env, instance)); - + CHECK_HANDLE(canvas) const jchar *nativeStr = env->GetStringChars(str, nullptr); alphaskia_typeface_t nativeTypeface = reinterpret_cast(get_handle(env, typeface)); + CHECK_HANDLE(nativeTypeface) jmethodID textAlignGetValue = env->GetMethodID(env->GetObjectClass(text_align), "getValue", "()I"); + if (!textAlignGetValue) + { + if (!env->ExceptionCheck()) + { + env->ThrowNew(env->FindClass("java/lang/IllegalStateException"), "Could not find 'int getValue' on text align"); + } + return; + } + jmethodID baselineGetValue = env->GetMethodID(env->GetObjectClass(baseline), "getValue", "()I"); + if (!baselineGetValue) + { + if (!env->ExceptionCheck()) + { + env->ThrowNew(env->FindClass("java/lang/IllegalStateException"), "Could not find 'int getValue' on text baseline"); + } + return; + } alphaskia_text_align_t nativeTextAlign = static_cast(env->CallIntMethod(text_align, textAlignGetValue)); alphaskia_text_baseline_t nativeBaseline = static_cast(env->CallIntMethod(baseline, baselineGetValue)); - alphaskia_canvas_fill_text(canvas, reinterpret_cast(nativeStr), nativeTypeface, static_cast(font_size), static_cast(x), static_cast(y), + alphaskia_canvas_fill_text(canvas, reinterpret_cast(nativeStr), nativeTypeface, static_cast(font_size), static_cast(x), static_cast(y), nativeTextAlign, nativeBaseline); env->ReleaseStringChars(str, nativeStr); @@ -141,11 +206,13 @@ extern "C" JNIEXPORT jfloat JNICALL Java_alphaTab_alphaSkia_AlphaSkiaCanvas_measureText(JNIEnv *env, jobject instance, jstring str, jobject typeface, jfloat font_size) { alphaskia_canvas_t canvas = reinterpret_cast(get_handle(env, instance)); + CHECK_HANDLE_RETURN(canvas, 0.0f) const jchar *nativeStr = env->GetStringChars(str, nullptr); alphaskia_typeface_t nativeTypeface = reinterpret_cast(get_handle(env, typeface)); + CHECK_HANDLE_RETURN(nativeTypeface, 0.0f) - float width = alphaskia_canvas_measure_text(canvas, reinterpret_cast(nativeStr), nativeTypeface, static_cast(font_size)); + float width = alphaskia_canvas_measure_text(canvas, reinterpret_cast(nativeStr), nativeTypeface, static_cast(font_size)); env->ReleaseStringChars(str, nativeStr); @@ -155,11 +222,14 @@ extern "C" JNIEXPORT void JNICALL Java_alphaTab_alphaSkia_AlphaSkiaCanvas_beginRotate(JNIEnv *env, jobject instance, jfloat x, jfloat y, jfloat angle) { alphaskia_canvas_t canvas = reinterpret_cast(get_handle(env, instance)); + CHECK_HANDLE(canvas) + alphaskia_canvas_begin_rotate(canvas, static_cast(x), static_cast(y), static_cast(angle)); } JNIEXPORT void JNICALL Java_alphaTab_alphaSkia_AlphaSkiaCanvas_endRotate(JNIEnv *env, jobject instance) { alphaskia_canvas_t canvas = reinterpret_cast(get_handle(env, instance)); + CHECK_HANDLE(canvas) alphaskia_canvas_end_rotate(canvas); } JNIEXPORT jlong JNICALL Java_alphaTab_alphaSkia_AlphaSkiaCanvas_alphaskiaCanvasAllocate(JNIEnv *env, jclass) diff --git a/lib/java/jni/src/AlphaSkiaData.cpp b/lib/java/jni/src/AlphaSkiaData.cpp index c2dd5dc..2a98c6e 100644 --- a/lib/java/jni/src/AlphaSkiaData.cpp +++ b/lib/java/jni/src/AlphaSkiaData.cpp @@ -17,6 +17,8 @@ extern "C" JNIEXPORT void JNICALL Java_alphaTab_alphaSkia_AlphaSkiaData_close(JNIEnv *env, jobject instance) { jlong handle = get_handle(env, instance); + CHECK_HANDLE(handle) + alphaskia_data_t data = reinterpret_cast(handle); alphaskia_data_free(data); set_handle(env, instance, 0); @@ -25,6 +27,8 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_alphaTab_alphaSkia_AlphaSkiaData_toArray(JNIEnv *env, jobject instance) { jlong handle = get_handle(env, instance); + CHECK_HANDLE_RETURN(handle, nullptr) + alphaskia_data_t data = reinterpret_cast(handle); uint8_t *raw = alphaskia_data_get_data(data); diff --git a/lib/java/jni/src/AlphaSkiaImage.cpp b/lib/java/jni/src/AlphaSkiaImage.cpp index c772a9a..c790f31 100644 --- a/lib/java/jni/src/AlphaSkiaImage.cpp +++ b/lib/java/jni/src/AlphaSkiaImage.cpp @@ -9,18 +9,23 @@ extern "C" JNIEXPORT jint JNICALL Java_alphaTab_alphaSkia_AlphaSkiaImage_getWidth(JNIEnv *env, jobject instance) { jlong handle = get_handle(env, instance); + CHECK_HANDLE_RETURN(handle, 0) return alphaskia_image_get_width(reinterpret_cast(handle)); } JNIEXPORT jint JNICALL Java_alphaTab_alphaSkia_AlphaSkiaImage_getHeight(JNIEnv *env, jobject instance) { jlong handle = get_handle(env, instance); + CHECK_HANDLE_RETURN(handle, 0) + return alphaskia_image_get_height(reinterpret_cast(handle)); } JNIEXPORT void JNICALL Java_alphaTab_alphaSkia_AlphaSkiaImage_close(JNIEnv *env, jobject instance) { jlong handle = get_handle(env, instance); + CHECK_HANDLE(handle) + alphaskia_image_free(reinterpret_cast(handle)); set_handle(env, instance, 0); } @@ -28,13 +33,15 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_alphaTab_alphaSkia_AlphaSkiaImage_readPixels(JNIEnv *env, jobject instance) { jlong handle = get_handle(env, instance); + CHECK_HANDLE_RETURN(handle, nullptr) + alphaskia_image_t image = reinterpret_cast(handle); jsize rowBytes = alphaskia_image_get_width(image) * sizeof(int32_t); jbyteArray pixels = env->NewByteArray( rowBytes * alphaskia_image_get_height(image)); jbyte *bytes = env->GetByteArrayElements(pixels, nullptr); - if ( alphaskia_image_read_pixels(image, reinterpret_cast(bytes), rowBytes) == 0) + if (alphaskia_image_read_pixels(image, reinterpret_cast(bytes), rowBytes) == 0) { env->ReleaseByteArrayElements(pixels, bytes, 0); return nullptr; @@ -47,6 +54,8 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_alphaTab_alphaSkia_AlphaSkiaImage_toPng(JNIEnv *env, jobject instance) { jlong handle = get_handle(env, instance); + CHECK_HANDLE_RETURN(handle, nullptr) + alphaskia_image_t image = reinterpret_cast(handle); alphaskia_data_t data = alphaskia_image_encode_png(image); uint8_t *raw = alphaskia_data_get_data(data); diff --git a/lib/java/jni/src/AlphaSkiaTypeface.cpp b/lib/java/jni/src/AlphaSkiaTypeface.cpp index 3e9c3cb..b0f5dc0 100644 --- a/lib/java/jni/src/AlphaSkiaTypeface.cpp +++ b/lib/java/jni/src/AlphaSkiaTypeface.cpp @@ -26,6 +26,8 @@ extern "C" JNIEXPORT jboolean JNICALL Java_alphaTab_alphaSkia_AlphaSkiaTypeface_isBold(JNIEnv *env, jobject instance) { jlong handle = get_handle(env, instance); + CHECK_HANDLE_RETURN(handle, static_cast(false)) + uint8_t is_bold = alphaskia_typeface_is_bold(reinterpret_cast(handle)); return static_cast(is_bold != 0); } @@ -33,15 +35,19 @@ extern "C" JNIEXPORT jboolean JNICALL Java_alphaTab_alphaSkia_AlphaSkiaTypeface_isItalic(JNIEnv *env, jobject instance) { jlong handle = get_handle(env, instance); + CHECK_HANDLE_RETURN(handle, static_cast(false)) + uint8_t is_italic = alphaskia_typeface_is_italic(reinterpret_cast(handle)); return static_cast(is_italic != 0); } JNIEXPORT jstring JNICALL Java_alphaTab_alphaSkia_AlphaSkiaTypeface_loadFamilyName(JNIEnv *env, jclass, jlong handle) { + CHECK_HANDLE_RETURN(handle, nullptr) + alphaskia_string_t family_name = alphaskia_typeface_get_family_name(reinterpret_cast(handle)); - const char* family_name_chars = alphaskia_string_get_utf8(family_name); + const char *family_name_chars = alphaskia_string_get_utf8(family_name); jstring java_family_name = env->NewStringUTF(family_name_chars); alphaskia_string_free(family_name);