Skip to content

Commit fcb1337

Browse files
committed
[win32] Dynamic handle creation for Path
This commit adapts Path in the win32 implementation to create handles only on demand. If a non-handle specific operation like getBounds() is called, a temporary handle will be created and disposed afterwards if no handle exists already.
1 parent 82e393b commit fcb1337

File tree

1 file changed

+105
-71
lines changed
  • bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics

1 file changed

+105
-71
lines changed

bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Path.java

Lines changed: 105 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package org.eclipse.swt.graphics;
1515

1616
import java.util.*;
17+
import java.util.function.*;
1718

1819
import org.eclipse.swt.*;
1920
import org.eclipse.swt.internal.*;
@@ -42,10 +43,12 @@
4243
* @since 3.1
4344
*/
4445
public class Path extends Resource {
45-
private int initialZoom;
46-
4746
private Map<Integer, PathHandle> zoomToHandle = new HashMap<>();
4847

48+
private List<Operation> operations = new ArrayList<>();
49+
50+
private boolean isDestroyed;
51+
4952
/**
5053
* Constructs a new empty Path.
5154
* <p>
@@ -72,16 +75,8 @@ public class Path extends Resource {
7275
* @see #dispose()
7376
*/
7477
public Path (Device device) {
75-
this(device, DPIUtil.getDeviceZoom());
76-
}
77-
78-
private Path(Device device, int zoom) {
7978
super(device);
8079
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));
8580
init();
8681
this.device.registerResourceWithZoomSupport(this);
8782
}
@@ -125,11 +120,10 @@ public Path (Device device, Path path, float flatness) {
125120
if (path == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
126121
if (path.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
127122
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+
operations.addAll(path.operations);
124+
if (flatness != 0) {
125+
operations.add(new FlattenOperation(flatness));
126+
}
133127
init();
134128
this.device.registerResourceWithZoomSupport(this);
135129
}
@@ -163,15 +157,9 @@ public Path (Device device, Path path, float flatness) {
163157
* @since 3.4
164158
*/
165159
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);
172161
if (data == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
173162
init(data);
174-
this.device.registerResourceWithZoomSupport(this);
175163
}
176164

177165
/**
@@ -205,7 +193,7 @@ private Path(Device device, PathData data, int zoom) {
205193
*/
206194
public void addArc (float x, float y, float width, float height, float startAngle, float arcAngle) {
207195
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));
209197
}
210198

211199
/**
@@ -225,7 +213,7 @@ public void addPath(Path path) {
225213
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
226214
if (path == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
227215
if (path.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
228-
applyOperationForAllHandles(new AddPathOperation(path));
216+
storeAndApplyOperationOnAllHandles(new AddPathOperation(path));
229217
}
230218

231219
/**
@@ -242,7 +230,7 @@ public void addPath(Path path) {
242230
*/
243231
public void addRectangle (float x, float y, float width, float height) {
244232
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
245-
applyOperationForAllHandles(new AddRectangleOperation(x, y, width, height));
233+
storeAndApplyOperationOnAllHandles(new AddRectangleOperation(x, y, width, height));
246234
}
247235

248236
/**
@@ -266,7 +254,7 @@ public void addString (String string, float x, float y, Font font) {
266254
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
267255
if (font == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
268256
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));
270258
}
271259

272260
/**
@@ -280,7 +268,7 @@ public void addString (String string, float x, float y, Font font) {
280268
*/
281269
public void close() {
282270
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
283-
applyOperationForAllHandles(new CloseOperation());
271+
storeAndApplyOperationOnAllHandles(new CloseOperation());
284272
}
285273

286274
/**
@@ -310,8 +298,9 @@ public boolean contains (float x, float y, GC gc, boolean outline) {
310298
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
311299
if (gc == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
312300
if (gc.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
313-
PathHandle handle = getPathHandle(initialZoom);
314-
return handle.contains(x, y, gc, outline);
301+
return applyOnAnyHandle(handle -> {
302+
return handle.contains(x, y, gc, outline);
303+
});
315304
}
316305

317306
/**
@@ -330,26 +319,22 @@ public boolean contains (float x, float y, GC gc, boolean outline) {
330319
*/
331320
public void cubicTo (float cx1, float cy1, float cx2, float cy2, float x, float y) {
332321
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));
334323
}
335324

336325
@Override
337326
void destroy() {
338327
device.deregisterResourceWithZoomSupport(this);
339328
zoomToHandle.values().forEach(PathHandle::destroy);
340329
zoomToHandle.clear();
330+
this.isDestroyed = true;
341331
}
342332

