From 65a7e3487104520950f6ee0e3c8491541af52b26 Mon Sep 17 00:00:00 2001 From: Mis012 Date: Tue, 10 Jun 2025 00:48:11 +0200 Subject: [PATCH] Path: add arcTo and addArc, minor cleanup --- src/api-impl-jni/defines.h | 2 +- .../generated_headers/android_graphics_Path.h | 16 ++++++ .../graphics/android_graphics_Path.c | 49 +++++++++++++++++ src/api-impl/android/graphics/Path.java | 55 ++++++++++++++----- 4 files changed, 108 insertions(+), 14 deletions(-) diff --git a/src/api-impl-jni/defines.h b/src/api-impl-jni/defines.h index 34acebbf..3e1cd807 100644 --- a/src/api-impl-jni/defines.h +++ b/src/api-impl-jni/defines.h @@ -3,7 +3,7 @@ #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) -#define DEG2RAD(deg) (deg * M_PI / 180) +#define DEG2RAD(deg) ((deg) * M_PI / 180) #define __likely__(x) __builtin_expect(x, 1) #define __unlikely__(x) __builtin_expect(x, 0) diff --git a/src/api-impl-jni/generated_headers/android_graphics_Path.h b/src/api-impl-jni/generated_headers/android_graphics_Path.h index 98f7fe11..c937eae4 100644 --- a/src/api-impl-jni/generated_headers/android_graphics_Path.h +++ b/src/api-impl-jni/generated_headers/android_graphics_Path.h @@ -79,6 +79,14 @@ JNIEXPORT void JNICALL Java_android_graphics_Path_native_1cubic_1to JNIEXPORT void JNICALL Java_android_graphics_Path_native_1quad_1to (JNIEnv *, jclass, jlong, jfloat, jfloat, jfloat, jfloat); +/* + * Class: android_graphics_Path + * Method: native_arc_to + * Signature: (JFFFFFFZ)V + */ +JNIEXPORT void JNICALL Java_android_graphics_Path_native_1arc_1to + (JNIEnv *, jclass, jlong, jfloat, jfloat, jfloat, jfloat, jfloat, jfloat, jboolean); + /* * Class: android_graphics_Path * Method: native_rel_move_to @@ -111,6 +119,14 @@ JNIEXPORT void JNICALL Java_android_graphics_Path_native_1rel_1cubic_1to JNIEXPORT void JNICALL Java_android_graphics_Path_native_1rel_1quad_1to (JNIEnv *, jclass, jlong, jfloat, jfloat, jfloat, jfloat); +/* + * Class: android_graphics_Path + * Method: native_add_arc + * Signature: (JFFFFFF)V + */ +JNIEXPORT void JNICALL Java_android_graphics_Path_native_1add_1arc + (JNIEnv *, jclass, jlong, jfloat, jfloat, jfloat, jfloat, jfloat, jfloat); + /* * Class: android_graphics_Path * Method: native_add_path diff --git a/src/api-impl-jni/graphics/android_graphics_Path.c b/src/api-impl-jni/graphics/android_graphics_Path.c index f18c4b3d..4a5bdfff 100644 --- a/src/api-impl-jni/graphics/android_graphics_Path.c +++ b/src/api-impl-jni/graphics/android_graphics_Path.c @@ -51,6 +51,44 @@ JNIEXPORT void JNICALL Java_android_graphics_Path_native_1line_1to(JNIEnv *env, gsk_path_builder_line_to(_PTR(builder_ptr), x, y); } +/* translated to gsk_path_builder_svg_arc_to, maybe there are more performant ways to implement this? */ +void Java_android_graphics_Path_native_1arc_1to(JNIEnv *env, jclass this, jlong builder_ptr, jfloat left, jfloat top, jfloat right, jfloat bottom, + jfloat start_angle_deg, jfloat sweep_angle_deg, jboolean force_move_to) +{ + GskPathBuilder *builder = _PTR(builder_ptr); + + /* compute ellipse center and radii */ + const graphene_point_t center = GRAPHENE_POINT_INIT((left + right) / 2.0, + (top + bottom) / 2.0); + const double rx = fabs(right - left) / 2.0; + const double ry = fabs(bottom - top) / 2.0; + + /* compute points on the ellipse from angles */ + const double start_angle = DEG2RAD(start_angle_deg); + const double end_angle = DEG2RAD(start_angle_deg + sweep_angle_deg); + + graphene_point_t p1; + graphene_point_t p2; + graphene_point_init(&p1, + center.x + rx * cos(start_angle), + center.y + ry * sin(start_angle)); + graphene_point_init(&p2, + center.x + rx * cos(end_angle), + center.y + ry * sin(end_angle)); + + /* handle force_move_to */ + if (force_move_to) + gsk_path_builder_move_to(builder, p1.x, p1.y); + else if (!graphene_point_equal(gsk_path_builder_get_current_point(builder), &p1)) + gsk_path_builder_line_to(builder, p1.x, p1.y); + + /* compute flags */ + const gboolean large_arc_flag = (fabs(sweep_angle_deg) >= 180.0); + const gboolean sweep_flag = (sweep_angle_deg > 0.0); + + gsk_path_builder_svg_arc_to(builder, rx, ry, 0.0, large_arc_flag, sweep_flag, p2.x, p2.y); +} + JNIEXPORT void JNICALL Java_android_graphics_Path_native_1cubic_1to(JNIEnv *env, jclass this, jlong builder_ptr, jfloat x1, jfloat y1, jfloat x2, jfloat y2, jfloat x3, jfloat y3) { gsk_path_builder_cubic_to(_PTR(builder_ptr), x1, y1, x2, y2, x3, y3); @@ -115,6 +153,17 @@ static gboolean path_foreach_transform(GskPathOperation op, const graphene_point return TRUE; } +void Java_android_graphics_Path_native_1add_1arc(JNIEnv *env, jclass this, jlong builder_ptr, jfloat left, jfloat top, jfloat right, jfloat bottom, + jfloat start_angle_deg, jfloat sweep_angle_deg) +{ + GskPathBuilder *builder = _PTR(builder_ptr); + GskPath *path; + GskPathBuilder *arc_builder = gsk_path_builder_new(); + Java_android_graphics_Path_native_1arc_1to(env, this, _INTPTR(arc_builder), left, top, right, bottom, start_angle_deg, sweep_angle_deg, true); + path = gsk_path_builder_free_to_path(arc_builder); + gsk_path_builder_add_path(builder, path); +} + JNIEXPORT void JNICALL Java_android_graphics_Path_native_1add_1path(JNIEnv *env, jclass this, jlong builder_ptr, jlong path_ptr, jlong matrix_ptr) { GskPathBuilder *builder = _PTR(builder_ptr); diff --git a/src/api-impl/android/graphics/Path.java b/src/api-impl/android/graphics/Path.java index 1f355bd4..d0a02dd5 100644 --- a/src/api-impl/android/graphics/Path.java +++ b/src/api-impl/android/graphics/Path.java @@ -1,5 +1,7 @@ package android.graphics; +import android.util.Log; + /* * Path is implemented as a GskPath or a GskPathBuilder. It can only be one of the two at a time. * The methods getGskPath() and getBuilder() automatically convert between the two as needed. @@ -82,6 +84,18 @@ public class Path { native_line_to(getBuilder(), x, y); } + public void arcTo(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo) { + arcTo(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, forceMoveTo); + } + + public void arcTo(RectF oval, float startAngle, float sweepAngle) { + arcTo(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, false); + } + + public void arcTo(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean forceMoveTo) { + native_arc_to(getBuilder(), left, top, right, bottom, startAngle, sweepAngle, forceMoveTo); + } + public void cubicTo(float x1, float y1, float x2, float y2, float x3, float y3) { native_cubic_to(getBuilder(), x1, y1, x2, y2, x3, y3); } @@ -90,12 +104,6 @@ public class Path { native_quad_to(getBuilder(), x1, y1, x2, y2); } - public void arcTo(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo) {} - - public void arcTo(RectF oval, float startAngle, float sweepAngle) {} - - public void arcTo(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean forceMoveTo) {} - public void rMoveTo(float x, float y) { native_rel_move_to(getBuilder(), x, y); } @@ -112,9 +120,13 @@ public class Path { native_rel_quad_to(getBuilder(), x1, y1, x2, y2); } - public void addArc (RectF oval, float startAngle, float sweepAngle) {} + public void addArc(RectF oval, float startAngle, float sweepAngle) { + addArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle); + } - public void addArc (float left, float top, float right, float bottom, float startAngle, float sweepAngle) {} + public void addArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle) { + native_add_arc(getBuilder(), left, top, right, bottom, startAngle, sweepAngle); + } public void addPath(Path path, Matrix matrix) { native_add_path(getBuilder(), path.getGskPath(), matrix.ni()); @@ -131,7 +143,11 @@ public class Path { } public void addRect(RectF rect, Direction direction) { - native_add_rect(getBuilder(), rect.left, rect.top, rect.right, rect.bottom); + addRect(rect.left, rect.top, rect.right, rect.bottom, direction); + } + + public void addRect(float left, float top, float right, float bottom, Path.Direction dir) { + native_add_rect(getBuilder(), left, top, right, bottom); } public void addRoundRect(RectF rect, float[] radii, Direction direction) { @@ -139,18 +155,26 @@ public class Path { } public void addRoundRect(float left, float top, float right, float bottom, - float[] radii, Direction direction) {} + float[] radii, Direction direction) { + Log.w("Path", "STUB: addRoundRect"); + } public void addRoundRect(RectF rect, float rx, float ry, Direction direction) { addRoundRect(rect.left, rect.top, rect.right, rect.bottom, rx, ry, direction); } public void addRoundRect(float left, float top, float right, float bottom, - float rx, float ry, Direction direction) {} + float rx, float ry, Direction direction) { + addRoundRect(left, top, right, bottom, new float[]{rx, ry, rx, ry, rx, ry, rx, ry}, direction); + } - public void addOval(RectF rect, Direction direction) {} + public void addOval(RectF rect, Direction direction) { + Log.w("Path", "STUB: addOval"); + } - public void addCircle(float x, float y, float radius, Direction direction) {} + public void addCircle(float x, float y, float radius, Direction direction) { + Log.w("Path", "STUB: addCircle"); + } public void transform(Matrix matrix) { builder = native_transform(getGskPath(), matrix.ni()); @@ -169,10 +193,12 @@ public class Path { } public boolean op(Path path, Op op) { + Log.w("Path", "STUB: op"); return false; } public boolean op(Path path, Path dst, Op op) { + Log.w("Path", "STUB: op"); return false; } @@ -183,6 +209,7 @@ public class Path { public void incReserve(int additionalPoints) {} public boolean isConvex() { + Log.w("Path", "STUB: isConvex"); return false; } @@ -216,10 +243,12 @@ public class Path { private static native void native_line_to(long builder, float x, float y); private static native void native_cubic_to(long builder, float x1, float y1, float x2, float y2, float x3, float y3); private static native void native_quad_to(long builder, float x1, float y1, float x2, float y2); + private static native void native_arc_to(long builder, float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean forceMoveTo); private static native void native_rel_move_to(long builder, float x, float y); private static native void native_rel_line_to(long builder, float x, float y); private static native void native_rel_cubic_to(long builder, float x1, float y1, float x2, float y2, float x3, float y3); private static native void native_rel_quad_to(long builder, float x1, float y1, float x2, float y2); + private static native void native_add_arc(long builder, float left, float top, float right, float bottom, float startAngle, float sweepAngle); private static native void native_add_path(long builder, long path, long matrix); private static native void native_add_rect(long builder, float left, float top, float right, float bottom); private static native void native_get_bounds(long path, RectF rect);