14
14
package org .eclipse .swt .graphics ;
15
15
16
16
import java .util .*;
17
+ import java .util .function .*;
17
18
18
19
import org .eclipse .swt .*;
19
20
import org .eclipse .swt .internal .*;
42
43
* @since 3.1
43
44
*/
44
45
public class Path extends Resource {
45
- private int initialZoom ;
46
-
47
46
private Map <Integer , PathHandle > zoomToHandle = new HashMap <>();
48
47
48
+ private List <Operation > operations = new ArrayList <>();
49
+
50
+ private boolean isDestroyed ;
51
+
49
52
/**
50
53
* Constructs a new empty Path.
51
54
* <p>
@@ -72,16 +75,8 @@ public class Path extends Resource {
72
75
* @see #dispose()
73
76
*/
74
77
public Path (Device device ) {
75
- this (device , DPIUtil .getDeviceZoom ());
76
- }
77
-
78
- private Path (Device device , int zoom ) {
79
78
super (device );
80
79
this .device .checkGDIP ();
81
- initialZoom = zoom ;
82
- long handle = Gdip .GraphicsPath_new (Gdip .FillModeAlternate );
83
- if (handle == 0 ) SWT .error (SWT .ERROR_NO_HANDLES );
84
- zoomToHandle .put (initialZoom , new PathHandle (handle , initialZoom ));
85
80
init ();
86
81
this .device .registerResourceWithZoomSupport (this );
87
82
}
@@ -125,11 +120,10 @@ public Path (Device device, Path path, float flatness) {
125
120
if (path == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
126
121
if (path .isDisposed ()) SWT .error (SWT .ERROR_INVALID_ARGUMENT );
127
122
flatness = Math .max (0 , flatness );
128
- long handle = Gdip .GraphicsPath_Clone (path .getHandle (path .initialZoom ));
129
- if (flatness != 0 ) Gdip .GraphicsPath_Flatten (handle , 0 , flatness );
130
- if (handle == 0 ) SWT .error (SWT .ERROR_NO_HANDLES );
131
- initialZoom = path .initialZoom ;
132
- zoomToHandle .put (initialZoom , new PathHandle (handle , initialZoom ));
123
+ path .operations .forEach (this ::storeAndApplyOperationOnAllHandles );
124
+ if (flatness != 0 ) {
125
+ storeAndApplyOperationOnAllHandles (new FlattenOperation (flatness ));
126
+ }
133
127
init ();
134
128
this .device .registerResourceWithZoomSupport (this );
135
129
}
@@ -163,15 +157,9 @@ public Path (Device device, Path path, float flatness) {
163
157
* @since 3.4
164
158
*/
165
159
public Path (Device device , PathData data ) {
166
- this (device , data , DPIUtil .getDeviceZoom ());
167
-
168
- }
169
-
170
- private Path (Device device , PathData data , int zoom ) {
171
- this (device , zoom );
160
+ this (device );
172
161
if (data == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
173
162
init (data );
174
- this .device .registerResourceWithZoomSupport (this );
175
163
}
176
164
177
165
/**
@@ -205,7 +193,7 @@ private Path(Device device, PathData data, int zoom) {
205
193
*/
206
194
public void addArc (float x , float y , float width , float height , float startAngle , float arcAngle ) {
207
195
if (width == 0 || height == 0 || arcAngle == 0 ) return ;
208
- applyOperationForAllHandles (new AddArcOperation (x , y , width , height , startAngle , arcAngle ));
196
+ storeAndApplyOperationOnAllHandles (new AddArcOperation (x , y , width , height , startAngle , arcAngle ));
209
197
}
210
198
211
199
/**
@@ -225,7 +213,7 @@ public void addPath(Path path) {
225
213
if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
226
214
if (path == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
227
215
if (path .isDisposed ()) SWT .error (SWT .ERROR_INVALID_ARGUMENT );
228
- applyOperationForAllHandles (new AddPathOperation (path ));
216
+ storeAndApplyOperationOnAllHandles (new AddPathOperation (path ));
229
217
}
230
218
231
219
/**
@@ -242,7 +230,7 @@ public void addPath(Path path) {
242
230
*/
243
231
public void addRectangle (float x , float y , float width , float height ) {
244
232
if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
245
- applyOperationForAllHandles (new AddRectangleOperation (x , y , width , height ));
233
+ storeAndApplyOperationOnAllHandles (new AddRectangleOperation (x , y , width , height ));
246
234
}
247
235
248
236
/**
@@ -266,7 +254,7 @@ public void addString (String string, float x, float y, Font font) {
266
254
if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
267
255
if (font == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
268
256
if (font .isDisposed ()) SWT .error (SWT .ERROR_INVALID_ARGUMENT );
269
- applyOperationForAllHandles (new AddStringOperation (string , x , y , font ));
257
+ storeAndApplyOperationOnAllHandles (new AddStringOperation (string , x , y , font ));
270
258
}
271
259
272
260
/**
@@ -280,7 +268,7 @@ public void addString (String string, float x, float y, Font font) {
280
268
*/
281
269
public void close () {
282
270
if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
283
- applyOperationForAllHandles (new CloseOperation ());
271
+ storeAndApplyOperationOnAllHandles (new CloseOperation ());
284
272
}
285
273
286
274
/**
@@ -310,8 +298,9 @@ public boolean contains (float x, float y, GC gc, boolean outline) {
310
298
if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
311
299
if (gc == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
312
300
if (gc .isDisposed ()) SWT .error (SWT .ERROR_INVALID_ARGUMENT );
313
- PathHandle handle = getPathHandle (initialZoom );
314
- return handle .contains (x , y , gc , outline );
301
+ return applyUsingAnyHandle (handle -> {
302
+ return handle .contains (x , y , gc , outline );
303
+ });
315
304
}
316
305
317
306
/**
@@ -330,21 +319,22 @@ public boolean contains (float x, float y, GC gc, boolean outline) {
330
319
*/
331
320
public void cubicTo (float cx1 , float cy1 , float cx2 , float cy2 , float x , float y ) {
332
321
if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
333
- applyOperationForAllHandles (new CubicToOperation (cx1 , cy1 , cx2 , cy2 , x , y ));
322
+ storeAndApplyOperationOnAllHandles (new CubicToOperation (cx1 , cy1 , cx2 , cy2 , x , y ));
334
323
}
335
324
336
325
@ Override
337
326
void destroy () {
338
327
device .deregisterResourceWithZoomSupport (this );
339
328
zoomToHandle .values ().forEach (PathHandle ::destroy );
340
329
zoomToHandle .clear ();
330
+ this .isDestroyed = true ;
341
331
}
342
332
343
333
@ Override
344
334
void destroyHandlesExcept (Set <Integer > zoomLevels ) {
345
335
zoomToHandle .entrySet ().removeIf (entry -> {
346
336
final Integer zoom = entry .getKey ();
347
- if (!zoomLevels .contains (zoom ) && zoom != initialZoom ) {
337
+ if (!zoomLevels .contains (zoom )) {
348
338
entry .getValue ().destroy ();
349
339
return true ;
350
340
}
@@ -371,8 +361,10 @@ public void getBounds (float[] bounds) {
371
361
if (bounds == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
372
362
if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
373
363
if (bounds .length < 4 ) SWT .error (SWT .ERROR_INVALID_ARGUMENT );
374
- PathHandle handle = getPathHandle (initialZoom );
375
- handle .fillBounds (bounds );
364
+ applyUsingAnyHandle (handle -> {
365
+ handle .fillBounds (bounds );
366
+ return true ;
367
+ });
376
368
}
377
369
378
370
/**
@@ -393,8 +385,10 @@ public void getCurrentPoint (float[] point) {
393
385
if (point == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
394
386
if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
395
387
if (point .length < 2 ) SWT .error (SWT .ERROR_INVALID_ARGUMENT );
396
- PathHandle handle = getPathHandle (initialZoom );
397
- handle .fillCurrentPoint (point );
388
+ applyUsingAnyHandle (handle -> {
389
+ handle .fillCurrentPoint (point );
390
+ return true ;
391
+ });
398
392
}
399
393
400
394
/**
@@ -410,8 +404,9 @@ public void getCurrentPoint (float[] point) {
410
404
*/
411
405
public PathData getPathData () {
412
406
if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
413
- PathHandle handle = getPathHandle (initialZoom );
414
- return handle .getPathData ();
407
+ return applyUsingAnyHandle (handle -> {
408
+ return handle .getPathData ();
409
+ });
415
410
}
416
411
417
412
/**
@@ -427,7 +422,7 @@ public PathData getPathData() {
427
422
*/
428
423
public void lineTo (float x , float y ) {
429
424
if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
430
- applyOperationForAllHandles (new LineToOperation (x , y ));
425
+ storeAndApplyOperationOnAllHandles (new LineToOperation (x , y ));
431
426
}
432
427
433
428
@@ -470,7 +465,7 @@ void init(PathData data) {
470
465
*/
471
466
@ Override
472
467
public boolean isDisposed () {
473
- return zoomToHandle . isEmpty () ;
468
+ return this . isDestroyed ;
474
469
}
475
470
476
471
/**
@@ -487,7 +482,7 @@ public boolean isDisposed() {
487
482
*/
488
483
public void moveTo (float x , float y ) {
489
484
if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
490
- applyOperationForAllHandles (new MoveToOperation (x , y ));
485
+ storeAndApplyOperationOnAllHandles (new MoveToOperation (x , y ));
491
486
}
492
487
493
488
/**
@@ -504,24 +499,25 @@ public void moveTo (float x, float y) {
504
499
*/
505
500
public void quadTo (float cx , float cy , float x , float y ) {
506
501
if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
507
- applyOperationForAllHandles (new QuadToOperation (cx , cy , x , y ));
502
+ storeAndApplyOperationOnAllHandles (new QuadToOperation (cx , cy , x , y ));
508
503
}
509
504
510
- private class PathHandle {
511
- private long handle ;
512
- private int zoom ;
505
+ private static class PathHandle {
506
+ private final Device device ;
507
+ private final long handle ;
508
+ private final int zoom ;
513
509
private PointF currentPoint = new PointF ();
514
510
private PointF startPoint = new PointF ();
515
511
516
- public PathHandle (final long handle , final int zoom ) {
512
+ public PathHandle (final Device device , final long handle , final int zoom ) {
513
+ this .device = device ;
517
514
this .handle = handle ;
518
515
this .zoom = zoom ;
519
516
}
520
517
521
518
boolean contains (float x , float y , GC gc , boolean outline ) {
522
- Drawable drawable = getDevice ();
523
- float xInPixels = DPIUtil .scaleUp (drawable , x , zoom );
524
- float yInPixels = DPIUtil .scaleUp (drawable , y , zoom );
519
+ float xInPixels = DPIUtil .scaleUp (device , x , zoom );
520
+ float yInPixels = DPIUtil .scaleUp (device , y , zoom );
525
521
return containsInPixels (xInPixels , yInPixels , gc , outline );
526
522
}
527
523
@@ -544,7 +540,7 @@ void destroy() {
544
540
545
541
void fillBounds (float [] bounds ) {
546
542
getBoundsInPixels (bounds );
547
- float [] scaledbounds = DPIUtil .scaleDown (getDevice () , bounds , zoom );
543
+ float [] scaledbounds = DPIUtil .scaleDown (device , bounds , zoom );
548
544
System .arraycopy (scaledbounds , 0 , bounds , 0 , 4 );
549
545
}
550
546
@@ -559,7 +555,7 @@ private void getBoundsInPixels(float[] bounds) {
559
555
560
556
void fillCurrentPoint (float [] point ) {
561
557
getCurrentPointInPixels (point );
562
- float [] scaledpoint = DPIUtil .scaleDown (getDevice () , point , zoom );
558
+ float [] scaledpoint = DPIUtil .scaleDown (device , point , zoom );
563
559
System .arraycopy (scaledpoint , 0 , point , 0 , 2 );
564
560
}
565
561
@@ -570,7 +566,7 @@ private void getCurrentPointInPixels(float[] point) {
570
566
571
567
PathData getPathData () {
572
568
PathData result = getPathDataInPixels ();
573
- result .points = DPIUtil .scaleDown (getDevice () , result .points , zoom );
569
+ result .points = DPIUtil .scaleDown (device , result .points , zoom );
574
570
return result ;
575
571
}
576
572
@@ -721,18 +717,20 @@ private void addRectangleInPixels(PathHandle pathHandle, float x, float y, float
721
717
}
722
718
723
719
private class AddPathOperation implements Operation {
724
- private final Path path ;
720
+ private final List < Operation > pathOperations ;
725
721
726
722
public AddPathOperation (Path path ) {
727
- this .path = path ;
723
+ this .pathOperations = path . operations ;
728
724
}
729
725
730
726
@ Override
731
727
public void apply (PathHandle pathHandle ) {
732
- PathHandle secondPathHandle = path .getPathHandle (pathHandle .zoom );
733
- Gdip .GraphicsPath_AddPath (pathHandle .handle , secondPathHandle .handle , false );
734
- pathHandle .currentPoint .X = secondPathHandle .currentPoint .X ;
735
- pathHandle .currentPoint .Y = secondPathHandle .currentPoint .Y ;
728
+ applyOnTemporaryHandle (getDevice (), pathHandle .zoom , pathOperations , temporaryHandle -> {
729
+ Gdip .GraphicsPath_AddPath (pathHandle .handle , temporaryHandle .handle , false );
730
+ pathHandle .currentPoint .X = temporaryHandle .currentPoint .X ;
731
+ pathHandle .currentPoint .Y = temporaryHandle .currentPoint .Y ;
732
+ return true ;
733
+ });
736
734
}
737
735
}
738
736
@@ -798,6 +796,14 @@ public void apply(PathHandle pathHandle) {
798
796
}
799
797
}
800
798
799
+ private record FlattenOperation (float flatness ) implements Operation {
800
+ @ Override
801
+ public void apply (PathHandle pathHandle ) {
802
+ long handle = pathHandle .handle ;
803
+ Gdip .GraphicsPath_Flatten (handle , 0 , flatness );
804
+ }
805
+ }
806
+
801
807
private class CubicToOperation implements Operation {
802
808
private final float cx1 ;
803
809
private final float cy1 ;
@@ -926,10 +932,31 @@ private interface Operation {
926
932
void apply (PathHandle pathHandle );
927
933
}
928
934
929
- private void applyOperationForAllHandles (Operation operation ) {
935
+ private void storeAndApplyOperationOnAllHandles (Operation operation ) {
936
+ operations .add (operation );
930
937
zoomToHandle .values ().forEach (operation ::apply );
931
938
}
932
939
940
+ private <T > T applyUsingAnyHandle (Function <PathHandle , T > function ) {
941
+ if (zoomToHandle .isEmpty ()) {
942
+ return applyOnTemporaryHandle (getDevice (), DPIUtil .getDeviceZoom (), this .operations , function );
943
+ } else {
944
+ return function .apply (zoomToHandle .values ().iterator ().next ());
945
+ }
946
+ }
947
+
948
+ private static <T > T applyOnTemporaryHandle (Device device , int zoom , List <Operation > operations , Function <PathHandle , T > function ) {
949
+ PathHandle temporaryHandle = newEmptyPathHandle (device , zoom );
950
+ try {
951
+ for (Operation operation : operations ) {
952
+ operation .apply (temporaryHandle );
953
+ }
954
+ return function .apply (temporaryHandle );
955
+ } finally {
956
+ temporaryHandle .destroy ();
957
+ }
958
+ }
959
+
933
960
/**
934
961
* Returns a string containing a concise, human-readable
935
962
* description of the receiver.
@@ -942,14 +969,26 @@ public String toString() {
942
969
return "Path " + zoomToHandle ;
943
970
}
944
971
972
+ private static PathHandle newEmptyPathHandle (Device device , int zoom ) {
973
+ long newHandle = Gdip .GraphicsPath_new (Gdip .FillModeAlternate );
974
+ if (newHandle == 0 ) SWT .error (SWT .ERROR_NO_HANDLES );
975
+ PathHandle newPathHandle = new PathHandle (device , newHandle , zoom );
976
+ return newPathHandle ;
977
+ }
978
+
979
+ private PathHandle newPathHandle (int zoom ) {
980
+ PathHandle newPathHandle = newEmptyPathHandle (getDevice (), zoom );
981
+ for (Operation operation : operations ) {
982
+ operation .apply (newPathHandle );
983
+ }
984
+ return newPathHandle ;
985
+ }
986
+
945
987
private PathHandle getPathHandle (int zoom ) {
946
988
if (!zoomToHandle .containsKey (zoom )) {
947
- PathData pathData = getPathData ();
948
- Path scaledPath = new Path (getDevice (), pathData , zoom );
949
- long handle = scaledPath .getHandle (scaledPath .initialZoom );
950
- PathHandle pathHandle = new PathHandle (handle , zoom );
951
- zoomToHandle .put (zoom , pathHandle );
952
- return pathHandle ;
989
+ PathHandle newHandle = newPathHandle (zoom );
990
+ zoomToHandle .put (zoom , newHandle );
991
+ return newHandle ;
953
992
}
954
993
return zoomToHandle .get (zoom );
955
994
}
0 commit comments