1515
1616
1717import java .util .*;
18+ import java .util .function .*;
1819import java .util .stream .*;
1920
2021import org .eclipse .swt .*;
3637 */
3738public 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 */
8081public 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 */
193190public 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 applyUsingAnyHandle (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,30 +219,26 @@ boolean containsInPixels (int x, int y) {
217219public 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 applyUsingAnyHandle (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
225230void destroy () {
226231 device .deregisterResourceWithZoomSupport (this );
227- zoomToHandle .values ().forEach (handle -> OS . DeleteObject ( handle ) );
232+ zoomToHandle .values ().forEach (RegionHandle :: destroy );
228233 zoomToHandle .clear ();
229- operations . clear () ;
234+ this . isDestroyed = true ;
230235}
231236
232237@ Override
233238void 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-
239+ // As long as we keep the operations, we can cleanup all handles
240+ zoomToHandle .values ().forEach (RegionHandle ::destroy );
241+ zoomToHandle .clear ();
244242}
245243
246244/**
@@ -258,16 +256,17 @@ void destroyHandlesExcept(Set<Integer> zoomLevels) {
258256 */
259257public Rectangle getBounds () {
260258 if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
261- return DPIUtil .scaleDown (getBoundsInPixels (), initialZoom );
259+ return applyUsingAnyHandle (regionHandle -> {
260+ return DPIUtil .scaleDown (getBoundsInPixels (regionHandle .handle ), regionHandle .zoom );
261+ });
262262}
263263
264- Rectangle getBoundsInPixels () {
264+ private Rectangle getBoundsInPixels (long handle ) {
265265 RECT rect = new RECT ();
266- OS .GetRgnBox (getHandleForInitialZoom () , rect );
266+ OS .GetRgnBox (handle , rect );
267267 return new Rectangle (rect .left , rect .top , rect .right - rect .left , rect .bottom - rect .top );
268268}
269269
270-
271270/**
272271 * Intersects the given rectangle to the collection of polygons
273272 * the receiver maintains to describe its area.
@@ -362,10 +361,10 @@ public boolean intersects (int x, int y, int width, int height) {
362361 return intersects (new Rectangle (x , y , width , height ));
363362}
364363
365- boolean intersectsInPixels (int x , int y , int width , int height ) {
364+ boolean intersectsInPixels (long handle , int x , int y , int width , int height ) {
366365 RECT r = new RECT ();
367366 OS .SetRect (r , x , y , x + width , y + height );
368- return OS .RectInRegion ( getHandleForInitialZoom () , r );
367+ return OS .RectInRegion ( handle , r );
369368}
370369
371370/**
@@ -388,8 +387,10 @@ boolean intersectsInPixels (int x, int y, int width, int height) {
388387public boolean intersects (Rectangle rect ) {
389388 if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
390389 if (rect == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
391- Rectangle r = DPIUtil .scaleUp (rect , initialZoom );
392- return intersectsInPixels (r .x , r .y , r .width , r .height );
390+ return applyUsingAnyHandle (regionHandle -> {
391+ Rectangle r = DPIUtil .scaleUp (rect , regionHandle .zoom );
392+ return intersectsInPixels (regionHandle .handle , r .x , r .y , r .width , r .height );
393+ });
393394}
394395
395396/**
@@ -404,7 +405,7 @@ public boolean intersects (Rectangle rect) {
404405 */
405406@ Override
406407public boolean isDisposed () {
407- return zoomToHandle . isEmpty () ;
408+ return isDestroyed ;
408409}
409410
410411/**
@@ -421,9 +422,11 @@ public boolean isDisposed() {
421422public boolean isEmpty () {
422423 if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
423424 RECT rect = new RECT ();
424- int result = OS .GetRgnBox (getHandleForInitialZoom (), rect );
425- if (result == OS .NULLREGION ) return true ;
426- return ((rect .right - rect .left ) <= 0 ) || ((rect .bottom - rect .top ) <= 0 );
425+ return applyUsingAnyHandle (regionHandle -> {
426+ int result = OS .GetRgnBox (regionHandle .handle , rect );
427+ if (result == OS .NULLREGION ) return true ;
428+ return ((rect .right - rect .left ) <= 0 ) || ((rect .bottom - rect .top ) <= 0 );
429+ });
427430}
428431
429432/**
@@ -561,13 +564,44 @@ public void translate (Point pt) {
561564 storeAndApplyOperationForAllHandles (operation );
562565}
563566
564- private long getHandleForInitialZoom () {
565- return win32_getHandle (this , initialZoom );
566- }
567-
568567private void storeAndApplyOperationForAllHandles (Operation operation ) {
569568 operations .add (operation );
570- zoomToHandle .forEach ((zoom , handle ) -> operation .apply (handle , zoom ));
569+ zoomToHandle .forEach ((zoom , handle ) -> operation .apply (handle ));
570+ }
571+
572+ private <T > T applyUsingAnyHandle (Function <RegionHandle , T > function ) {
573+ if (zoomToHandle .isEmpty ()) {
574+ return applyUsingTemporaryHandle (device .getDeviceZoom (), function );
575+ } else {
576+ return function .apply (zoomToHandle .values ().iterator ().next ());
577+ }
578+ }
579+
580+ private <T > T applyUsingTemporaryHandle (int zoom , Function <RegionHandle , T > function ) {
581+ RegionHandle temporaryHandle = newRegionHandle (zoom );
582+ try {
583+ return function .apply (temporaryHandle );
584+ } finally {
585+ temporaryHandle .destroy ();
586+ }
587+ }
588+
589+ private RegionHandle newRegionHandle (int zoom ) {
590+ long newHandle = OS .CreateRectRgn (0 , 0 , 0 , 0 );
591+ if (newHandle == 0 ) SWT .error (SWT .ERROR_NO_HANDLES );
592+ RegionHandle newRegionHandle = new RegionHandle (newHandle , zoom );
593+ for (Operation operation : operations ) {
594+ operation .apply (newRegionHandle );
595+ }
596+ return newRegionHandle ;
597+ }
598+
599+ private RegionHandle getRegionHandle (int zoom ) {
600+ if (!zoomToHandle .containsKey (zoom )) {
601+ RegionHandle regionHandle = newRegionHandle (zoom );
602+ zoomToHandle .put (zoom , regionHandle );
603+ }
604+ return zoomToHandle .get (zoom );
571605}
572606
573607/**
@@ -588,14 +622,7 @@ private void storeAndApplyOperationForAllHandles(Operation operation) {
588622 * @noreference This method is not intended to be referenced by clients.
589623 */
590624public static long win32_getHandle (Region region , int zoom ) {
591- if (!region .zoomToHandle .containsKey (zoom )) {
592- long handle = OS .CreateRectRgn (0 , 0 , 0 , 0 );
593- for (Operation operation : region .operations ) {
594- operation .apply (handle , zoom );
595- }
596- region .zoomToHandle .put (zoom , handle );
597- }
598- return region .zoomToHandle .get (zoom );
625+ return region .getRegionHandle (zoom ).handle ;
599626}
600627
601628/**
@@ -610,20 +637,34 @@ public String toString () {
610637 return "Region {" + zoomToHandle .entrySet ().stream ().map (entry -> entry .getValue () + "(zoom:" + entry .getKey () + ")" ).collect (Collectors .joining ("," ));
611638}
612639
640+ private class RegionHandle {
641+ private long handle ;
642+ private int zoom ;
643+
644+ public RegionHandle (long handle , int zoom ) {
645+ this .handle = handle ;
646+ this .zoom = zoom ;
647+ }
648+
649+ void destroy () {
650+ OS .DeleteObject (handle );
651+ }
652+ }
653+
613654@ FunctionalInterface
614655private interface OperationStrategy {
615656 void apply (Operation operation , long handle , int zoom );
616657}
617658
618659private abstract class Operation {
619- private OperationStrategy operationStrategy ;
660+ private final OperationStrategy operationStrategy ;
620661
621662 Operation (OperationStrategy operationStrategy ) {
622663 this .operationStrategy = operationStrategy ;
623664 }
624665
625- void apply (long handle , int zoom ) {
626- operationStrategy .apply (this , handle , zoom );
666+ void apply (RegionHandle regionHandle ) {
667+ operationStrategy .apply (this , regionHandle . handle , regionHandle . zoom );
627668 }
628669
629670 abstract void add (long handle , int zoom );
@@ -636,8 +677,7 @@ void apply(long handle, int zoom) {
636677}
637678
638679private class OperationWithRectangle extends Operation {
639-
640- Rectangle data ;
680+ private final Rectangle data ;
641681
642682 OperationWithRectangle (OperationStrategy operationStrategy , Rectangle data ) {
643683 super (operationStrategy );
@@ -695,8 +735,7 @@ private Rectangle getScaledRectangle(int zoom) {
695735}
696736
697737private class OperationWithArray extends Operation {
698-
699- int [] data ;
738+ private final int [] data ;
700739
701740 public OperationWithArray (OperationStrategy operationStrategy , int [] data ) {
702741 super (operationStrategy );
@@ -743,8 +782,7 @@ private int[] getScaledPoints(int zoom) {
743782}
744783
745784private class OperationWithPoint extends Operation {
746-
747- Point data ;
785+ private final Point data ;
748786
749787 public OperationWithPoint (OperationStrategy operationStrategy , Point data ) {
750788 super (operationStrategy );
0 commit comments