From 7290adbd307a6dad2bea6a0c27d19e547d755962 Mon Sep 17 00:00:00 2001 From: Andreas Koch Date: Tue, 25 Feb 2025 17:15:16 +0100 Subject: [PATCH] [win32] Dynamic handle creation for region This commit refactors Region in the win32 implementation to better support multiple handles for different zoom settings by creating all handles only on demand. --- .../org/eclipse/swt/graphics/Region.java | 158 ++++++++++-------- 1 file changed, 89 insertions(+), 69 deletions(-) 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 baf6cade1ae..e0c072c3b72 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 @@ -37,12 +37,12 @@ */ public final class Region extends Resource { - private int initialZoom; - - private HashMap zoomToHandle = new HashMap<>(); + private Map zoomToHandle = new HashMap<>(); private List operations = new ArrayList<>(); + private boolean isDestroyed; + /** * Constructs a new empty region. *

@@ -80,9 +80,6 @@ public Region () { */ public Region (Device device) { super(device); - initialZoom = DPIUtil.getDeviceZoom(); - long handle = newEmptyRegionHandle(); - zoomToHandle.put(initialZoom, handle); init(); this.device.registerResourceWithZoomSupport(this); } @@ -173,8 +170,10 @@ 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); - final Operation operation = new OperationWithRegion(Operation::add, region); - storeAndApplyOperationForAllHandles(operation); + if (!region.operations.isEmpty()) { + final Operation operation = new OperationWithRegion(Operation::add, region.operations); + storeAndApplyOperationForAllHandles(operation); + } } /** @@ -192,11 +191,16 @@ public void add (Region region) { */ public boolean contains (int x, int y) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); - return containsInPixels(DPIUtil.scaleUp(x, initialZoom), DPIUtil.scaleUp(y, initialZoom)); + return applyUsingAnyHandle(regionHandle -> { + int zoom = regionHandle.zoom(); + int xInPixels = DPIUtil.scaleUp(x, zoom); + int yInPixels = DPIUtil.scaleUp(y, zoom); + return containsInPixels(regionHandle.handle(), xInPixels, yInPixels); + }); } -boolean containsInPixels (int x, int y) { - return OS.PtInRegion (getHandleForInitialZoom(), x, y); +boolean containsInPixels (long handle, int x, int y) { + return OS.PtInRegion (handle, x, y); } /** @@ -217,24 +221,28 @@ 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); - Point p = DPIUtil.scaleUp(pt, initialZoom); - return containsInPixels(p.x, p.y); + return applyUsingAnyHandle(regionHandle -> { + int zoom = regionHandle.zoom(); + Point p = DPIUtil.scaleUp(pt, zoom); + return containsInPixels(regionHandle.handle(), p.x, p.y); + }); } @Override void destroy () { device.deregisterResourceWithZoomSupport(this); - zoomToHandle.values().forEach(handle -> OS.DeleteObject(handle)); + zoomToHandle.values().forEach(RegionHandle::destroy); zoomToHandle.clear(); operations.clear(); + this.isDestroyed = true; } @Override void destroyHandlesExcept(Set zoomLevels) { zoomToHandle.entrySet().removeIf(entry -> { final Integer zoom = entry.getKey(); - if (!zoomLevels.contains(zoom) && zoom != initialZoom) { - OS.DeleteObject(entry.getValue()); + if (!zoomLevels.contains(zoom)) { + entry.getValue().destroy(); return true; } return false; @@ -271,12 +279,14 @@ public boolean equals (Object object) { */ public Rectangle getBounds () { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); - return DPIUtil.scaleDown(getBoundsInPixels(), initialZoom); + return applyUsingAnyHandle(regionHandle -> { + return DPIUtil.scaleDown(getBoundsInPixels(regionHandle.handle()), regionHandle.zoom()); + }); } -Rectangle getBoundsInPixels() { +private Rectangle getBoundsInPixels(long handle) { RECT rect = new RECT(); - OS.GetRgnBox(getHandleForInitialZoom(), rect); + OS.GetRgnBox(handle, rect); return new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); } @@ -294,7 +304,6 @@ Rectangle getBoundsInPixels() { public int hashCode () { return super.hashCode(); } - /** * Intersects the given rectangle to the collection of polygons * the receiver maintains to describe its area. @@ -363,8 +372,10 @@ 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); - final Operation operation = new OperationWithRegion(Operation::intersect, region); - storeAndApplyOperationForAllHandles(operation); + if (!region.operations.isEmpty()) { + final Operation operation = new OperationWithRegion(Operation::intersect, region.operations); + storeAndApplyOperationForAllHandles(operation); + } } /** @@ -389,10 +400,10 @@ public boolean intersects (int x, int y, int width, int height) { return intersects(new Rectangle(x, y, width, height)); } -boolean intersectsInPixels (int x, int y, int width, int height) { +boolean intersectsInPixels (long handle, int x, int y, int width, int height) { RECT r = new RECT (); OS.SetRect (r, x, y, x + width, y + height); - return OS.RectInRegion (getHandleForInitialZoom(), r); + return OS.RectInRegion(handle, r); } /** @@ -415,8 +426,10 @@ 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); - Rectangle r = DPIUtil.scaleUp(rect, initialZoom); - return intersectsInPixels(r.x, r.y, r.width, r.height); + return applyUsingAnyHandle(regionHandle -> { + Rectangle r = DPIUtil.scaleUp(rect, regionHandle.zoom()); + return intersectsInPixels(regionHandle.handle(), r.x, r.y, r.width, r.height); + }); } /** @@ -431,7 +444,7 @@ public boolean intersects (Rectangle rect) { */ @Override public boolean isDisposed() { - return zoomToHandle.isEmpty(); + return isDestroyed; } /** @@ -448,9 +461,11 @@ public boolean isDisposed() { public boolean isEmpty () { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); RECT rect = new RECT (); - int result = OS.GetRgnBox (getHandleForInitialZoom(), rect); - if (result == OS.NULLREGION) return true; - return ((rect.right - rect.left) <= 0) || ((rect.bottom - rect.top) <= 0); + return applyUsingAnyHandle(regionHandle -> { + int result = OS.GetRgnBox(regionHandle.handle(), rect); + if (result == OS.NULLREGION) return true; + return ((rect.right - rect.left) <= 0) || ((rect.bottom - rect.top) <= 0); + }); } /** @@ -543,8 +558,10 @@ 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); - final Operation operation = new OperationWithRegion(Operation::subtract, region); - storeAndApplyOperationForAllHandles(operation); + if (!region.operations.isEmpty()) { + final Operation operation = new OperationWithRegion(Operation::subtract, region.operations); + storeAndApplyOperationForAllHandles(operation); + } } /** @@ -588,36 +605,43 @@ public void translate (Point pt) { storeAndApplyOperationForAllHandles(operation); } -private long getHandleForInitialZoom() { - return win32_getHandle(this, initialZoom); -} - private void storeAndApplyOperationForAllHandles(Operation operation) { operations.add(operation); - zoomToHandle.forEach((zoom, handle) -> operation.apply(handle, zoom)); + zoomToHandle.forEach((zoom, handle) -> operation.apply(handle)); +} + +private T applyUsingAnyHandle(Function function) { + if (zoomToHandle.isEmpty()) { + return applyUsingTemporaryHandle(device.getDeviceZoom(), operations, function); + } + return function.apply(zoomToHandle.values().iterator().next()); } -private static T applyUsingTemporaryHandle(int zoom, List operations, Function function) { - long temporaryHandle = newRegionHandle(operations, zoom); +private static T applyUsingTemporaryHandle(int zoom, List operations, Function function) { + RegionHandle temporaryHandle = newRegionHandle(zoom, operations); try { return function.apply(temporaryHandle); } finally { - OS.DeleteObject(temporaryHandle); + temporaryHandle.destroy(); } } -private static long newEmptyRegionHandle() { +private static RegionHandle newRegionHandle(int zoom, List operations) { long newHandle = OS.CreateRectRgn (0, 0, 0, 0); if (newHandle == 0) SWT.error(SWT.ERROR_NO_HANDLES); - return newHandle; + RegionHandle newRegionHandle = new RegionHandle(newHandle, zoom); + for (Operation operation : operations) { + operation.apply(newRegionHandle); + } + return newRegionHandle; } -private static long newRegionHandle(List operations, int zoom) { - long newHandle = newEmptyRegionHandle(); - for (Operation operation : operations) { - operation.apply(newHandle, zoom); +private RegionHandle getRegionHandle(int zoom) { + if (!zoomToHandle.containsKey(zoom)) { + RegionHandle regionHandle = newRegionHandle(zoom, operations); + zoomToHandle.put(zoom, regionHandle); } - return newHandle; + return zoomToHandle.get(zoom); } /** @@ -638,14 +662,7 @@ private static long newRegionHandle(List operations, int zoom) { * @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 = newEmptyRegionHandle(); - for (Operation operation : region.operations) { - operation.apply(handle, zoom); - } - region.zoomToHandle.put(zoom, handle); - } - return region.zoomToHandle.get(zoom); + return region.getRegionHandle(zoom).handle(); } /** @@ -660,20 +677,26 @@ public String toString () { return "Region {" + zoomToHandle.entrySet().stream().map(entry -> entry.getValue() + "(zoom:" + entry.getKey() + ")").collect(Collectors.joining(",")); } +private record RegionHandle(long handle, int zoom) { + void destroy() { + OS.DeleteObject(handle()); + } +} + @FunctionalInterface private interface OperationStrategy { void apply(Operation operation, long handle, int zoom); } private abstract static class Operation { - private OperationStrategy operationStrategy; + private final OperationStrategy operationStrategy; Operation(OperationStrategy operationStrategy) { this.operationStrategy = operationStrategy; } - void apply(long handle, int zoom) { - operationStrategy.apply(this, handle, zoom); + void apply(RegionHandle regionHandle) { + operationStrategy.apply(this, regionHandle.handle(), regionHandle.zoom()); } abstract void add(long handle, int zoom); @@ -686,8 +709,7 @@ void apply(long handle, int zoom) { } private static class OperationWithRectangle extends Operation { - - Rectangle data; + private final Rectangle data; OperationWithRectangle(OperationStrategy operationStrategy, Rectangle data) { super(operationStrategy); @@ -745,8 +767,7 @@ private Rectangle getScaledRectangle(int zoom) { } private static class OperationWithArray extends Operation { - - int[] data; + private final int[] data; public OperationWithArray(OperationStrategy operationStrategy, int[] data) { super(operationStrategy); @@ -793,8 +814,7 @@ private int[] getScaledPoints(int zoom) { } private static class OperationWithPoint extends Operation { - - Point data; + private final Point data; public OperationWithPoint(OperationStrategy operationStrategy, Point data) { super(operationStrategy); @@ -827,29 +847,29 @@ void translate(long handle, int zoom) { private static class OperationWithRegion extends Operation { private final List operations; - OperationWithRegion(OperationStrategy operationStrategy, Region data) { + OperationWithRegion(OperationStrategy operationStrategy, List operations) { super(operationStrategy); - this.operations = data.operations; + this.operations = List.copyOf(operations); } @Override void add(long handle, int zoom) { applyUsingTemporaryHandle(zoom, operations, regionHandle -> { - return OS.CombineRgn (handle, handle, regionHandle, OS.RGN_OR); + return OS.CombineRgn (handle, handle, regionHandle.handle(), OS.RGN_OR); }); } @Override void subtract(long handle, int zoom) { applyUsingTemporaryHandle(zoom, operations, regionHandle -> { - return OS.CombineRgn (handle, handle, regionHandle, OS.RGN_DIFF); + return OS.CombineRgn (handle, handle, regionHandle.handle(), OS.RGN_DIFF); }); } @Override void intersect(long handle, int zoom) { applyUsingTemporaryHandle(zoom, operations, regionHandle -> { - return OS.CombineRgn (handle, handle, regionHandle, OS.RGN_AND); + return OS.CombineRgn (handle, handle, regionHandle.handle(), OS.RGN_AND); }); }