Skip to content

Commit d29a06f

Browse files
authored
[win32] Dynamic handle creation for Path (#1869)
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 326658a commit d29a06f

File tree

3 files changed

+220
-64
lines changed

3 files changed

+220
-64
lines changed

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

Lines changed: 103 additions & 64 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+
path.operations.forEach(this::storeAndApplyOperationOnAllHandles);
124+
if (flatness != 0) {
125+
storeAndApplyOperationOnAllHandles(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 applyUsingAnyHandle(handle -> {
302+
return handle.contains(x, y, gc, outline);
303+
});
315304
}
316305

317306
/**
@@ -330,21 +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) {
345335
zoomToHandle.entrySet().removeIf(entry -> {
346336
final Integer zoom = entry.getKey();
347-
if (!zoomLevels.contains(zoom) && zoom != initialZoom) {
337+
if (!zoomLevels.contains(zoom)) {
348338
entry.getValue().destroy();
349339
return true;
350340
}
@@ -371,8 +361,10 @@ public void getBounds (float[] bounds) {
371361
if (bounds == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
372362
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
373363
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+
});
376368
}
377369

378370
/**
@@ -393,8 +385,10 @@ public void getCurrentPoint (float[] point) {
393385
if (point == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
394386
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
395387
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+
});
398392
}
399393

400394
/**
@@ -410,8 +404,9 @@ public void getCurrentPoint (float[] point) {
410404
*/
411405
public PathData getPathData() {
412406
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+
});
415410
}
416411

417412
/**
@@ -427,7 +422,7 @@ public PathData getPathData() {
427422
*/
428423
public void lineTo (float x, float y) {
429424
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
430-
applyOperationForAllHandles(new LineToOperation(x, y));
425+
storeAndApplyOperationOnAllHandles(new LineToOperation(x, y));
431426
}
432427

433428

@@ -470,7 +465,7 @@ void init(PathData data) {
470465
*/
471466
@Override
472467
public boolean isDisposed() {
473-
return zoomToHandle.isEmpty();
468+
return this.isDestroyed;
474469
}
475470

476471
/**
@@ -487,7 +482,7 @@ public boolean isDisposed() {
487482
*/
488483
public void moveTo (float x, float y) {
489484
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
490-
applyOperationForAllHandles(new MoveToOperation(x, y));
485+
storeAndApplyOperationOnAllHandles(new MoveToOperation(x, y));
491486
}
492487

493488
/**
@@ -504,24 +499,25 @@ public void moveTo (float x, float y) {
504499
*/
505500
public void quadTo (float cx, float cy, float x, float y) {
506501
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
507-
applyOperationForAllHandles(new QuadToOperation(cx, cy, x, y));
502+
storeAndApplyOperationOnAllHandles(new QuadToOperation(cx, cy, x, y));
508503
}
509504

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;
513509
private PointF currentPoint = new PointF();
514510
private PointF startPoint = new PointF();
515511

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;
517514
this.handle = handle;
518515
this.zoom = zoom;
519516
}
520517

521518
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);
525521
return containsInPixels(xInPixels, yInPixels, gc, outline);
526522
}
527523

@@ -544,7 +540,7 @@ void destroy() {
544540

545541
void fillBounds (float[] bounds) {
546542
getBoundsInPixels(bounds);
547-
float[] scaledbounds= DPIUtil.scaleDown(getDevice(), bounds, zoom);
543+
float[] scaledbounds= DPIUtil.scaleDown(device, bounds, zoom);
548544
System.arraycopy(scaledbounds, 0, bounds, 0, 4);
549545
}
550546

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

560556
void fillCurrentPoint (float[] point) {
561557
getCurrentPointInPixels(point);
562-
float[] scaledpoint= DPIUtil.scaleDown(getDevice(), point, zoom);
558+
float[] scaledpoint= DPIUtil.scaleDown(device, point, zoom);
563559
System.arraycopy(scaledpoint, 0, point, 0, 2);
564560
}
565561

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

571567
PathData getPathData() {
572568
PathData result = getPathDataInPixels();
573-
result.points = DPIUtil.scaleDown(getDevice(), result.points, zoom);
569+
result.points = DPIUtil.scaleDown(device, result.points, zoom);
574570
return result;
575571
}
576572

@@ -721,18 +717,20 @@ private void addRectangleInPixels(PathHandle pathHandle, float x, float y, float
721717
}
722718

723719
private class AddPathOperation implements Operation {
724-
private final Path path;
720+
private final List<Operation> pathOperations;
725721

726722
public AddPathOperation(Path path) {
727-
this.path = path;
723+
this.pathOperations = path.operations;
728724
}
729725

730726
@Override
731727
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+
});
736734
}
737735
}
738736

@@ -798,6 +796,14 @@ public void apply(PathHandle pathHandle) {
798796
}
799797
}
800798

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+
801807
private class CubicToOperation implements Operation {
802808
private final float cx1;
803809
private final float cy1;
@@ -926,10 +932,31 @@ private interface Operation {
926932
void apply(PathHandle pathHandle);
927933
}
928934

929-
private void applyOperationForAllHandles(Operation operation) {
935+
private void storeAndApplyOperationOnAllHandles(Operation operation) {
936+
operations.add(operation);
930937
zoomToHandle.values().forEach(operation::apply);
931938
}
932939

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+
933960
/**
934961
* Returns a string containing a concise, human-readable
935962
* description of the receiver.
@@ -942,14 +969,26 @@ public String toString() {
942969
return "Path " + zoomToHandle;
943970
}
944971

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+
945987
private PathHandle getPathHandle(int zoom) {
946988
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;
953992
}
954993
return zoomToHandle.get(zoom);
955994
}

tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/AllGraphicsTests.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
Test_org_eclipse_swt_graphics_Image.class,
3232
Test_org_eclipse_swt_graphics_ImageData.class,
3333
Test_org_eclipse_swt_graphics_PaletteData.class,
34+
Test_org_eclipse_swt_graphics_Path.class,
3435
Test_org_eclipse_swt_graphics_Point.class,
3536
Test_org_eclipse_swt_graphics_Rectangle.class,
3637
Test_org_eclipse_swt_graphics_Region.class,

0 commit comments

Comments
 (0)