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 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) {
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 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
225230void 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
233239void 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 */
275258public 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) {
418388public 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
436408public boolean isDisposed () {
437- return zoomToHandle . isEmpty () ;
409+ return isDestroyed ;
438410}
439411
440412/**
@@ -451,9 +423,11 @@ public boolean isDisposed() {
451423public 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-
598568private 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 */
620621public 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
644652private interface OperationStrategy {
645653 void apply (Operation operation , long handle , int zoom );
646654}
647655
648656private 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
668676private 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
727734private 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
775781private 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
807812private 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