From 37d9b13470dc2a5d5ec15cf773753b0f640ff725 Mon Sep 17 00:00:00 2001 From: Julian Winkler Date: Sat, 14 Oct 2023 11:06:27 +0200 Subject: [PATCH] View.onMeasure: handle MEASURE_SPEC_AT_MOST properly We decide between simple widgets which handles MEASURE_SPEC_AT_MOST the same way as MEASURE_SPEC_EXACTLY, and complex widgets which handles MEASURE_SPEC_AT_MOST by measuring the content --- .../generated_headers/android_view_View.h | 4 +-- src/api-impl-jni/views/android_view_View.c | 25 +++++++++++++------ src/api-impl/android/view/View.java | 8 ++++-- src/api-impl/android/view/ViewGroup.java | 5 ++++ src/api-impl/android/widget/ImageView.java | 5 ++++ src/api-impl/android/widget/TextView.java | 5 ++++ 6 files changed, 41 insertions(+), 11 deletions(-) diff --git a/src/api-impl-jni/generated_headers/android_view_View.h b/src/api-impl-jni/generated_headers/android_view_View.h index 6073d3c6..eb6eb209 100644 --- a/src/api-impl-jni/generated_headers/android_view_View.h +++ b/src/api-impl-jni/generated_headers/android_view_View.h @@ -258,10 +258,10 @@ JNIEXPORT void JNICALL Java_android_view_View_native_1destructor /* * Class: android_view_View * Method: native_measure - * Signature: (JII)V + * Signature: (JIIZ)V */ JNIEXPORT void JNICALL Java_android_view_View_native_1measure - (JNIEnv *, jobject, jlong, jint, jint); + (JNIEnv *, jobject, jlong, jint, jint, jboolean); /* * Class: android_view_View diff --git a/src/api-impl-jni/views/android_view_View.c b/src/api-impl-jni/views/android_view_View.c index ccdd4164..46416b8d 100644 --- a/src/api-impl-jni/views/android_view_View.c +++ b/src/api-impl-jni/views/android_view_View.c @@ -218,27 +218,38 @@ JNIEXPORT void JNICALL Java_android_view_View_native_1destructor(JNIEnv *env, jo #define MEASURE_SPEC_UNSPECIFIED (0 << 30) #define MEASURE_SPEC_EXACTLY (1 << 30) +#define MEASURE_SPEC_AT_MOST (2 << 30) #define MEASURE_SPEC_MASK (0x3 << 30) -JNIEXPORT void JNICALL Java_android_view_View_native_1measure(JNIEnv *env, jobject this, jlong widget_ptr, jint width_spec, jint height_spec) { +JNIEXPORT void JNICALL Java_android_view_View_native_1measure(JNIEnv *env, jobject this, jlong widget_ptr, jint width_spec, jint height_spec, jboolean is_complex) { int width; int height; int for_size; GtkWidget *widget = gtk_widget_get_parent(GTK_WIDGET(_PTR(widget_ptr))); + int width_spec_size = width_spec & ~MEASURE_SPEC_MASK; + int height_spec_size = height_spec & ~MEASURE_SPEC_MASK; + int width_spec_mode = width_spec & MEASURE_SPEC_MASK; + int height_spec_mode = height_spec & MEASURE_SPEC_MASK; - if ((width_spec & MEASURE_SPEC_MASK) == MEASURE_SPEC_EXACTLY) { - width = width_spec & ~MEASURE_SPEC_MASK; + if (width_spec_mode == MEASURE_SPEC_EXACTLY || (!is_complex && width_spec_mode == MEASURE_SPEC_AT_MOST)) { + width = width_spec_size; } else { - for_size = ((height_spec & MEASURE_SPEC_MASK) == MEASURE_SPEC_EXACTLY) ? (height_spec & ~MEASURE_SPEC_MASK) : -1; + for_size = (height_spec_mode == MEASURE_SPEC_EXACTLY) ? height_spec_size : -1; gtk_widget_measure(widget, GTK_ORIENTATION_HORIZONTAL, for_size, NULL, &width, NULL, NULL); } + if (width_spec_mode == MEASURE_SPEC_AT_MOST && width > width_spec_size) { + width = width_spec_size; + } - if ((height_spec & MEASURE_SPEC_MASK) == MEASURE_SPEC_EXACTLY) { - height = height_spec & ~MEASURE_SPEC_MASK; + if (height_spec_mode == MEASURE_SPEC_EXACTLY || (!is_complex && height_spec_mode == MEASURE_SPEC_AT_MOST)) { + height = height_spec_size; } else { - for_size = ((width_spec & MEASURE_SPEC_MASK) == MEASURE_SPEC_EXACTLY) ? (width_spec & ~MEASURE_SPEC_MASK) : -1; + for_size = (width_spec_mode == MEASURE_SPEC_EXACTLY) ? width_spec_size : -1; gtk_widget_measure(widget, GTK_ORIENTATION_VERTICAL, for_size, NULL, &height, NULL, NULL); } + if (height_spec_mode == MEASURE_SPEC_AT_MOST && height > height_spec_size) { + height = height_spec_size; + } (*env)->CallVoidMethod(env, this, handle_cache.view.setMeasuredDimension, width, height); } diff --git a/src/api-impl/android/view/View.java b/src/api-impl/android/view/View.java index e0986fb0..d3290e6a 100644 --- a/src/api-impl/android/view/View.java +++ b/src/api-impl/android/view/View.java @@ -876,7 +876,11 @@ public class View extends Object { protected native long native_constructor(Context context, AttributeSet attrs); // will create a custom GtkWidget with a custom drawing function public native void native_setLayoutParams(long widget, int width, int height, int gravity, float weight); protected native void native_destructor(long widget); - protected native void native_measure(long widget, int widthMeasureSpec, int heightMeasureSpec); + /** + * We decide between simple widgets which handles MEASURE_SPEC_AT_MOST the same way as + * MEASURE_SPEC_EXACTLY, and complex widgets which handles MEASURE_SPEC_AT_MOST by measuring the content + */ + protected native void native_measure(long widget, int widthMeasureSpec, int heightMeasureSpec, boolean isComplex); protected native void native_layout(long widget, int l, int t, int r, int b); protected native void native_requestLayout(long widget); @@ -913,7 +917,7 @@ public class View extends Object { }; protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - native_measure(widget, widthMeasureSpec, heightMeasureSpec); + native_measure(widget, widthMeasureSpec, heightMeasureSpec, false); } public void setPressed(boolean pressed) { diff --git a/src/api-impl/android/view/ViewGroup.java b/src/api-impl/android/view/ViewGroup.java index 9474889e..3d2ceffe 100644 --- a/src/api-impl/android/view/ViewGroup.java +++ b/src/api-impl/android/view/ViewGroup.java @@ -119,6 +119,11 @@ public class ViewGroup extends View implements ViewParent, ViewManager { removeView(child); } + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + native_measure(widget, widthMeasureSpec, heightMeasureSpec, true); + } + @Override protected native long native_constructor(Context context, AttributeSet attrs); protected native void native_addView(long widget, long child, int index, LayoutParams params); diff --git a/src/api-impl/android/widget/ImageView.java b/src/api-impl/android/widget/ImageView.java index 7335f48a..3f75b2de 100644 --- a/src/api-impl/android/widget/ImageView.java +++ b/src/api-impl/android/widget/ImageView.java @@ -33,6 +33,11 @@ public class ImageView extends View { super(context, attrs, defStyleAttr); } + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + native_measure(widget, widthMeasureSpec, heightMeasureSpec, true); + } + @Override protected native long native_constructor(Context context, AttributeSet attrs); protected native void native_setPixbuf(long pixbuf); diff --git a/src/api-impl/android/widget/TextView.java b/src/api-impl/android/widget/TextView.java index bb2d101f..1743faf1 100644 --- a/src/api-impl/android/widget/TextView.java +++ b/src/api-impl/android/widget/TextView.java @@ -66,6 +66,11 @@ public class TextView extends View { setText(getContext().getResources().getText(resId)); } + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + native_measure(widget, widthMeasureSpec, heightMeasureSpec, true); + } + private native final void native_set_markup(int bool); public native final void native_setText(String text);