343333
@Override
344334
void destroyHandlesExcept(Set<Integer> zoomLevels) {
345-
zoomToHandle.entrySet().removeIf(entry -> {
346-
final Integer zoom = entry.getKey();
347-
if (!zoomLevels.contains(zoom) && zoom != initialZoom) {
348-
entry.getValue().destroy();
349-
return true;
350-
}
351-
return false;
352-
});
335+
// As long as we keep the operations, we can cleanup all handles
336+
zoomToHandle.values().forEach(PathHandle::destroy);
337+
zoomToHandle.clear();
353338
}
354339

355340
/**
@@ -371,8 +356,10 @@ public void getBounds (float[] bounds) {
371356
if (bounds == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
372357
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
373358
if (bounds.length < 4) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
374-
PathHandle handle = getPathHandle(initialZoom);
375-
handle.fillBounds(bounds);
359+
applyOnAnyHandle(handle -> {
360+
handle.fillBounds(bounds);
361+
return true;
362+
});
376363
}
377364

378365
/**
@@ -393,8 +380,10 @@ public void getCurrentPoint (float[] point) {
393380
if (point == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
394381
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
395382
if (point.length < 2) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
396-
PathHandle handle = getPathHandle(initialZoom);
397-
handle.fillCurrentPoint(point);
383+
applyOnAnyHandle(handle -> {
384+
handle.fillCurrentPoint(point);
385+
return true;
386+
});
398387
}
399388

400389
/**
@@ -410,8 +399,9 @@ public void getCurrentPoint (float[] point) {
410399
*/
411400
public PathData getPathData() {
412401
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
413-
PathHandle handle = getPathHandle(initialZoom);
414-
return handle.getPathData();
402+
return applyOnAnyHandle(handle -> {
403+
return handle.getPathData();
404+
});
415405
}
416406

417407
/**
@@ -427,7 +417,7 @@ public PathData getPathData() {
427417
*/
428418
public void lineTo (float x, float y) {
429419
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
430-
applyOperationForAllHandles(new LineToOperation(x, y));
420+
storeAndApplyOperationOnAllHandles(new LineToOperation(x, y));
431421
}
432422

433423

