From 9598424a1d03a45468f7f2a139bfcb7121553260 Mon Sep 17 00:00:00 2001 From: Amartya Parijat Date: Mon, 15 Apr 2024 13:40:58 +0200 Subject: [PATCH] Multi Zoom Support for region for win32 This commit adds the feature of scaling region based on the zoom level of the monitor it is drawn on. The mentioned functionality is attained by using a map to maintain the handle of the region scale as per zoom level. The handle can then be obtained by the method win32_getHandle by passing the zoom information from the client. The region object stores a history of all the operations performed on it so that it can be used to create handles for different zoom level. Additionally, this commit removes the public handle field from Region for win32 since it is now replaced by win32_getHandle method for the clients and internally the class uses a hashMap zoomToHandle to get the handle for the particular zoomlevel. The default handle is stored in zoomToHandle mapped to the initialZoom. contributes #62 and #127 --- .../swt/graphics/RegionWin32Tests.java | 52 +++ .../win32/org/eclipse/swt/graphics/GC.java | 16 +- .../org/eclipse/swt/graphics/Region.java | 371 ++++++++++++++---- .../org/eclipse/swt/widgets/Control.java | 5 +- .../Test_org_eclipse_swt_widgets_Shell.java | 4 +- 5 files changed, 351 insertions(+), 97 deletions(-) create mode 100644 bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/graphics/RegionWin32Tests.java diff --git a/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/graphics/RegionWin32Tests.java b/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/graphics/RegionWin32Tests.java new file mode 100644 index 00000000000..48f68684b36 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/graphics/RegionWin32Tests.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2024 Yatta Solutions + * + * 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: + * Yatta Solutions - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.graphics; + +import static org.junit.Assert.assertEquals; + +import org.eclipse.swt.internal.*; +import org.eclipse.swt.internal.win32.*; +import org.junit.jupiter.api.*; + +class RegionWin32Tests extends Win32AutoscaleTestBase { + + @Test + public void testRegionMustBeScaledOnHandleOfScaledZoomLevel() { + int zoom = DPIUtil.getDeviceZoom(); + int scalingFactor = 2; + + Region region = new Region(display); + region.add(0, 0, 5, 10); + region.subtract(0,0,1,1); + region.translate(0, 5); + region.intersect(1,1,1,1); + + long handle = Region.win32_getHandle(region, zoom); + long scaledRegionHandle = Region.win32_getHandle(region, zoom * scalingFactor); + + RECT rect = new RECT(); + OS.GetRgnBox(handle, rect); + Rectangle bounds = new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); + + rect = new RECT(); + OS.GetRgnBox(scaledRegionHandle, rect); + Rectangle scaledBounds = new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); + + assertEquals("scaled region's height should be double of unscaled region", bounds.height * scalingFactor, scaledBounds.height); + assertEquals("scaled region's width should be double of unscaled region", bounds.width * scalingFactor, scaledBounds.width); + assertEquals("scaled region's x position should be double of unscaled region", bounds.x * scalingFactor, scaledBounds.x); + assertEquals("scaled region's y position should be double of unscaled region", bounds.y * scalingFactor, scaledBounds.y); + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java index 0f5b0aed74b..7bcde04a888 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java @@ -3386,7 +3386,7 @@ public void getClipping (Region region) { Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeNone); Gdip.Graphics_GetVisibleClipBounds(gdipGraphics, rect); Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeHalf); - OS.SetRectRgn(region.handle, rect.X, rect.Y, rect.X + rect.Width, rect.Y + rect.Height); + OS.SetRectRgn(Region.win32_getHandle(region, getZoom()), rect.X, rect.Y, rect.X + rect.Width, rect.Y + rect.Height); } else { long matrix = Gdip.Matrix_new(1, 0, 0, 1, 0, 0); long identity = Gdip.Matrix_new(1, 0, 0, 1, 0, 0); @@ -3399,7 +3399,7 @@ public void getClipping (Region region) { POINT pt = new POINT (); OS.GetWindowOrgEx (handle, pt); OS.OffsetRgn (hRgn, pt.x, pt.y); - OS.CombineRgn(region.handle, hRgn, 0, OS.RGN_COPY); + OS.CombineRgn(Region.win32_getHandle(region, getZoom()), hRgn, 0, OS.RGN_COPY); OS.DeleteObject(hRgn); } Gdip.Region_delete(rgn); @@ -3407,18 +3407,18 @@ public void getClipping (Region region) { } POINT pt = new POINT (); OS.GetWindowOrgEx (handle, pt); - int result = OS.GetClipRgn (handle, region.handle); + int result = OS.GetClipRgn (handle, Region.win32_getHandle(region, getZoom())); if (result != 1) { RECT rect = new RECT(); OS.GetClipBox(handle, rect); - OS.SetRectRgn(region.handle, rect.left, rect.top, rect.right, rect.bottom); + OS.SetRectRgn(Region.win32_getHandle(region, getZoom()), rect.left, rect.top, rect.right, rect.bottom); } else { - OS.OffsetRgn (region.handle, pt.x, pt.y); + OS.OffsetRgn (Region.win32_getHandle(region, getZoom()), pt.x, pt.y); } long metaRgn = OS.CreateRectRgn (0, 0, 0, 0); if (OS.GetMetaRgn (handle, metaRgn) != 0) { OS.OffsetRgn (metaRgn, pt.x, pt.y); - OS.CombineRgn (region.handle, metaRgn, region.handle, OS.RGN_AND); + OS.CombineRgn (Region.win32_getHandle(region, getZoom()), metaRgn, Region.win32_getHandle(region, getZoom()), OS.RGN_AND); } OS.DeleteObject(metaRgn); long hwnd = data.hwnd; @@ -3435,7 +3435,7 @@ public void getClipping (Region region) { } OS.MapWindowPoints (0, hwnd, pt, 1); OS.OffsetRgn (sysRgn, pt.x, pt.y); - OS.CombineRgn (region.handle, sysRgn, region.handle, OS.RGN_AND); + OS.CombineRgn (Region.win32_getHandle(region, getZoom()), sysRgn, Region.win32_getHandle(region, getZoom()), OS.RGN_AND); } OS.DeleteObject(sysRgn); } @@ -4374,7 +4374,7 @@ public void setClipping (Rectangle rect) { public void setClipping (Region region) { if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (region != null && region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); - setClipping(region != null ? region.handle : 0); + setClipping(region != null ? Region.win32_getHandle(region, getZoom()) : 0); } /** diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Region.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Region.java index 636c311536e..74398cd8deb 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Region.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Region.java @@ -14,6 +14,8 @@ package org.eclipse.swt.graphics; +import java.util.*; + import org.eclipse.swt.*; import org.eclipse.swt.internal.*; import org.eclipse.swt.internal.win32.*; @@ -33,19 +35,11 @@ */ public final class Region extends Resource { - /** - * the OS resource for the region - * (Warning: This field is platform dependent) - *

