Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Williams2019-04-23 10:04:21 -0400
committerEric Williams2019-04-24 09:58:36 -0400
commitd877d46d88755a5a5db5d2ee49bcaa8d6d496b9f (patch)
treebc63e1f6c49a636010faa4de696f158c516bda40
parent3d47beb6a71aa3e72762c9a55af531c0aedab8df (diff)
downloadeclipse.platform.swt-d877d46d88755a5a5db5d2ee49bcaa8d6d496b9f.tar.gz
eclipse.platform.swt-d877d46d88755a5a5db5d2ee49bcaa8d6d496b9f.tar.xz
eclipse.platform.swt-d877d46d88755a5a5db5d2ee49bcaa8d6d496b9f.zip
Bug 546274: [GTK] vm crash when scrolling StyledText
The method scrollInPixels() doesn't seem to be needed. I've reverted the fix from commit 64ae338b9c279c9bbcc158165aa451193a503c0a to preserve stability on GTK3, but on GTK4 this method is never called. Tested with the snippet attached, as well as the Canvas tab on ControlExample (GTK3 and GTK4). Change-Id: If907bf6c4c805c24eb021b687d5affbbc2e8bc3f Signed-off-by: Eric Williams <ericwill@redhat.com>
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c40
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c2
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h2
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GDK.java28
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Canvas.java91
-rw-r--r--tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug546274_StyledTextVMCrash.java102
6 files changed, 227 insertions, 38 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c
index 16ae5c75c4..8e32951ff9 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c
@@ -2747,6 +2747,26 @@ JNIEXPORT jint JNICALL GDK_NATIVE(_1gdk_1visual_1get_1depth)
}
#endif
+#ifndef NO__1gdk_1window_1begin_1draw_1frame
+JNIEXPORT jlong JNICALL GDK_NATIVE(_1gdk_1window_1begin_1draw_1frame)
+ (JNIEnv *env, jclass that, jlong arg0, jlong arg1)
+{
+ jlong rc = 0;
+ GDK_NATIVE_ENTER(env, that, _1gdk_1window_1begin_1draw_1frame_FUNC);
+/*
+ rc = (jlong)gdk_window_begin_draw_frame((GdkWindow *)arg0, (cairo_region_t *)arg1);
+*/
+ {
+ GDK_LOAD_FUNCTION(fp, gdk_window_begin_draw_frame)
+ if (fp) {
+ rc = (jlong)((jlong (CALLING_CONVENTION*)(GdkWindow *, cairo_region_t *))fp)((GdkWindow *)arg0, (cairo_region_t *)arg1);
+ }
+ }
+ GDK_NATIVE_EXIT(env, that, _1gdk_1window_1begin_1draw_1frame_FUNC);
+ return rc;
+}
+#endif
+
#ifndef NO__1gdk_1window_1create_1similar_1surface
JNIEXPORT jlong JNICALL GDK_NATIVE(_1gdk_1window_1create_1similar_1surface)
(JNIEnv *env, jclass that, jlong arg0, jint arg1, jint arg2, jint arg3)
@@ -2769,6 +2789,26 @@ JNIEXPORT void JNICALL GDK_NATIVE(_1gdk_1window_1destroy)
}
#endif
+#ifndef NO__1gdk_1window_1end_1draw_1frame
+JNIEXPORT jlong JNICALL GDK_NATIVE(_1gdk_1window_1end_1draw_1frame)
+ (JNIEnv *env, jclass that, jlong arg0, jlong arg1)
+{
+ jlong rc = 0;
+ GDK_NATIVE_ENTER(env, that, _1gdk_1window_1end_1draw_1frame_FUNC);
+/*
+ rc = (jlong)gdk_window_end_draw_frame((GdkWindow *)arg0, (GdkDrawingContext *)arg1);
+*/
+ {
+ GDK_LOAD_FUNCTION(fp, gdk_window_end_draw_frame)
+ if (fp) {
+ rc = (jlong)((jlong (CALLING_CONVENTION*)(GdkWindow *, GdkDrawingContext *))fp)((GdkWindow *)arg0, (GdkDrawingContext *)arg1);
+ }
+ }
+ GDK_NATIVE_EXIT(env, that, _1gdk_1window_1end_1draw_1frame_FUNC);
+ return rc;
+}
+#endif
+
#ifndef NO__1gdk_1window_1focus
JNIEXPORT void JNICALL GDK_NATIVE(_1gdk_1window_1focus)
(JNIEnv *env, jclass that, jlong arg0, jint arg1)
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c
index 40806b67d5..b0eac77a80 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c
@@ -212,8 +212,10 @@ char * GDK_nativeFunctionNames[] = {
"_1gdk_1unicode_1to_1keyval",
"_1gdk_1utf8_1to_1string_1target",
"_1gdk_1visual_1get_1depth",
+ "_1gdk_1window_1begin_1draw_1frame",
"_1gdk_1window_1create_1similar_1surface",
"_1gdk_1window_1destroy",
+ "_1gdk_1window_1end_1draw_1frame",
"_1gdk_1window_1focus",
"_1gdk_1window_1get_1children",
"_1gdk_1window_1get_1device_1position",
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h
index 935e7d2522..5145d14c27 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h
@@ -222,8 +222,10 @@ typedef enum {
_1gdk_1unicode_1to_1keyval_FUNC,
_1gdk_1utf8_1to_1string_1target_FUNC,
_1gdk_1visual_1get_1depth_FUNC,
+ _1gdk_1window_1begin_1draw_1frame_FUNC,
_1gdk_1window_1create_1similar_1surface_FUNC,
_1gdk_1window_1destroy_FUNC,
+ _1gdk_1window_1end_1draw_1frame_FUNC,
_1gdk_1window_1focus_FUNC,
_1gdk_1window_1get_1children_FUNC,
_1gdk_1window_1get_1device_1position_FUNC,
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GDK.java b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GDK.java
index 62f8fc2ff8..6132c5c132 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GDK.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GDK.java
@@ -524,6 +524,34 @@ public class GDK extends OS {
}
/**
* @param window cast=(GdkWindow *)
+ * @param region cast=(cairo_region_t *)
+ * @method flags=dynamic
+ */
+ public static final native long _gdk_window_begin_draw_frame(long window, long region);
+ public static final long gdk_window_begin_draw_frame(long window, long region) {
+ lock.lock();
+ try {
+ return _gdk_window_begin_draw_frame(window, region);
+ } finally {
+ lock.unlock();
+ }
+ }
+ /**
+ * @param window cast=(GdkWindow *)
+ * @param context cast=(GdkDrawingContext *)
+ * @method flags=dynamic
+ */
+ public static final native long _gdk_window_end_draw_frame(long window, long context);
+ public static final long gdk_window_end_draw_frame(long window, long context) {
+ lock.lock();
+ try {
+ return _gdk_window_end_draw_frame(window, context);
+ } finally {
+ lock.unlock();
+ }
+ }
+ /**
+ * @param window cast=(GdkWindow *)
*/
public static final native int _gdk_window_get_state(long window);
/** [GTK3 only, if-def'd in os.h] */
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Canvas.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Canvas.java
index fc6e3e411b..81e68c30d5 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Canvas.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Canvas.java
@@ -45,7 +45,6 @@ import org.eclipse.swt.internal.gtk.*;
public class Canvas extends Composite {
Caret caret;
IME ime;
- long cachedCairo;
boolean blink, drawFlag;
Canvas () {}
@@ -179,7 +178,6 @@ long gtk_draw (long widget, long cairo) {
result = super.gtk_draw (widget, cairo);
if (isFocus) caret.setFocus ();
} else {
- this.cachedCairo = cairo;
result = super.gtk_draw (widget, cairo);
/*
* blink is needed to be checked as gtk_draw() signals sent from other parts of the canvas
@@ -313,14 +311,19 @@ void reskinChildren (int flags) {
public void scroll (int destX, int destY, int x, int y, int width, int height, boolean all) {
checkWidget();
if (width <= 0 || height <= 0) return;
+ /*
+ * scrollInPixels() doesn't seem to be needed on GTK4, so we can return early.
+ * In fact it doesn't seem to be needed on GTK3 either, but it's been left
+ * here for stability on older GTK3 versions. The investigation
+ * as to why it's unneeded is left as a TODO. See bug 546274.
+ */
+ if (GTK.GTK4) return;
Point destination = DPIUtil.autoScaleUp (new Point (destX, destY));
Rectangle srcRect = DPIUtil.autoScaleUp (new Rectangle (x, y, width, height));
scrollInPixels(destination.x, destination.y, srcRect.x, srcRect.y, srcRect.width, srcRect.height, all);
}
void scrollInPixels (int destX, int destY, int x, int y, int width, int height, boolean all) {
- long cairo = this.cachedCairo;
- if (cairo == 0) return;
if ((style & SWT.MIRRORED) != 0) {
int clientWidth = getClientWidth ();
x = clientWidth - width - x;
@@ -331,12 +334,9 @@ void scrollInPixels (int destX, int destY, int x, int y, int width, int height,
if (!isVisible ()) return;
boolean isFocus = caret != null && caret.isFocusCaret ();
if (isFocus) caret.killFocus ();
- GdkRectangle clipRect = new GdkRectangle ();
- GDK.gdk_cairo_get_clip_rectangle (cairo, clipRect);
+ long window = paintWindow ();
+ long visibleRegion = GDK.gdk_window_get_visible_region (window);
cairo_rectangle_int_t srcRect = new cairo_rectangle_int_t ();
- srcRect.convertFromGdkRectangle(clipRect);
- long gdkResource = GTK.GTK4? paintSurface () : paintWindow ();
- long visibleRegion = Cairo.cairo_region_create_rectangle(srcRect);
srcRect.x = x;
srcRect.y = y;
/*
@@ -384,48 +384,63 @@ void scrollInPixels (int destX, int destY, int x, int y, int width, int height,
redrawWidget (x, y, width, height, false, false, false);
redrawWidget (destX, destY, width, height, false, false, false);
} else {
- Cairo.cairo_push_group(cairo);
- Cairo.cairo_paint(cairo);
- Cairo.cairo_pop_group_to_source(cairo);
+ long cairo = 0;
+ long context = 0;
+ if (GTK.GTK_VERSION >= OS.VERSION(3, 22, 0)) {
+ long cairo_region = GDK.gdk_window_get_visible_region(window);
+ context = GDK.gdk_window_begin_draw_frame(window, cairo_region);
+ cairo = GDK.gdk_drawing_context_get_cairo_context(context);
+ } else {
+ cairo = GDK.gdk_cairo_create(window);
+ }
+ if (Cairo.cairo_version() < Cairo.CAIRO_VERSION_ENCODE(1, 12, 0)) {
+ GDK.gdk_cairo_set_source_window(cairo, window, 0, 0);
+ } else {
+ Cairo.cairo_push_group(cairo);
+ GDK.gdk_cairo_set_source_window(cairo, window, 0, 0);
+ Cairo.cairo_paint(cairo);
+ Cairo.cairo_pop_group_to_source(cairo);
+ }
double[] matrix = {1, 0, 0, 1, -deltaX, -deltaY};
Cairo.cairo_pattern_set_matrix(Cairo.cairo_get_source(cairo), matrix);
Cairo.cairo_rectangle(cairo, copyRect.x + deltaX, copyRect.y + deltaY, copyRect.width, copyRect.height);
Cairo.cairo_clip(cairo);
Cairo.cairo_paint(cairo);
+ if (GTK.GTK_VERSION >= OS.VERSION(3, 22, 0)) {
+ if (context != 0) GDK.gdk_window_end_draw_frame(window, context);
+ } else {
+ Cairo.cairo_destroy(cairo);
+ }
boolean disjoint = (destX + width < x) || (x + width < destX) || (destY + height < y) || (y + height < destY);
if (disjoint) {
- cairo_rectangle_int_t cairoRect = new cairo_rectangle_int_t();
- cairoRect.x = x;
- cairoRect.y = y;
- cairoRect.width = width;
- cairoRect.height = height;
- Cairo.cairo_region_union_rectangle (invalidateRegion, cairoRect);
+ cairo_rectangle_int_t rect = new cairo_rectangle_int_t();
+ rect.x = x;
+ rect.y = y;
+ rect.width = width;
+ rect.height = height;
+ Cairo.cairo_region_union_rectangle (invalidateRegion, rect);
} else {
- cairo_rectangle_int_t cairoRect = new cairo_rectangle_int_t();
+ cairo_rectangle_int_t rect = new cairo_rectangle_int_t();
if (deltaX != 0) {
int newX = destX - deltaX;
if (deltaX < 0) newX = destX + width;
- cairoRect.x = newX;
- cairoRect.y = y;
- cairoRect.width = Math.abs(deltaX);
- cairoRect.height = height;
- Cairo.cairo_region_union_rectangle (invalidateRegion, cairoRect);
+ rect.x = newX;
+ rect.y = y;
+ rect.width = Math.abs(deltaX);
+ rect.height = height;
+ Cairo.cairo_region_union_rectangle (invalidateRegion, rect);
}
if (deltaY != 0) {
int newY = destY - deltaY;
if (deltaY < 0) newY = destY + height;
- cairoRect.x = x;
- cairoRect.y = newY;
- cairoRect.width = width;
- cairoRect.height = Math.abs(deltaY);
- Cairo.cairo_region_union_rectangle (invalidateRegion, cairoRect);
+ rect.x = x;
+ rect.y = newY;
+ rect.width = width;
+ rect.height = Math.abs(deltaY);
+ Cairo.cairo_region_union_rectangle (invalidateRegion, rect);
}
}
- if (GTK.GTK4) {
- GDK.gdk_surface_invalidate_region(gdkResource, invalidateRegion);
- } else {
- GDK.gdk_window_invalidate_region(gdkResource, invalidateRegion, all);
- }
+ GDK.gdk_window_invalidate_region(window, invalidateRegion, all);
}
Cairo.cairo_region_destroy (visibleRegion);
Cairo.cairo_region_destroy (copyRegion);
@@ -434,10 +449,10 @@ void scrollInPixels (int destX, int destY, int x, int y, int width, int height,
Control [] children = _getChildren ();
for (int i=0; i<children.length; i++) {
Control child = children [i];
- Rectangle childBounds = child.getBoundsInPixels ();
- if (Math.min(x + width, childBounds.x + childBounds.width) >= Math.max (x, childBounds.x) &&
- Math.min(y + height, childBounds.y + childBounds.height) >= Math.max (y, childBounds.y)) {
- child.setLocationInPixels (childBounds.x + deltaX, childBounds.y + deltaY);
+ Rectangle rect = child.getBoundsInPixels ();
+ if (Math.min(x + width, rect.x + rect.width) >= Math.max (x, rect.x) &&
+ Math.min(y + height, rect.y + rect.height) >= Math.max (y, rect.y)) {
+ child.setLocationInPixels (rect.x + deltaX, rect.y + deltaY);
}
}
}
diff --git a/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug546274_StyledTextVMCrash.java b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug546274_StyledTextVMCrash.java
new file mode 100644
index 0000000000..878da10e23
--- /dev/null
+++ b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug546274_StyledTextVMCrash.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Syntevo and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Syntevo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.tests.gtk.snippets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+public class Bug546274_StyledTextVMCrash {
+ private static class MyStyledText extends StyledText {
+ int cairoCacheSize = 16; // see MAX_FREED_POOL_SIZE in cairo
+ Image tempImages[] = new Image[cairoCacheSize];
+ GC tempGCs[] = new GC[cairoCacheSize];
+
+ public MyStyledText(Composite parent, int style) {
+ super(parent, style);
+ allocTempGCs();
+ }
+
+ void allocTempGCs() {
+ for (int i = 0; i < cairoCacheSize; i++) {
+ tempImages[i] = new Image(this.getDisplay(), 1, 1);
+ tempGCs[i] = new GC(tempImages[i]);
+ }
+ }
+
+ @Override
+ public void scroll(int destX, int destY, int x, int y, int width, int height, boolean all) {
+ // Evaluate with debugger: (cachedCairo.handle == this.cachedCairo);
+ // This already shows that 'this.cachedCairo' can't be used.
+ Image tempImage = new Image(this.getDisplay(), 1, 1);
+ GC cachedCairo = new GC(tempImage);
+
+ // Evict 'cachedCairo' from Cairo's cache 'context_pool' by
+ // 1) Populating cache with free objects
+ // 2) Releasing 'cachedCairo' and it will be truly deleted
+ {
+ if (tempGCs != null) {
+ for (int i = 0; i < tempGCs.length; i++) {
+ tempGCs[i].dispose();
+ tempImages[i].dispose();
+ }
+ }
+
+ cachedCairo.dispose();
+ tempImage.dispose();
+ }
+
+ // Make sure the same malloc() block can't be used again
+ for (int i = 1; i < 1024; i++) {
+ // Intentional leak
+ org.eclipse.swt.internal.gtk.GTK.malloc(i);
+ }
+
+ super.scroll(destX, destY, x, y, width, height, all);
+
+ // Drain Cairo's cache 'context_pool' to force the next cairo to use malloc()
+ allocTempGCs();
+ }
+ }
+
+ public static void main(String[] args) {
+ final Display display = new Display();
+
+ final Shell shell = new Shell(display, SWT.SHELL_TRIM);
+ shell.setLayout(new FillLayout(SWT.VERTICAL));
+ shell.setSize(300, 200);
+
+ String hintText = "Try to horz scroll this StyledText\n" +
+ "\n" +
+ "Horz scrollbar is forced by this long line of text xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+
+ final StyledText text = new MyStyledText(shell, SWT.BORDER | SWT.H_SCROLL);
+ text.setText(hintText);
+
+ shell.open();
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+
+ display.dispose();
+ }
+}

Back to the top