@@ -470,7 +460,7 @@ void init(PathData data) {
470460
*/
471461
@Override
472462
public boolean isDisposed() {
473-
return zoomToHandle.isEmpty();
463+
return this.isDestroyed;
474464
}
475465

476466
/**
@@ -487,7 +477,7 @@ public boolean isDisposed() {
487477
*/
488478
public void moveTo (float x, float y) {
489479
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
490-
applyOperationForAllHandles(new MoveToOperation(x, y));
480+
storeAndApplyOperationOnAllHandles(new MoveToOperation(x, y));
491481
}
492482

493483
/**
@@ -504,24 +494,25 @@ public void moveTo (float x, float y) {
504494
*/
505495
public void quadTo (float cx, float cy, float x, float y) {
506496
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
507-
applyOperationForAllHandles(new QuadToOperation(cx, cy, x, y));
497+
storeAndApplyOperationOnAllHandles(new QuadToOperation(cx, cy, x, y));
508498
}
509499

510-
private class PathHandle {
511-
private long handle;
512-
private int zoom;
500+
private static class PathHandle {
501+
private final Device device;
502+
private final long handle;
503+
private final int zoom;
513504
private PointF currentPoint = new PointF();
514505
private PointF startPoint = new PointF();
515506

516-
public PathHandle(final long handle, final int zoom) {
507+
public PathHandle(final Device device, final long handle, final int zoom) {
508+
this.device = device;
517509
this.handle = handle;
518510
this.zoom = zoom;
519511
}
520512

521513
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);
514+
float xInPixels = DPIUtil.scaleUp(device, x, zoom);
515+
float yInPixels = DPIUtil.scaleUp(device, y, zoom);
525516
return containsInPixels(xInPixels, yInPixels, gc, outline);
526517
}
527518

@@ -544,7 +535,7 @@ void destroy() {
544535

545536
void fillBounds (float[] bounds) {
546537
getBoundsInPixels(bounds);
547-
float[] scaledbounds= DPIUtil.scaleDown(getDevice(), bounds, zoom);
538+
float[] scaledbounds= DPIUtil.scaleDown(device, bounds, zoom);
548539
System.arraycopy(scaledbounds, 0, bounds, 0, 4);
549540
}
550541

@@ -559,7 +550,7 @@ private void getBoundsInPixels(float[] bounds) {
559550

560551
void fillCurrentPoint (float[] point) {
561552
getCurrentPointInPixels(point);
562-
float[] scaledpoint= DPIUtil.scaleDown(getDevice(), point, zoom);
553+
float[] scaledpoint= DPIUtil.scaleDown(device, point, zoom);
563554
System.arraycopy(scaledpoint, 0, point, 0, 2);
564555
}
565556

@@ -570,7 +561,7 @@ private void getCurrentPointInPixels(float[] point) {
570561

571562
PathData getPathData() {
572563
PathData result = getPathDataInPixels();
573-
result.points = DPIUtil.scaleDown(getDevice(), result.points, zoom);
564+
result.points = DPIUtil.scaleDown(device, result.points, zoom);
574565
return result;
575566
}
576567

@@ -721,18 +712,20 @@ private void addRectangleInPixels(PathHandle pathHandle, float x, float y, float
721712
}
722713

723714
private class AddPathOperation implements Operation {
724-
private final Path path;
715+
private final List<Operation> operations;
725716

726717
public AddPathOperation(Path path) {
727-
this.path = path;
718+
this.operations = path.operations;
728719
}
729720

730721
@Override
731722
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;
723+
applyOnTemporaryHandle(getDevice(), pathHandle.zoom, operations, temporaryHandle -> {
724+
Gdip.GraphicsPath_AddPath(pathHandle.handle, temporaryHandle.handle, false);
725+
pathHandle.currentPoint.X = temporaryHandle.currentPoint.X;
726+
pathHandle.currentPoint.Y = temporaryHandle.currentPoint.Y;
727+
return true;
728+
});
736729
}
737730
}
738731

@@ -798,6 +791,14 @@ public void apply(PathHandle pathHandle) {
798791
}
799792
}
800793

794+
private record FlattenOperation(float flatness) implements Operation {
795+
@Override
796+
public void apply(PathHandle pathHandle) {
797+
long handle = pathHandle.handle;
798+
Gdip.GraphicsPath_Flatten(handle, 0, flatness);
799+
}
800+
}
801+
801802
private class CubicToOperation implements Operation {
802803
private final float cx1;
803804
private final float cy1;
@@ -926,10 +927,31 @@ private interface Operation {
926927
void apply(PathHandle pathHandle);
927928
}
928929

929-
private void applyOperationForAllHandles(Operation operation) {
930+
private void storeAndApplyOperationOnAllHandles(Operation operation) {
931+
operations.add(operation);
930932
zoomToHandle.values().forEach(operation::apply);
931933
}
932934

935+
private <T> T applyOnAnyHandle(Function<PathHandle, T> function) {
936+
if (zoomToHandle.isEmpty()) {
937+
return applyOnTemporaryHandle(getDevice(), DPIUtil.getDeviceZoom(), this.operations, function);
938+
} else {
939+
return function.apply(zoomToHandle.values().iterator().next());
940+
}
941+
}
942+
943+
private static <T> T applyOnTemporaryHandle(Device device, int zoom, List<Operation> operations, Function<PathHandle, T> function) {
944+
PathHandle temporaryHandle = newEmptyPathHandle(device, zoom);
945+
try {
946+
for (Operation operation : operations) {
947+
operation.apply(temporaryHandle);
948+
}
949+
return function.apply(temporaryHandle);
950+
} finally {
951+
temporaryHandle.destroy();
952+
}
953+
}
954+
933955
/**
934956
* Returns a string containing a concise, human-readable
935957
* description of the receiver.
@@ -942,14 +964,26 @@ public String toString() {
942964
return "Path " + zoomToHandle;
943965
}
944966

967+
private static PathHandle newEmptyPathHandle(Device device, int zoom) {
968+
long newHandle = Gdip.GraphicsPath_new(Gdip.FillModeAlternate);
969+
if (newHandle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
970+
PathHandle newPathHandle = new PathHandle(device, newHandle, zoom);
971+
return newPathHandle;
972+
}
973+
974+
private PathHandle newPathHandle(int zoom) {
975+
PathHandle newPathHandle = newEmptyPathHandle(getDevice(), zoom);
976+
for (Operation operation : operations) {
977+
operation.apply(newPathHandle);
978+
}
979+
return newPathHandle;
980+
}
981+
945982
private PathHandle getPathHandle(int zoom) {
946983
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;
984+
PathHandle newHandle = newPathHandle(zoom);
985+
zoomToHandle.put(zoom, newHandle);
986+
return newHandle;
953987
}
954988
return zoomToHandle.get(zoom);
955989
}

0 commit comments

Comments
 (0)