Skip to content

Commit 95ce29b

Browse files
committed
[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.
1 parent 9f60279 commit 95ce29b

File tree

1 file changed

+93
-89
lines changed
  • bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics

1 file changed

+93
-89
lines changed

bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Region.java

Lines changed: 93 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616

1717
import java.util.*;
18+
import java.util.function.*;
1819
import java.util.stream.*;
1920

2021
import org.eclipse.swt.*;
@@ -36,12 +37,12 @@
3637
*/
3738
public final class Region extends Resource {
3839

39-
private int initialZoom;
40-
41-
private HashMap<Integer, Long> zoomToHandle = new HashMap<>();
40+
private Map<Integer, RegionHandle> zoomToHandle = new HashMap<>();
4241

4342
private List<Operation> operations = new ArrayList<>();
4443

44+
private boolean isDestroyed;
45+
4546
/**
4647
* Constructs a new empty region.
4748
* <p>
@@ -79,10 +80,6 @@ public Region () {
7980
*/
8081
public Region (Device device) {
8182
super(device);
82-
initialZoom = DPIUtil.getDeviceZoom();
83-
long handle = OS.CreateRectRgn (0, 0, 0, 0);
84-
zoomToHandle.put(initialZoom, handle);
85-
if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
8683
init();
8784
this.device.registerResourceWithZoomSupport(this);
8885
}
@@ -192,11 +189,16 @@ public void add (Region region) {
192189
*/
193190
public boolean contains (int x, int y) {
194191
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
195-
return containsInPixels(DPIUtil.scaleUp(x, initialZoom), DPIUtil.scaleUp(y, initialZoom));
192+
return applyOnAnyHandle(regionHandle -> {
193+
int zoom = regionHandle.zoom;
194+
int xInPixels = DPIUtil.scaleUp(x, zoom);
195+
int yInPixels = DPIUtil.scaleUp(y, zoom);
196+
return containsInPixels(regionHandle.handle, xInPixels, yInPixels);
197+
});
196198
}
197199

198-
boolean containsInPixels (int x, int y) {
199-
return OS.PtInRegion (getHandleForInitialZoom(), x, y);
200+
boolean containsInPixels (long handle, int x, int y) {
201+
return OS.PtInRegion (handle, x, y);
200202
}
201203

202204
/**
@@ -217,46 +219,27 @@ boolean containsInPixels (int x, int y) {
217219
public boolean contains (Point pt) {
218220
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
219221
if (pt == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
220-
Point p = DPIUtil.scaleUp(pt, initialZoom);
221-
return containsInPixels(p.x, p.y);
222+
return applyOnAnyHandle(regionHandle -> {
223+
int zoom = regionHandle.zoom;
224+
Point p = DPIUtil.scaleUp(pt, zoom);
225+
return containsInPixels(regionHandle.handle, p.x, p.y);
226+
});
222227
}
223228

224229
@Override
225230
void destroy () {
226231
device.deregisterResourceWithZoomSupport(this);
227-
zoomToHandle.values().forEach(handle -> OS.DeleteObject(handle));
232+
zoomToHandle.values().forEach(RegionHandle::destroy);
228233
zoomToHandle.clear();
229234
operations.clear();
235+
this.isDestroyed = true;
230236
}
231237

232238
@Override
233239
void destroyHandlesExcept(Set<Integer> zoomLevels) {
234-
zoomToHandle.entrySet().removeIf(entry -> {
235-
final Integer zoom = entry.getKey();
236-
if (!zoomLevels.contains(zoom) && zoom != initialZoom) {
237-
OS.DeleteObject(entry.getValue());
238-
return true;
239-
}
240-
return false;
241-
});
242-
}
243-
244-
/**
245-
* Compares the argument to the receiver, and returns true
246-
* if they represent the <em>same</em> object using a class
247-
* specific comparison.
248-
*
249-
* @param object the object to compare with this object
250-
* @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise
251-
*
252-
* @see #hashCode
253-
*/
254-
@Override
255-
public boolean equals (Object object) {
256-
if (this == object) return true;
257-
if (!(object instanceof Region)) return false;
258-
Region rgn = (Region)object;
259-
return getHandleForInitialZoom() == rgn.getHandleForInitialZoom();
240+
// As long as we keep the operations, we can cleanup all handles
241+
zoomToHandle.values().forEach(RegionHandle::destroy);
242+
zoomToHandle.clear();
260243
}
261244

262245
/**
@@ -274,30 +257,17 @@ public boolean equals (Object object) {
274257
*/
275258
public Rectangle getBounds () {
276259
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
277-
return DPIUtil.scaleDown(getBoundsInPixels(), initialZoom);
260+
return applyOnAnyHandle(regionHandle -> {
261+
return DPIUtil.scaleDown(getBoundsInPixels(regionHandle.handle), regionHandle.zoom);
262+
});
278263
}
279264

280-
Rectangle getBoundsInPixels() {
265+
private Rectangle getBoundsInPixels(long handle) {
281266
RECT rect = new RECT();
282-
OS.GetRgnBox(getHandleForInitialZoom(), rect);
267+
OS.GetRgnBox(handle, rect);
283268
return new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
284269
}
285270

286-
/**
287-
* Returns an integer hash code for the receiver. Any two
288-
* objects that return <code>true</code> when passed to
289-
* <code>equals</code> must return the same value for this
290-
* method.
291-
*
292-
* @return the receiver's hash
293-
*
294-
* @see #equals
295-
*/
296-
@Override
297-
public int hashCode () {
298-
return (int)getHandleForInitialZoom();
299-
}
300-
301271
/**
302272
* Intersects the given rectangle to the collection of polygons
303273
* the receiver maintains to describe its area.
@@ -392,10 +362,10 @@ public boolean intersects (int x, int y, int width, int height) {
392362
return intersects(new Rectangle(x, y, width, height));
393363
}
394364

395-
boolean intersectsInPixels (int x, int y, int width, int height) {
365+
boolean intersectsInPixels (long handle, int x, int y, int width, int height) {
396366
RECT r = new RECT ();
397367
OS.SetRect (r, x, y, x + width, y + height);
398-
return OS.RectInRegion (getHandleForInitialZoom(), r);
368+
return OS.RectInRegion(handle, r);
399369
}
400370

401371
/**
@@ -418,8 +388,10 @@ boolean intersectsInPixels (int x, int y, int width, int height) {
418388
public boolean intersects (Rectangle rect) {
419389
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
420390
if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
421-
Rectangle r = DPIUtil.scaleUp(rect, initialZoom);
422-
return intersectsInPixels(r.x, r.y, r.width, r.height);
391+
return applyOnAnyHandle(regionHandle -> {
392+
Rectangle r = DPIUtil.scaleUp(rect, regionHandle.zoom);
393+
return intersectsInPixels(regionHandle.handle, r.x, r.y, r.width, r.height);
394+
});
423395
}
424396

425397
/**
@@ -434,7 +406,7 @@ public boolean intersects (Rectangle rect) {
434406
*/
435407
@Override
436408
public boolean isDisposed() {
437-
return zoomToHandle.isEmpty();
409+
return isDestroyed;
438410
}
439411

440412
/**
@@ -451,9 +423,11 @@ public boolean isDisposed() {
451423
public boolean isEmpty () {
452424
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
453425
RECT rect = new RECT ();
454-
int result = OS.GetRgnBox (getHandleForInitialZoom(), rect);
455-
if (result == OS.NULLREGION) return true;
456-
return ((rect.right - rect.left) <= 0) || ((rect.bottom - rect.top) <= 0);
426+
return applyOnAnyHandle(regionHandle -> {
427+
int result = OS.GetRgnBox(regionHandle.handle, rect);
428+
if (result == OS.NULLREGION) return true;
429+
return ((rect.right - rect.left) <= 0) || ((rect.bottom - rect.top) <= 0);
430+
});
457431
}
458432

459433
/**
@@ -591,13 +565,40 @@ public void translate (Point pt) {
591565
storeAndApplyOperationForAllHandles(operation);
592566
}
593567

594-
private long getHandleForInitialZoom() {
595-
return win32_getHandle(this, initialZoom);
596-
}
597-
598568
private void storeAndApplyOperationForAllHandles(Operation operation) {
599569
operations.add(operation);
600-
zoomToHandle.forEach((zoom, handle) -> operation.apply(handle, zoom));
570+
zoomToHandle.forEach((zoom, handle) -> operation.apply(handle));
571+
}
572+
573+
private <T> T applyOnAnyHandle(Function<RegionHandle, T> function) {
574+
if (zoomToHandle.isEmpty()) {
575+
RegionHandle handle = newRegionHandle(DPIUtil.getDeviceZoom());
576+
try {
577+
return function.apply(handle);
578+
} finally {
579+
handle.destroy();
580+
}
581+
} else {
582+
return function.apply(zoomToHandle.values().iterator().next());
583+
}
584+
}
585+
586+
private RegionHandle newRegionHandle(int zoom) {
587+
long newHandle = OS.CreateRectRgn (0, 0, 0, 0);
588+
if (newHandle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
589+
RegionHandle newRegionHandle = new RegionHandle(newHandle, zoom);
590+
for (Operation operation : operations) {
591+
operation.apply(newRegionHandle);
592+
}
593+
return newRegionHandle;
594+
}
595+
596+
private RegionHandle getRegionHandle(int zoom) {
597+
if (!zoomToHandle.containsKey(zoom)) {
598+
RegionHandle regionHandle = newRegionHandle(zoom);
599+
zoomToHandle.put(zoom, regionHandle);
600+
}
601+
return zoomToHandle.get(zoom);
601602
}
602603

603604
/**
@@ -618,14 +619,7 @@ private void storeAndApplyOperationForAllHandles(Operation operation) {
618619
* @noreference This method is not intended to be referenced by clients.
619620
*/
620621
public static long win32_getHandle(Region region, int zoom) {
621-
if(!region.zoomToHandle.containsKey(zoom)) {
622-
long handle = OS.CreateRectRgn(0, 0, 0, 0);
623-
for(Operation operation : region.operations) {
624-
operation.apply(handle, zoom);
625-
}
626-
region.zoomToHandle.put(zoom, handle);
627-
}
628-
return region.zoomToHandle.get(zoom);
622+
return region.getRegionHandle(zoom).handle;
629623
}
630624

631625
/**
@@ -640,20 +634,34 @@ public String toString () {
640634
return "Region {" + zoomToHandle.entrySet().stream().map(entry -> entry.getValue() + "(zoom:" + entry.getKey() + ")").collect(Collectors.joining(","));
641635
}
642636

637+
private class RegionHandle {
638+
private long handle;
639+
private int zoom;
640+
641+
public RegionHandle(long handle, int zoom) {
642+
this.handle = handle;
643+
this.zoom = zoom;
644+
}
645+
646+
void destroy() {
647+
OS.DeleteObject(handle);
648+
}
649+
}
650+
643651
@FunctionalInterface
644652
private interface OperationStrategy {
645653
void apply(Operation operation, long handle, int zoom);
646654
}
647655

648656
private abstract class Operation {
649-
private OperationStrategy operationStrategy;
657+
private final OperationStrategy operationStrategy;
650658

651659
Operation(OperationStrategy operationStrategy) {
652660
this.operationStrategy = operationStrategy;
653661
}
654662

655-
void apply(long handle, int zoom) {
656-
operationStrategy.apply(this, handle, zoom);
663+
void apply(RegionHandle regionHandle) {
664+
operationStrategy.apply(this, regionHandle.handle, regionHandle.zoom);
657665
}
658666

659667
abstract void add(long handle, int zoom);
@@ -666,8 +674,7 @@ void apply(long handle, int zoom) {
666674
}
667675

668676
private class OperationWithRectangle extends Operation {
669-
670-
Rectangle data;
677+
private final Rectangle data;
671678

672679
OperationWithRectangle(OperationStrategy operationStrategy, Rectangle data) {
673680
super(operationStrategy);
@@ -725,8 +732,7 @@ private Rectangle getScaledRectangle(int zoom) {
725732
}
726733

727734
private class OperationWithArray extends Operation {
728-
729-
int[] data;
735+
private final int[] data;
730736

731737
public OperationWithArray(OperationStrategy operationStrategy, int[] data) {
732738
super(operationStrategy);
@@ -773,8 +779,7 @@ private int[] getScaledPoints(int zoom) {
773779
}
774780

775781
private class OperationWithPoint extends Operation {
776-
777-
Point data;
782+
private final Point data;
778783

779784
public OperationWithPoint(OperationStrategy operationStrategy, Point data) {
780785
super(operationStrategy);
@@ -805,8 +810,7 @@ void translate(long handle, int zoom) {
805810
}
806811

807812
private class OperationWithRegion extends Operation {
808-
809-
Region data;
813+
private final Region data;
810814

811815
OperationWithRegion(OperationStrategy operationStrategy, Region data) {
812816
super(operationStrategy);

0 commit comments

Comments
 (0)