make android.text.Layout.draw() compatible custom Canvas classes

TextAndroidCanvas is a proxy canvas class which prevents us from
accessing the GtkSnapshot of the real canvas. To solve this problem, we
call Canvas.drawText() for each line.
This commit is contained in:
Julian Winkler 2025-02-19 20:40:37 +01:00
parent 4bb5dfd86e
commit 24f839f556
7 changed files with 44 additions and 4 deletions

View file

@ -143,6 +143,14 @@ JNIEXPORT jint JNICALL Java_android_text_Layout_native_1get_1ellipsis_1count
JNIEXPORT void JNICALL Java_android_text_Layout_native_1draw
(JNIEnv *, jobject, jlong, jlong, jlong);
/*
* Class: android_text_Layout
* Method: native_draw_custom_canvas
* Signature: (JLandroid/graphics/Canvas;Landroid/graphics/Paint;)V
*/
JNIEXPORT void JNICALL Java_android_text_Layout_native_1draw_1custom_1canvas
(JNIEnv *, jobject, jlong, jobject, jobject);
#ifdef __cplusplus
}
#endif

View file

@ -104,7 +104,7 @@ JNIEXPORT void JNICALL Java_android_graphics_GskCanvas_native_1drawText(JNIEnv *
(*env)->ReleaseStringUTFChars(env, text, str);
PangoRectangle rect;
pango_layout_get_pixel_extents(layout, NULL, &rect);
y -= rect.height;
y -= (float)pango_layout_get_baseline(layout) / PANGO_SCALE;
if (paint->alignment == PANGO_ALIGN_CENTER)
x -= rect.width / 2.f;
else if (paint->alignment == PANGO_ALIGN_RIGHT)

View file

@ -2,6 +2,7 @@
#include <pango/pango.h>
#include "../defines.h"
#include "../util.h"
#include "../graphics/AndroidPaint.h"
#include "../generated_headers/android_text_Layout.h"
@ -149,3 +150,22 @@ JNIEXPORT void JNICALL Java_android_text_Layout_native_1draw(JNIEnv *env, jobjec
gtk_snapshot_append_layout(snapshot, pango_layout, &android_paint->color);
}
JNIEXPORT void JNICALL Java_android_text_Layout_native_1draw_1custom_1canvas(JNIEnv *env, jobject object, jlong layout, jobject canvas, jobject paint)
{
PangoLayout *pango_layout = PANGO_LAYOUT(_PTR(layout));
const gchar *text = pango_layout_get_text(pango_layout);
PangoLayoutIter *pango_iter = pango_layout_get_iter(pango_layout);
do {
PangoLayoutLine *pango_line = pango_layout_iter_get_line_readonly(pango_iter);
jstring text_jstr = (*env)->NewStringUTF(env, text + pango_line->start_index);
jint end = (*env)->GetStringLength(env, text_jstr);
if (pango_line->length < end)
end = pango_line->length;
jfloat y = (float)pango_layout_iter_get_baseline(pango_iter) / PANGO_SCALE;
(*env)->CallVoidMethod(env, canvas, handle_cache.canvas.drawText, text_jstr, (jint)0, end, (jfloat)0, y, paint);
(*env)->DeleteLocalRef(env, text_jstr);
} while (pango_layout_iter_next_line(pango_iter));
}

View file

@ -175,6 +175,9 @@ void set_up_handle_cache(JNIEnv *env)
handle_cache.webview.class = _REF((*env)->FindClass(env, "android/webkit/WebView"));
handle_cache.webview.internalGetAssetManager = _METHOD(handle_cache.webview.class, "internalGetAssetManager", "()Landroid/content/res/AssetManager;");
handle_cache.webview.internalLoadChanged = _METHOD(handle_cache.webview.class, "internalLoadChanged", "(ILjava/lang/String;)V");
handle_cache.canvas.class = _REF((*env)->FindClass(env, "android/graphics/Canvas"));
handle_cache.canvas.drawText = _METHOD(handle_cache.canvas.class, "drawText", "(Ljava/lang/CharSequence;IIFFLandroid/graphics/Paint;)V");
}
void extract_from_apk(const char *path, const char *target) {

View file

@ -128,6 +128,10 @@ struct handle_cache {
jmethodID onCreate;
jmethodID start;
} instrumentation;
struct {
jclass class;
jmethodID drawText;
} canvas;
};
extern struct handle_cache handle_cache;

View file

@ -136,6 +136,11 @@ public class GskCanvas extends Canvas {
native_concat(snapshot, matrix.native_instance);
}
@Override
public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
drawText(text.toString().substring(start, end), x, y, paint);
}
protected native void native_drawBitmap(long snapshot, long texture, int x, int y, int width, int height, long paint);
protected native void native_drawRect(long snapshot, float left, float top, float right, float bottom, long paint);
protected native void native_drawPath(long snapshot, long path, long paint);

View file

@ -2,6 +2,7 @@ package android.text;
import android.graphics.Canvas;
import android.graphics.GskCanvas;
import android.graphics.Paint;
import android.graphics.Path;
public class Layout {
@ -59,8 +60,6 @@ public class Layout {
}
public int getHeight() {
System.out.println("height = " + native_get_height(layout));
System.out.println("should be " + ((int)(paint.measureText("_") * 3)));
return native_get_height(layout);
}
@ -68,7 +67,7 @@ public class Layout {
if (canvas instanceof GskCanvas)
native_draw(layout, ((GskCanvas)canvas).snapshot, paint.paint);
else
canvas.drawText(text.toString(), 0, 0, paint);
native_draw_custom_canvas(layout, canvas, paint);
}
public int getParagraphDirection(int line) {
@ -251,4 +250,5 @@ public class Layout {
protected native void native_set_ellipsize(long layout, int ellipsize_mode, float ellipsize_width);
protected native int native_get_ellipsis_count(long layout, int line);
protected native void native_draw(long layout, long snapshot, long paint);
protected native void native_draw_custom_canvas(long layout, Canvas canvas, Paint paint);
}