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,9 +80,6 @@ public Region () {
8080 */
8181public Region (Device device ) {
8282 super (device );
83- initialZoom = DPIUtil .getDeviceZoom ();
84- long handle = newEmptyRegionHandle ();
85- zoomToHandle .put (initialZoom , handle );
8683 init ();
8784 this .device .registerResourceWithZoomSupport (this );
8885}
@@ -173,8 +170,10 @@ public void add (Region region) {
173170 if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
174171 if (region == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
175172 if (region .isDisposed ()) SWT .error (SWT .ERROR_INVALID_ARGUMENT );
176- final Operation operation = new OperationWithRegion (Operation ::add , region );
177- storeAndApplyOperationForAllHandles (operation );
173+ if (!region .operations .isEmpty ()) {
174+ final Operation operation = new OperationWithRegion (Operation ::add , region .operations );
175+ storeAndApplyOperationForAllHandles (operation );
176+ }
178177}
179178
180179/**
@@ -192,11 +191,16 @@ public void add (Region region) {
192191 */
193192public boolean contains (int x , int y ) {
194193 if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
195- return containsInPixels (DPIUtil .scaleUp (x , initialZoom ), DPIUtil .scaleUp (y , initialZoom ));
194+ return applyUsingAnyHandle (regionHandle -> {
195+ int zoom = regionHandle .zoom ();
196+ int xInPixels = DPIUtil .scaleUp (x , zoom );
197+ int yInPixels = DPIUtil .scaleUp (y , zoom );
198+ return containsInPixels (regionHandle .handle (), xInPixels , yInPixels );
199+ });
196200}
197201
198- boolean containsInPixels (int x , int y ) {
199- return OS .PtInRegion (getHandleForInitialZoom () , x , y );
202+ boolean containsInPixels (long handle , int x , int y ) {
203+ return OS .PtInRegion (handle , x , y );
200204}
201205
202206/**
@@ -217,24 +221,28 @@ boolean containsInPixels (int x, int y) {
217221public boolean contains (Point pt ) {
218222 if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
219223 if (pt == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
220- Point p = DPIUtil .scaleUp (pt , initialZoom );
221- return containsInPixels (p .x , p .y );
224+ return applyUsingAnyHandle (regionHandle -> {
225+ int zoom = regionHandle .zoom ();
226+ Point p = DPIUtil .scaleUp (pt , zoom );
227+ return containsInPixels (regionHandle .handle (), p .x , p .y );
228+ });
222229}
223230
224231@ Override
225232void destroy () {
226233 device .deregisterResourceWithZoomSupport (this );
227- zoomToHandle .values ().forEach (handle -> OS . DeleteObject ( handle ) );
234+ zoomToHandle .values ().forEach (RegionHandle :: destroy );
228235 zoomToHandle .clear ();
229236 operations .clear ();
237+ this .isDestroyed = true ;
230238}
231239
232240@ Override
233241void destroyHandlesExcept (Set <Integer > zoomLevels ) {
234242 zoomToHandle .entrySet ().removeIf (entry -> {
235243 final Integer zoom = entry .getKey ();
236- if (!zoomLevels .contains (zoom ) && zoom != initialZoom ) {
237- OS . DeleteObject ( entry .getValue ());
244+ if (!zoomLevels .contains (zoom )) {
245+ entry .getValue (). destroy ( );
238246 return true ;
239247 }
240248 return false ;
@@ -271,12 +279,14 @@ public boolean equals (Object object) {
271279 */
272280public Rectangle getBounds () {
273281 if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
274- return DPIUtil .scaleDown (getBoundsInPixels (), initialZoom );
282+ return applyUsingAnyHandle (regionHandle -> {
283+ return DPIUtil .scaleDown (getBoundsInPixels (regionHandle .handle ()), regionHandle .zoom ());
284+ });
275285}
276286
277- Rectangle getBoundsInPixels () {
287+ private Rectangle getBoundsInPixels (long handle ) {
278288 RECT rect = new RECT ();
279- OS .GetRgnBox (getHandleForInitialZoom () , rect );
289+ OS .GetRgnBox (handle , rect );
280290 return new Rectangle (rect .left , rect .top , rect .right - rect .left , rect .bottom - rect .top );
281291}
282292
@@ -294,7 +304,6 @@ Rectangle getBoundsInPixels() {
294304public int hashCode () {
295305 return super .hashCode ();
296306}
297-
298307/**
299308 * Intersects the given rectangle to the collection of polygons
300309 * the receiver maintains to describe its area.
@@ -363,8 +372,10 @@ public void intersect (Region region) {
363372 if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
364373 if (region == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
365374 if (region .isDisposed ()) SWT .error (SWT .ERROR_INVALID_ARGUMENT );
366- final Operation operation = new OperationWithRegion (Operation ::intersect , region );
367- storeAndApplyOperationForAllHandles (operation );
375+ if (!region .operations .isEmpty ()) {
376+ final Operation operation = new OperationWithRegion (Operation ::intersect , region .operations );
377+ storeAndApplyOperationForAllHandles (operation );
378+ }
368379}
369380
370381/**
@@ -389,10 +400,10 @@ public boolean intersects (int x, int y, int width, int height) {
389400 return intersects (new Rectangle (x , y , width , height ));
390401}
391402
392- boolean intersectsInPixels (int x , int y , int width , int height ) {
403+ boolean intersectsInPixels (long handle , int x , int y , int width , int height ) {
393404 RECT r = new RECT ();
394405 OS .SetRect (r , x , y , x + width , y + height );
395- return OS .RectInRegion ( getHandleForInitialZoom () , r );
406+ return OS .RectInRegion ( handle , r );
396407}
397408
398409/**
@@ -415,8 +426,10 @@ boolean intersectsInPixels (int x, int y, int width, int height) {
415426public boolean intersects (Rectangle rect ) {
416427 if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
417428 if (rect == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
418- Rectangle r = DPIUtil .scaleUp (rect , initialZoom );
419- return intersectsInPixels (r .x , r .y , r .width , r .height );
429+ return applyUsingAnyHandle (regionHandle -> {
430+ Rectangle r = DPIUtil .scaleUp (rect , regionHandle .zoom ());
431+ return intersectsInPixels (regionHandle .handle (), r .x , r .y , r .width , r .height );
432+ });
420433}
421434
422435/**
@@ -431,7 +444,7 @@ public boolean intersects (Rectangle rect) {
431444 */
432445@ Override
433446public boolean isDisposed () {
434- return zoomToHandle . isEmpty () ;
447+ return isDestroyed ;
435448}
436449
437450/**
@@ -448,9 +461,11 @@ public boolean isDisposed() {
448461public boolean isEmpty () {
449462 if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
450463 RECT rect = new RECT ();
451- int result = OS .GetRgnBox (getHandleForInitialZoom (), rect );
452- if (result == OS .NULLREGION ) return true ;
453- return ((rect .right - rect .left ) <= 0 ) || ((rect .bottom - rect .top ) <= 0 );
464+ return applyUsingAnyHandle (regionHandle -> {
465+ int result = OS .GetRgnBox (regionHandle .handle (), rect );
466+ if (result == OS .NULLREGION ) return true ;
467+ return ((rect .right - rect .left ) <= 0 ) || ((rect .bottom - rect .top ) <= 0 );
468+ });
454469}
455470
456471/**
@@ -543,8 +558,10 @@ public void subtract (Region region) {
543558 if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
544559 if (region == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
545560 if (region .isDisposed ()) SWT .error (SWT .ERROR_INVALID_ARGUMENT );
546- final Operation operation = new OperationWithRegion (Operation ::subtract , region );
547- storeAndApplyOperationForAllHandles (operation );
561+ if (!region .operations .isEmpty ()) {
562+ final Operation operation = new OperationWithRegion (Operation ::subtract , region .operations );
563+ storeAndApplyOperationForAllHandles (operation );
564+ }
548565}
549566
550567/**
@@ -588,36 +605,43 @@ public void translate (Point pt) {
588605 storeAndApplyOperationForAllHandles (operation );
589606}
590607
591- private long getHandleForInitialZoom () {
592- return win32_getHandle (this , initialZoom );
593- }
594-
595608private void storeAndApplyOperationForAllHandles (Operation operation ) {
596609 operations .add (operation );
597- zoomToHandle .forEach ((zoom , handle ) -> operation .apply (handle , zoom ));
610+ zoomToHandle .forEach ((zoom , handle ) -> operation .apply (handle ));
611+ }
612+
613+ private <T > T applyUsingAnyHandle (Function <RegionHandle , T > function ) {
614+ if (zoomToHandle .isEmpty ()) {
615+ return applyUsingTemporaryHandle (device .getDeviceZoom (), operations , function );
616+ }
617+ return function .apply (zoomToHandle .values ().iterator ().next ());
598618}
599619
600- private static <T > T applyUsingTemporaryHandle (int zoom , List <Operation > operations , Function <Long , T > function ) {
601- long temporaryHandle = newRegionHandle (operations , zoom );
620+ private static <T > T applyUsingTemporaryHandle (int zoom , List <Operation > operations , Function <RegionHandle , T > function ) {
621+ RegionHandle temporaryHandle = newRegionHandle (zoom , operations );
602622 try {
603623 return function .apply (temporaryHandle );
604624 } finally {
605- OS . DeleteObject ( temporaryHandle );
625+ temporaryHandle . destroy ( );
606626 }
607627}
608628
609- private static long newEmptyRegionHandle ( ) {
629+ private static RegionHandle newRegionHandle ( int zoom , List < Operation > operations ) {
610630 long newHandle = OS .CreateRectRgn (0 , 0 , 0 , 0 );
611631 if (newHandle == 0 ) SWT .error (SWT .ERROR_NO_HANDLES );
612- return newHandle ;
632+ RegionHandle newRegionHandle = new RegionHandle (newHandle , zoom );
633+ for (Operation operation : operations ) {
634+ operation .apply (newRegionHandle );
635+ }
636+ return newRegionHandle ;
613637}
614638
615- private static long newRegionHandle ( List < Operation > operations , int zoom ) {
616- long newHandle = newEmptyRegionHandle ();
617- for ( Operation operation : operations ) {
618- operation . apply ( newHandle , zoom );
639+ private RegionHandle getRegionHandle ( int zoom ) {
640+ if (! zoomToHandle . containsKey ( zoom )) {
641+ RegionHandle regionHandle = newRegionHandle ( zoom , operations );
642+ zoomToHandle . put ( zoom , regionHandle );
619643 }
620- return newHandle ;
644+ return zoomToHandle . get ( zoom ) ;
621645}
622646
623647/**
@@ -638,14 +662,7 @@ private static long newRegionHandle(List<Operation> operations, int zoom) {
638662 * @noreference This method is not intended to be referenced by clients.
639663 */
640664public static long win32_getHandle (Region region , int zoom ) {
641- if (!region .zoomToHandle .containsKey (zoom )) {
642- long handle = newEmptyRegionHandle ();
643- for (Operation operation : region .operations ) {
644- operation .apply (handle , zoom );
645- }
646- region .zoomToHandle .put (zoom , handle );
647- }
648- return region .zoomToHandle .get (zoom );
665+ return region .getRegionHandle (zoom ).handle ();
649666}
650667
651668/**
@@ -660,20 +677,26 @@ public String toString () {
660677 return "Region {" + zoomToHandle .entrySet ().stream ().map (entry -> entry .getValue () + "(zoom:" + entry .getKey () + ")" ).collect (Collectors .joining ("," ));
661678}
662679
680+ private record RegionHandle (long handle , int zoom ) {
681+ void destroy () {
682+ OS .DeleteObject (handle ());
683+ }
684+ }
685+
663686@ FunctionalInterface
664687private interface OperationStrategy {
665688 void apply (Operation operation , long handle , int zoom );
666689}
667690
668691private abstract static class Operation {
669- private OperationStrategy operationStrategy ;
692+ private final OperationStrategy operationStrategy ;
670693
671694 Operation (OperationStrategy operationStrategy ) {
672695 this .operationStrategy = operationStrategy ;
673696 }
674697
675- void apply (long handle , int zoom ) {
676- operationStrategy .apply (this , handle , zoom );
698+ void apply (RegionHandle regionHandle ) {
699+ operationStrategy .apply (this , regionHandle . handle (), regionHandle . zoom () );
677700 }
678701
679702 abstract void add (long handle , int zoom );
@@ -686,8 +709,7 @@ void apply(long handle, int zoom) {
686709}
687710
688711private static class OperationWithRectangle extends Operation {
689-
690- Rectangle data ;
712+ private final Rectangle data ;
691713
692714 OperationWithRectangle (OperationStrategy operationStrategy , Rectangle data ) {
693715 super (operationStrategy );
@@ -745,8 +767,7 @@ private Rectangle getScaledRectangle(int zoom) {
745767}
746768
747769private static class OperationWithArray extends Operation {
748-
749- int [] data ;
770+ private final int [] data ;
750771
751772 public OperationWithArray (OperationStrategy operationStrategy , int [] data ) {
752773 super (operationStrategy );
@@ -793,8 +814,7 @@ private int[] getScaledPoints(int zoom) {
793814}
794815
795816private static class OperationWithPoint extends Operation {
796-
797- Point data ;
817+ private final Point data ;
798818
799819 public OperationWithPoint (OperationStrategy operationStrategy , Point data ) {
800820 super (operationStrategy );
@@ -827,29 +847,29 @@ void translate(long handle, int zoom) {
827847private static class OperationWithRegion extends Operation {
828848 private final List <Operation > operations ;
829849
830- OperationWithRegion (OperationStrategy operationStrategy , Region data ) {
850+ OperationWithRegion (OperationStrategy operationStrategy , List < Operation > operations ) {
831851 super (operationStrategy );
832- this .operations = data . operations ;
852+ this .operations = List . copyOf ( operations ) ;
833853 }
834854
835855 @ Override
836856 void add (long handle , int zoom ) {
837857 applyUsingTemporaryHandle (zoom , operations , regionHandle -> {
838- return OS .CombineRgn (handle , handle , regionHandle , OS .RGN_OR );
858+ return OS .CombineRgn (handle , handle , regionHandle . handle () , OS .RGN_OR );
839859 });
840860 }
841861
842862 @ Override
843863 void subtract (long handle , int zoom ) {
844864 applyUsingTemporaryHandle (zoom , operations , regionHandle -> {
845- return OS .CombineRgn (handle , handle , regionHandle , OS .RGN_DIFF );
865+ return OS .CombineRgn (handle , handle , regionHandle . handle () , OS .RGN_DIFF );
846866 });
847867 }
848868
849869 @ Override
850870 void intersect (long handle , int zoom ) {
851871 applyUsingTemporaryHandle (zoom , operations , regionHandle -> {
852- return OS .CombineRgn (handle , handle , regionHandle , OS .RGN_AND );
872+ return OS .CombineRgn (handle , handle , regionHandle . handle () , OS .RGN_AND );
853873 });
854874 }
855875
0 commit comments