Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimeon Andreev2019-05-21 06:30:43 -0400
committerSimeon Andreev2019-06-12 10:13:35 -0400
commit73ef71fcbec0f8c22797049437f4824612ef3a64 (patch)
treed6f8790464f7f5d5c87678f5be2d678629f4af3b
parenta09fd5ce015e751c6e1b365e563e6cba8a65fa3d (diff)
downloadeclipse.platform.swt-73ef71fcbec0f8c22797049437f4824612ef3a64.tar.gz
eclipse.platform.swt-73ef71fcbec0f8c22797049437f4824612ef3a64.tar.xz
eclipse.platform.swt-73ef71fcbec0f8c22797049437f4824612ef3a64.zip
Bug 545226 - [GTK3] GC transforms don't affect GC.getClipping()
Changes done to fix bug 531667 and follow-up problems introduce a regression. Namely, the result of GC.getClipping() is incorrect. Drawing is correct, but the bounds returned by GC.getClipping() are not affected by transformations set by the user on the GC object. This is not consistent with previous behaviour and with behaviour on other platforms (e.g. Windows 10). This change re-adds the necessary transformations, in order to have a consistent GC.getClipping() result. A snippet is added that showcases the problem. Change-Id: I33b06bb8338215f52cb02d248564b792a750067e Signed-off-by: Simeon Andreev <simeon.danailov.andreev@gmail.com>
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/GC.java55
-rw-r--r--tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug545226_GC_getClipping_is_wrong.java123
2 files changed, 177 insertions, 1 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/GC.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/GC.java
index 61386eda38..a841d7e07a 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/GC.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/GC.java
@@ -13,6 +13,8 @@
*******************************************************************************/
package org.eclipse.swt.graphics;
+import java.util.*;
+
import org.eclipse.swt.*;
import org.eclipse.swt.internal.*;
import org.eclipse.swt.internal.cairo.*;
@@ -2054,7 +2056,53 @@ Rectangle getClippingInPixels() {
if (clipRgn != 0) {
/* Convert clipping to device space if needed */
if (data.clippingTransform != null && GTK.GTK_VERSION < OS.VERSION (3, 14, 0)) {
- clipRgn = convertRgn(clipRgn, data.clippingTransform);
+ clipRgn = convertRgn(clipRgn, data.clippingTransform);
+ Cairo.cairo_region_intersect(rgn, clipRgn);
+ Cairo.cairo_region_destroy(clipRgn);
+ } else if (!Arrays.equals(data.clippingTransform, currentTransform) && GTK.GTK_VERSION >= OS.VERSION (3, 14, 0)) {
+ double[] clippingTransform;
+ if (currentTransform != null && data.clippingTransform == null) {
+ /*
+ * User actions in this case are:
+ * 1. Set clipping.
+ * 2. Set a transformation B.
+ *
+ * The clipping was specified before transformation B was set.
+ * So to convert it to the new space, we just invert the transformation B.
+ */
+ clippingTransform = currentTransform.clone();
+ Cairo.cairo_matrix_invert(clippingTransform);
+ } else if (currentTransform != null && data.clippingTransform != null) {
+ /*
+ * User actions in this case are:
+ * 1. Set a transformation A.
+ * 2. Set clipping.
+ * 3. Set a different transformation B. This is global and wipes out transformation A.
+ *
+ * Since step 3. wipes out transformation A, we must apply A on the clipping rectangle to have
+ * the correct clipping rectangle after transformation A is wiped.
+ * Then, we apply the inverted transformation B on the resulting clipping,
+ * to convert it to the new space (which results after applying B).
+ */
+ clippingTransform = new double[6];
+ double[] invertedCurrentTransform = currentTransform.clone();
+ Cairo.cairo_matrix_invert(invertedCurrentTransform);
+ Cairo.cairo_matrix_multiply(clippingTransform, data.clippingTransform, invertedCurrentTransform);
+ } else {
+ /*
+ * User actions in this case are:
+ * 1. Set a transformation A.
+ * 2. Set clipping.
+ * 3. Wipe the transformation A (i.e. call GC.setTransformation(A)).
+ *
+ * We must apply transformation A on the clipping, to convert it to the new space.
+ */
+ clippingTransform = data.clippingTransform.clone();
+ }
+ long oldRgn = rgn;
+ rgn = convertRgn(rgn, clippingTransform);
+ Cairo.cairo_region_destroy(oldRgn);
+ clipRgn = convertRgn(clipRgn, clippingTransform);
Cairo.cairo_region_intersect(rgn, clipRgn);
Cairo.cairo_region_destroy(clipRgn);
} else {
@@ -3047,6 +3095,11 @@ void setClipping(long clipRgn) {
if (GTK.GTK_VERSION < OS.VERSION (3, 14, 0)) {
if (data.clippingTransform == null) data.clippingTransform = new double[6];
Cairo.cairo_get_matrix(cairo, data.clippingTransform);
+ } else if (currentTransform != null) {
+ // store the current transformation, to use it when the user requests clipping bounds
+ data.clippingTransform = currentTransform.clone();
+ } else {
+ data.clippingTransform = null;
}
setCairoClip(data.damageRgn, clipRgn);
}
diff --git a/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug545226_GC_getClipping_is_wrong.java b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug545226_GC_getClipping_is_wrong.java
new file mode 100644
index 0000000000..290333b36d
--- /dev/null
+++ b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug545226_GC_getClipping_is_wrong.java
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Simeon Andreev and others. All rights reserved.
+ * The contents of this file are made available under the terms
+ * of the GNU Lesser General Public License (LGPL) Version 2.1 that
+ * accompanies this distribution (lgpl-v21.txt). The LGPL is also
+ * available at http://www.gnu.org/licenses/lgpl.html. If the version
+ * of the LGPL at http://www.gnu.org is different to the version of
+ * the LGPL accompanying this distribution and there is any conflict
+ * between the two license versions, the terms of the LGPL accompanying
+ * this distribution shall govern.
+ *
+ * Contributors:
+ * Simeon Andreev - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.tests.gtk.snippets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.graphics.Device;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.graphics.Transform;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Description: {@link GC#getClipping()} returns wrong results when the user has set a transformation. Steps to reproduce:
+ * <ol>
+ * <li>Run the snippet.</li>
+ * <li>Observe {@link GC#getClipping()} states that the clipping starts at (10, 10), while it actually starts at (6, 18).</li>
+ * </ol>
+ * Expected results: The user specified and transformed clipping area is painted in dark red.
+ * The result of {@link GC#getClipping()} is painted in transparent red, the dark red area is bound by {@link GC#getClipping()}.
+ * The drawn text indicates the correct bounds of {@link GC#getClipping()} result.
+ * Actual results: Drawing is done correctly in regard of API, however
+ * the bounds returned by {@link GC#getClipping()} are incorrect, in particular the upper-left point is stated to be (10, 10).
+ */
+public class Bug545226_GC_getClipping_is_wrong {
+
+ public static void main(String[] args) {
+ Display display = new Display();
+ Shell shell = new Shell(display);
+ shell.setSize(600, 450);
+ shell.setText("Bug 545226 GC clipping is wrong");
+ shell.setLayout(new FillLayout());
+ Composite main = new Composite(shell, SWT.NONE);
+ main.setLayout(new FillLayout());
+
+ Composite[] squares = showCaseClipping(main);
+ for (Composite square : squares) {
+ square.layout();
+ }
+
+ shell.open();
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch())
+ display.sleep();
+ }
+ display.dispose();
+ }
+
+ private static Composite[] showCaseClipping(Composite main) {
+ Composite composite = new Composite(main, SWT.NONE);
+ composite.setLayout(new FillLayout());
+
+ Composite left = new Composite(composite, SWT.NONE);
+ left.setLayout(new FillLayout(SWT.VERTICAL));
+ Composite upperLeft = new Composite(left, SWT.BORDER);
+ Composite bottomLeft = new Composite(left, SWT.BORDER);
+
+ Composite right = new Composite(composite, SWT.NONE);
+ right.setLayout(new FillLayout(SWT.VERTICAL));
+ Composite upperRight = new Composite(right, SWT.BORDER);
+ Composite bottomRight = new Composite(right, SWT.BORDER);
+
+ Composite[] squares = { upperLeft, upperRight, bottomLeft, bottomRight };
+ for (int i = 0; i < squares.length; ++i) {
+ Composite square = squares[i];
+ square.setLayout(new FillLayout(SWT.VERTICAL));
+
+ Canvas canvas = new Canvas(square, SWT.BORDER);
+ PaintListener paint = new ShowCaseClipping();
+ canvas.addPaintListener(paint);
+ }
+
+ return squares;
+ }
+
+ private static class ShowCaseClipping implements PaintListener {
+
+ @Override
+ public void paintControl(PaintEvent event) {
+ GC gc = event.gc;
+ Device device = gc.getDevice();
+ Rectangle originalClipping = gc.getClipping();
+
+ Transform transform = new Transform(device);
+ transform.translate(10.f, 10.f);
+ transform.scale(0.8f, 0.8f);
+ transform.rotate(5.f);
+ gc.setTransform(transform);
+ gc.setClipping(10, 10, 225, 150);
+ gc.setTransform(null);
+
+ gc.setAlpha(155);
+ gc.setBackground(device.getSystemColor(SWT.COLOR_DARK_RED));
+ gc.fillRectangle(originalClipping);
+
+ Rectangle transformedClipping = gc.getClipping();
+ gc.setClipping(gc.getClipping());
+ gc.setBackground(device.getSystemColor(SWT.COLOR_DARK_RED));
+ gc.setAlpha(75);
+ gc.fillRectangle(transformedClipping);
+ gc.setBackground(device.getSystemColor(SWT.COLOR_GRAY));
+ gc.setAlpha(255);
+ gc.drawText(transformedClipping.toString(), 6, 18);
+ }
+ }
+} \ No newline at end of file

Back to the top