3737 */
3838public final class Region extends Resource {
3939
40- private int initialZoom ;
41-
42- private HashMap <Integer , Long > zoomToHandle = new HashMap <>();
40+ private Map <Integer , RegionHandle > zoomToHandle = new HashMap <>();
4341
4442 private List <Operation > operations = new ArrayList <>();
4543
44+ private boolean isDestroyed ;
45+
4646/**
4747 * Constructs a new empty region.
4848 * <p>
@@ -80,10 +80,6 @@ public Region () {
8080 */
8181public Region (Device device ) {
8282 super (device );
83- initialZoom = DPIUtil .getDeviceZoom ();
84- long handle = OS .CreateRectRgn (0 , 0 , 0 , 0 );
85- zoomToHandle .put (initialZoom , handle );
86- if (handle == 0 ) SWT .error (SWT .ERROR_NO_HANDLES );
8783 init ();
8884 this .device .registerResourceWithZoomSupport (this );
8985}
@@ -193,11 +189,16 @@ public void add (Region region) {
193189 */
194190public boolean contains (int x , int y ) {
195191 if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
196- 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+ });
197198}
198199
199- boolean containsInPixels (int x , int y ) {
200- return OS .PtInRegion (getHandleForInitialZoom () , x , y );
200+ boolean containsInPixels (long handle , int x , int y ) {
201+ return OS .PtInRegion (handle , x , y );
201202}
202203
203204/**
@@ -218,28 +219,26 @@ boolean containsInPixels (int x, int y) {
218219public boolean contains (Point pt ) {
219220 if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
220221 if (pt == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
221- Point p = DPIUtil .scaleUp (pt , initialZoom );
222- 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+ });
223227}
224228
225229@ Override
226230void destroy () {
227231 device .deregisterResourceWithZoomSupport (this );
228- zoomToHandle .values ().forEach (handle -> OS . DeleteObject ( handle ) );
232+ zoomToHandle .values ().forEach (RegionHandle :: destroy );
229233 zoomToHandle .clear ();
230- operations . clear () ;
234+ this . isDestroyed = true ;
231235}
232236
233237@ Override
234238void destroyHandlesExcept (Set <Integer > zoomLevels ) {
235- zoomToHandle .entrySet ().removeIf (entry -> {
236- final Integer zoom = entry .getKey ();
237- if (!zoomLevels .contains (zoom ) && zoom != initialZoom ) {
238- OS .DeleteObject (entry .getValue ());
239- return true ;
240- }
241- return false ;
242- });
239+ // As long as we keep the operations, we can cleanup all handles
240+ zoomToHandle .values ().forEach (RegionHandle ::destroy );
241+ zoomToHandle .clear ();
243242}
244243
245244/**
@@ -272,12 +271,14 @@ public boolean equals (Object object) {
272271 */
273272public Rectangle getBounds () {
274273 if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
275- return DPIUtil .scaleDown (getBoundsInPixels (), initialZoom );
274+ return applyUsingAnyHandle (regionHandle -> {
275+ return DPIUtil .scaleDown (getBoundsInPixels (regionHandle .handle ), regionHandle .zoom );
276+ });
276277}
277278
278- Rectangle getBoundsInPixels () {
279+ private Rectangle getBoundsInPixels (long handle ) {
279280 RECT rect = new RECT ();
280- OS .GetRgnBox (getHandleForInitialZoom () , rect );
281+ OS .GetRgnBox (handle , rect );
281282 return new Rectangle (rect .left , rect .top , rect .right - rect .left , rect .bottom - rect .top );
282283}
283284
@@ -295,7 +296,6 @@ Rectangle getBoundsInPixels() {
295296public int hashCode () {
296297 return super .hashCode ();
297298}
298-
299299/**
300300 * Intersects the given rectangle to the collection of polygons
301301 * the receiver maintains to describe its area.
@@ -390,10 +390,10 @@ public boolean intersects (int x, int y, int width, int height) {
390390 return intersects (new Rectangle (x , y , width , height ));
391391}
392392
393- boolean intersectsInPixels (int x , int y , int width , int height ) {
393+ boolean intersectsInPixels (long handle , int x , int y , int width , int height ) {
394394 RECT r = new RECT ();
395395 OS .SetRect (r , x , y , x + width , y + height );
396- return OS .RectInRegion ( getHandleForInitialZoom () , r );
396+ return OS .RectInRegion ( handle , r );
397397}
398398
399399/**
@@ -416,8 +416,10 @@ boolean intersectsInPixels (int x, int y, int width, int height) {
416416public boolean intersects (Rectangle rect ) {
417417 if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
418418 if (rect == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
419- Rectangle r = DPIUtil .scaleUp (rect , initialZoom );
420- return intersectsInPixels (r .x , r .y , r .width , r .height );
419+ return applyUsingAnyHandle (regionHandle -> {
420+ Rectangle r = DPIUtil .scaleUp (rect , regionHandle .zoom );
421+ return intersectsInPixels (regionHandle .handle , r .x , r .y , r .width , r .height );
422+ });
421423}
422424
423425/**
@@ -432,7 +434,7 @@ public boolean intersects (Rectangle rect) {
432434 */
433435@ Override
434436public boolean isDisposed () {
435- return zoomToHandle . isEmpty () ;
437+ return isDestroyed ;
436438}
437439
438440/**
@@ -449,9 +451,11 @@ public boolean isDisposed() {
449451public boolean isEmpty () {
450452 if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
451453 RECT rect = new RECT ();
452- int result = OS .GetRgnBox (getHandleForInitialZoom (), rect );
453- if (result == OS .NULLREGION ) return true ;
454- return ((rect .right - rect .left ) <= 0 ) || ((rect .bottom - rect .top ) <= 0 );
454+ return applyUsingAnyHandle (regionHandle -> {
455+ int result = OS .GetRgnBox (regionHandle .handle , rect );
456+ if (result == OS .NULLREGION ) return true ;
457+ return ((rect .right - rect .left ) <= 0 ) || ((rect .bottom - rect .top ) <= 0 );
458+ });
455459}
456460
457461/**
@@ -589,36 +593,48 @@ public void translate (Point pt) {
589593 storeAndApplyOperationForAllHandles (operation );
590594}
591595
592- private long getHandleForInitialZoom () {
593- return win32_getHandle (this , initialZoom );
594- }
595-
596596private void storeAndApplyOperationForAllHandles (Operation operation ) {
597597 operations .add (operation );
598- zoomToHandle .forEach ((zoom , handle ) -> operation .apply (handle , zoom ));
598+ zoomToHandle .forEach ((zoom , handle ) -> operation .apply (handle ));
599+ }
600+
601+ private <T > T applyUsingAnyHandle (Function <RegionHandle , T > function ) {
602+ if (zoomToHandle .isEmpty ()) {
603+ return applyUsingTemporaryHandle (device .getDeviceZoom (), operations , function );
604+ } else {
605+ return function .apply (zoomToHandle .values ().iterator ().next ());
606+ }
599607}
600608
601- private static <T > T applyUsingTemporaryHandle (int zoom , List <Operation > operations , Function <Long , T > function ) {
602- long temporaryHandle = newRegionHandle (operations , zoom );
609+ private static <T > T applyUsingTemporaryHandle (int zoom , List <Operation > operations , Function <RegionHandle , T > function ) {
610+ RegionHandle temporaryHandle = newRegionHandle (zoom , operations );
603611 try {
604612 return function .apply (temporaryHandle );
605613 } finally {
606- OS . DeleteObject ( temporaryHandle );
614+ temporaryHandle . destroy ( );
607615 }
608616}
609617
610- private static long newEmptyRegionHandle () {
618+ private static RegionHandle newRegionHandle (int zoom , List <Operation > operations ) {
619+ RegionHandle newHandle = newEmptyRegionHandle (zoom );
620+ for (Operation operation : operations ) {
621+ operation .apply (newHandle );
622+ }
623+ return newHandle ;
624+ }
625+
626+ private static RegionHandle newEmptyRegionHandle (int zoom ) {
611627 long newHandle = OS .CreateRectRgn (0 , 0 , 0 , 0 );
612628 if (newHandle == 0 ) SWT .error (SWT .ERROR_NO_HANDLES );
613- return newHandle ;
629+ return new RegionHandle ( newHandle , zoom ) ;
614630}
615631
616- private static long newRegionHandle ( List < Operation > operations , int zoom ) {
617- long newHandle = newEmptyRegionHandle ();
618- for ( Operation operation : operations ) {
619- operation . apply ( newHandle , zoom );
632+ private RegionHandle getRegionHandle ( int zoom ) {
633+ if (! zoomToHandle . containsKey ( zoom )) {
634+ RegionHandle regionHandle = newRegionHandle ( zoom , operations );
635+ zoomToHandle . put ( zoom , regionHandle );
620636 }
621- return newHandle ;
637+ return zoomToHandle . get ( zoom ) ;
622638}
623639
624640/**
@@ -639,14 +655,7 @@ private static long newRegionHandle(List<Operation> operations, int zoom) {
639655 * @noreference This method is not intended to be referenced by clients.
640656 */
641657public static long win32_getHandle (Region region , int zoom ) {
642- if (!region .zoomToHandle .containsKey (zoom )) {
643- long handle = newEmptyRegionHandle ();
644- for (Operation operation : region .operations ) {
645- operation .apply (handle , zoom );
646- }
647- region .zoomToHandle .put (zoom , handle );
648- }
649- return region .zoomToHandle .get (zoom );
658+ return region .getRegionHandle (zoom ).handle ;
650659}
651660
652661/**
@@ -661,20 +670,26 @@ public String toString () {
661670 return "Region {" + zoomToHandle .entrySet ().stream ().map (entry -> entry .getValue () + "(zoom:" + entry .getKey () + ")" ).collect (Collectors .joining ("," ));
662671}
663672
673+ private record RegionHandle (long handle , int zoom ) {
674+ void destroy () {
675+ OS .DeleteObject (handle );
676+ }
677+ }
678+
664679@ FunctionalInterface
665680private interface OperationStrategy {
666681 void apply (Operation operation , long handle , int zoom );
667682}
668683
669684private abstract static class Operation {
670- private OperationStrategy operationStrategy ;
685+ private final OperationStrategy operationStrategy ;
671686
672687 Operation (OperationStrategy operationStrategy ) {
673688 this .operationStrategy = operationStrategy ;
674689 }
675690
676- void apply (long handle , int zoom ) {
677- operationStrategy .apply (this , handle , zoom );
691+ void apply (RegionHandle regionHandle ) {
692+ operationStrategy .apply (this , regionHandle . handle , regionHandle . zoom );
678693 }
679694
680695 abstract void add (long handle , int zoom );
@@ -687,8 +702,7 @@ void apply(long handle, int zoom) {
687702}
688703
689704private static class OperationWithRectangle extends Operation {
690-
691- Rectangle data ;
705+ private final Rectangle data ;
692706
693707 OperationWithRectangle (OperationStrategy operationStrategy , Rectangle data ) {
694708 super (operationStrategy );
@@ -746,8 +760,7 @@ private Rectangle getScaledRectangle(int zoom) {
746760}
747761
748762private static class OperationWithArray extends Operation {
749-
750- int [] data ;
763+ private final int [] data ;
751764
752765 public OperationWithArray (OperationStrategy operationStrategy , int [] data ) {
753766 super (operationStrategy );
@@ -794,8 +807,7 @@ private int[] getScaledPoints(int zoom) {
794807}
795808
796809private static class OperationWithPoint extends Operation {
797-
798- Point data ;
810+ private final Point data ;
799811
800812 public OperationWithPoint (OperationStrategy operationStrategy , Point data ) {
801813 super (operationStrategy );
@@ -836,21 +848,21 @@ private static class OperationWithRegion extends Operation {
836848 @ Override
837849 void add (long handle , int zoom ) {
838850 applyUsingTemporaryHandle (zoom , operations , regionHandle -> {
839- return OS .CombineRgn (handle , handle , regionHandle , OS .RGN_OR );
851+ return OS .CombineRgn (handle , handle , regionHandle . handle , OS .RGN_OR );
840852 });
841853 }
842854
843855 @ Override
844856 void subtract (long handle , int zoom ) {
845857 applyUsingTemporaryHandle (zoom , operations , regionHandle -> {
846- return OS .CombineRgn (handle , handle , regionHandle , OS .RGN_DIFF );
858+ return OS .CombineRgn (handle , handle , regionHandle . handle , OS .RGN_DIFF );
847859 });
848860 }
849861
850862 @ Override
851863 void intersect (long handle , int zoom ) {
852864 applyUsingTemporaryHandle (zoom , operations , regionHandle -> {
853- return OS .CombineRgn (handle , handle , regionHandle , OS .RGN_AND );
865+ return OS .CombineRgn (handle , handle , regionHandle . handle , OS .RGN_AND );
854866 });
855867 }
856868
0 commit comments