- * IMPORTANT: This field is not part of the SWT - * public API. It is marked public only so that it can be shared - * within the packages provided by SWT. It is not available on all - * platforms and should never be accessed from application code. - *

- * - * @noreference This field is not intended to be referenced by clients. - */ - public long handle; + private int initialZoom; + + private HashMap zoomToHandle = new HashMap<>(); + + private List operations = new ArrayList<>(); /** * Constructs a new empty region. @@ -84,7 +78,9 @@ public Region () { */ public Region (Device device) { super(device); - handle = OS.CreateRectRgn (0, 0, 0, 0); + initialZoom = DPIUtil.getDeviceZoom(); + long handle = OS.CreateRectRgn (0, 0, 0, 0); + zoomToHandle.put(initialZoom, handle); if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); init(); } @@ -107,13 +103,8 @@ public Region (Device device) { public void add (int[] pointArray) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - addInPixels(DPIUtil.autoScaleUp(pointArray)); -} - -void addInPixels (int[] pointArray) { - long polyRgn = OS.CreatePolygonRgn(pointArray, pointArray.length / 2, OS.ALTERNATE); - OS.CombineRgn (handle, handle, polyRgn, OS.RGN_OR); - OS.DeleteObject (polyRgn); + final Operation operation = new OperationWithArray(Operation::add, Arrays.copyOf(pointArray, pointArray.length)); + storeAndApplyOperationForAllHandles(operation); } /** @@ -133,8 +124,8 @@ void addInPixels (int[] pointArray) { public void add (Rectangle rect) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - rect = DPIUtil.autoScaleUp(rect); - addInPixels(rect.x, rect.y, rect.width, rect.height); + final Operation operation = new OperationWithRectangle(Operation::add, new Rectangle(rect.x, rect.y, rect.width, rect.height)); + storeAndApplyOperationForAllHandles(operation); } /** @@ -157,14 +148,8 @@ public void add (Rectangle rect) { */ public void add (int x, int y, int width, int height) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); - addInPixels(DPIUtil.autoScaleUp(x), DPIUtil.autoScaleUp(y), DPIUtil.autoScaleUp(width), DPIUtil.autoScaleUp(height)); -} - -void addInPixels (int x, int y, int width, int height) { - if (width < 0 || height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); - long rectRgn = OS.CreateRectRgn (x, y, x + width, y + height); - OS.CombineRgn (handle, handle, rectRgn, OS.RGN_OR); - OS.DeleteObject (rectRgn); + final Operation operation = new OperationWithRectangle(Operation::add, new Rectangle(x, y, width, height)); + storeAndApplyOperationForAllHandles(operation); } /** @@ -186,7 +171,8 @@ public void add (Region region) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (region == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); if (region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); - OS.CombineRgn (handle, handle, region.handle, OS.RGN_OR); + final Operation operation = new OperationWithRegion(Operation::add, region); + storeAndApplyOperationForAllHandles(operation); } /** @@ -204,11 +190,11 @@ public void add (Region region) { */ public boolean contains (int x, int y) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); - return containsInPixels(DPIUtil.autoScaleUp(x), DPIUtil.autoScaleUp(y)); + return containsInPixels(DPIUtil.autoScaleUp(x, initialZoom), DPIUtil.autoScaleUp(y, initialZoom)); } boolean containsInPixels (int x, int y) { - return OS.PtInRegion (handle, x, y); + return OS.PtInRegion (win32_getHandle(this, initialZoom), x, y); } /** @@ -229,14 +215,15 @@ boolean containsInPixels (int x, int y) { public boolean contains (Point pt) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (pt == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - pt = DPIUtil.autoScaleUp(pt); - return containsInPixels(pt.x, pt.y); + Point p = DPIUtil.autoScaleUp(pt, initialZoom); + return containsInPixels(p.x, p.y); } @Override void destroy () { - OS.DeleteObject(handle); - handle = 0; + zoomToHandle.values().forEach(handle -> OS.DeleteObject(handle)); + zoomToHandle.clear(); + operations.clear(); } /** @@ -254,7 +241,7 @@ public boolean equals (Object object) { if (this == object) return true; if (!(object instanceof Region)) return false; Region rgn = (Region)object; - return handle == rgn.handle; + return win32_getHandle(this, initialZoom) == win32_getHandle(rgn, initialZoom); } /** @@ -272,12 +259,12 @@ public boolean equals (Object object) { */ public Rectangle getBounds () { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); - return DPIUtil.autoScaleDown(getBoundsInPixels()); + return DPIUtil.scaleDown(getBoundsInPixels(), initialZoom); } Rectangle getBoundsInPixels() { RECT rect = new RECT(); - OS.GetRgnBox(handle, rect); + OS.GetRgnBox(win32_getHandle(this, initialZoom), rect); return new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); } @@ -293,7 +280,7 @@ Rectangle getBoundsInPixels() { */ @Override public int hashCode () { - return (int)handle; + return (int)win32_getHandle(this, initialZoom); } /** @@ -315,8 +302,8 @@ public int hashCode () { public void intersect (Rectangle rect) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - rect = DPIUtil.autoScaleUp(rect); - intersectInPixels(rect.x, rect.y, rect.width, rect.height); + final Operation operation = new OperationWithRectangle(Operation::intersect, new Rectangle(rect.x, rect.y, rect.width, rect.height)); + storeAndApplyOperationForAllHandles(operation); } /** @@ -339,15 +326,9 @@ public void intersect (Rectangle rect) { */ public void intersect (int x, int y, int width, int height) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); - intersectInPixels(DPIUtil.autoScaleUp(x), DPIUtil.autoScaleUp(y), DPIUtil.autoScaleUp(width), DPIUtil.autoScaleUp(height)); -} - -void intersectInPixels (int x, int y, int width, int height) { - if (width < 0 || height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); - long rectRgn = OS.CreateRectRgn (x, y, x + width, y + height); - OS.CombineRgn (handle, handle, rectRgn, OS.RGN_AND); - OS.DeleteObject (rectRgn); -} + final Operation operation = new OperationWithRectangle(Operation::intersect, new Rectangle(x, y, width, height)); + storeAndApplyOperationForAllHandles(operation); + } /** * Intersects all of the polygons which make up the area covered @@ -370,7 +351,8 @@ public void intersect (Region region) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (region == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); if (region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); - OS.CombineRgn (handle, handle, region.handle, OS.RGN_AND); + final Operation operation = new OperationWithRegion(Operation::intersect, region); + storeAndApplyOperationForAllHandles(operation); } /** @@ -392,13 +374,13 @@ public void intersect (Region region) { */ public boolean intersects (int x, int y, int width, int height) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); - return intersectsInPixels(DPIUtil.autoScaleUp(x), DPIUtil.autoScaleUp(y), DPIUtil.autoScaleUp(width), DPIUtil.autoScaleUp(height)); + return intersectsInPixels(DPIUtil.autoScaleUp(x, initialZoom), DPIUtil.autoScaleUp(y, initialZoom), DPIUtil.autoScaleUp(width, initialZoom), DPIUtil.autoScaleUp(height, initialZoom)); } boolean intersectsInPixels (int x, int y, int width, int height) { RECT r = new RECT (); OS.SetRect (r, x, y, x + width, y + height); - return OS.RectInRegion (handle, r); + return OS.RectInRegion (win32_getHandle(this, initialZoom), r); } /** @@ -421,8 +403,8 @@ boolean intersectsInPixels (int x, int y, int width, int height) { public boolean intersects (Rectangle rect) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - rect = DPIUtil.autoScaleUp(rect); - return intersectsInPixels(rect.x, rect.y, rect.width, rect.height); + Rectangle r = DPIUtil.autoScaleUp(rect, initialZoom); + return intersectsInPixels(r.x, r.y, r.width, r.height); } /** @@ -437,7 +419,7 @@ public boolean intersects (Rectangle rect) { */ @Override public boolean isDisposed() { - return handle == 0; + return zoomToHandle.isEmpty(); } /** @@ -454,7 +436,7 @@ public boolean isDisposed() { public boolean isEmpty () { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); RECT rect = new RECT (); - int result = OS.GetRgnBox (handle, rect); + int result = OS.GetRgnBox (win32_getHandle(this, initialZoom), rect); if (result == OS.NULLREGION) return true; return ((rect.right - rect.left) <= 0) || ((rect.bottom - rect.top) <= 0); } @@ -477,13 +459,8 @@ public boolean isEmpty () { public void subtract (int[] pointArray) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - subtractInPixels(DPIUtil.autoScaleUp(pointArray)); -} - -void subtractInPixels (int[] pointArray) { - long polyRgn = OS.CreatePolygonRgn(pointArray, pointArray.length / 2, OS.ALTERNATE); - OS.CombineRgn (handle, handle, polyRgn, OS.RGN_DIFF); - OS.DeleteObject (polyRgn); + final Operation operation = new OperationWithArray(Operation::subtract, Arrays.copyOf(pointArray, pointArray.length)); + storeAndApplyOperationForAllHandles(operation); } /** @@ -505,8 +482,8 @@ void subtractInPixels (int[] pointArray) { public void subtract (Rectangle rect) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - rect = DPIUtil.autoScaleUp(rect); - subtractInPixels(rect.x, rect.y, rect.width, rect.height); + final Operation operation = new OperationWithRectangle(Operation::subtract, new Rectangle(rect.x, rect.y, rect.width, rect.height)); + storeAndApplyOperationForAllHandles(operation); } /** @@ -529,14 +506,8 @@ public void subtract (Rectangle rect) { */ public void subtract (int x, int y, int width, int height) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); - subtractInPixels(DPIUtil.autoScaleUp(x), DPIUtil.autoScaleUp(y), DPIUtil.autoScaleUp(width), DPIUtil.autoScaleUp(height)); -} - -void subtractInPixels (int x, int y, int width, int height) { - if (width < 0 || height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); - long rectRgn = OS.CreateRectRgn (x, y, x + width, y + height); - OS.CombineRgn (handle, handle, rectRgn, OS.RGN_DIFF); - OS.DeleteObject (rectRgn); + final Operation operation = new OperationWithRectangle(Operation::subtract, new Rectangle(x, y, width, height)); + storeAndApplyOperationForAllHandles(operation); } /** @@ -560,7 +531,8 @@ public void subtract (Region region) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (region == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); if (region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); - OS.CombineRgn (handle, handle, region.handle, OS.RGN_DIFF); + final Operation operation = new OperationWithRegion(Operation::subtract, region); + storeAndApplyOperationForAllHandles(operation); } /** @@ -578,11 +550,8 @@ public void subtract (Region region) { */ public void translate (int x, int y) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); - translateInPixels(DPIUtil.autoScaleUp(x), DPIUtil.autoScaleUp(y)); -} - -void translateInPixels (int x, int y) { - OS.OffsetRgn (handle, x, y); + final Operation operation = new OperationWithPoint(Operation::translate, new Point(x, y)); + storeAndApplyOperationForAllHandles(operation); } /** @@ -603,8 +572,41 @@ void translateInPixels (int x, int y) { public void translate (Point pt) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (pt == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - pt = DPIUtil.autoScaleUp(pt); - translateInPixels(pt.x, pt.y); + final Operation operation = new OperationWithPoint(Operation::translate, new Point(pt.x, pt.y)); + storeAndApplyOperationForAllHandles(operation); +} + +private void storeAndApplyOperationForAllHandles(Operation operation) { + operations.add(operation); + zoomToHandle.forEach((zoom, handle) -> operation.apply(handle, zoom)); +} + +/** + * IMPORTANT: This method is not part of the public + * API for Image. It is marked public only so that it + * can be shared within the packages provided by SWT. It is not + * available on all platforms, and should never be called from + * application code. + * + * Gets the handle for the region scaled at required zoom level + * + * @param region the region to be scaled + * + * @param zoom the zoom level for which the region is needed + * + * @return the handle of the region scaled for the zoom level + * + * @noreference This method is not intended to be referenced by clients. + */ +public static long win32_getHandle(Region region, int zoom) { + if(!region.zoomToHandle.containsKey(zoom)) { + long handle = OS.CreateRectRgn(0, 0, 0, 0); + for(Operation operation : region.operations) { + operation.apply(handle, zoom); + } + region.zoomToHandle.put(zoom, handle); + } + return region.zoomToHandle.get(zoom); } /** @@ -616,7 +618,204 @@ public void translate (Point pt) { @Override public String toString () { if (isDisposed()) return "Region {*DISPOSED*}"; - return "Region {" + handle + "}"; + return "Region " + zoomToHandle; +} + +@FunctionalInterface +private interface OperationStrategy { + void apply(Operation operation, long handle, int zoom); +} + +abstract class Operation { + OperationStrategy operationStrategy; + + void apply(long handle, int zoom) { + operationStrategy.apply(this, handle, zoom); + } + + abstract void add(long handle, int zoom); + + abstract void subtract(long handle, int zoom); + + abstract void intersect(long handle, int zoom); + + abstract void translate(long handle, int zoom); } +private class OperationWithRectangle extends Operation { + + Rectangle data; + + OperationWithRectangle(OperationStrategy operationStrategy, Rectangle data) { + this.operationStrategy = operationStrategy; + this.data = data; + } + + @Override + void add(long handle, int zoom) { + Rectangle bounds = getScaledRectangle(zoom); + addInPixels(handle, bounds.x, bounds.y, bounds.width, bounds.height); + } + + @Override + void subtract(long handle, int zoom) { + Rectangle bounds = getScaledRectangle(zoom); + subtractInPixels(handle, bounds.x, bounds.y, bounds.width, bounds.height); + } + + @Override + void intersect(long handle, int zoom) { + Rectangle bounds = getScaledRectangle(zoom); + intersectInPixels(handle, bounds.x, bounds.y, bounds.width, bounds.height); + } + + @Override + void translate(long handle, int zoom) { + // No implementation required + } + + private void addInPixels (long handle, int x, int y, int width, int height) { + if (width < 0 || height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + long rectRgn = OS.CreateRectRgn (x, y, x + width, y + height); + OS.CombineRgn (handle, handle, rectRgn, OS.RGN_OR); + OS.DeleteObject (rectRgn); + } + + private void subtractInPixels (long handle, int x, int y, int width, int height) { + if (width < 0 || height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + long rectRgn = OS.CreateRectRgn (x, y, x + width, y + height); + OS.CombineRgn (handle, handle, rectRgn, OS.RGN_DIFF); + OS.DeleteObject (rectRgn); + } + + private void intersectInPixels (long handle, int x, int y, int width, int height) { + if (width < 0 || height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + long rectRgn = OS.CreateRectRgn (x, y, x + width, y + height); + OS.CombineRgn (handle, handle, rectRgn, OS.RGN_AND); + OS.DeleteObject (rectRgn); + } + + private Rectangle getScaledRectangle(int zoom) { + return DPIUtil.autoScaleUp(data, zoom); + } + +} + +private class OperationWithArray extends Operation { + + int[] data; + + public OperationWithArray(OperationStrategy operationStrategy, int[] data) { + this.operationStrategy = operationStrategy; + this.data = data; + } + + @Override + void add(long handle, int zoom) { + int[] points = getScaledPoints(zoom); + addInPixels(handle, points); + } + + @Override + void subtract(long handle, int zoom) { + int[] pointArray = getScaledPoints(zoom); + subtractInPixels(handle, pointArray); + } + + @Override + void intersect(long handle, int zoom) { + // No implementation required + } + + @Override + void translate(long handle, int zoom) { + // No implementation required + } + + private void addInPixels (long handle, int[] pointArray) { + long polyRgn = OS.CreatePolygonRgn(pointArray, pointArray.length / 2, OS.ALTERNATE); + OS.CombineRgn (handle, handle, polyRgn, OS.RGN_OR); + OS.DeleteObject (polyRgn); + } + + private void subtractInPixels (long handle, int[] pointArray) { + long polyRgn = OS.CreatePolygonRgn(pointArray, pointArray.length / 2, OS.ALTERNATE); + OS.CombineRgn (handle, handle, polyRgn, OS.RGN_DIFF); + OS.DeleteObject (polyRgn); + } + + private int[] getScaledPoints(int zoom) { + return DPIUtil.autoScaleUp(data, zoom); + } +} + +private class OperationWithPoint extends Operation { + + Point data; + + public OperationWithPoint(OperationStrategy operationStrategy, Point data) { + this.operationStrategy = operationStrategy; + this.data = data; + } + + @Override + void add(long handle, int zoom) { + // No implementation required + } + + @Override + void subtract(long handle, int zoom) { + // No implementation required + } + + @Override + void intersect(long handle, int zoom) { + // No implementation required + } + + @Override + void translate(long handle, int zoom) { + Point pt = DPIUtil.autoScaleUp((Point) data, zoom); + OS.OffsetRgn (handle, pt.x, pt.y); + } + +} + +private class OperationWithRegion extends Operation { + + Region data; + + OperationWithRegion(OperationStrategy operationStrategy, Region data) { + this.operationStrategy = operationStrategy; + this.data = data; + } + + @Override + void add(long handle, int zoom) { + long scaledHandle = getHandleForScaledRegion(zoom); + OS.CombineRgn (handle, handle, scaledHandle, OS.RGN_OR); + } + + @Override + void subtract(long handle, int zoom) { + long scaledHandle = getHandleForScaledRegion(zoom); + OS.CombineRgn (handle, handle, scaledHandle, OS.RGN_DIFF); + } + + @Override + void intersect(long handle, int zoom) { + long scaledHandle = getHandleForScaledRegion(zoom); + OS.CombineRgn (handle, handle, scaledHandle, OS.RGN_AND); + } + + @Override + void translate(long handle, int zoom) { + // No implementation required + } + + private long getHandleForScaledRegion(int zoom) { + if (data.isDisposed() || data == Region.this) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + return win32_getHandle(data, zoom); + } +} } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java index 944596751f7..9d71bd58ec7 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java @@ -3690,7 +3690,7 @@ public void setRegion (Region region) { long hRegion = 0; if (region != null) { hRegion = OS.CreateRectRgn (0, 0, 0, 0); - OS.CombineRgn (hRegion, region.handle, hRegion, OS.RGN_OR); + OS.CombineRgn (hRegion, Region.win32_getHandle(region, getZoom()), hRegion, OS.RGN_OR); } OS.SetWindowRgn (handle, hRegion, true); this.region = region; @@ -5815,6 +5815,9 @@ private static void handleDPIChange(Widget widget, int newZoom, float scalingFac control.setBackgroundImage(image); } } + if (control.getRegion() != null) { + control.setRegion(control.getRegion()); + } } private static void resizeFont(Control control, int newZoom) { diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Shell.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Shell.java index a900d17be0f..014ca3eeca9 100644 --- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Shell.java +++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Shell.java @@ -712,7 +712,7 @@ private void logUnlessEquals(Appendable log, String message, Rectangle expected, } } -//TODO This test was not hooked for running with the runTest override. It fails on GTK/Cocoa. Investigate. +@Test public void a_test_setRegion() { Region region = new Region(); region.add(new Rectangle(10, 20, 100, 200)); @@ -727,7 +727,7 @@ public void a_test_setRegion() { Shell shell2 = new Shell(display, SWT.NO_TRIM); assertNull(":d:", shell2.getRegion()); shell2.setRegion(region); - assertEquals(":e:", region.handle, shell2.getRegion().handle); + assertEquals(":e:", region, shell2.getRegion()); region.dispose(); assertTrue(":f:", shell2.getRegion().isDisposed()); shell2.setRegion(null);