From a0b6fb07cdc38a36cbbd1506624e88620c872273 Mon Sep 17 00:00:00 2001 From: Patrick Ziegler Date: Thu, 5 Mar 2026 21:26:32 +0100 Subject: [PATCH] GC.setClipping(path) doesn't paint on Linux when transformed #3120 The fix for Bug 531667 (d7ce5978d32a9dd4bf77dfa77e4b1c696992af4a) introduced a regression when calling `setClipping(Path)` after `setTransform(Transform)`. The rectangle used when resetting the clip doesn't consider the previously done transformation, producing an empty clip if this rectangle and the `Path` don't intersect. Instead of using the local `clipping` variable (which contains the initial clip when the GC was created), the `resetClipping()` method now uses the rectangle returned by `getClipping()`, which internally applies the transformation matrix. To reproduce, execute the attached snippet. The rectangle in this example should be green, as it is drawn over the red rectangle. Closes https://github.com/eclipse-platform/eclipse.platform.swt/issues/3120 --- ..._setClipping_is_wrong_after_transform.java | 75 +++++++++++ .../Test_org_eclipse_swt_graphics_GC.java | 122 +++++++++++++----- 2 files changed, 167 insertions(+), 30 deletions(-) create mode 100644 tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Issue3120_GC_setClipping_is_wrong_after_transform.java diff --git a/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Issue3120_GC_setClipping_is_wrong_after_transform.java b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Issue3120_GC_setClipping_is_wrong_after_transform.java new file mode 100644 index 0000000000..c3529a0bd1 --- /dev/null +++ b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Issue3120_GC_setClipping_is_wrong_after_transform.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2026 Patrick Ziegler and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Patrick Ziegler - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.tests.gtk.snippets; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Path; +import org.eclipse.swt.graphics.Transform; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; + +/** + * Description: {@link GC#setClipping(Path)} doesn't respect a previous call to + * {@link GC#setTransform(Transform)}. + *
    + *
  1. Run the snippet.
  2. + *
+ * Expected results: The painted rectangle should be green.
+ * Actual results: The painted rectangle is red. + * + * @see Bug + * 531667 - [GTK3] Cannot draw Canvas with Control.print(GC) + */ +public class Issue3120_GC_setClipping_is_wrong_after_transform { + + public static void main(String[] args) { + Shell shell = new Shell(); + shell.setLayout(new FillLayout()); + shell.setSize(600, 300); + + Display display = shell.getDisplay(); + + shell.addPaintListener(event -> { + GC gc = event.gc; + + Path p = new Path(display); + p.addRectangle(50, 350, 100, 100); + + Transform t = new Transform(display); + t.translate(0, -300); + + gc.setTransform(t); + + gc.setBackground(display.getSystemColor(SWT.COLOR_RED)); + gc.fillPath(p); + gc.setClipping(p); + gc.setBackground(display.getSystemColor(SWT.COLOR_GREEN)); + gc.fillPath(p); + + p.dispose(); + + gc.setTransform(null); + t.dispose(); + }); + + shell.open(); + + while(!shell.isDisposed()) { + if(!display.readAndDispatch()) { + display.sleep(); + } + } + } +} \ No newline at end of file diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_GC.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_GC.java index 563f4cbecb..1aea90fb92 100644 --- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_GC.java +++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_GC.java @@ -16,6 +16,7 @@ import static org.eclipse.swt.internal.DPIUtil.pointToPixel; import static org.eclipse.swt.tests.junit.SwtTestUtil.assertSWTProblem; +import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -45,6 +46,7 @@ import org.eclipse.swt.graphics.ImageGcDrawer; import org.eclipse.swt.graphics.LineAttributes; import org.eclipse.swt.graphics.PaletteData; +import org.eclipse.swt.graphics.Path; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.graphics.Rectangle; @@ -791,42 +793,102 @@ public void test_setBackgroundLorg_eclipse_swt_graphics_Color() { "No exception thrown for color disposed"); } +@Test +public void test_setClippingIIII_withTransform() { + Transform t = new Transform(gc.getDevice()); + t.scale(1.5f,0.5f); + t.translate(-5,-25); + + gc.setClipping(0,5,10,20); + gc.setTransform(t); + t.dispose(); + + Rectangle rect = gc.getClipping(); + assertAll( + () -> assertEquals(5,rect.x), + () -> assertEquals(35, rect.y), + () -> assertEquals(7,rect.width), + () -> assertEquals(40,rect.height)); + +} + @Test public void test_setClippingIIII() { - // intermittently fails on XP for reasons unknown, comment out the test case - // until the problem is figured out -// Canvas canvas = new Canvas(shell, SWT.BORDER); -// shell.setSize(110,110); -// canvas.setSize(100,100); -// shell.open(); -// GC testGc = new GC(canvas); -// testGc.setClipping(0,5,10,20); -// Rectangle rect = testGc.getClipping(); -// assertTrue(rect.x == 0); -// assertTrue(rect.y == 5); -// assertTrue(rect.width == 10); -// assertTrue(rect.height == 20); -// testGc.dispose(); -// canvas.dispose(); + gc.setClipping(0,5,10,20); + Rectangle rect = gc.getClipping(); + assertAll( + () -> assertEquals(0,rect.x), + () -> assertEquals(5, rect.y), + () -> assertEquals(10,rect.width), + () -> assertEquals(20,rect.height)); +} + +@Test +public void test_setClippingLorg_eclipse_swt_graphics_Rectangle_withTransform() { + Transform t = new Transform(gc.getDevice()); + t.scale(1.5f,0.5f); + t.translate(-5,-25); + + gc.setClipping(new Rectangle(0,5,10,20)); + gc.setTransform(t); + t.dispose(); + + Rectangle rect = gc.getClipping(); + assertAll( + () -> assertEquals(5,rect.x), + () -> assertEquals(35, rect.y), + () -> assertEquals(7,rect.width), + () -> assertEquals(40,rect.height)); + } @Test public void test_setClippingLorg_eclipse_swt_graphics_Rectangle() { - // intermittently fails on XP for reasons unknown, comment out the test case - // until the problem is figured out -// Canvas canvas = new Canvas(shell, SWT.BORDER); -// shell.setSize(110,110); -// canvas.setSize(100,100); -// shell.open(); -// GC testGc = new GC(canvas); -// testGc.setClipping(new Rectangle(0,5,10,20)); -// Rectangle rect = testGc.getClipping(); -// assertTrue(rect.x == 0); -// assertTrue(rect.y == 5); -// assertTrue(rect.width == 10); -// assertTrue(rect.height == 20); -// testGc.dispose(); -// canvas.dispose(); + gc.setClipping(new Rectangle(0,5,10,20)); + Rectangle rect = gc.getClipping(); + assertAll( + () -> assertEquals(0,rect.x), + () -> assertEquals(5, rect.y), + () -> assertEquals(10,rect.width), + () -> assertEquals(20,rect.height)); +} + +@Test +public void test_setClippingLorg_eclipse_swt_graphics_Path_withTransform() { + Transform t = new Transform(gc.getDevice()); + t.scale(1.5f,0.5f); + t.translate(-5,-25); + + Path p = new Path(gc.getDevice()); + p.addRectangle(0, 5, 10, 20); + + gc.setClipping(p); + p.dispose(); + gc.setTransform(t); + t.dispose(); + + Rectangle rect = gc.getClipping(); + assertAll( + () -> assertEquals(5,rect.x), + () -> assertEquals(35, rect.y), + () -> assertEquals(7,rect.width), + () -> assertEquals(40,rect.height)); + + t.dispose(); +} + +@Test +public void test_setClippingLorg_eclipse_swt_graphics_Path() { + Path p = new Path(gc.getDevice()); + p.addRectangle(0, 5, 10, 20); + gc.setClipping(p); + p.dispose(); + Rectangle rect = gc.getClipping(); + assertAll( + () -> assertEquals(0,rect.x), + () -> assertEquals(5, rect.y), + () -> assertEquals(10,rect.width), + () -> assertEquals(20,rect.height)); } @Test