Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@
*/
public final class Region extends Resource {

private int initialZoom;

private HashMap<Integer, Long> zoomToHandle = new HashMap<>();
private Map<Integer, RegionHandle> zoomToHandle = new HashMap<>();

private List<Operation> operations = new ArrayList<>();

private boolean isDestroyed;

/**
* Constructs a new empty region.
* <p>
Expand Down Expand Up @@ -80,9 +80,6 @@ public Region () {
*/
public Region (Device device) {
super(device);
initialZoom = DPIUtil.getDeviceZoom();
long handle = newEmptyRegionHandle();
zoomToHandle.put(initialZoom, handle);
init();
this.device.registerResourceWithZoomSupport(this);
}
Expand Down Expand Up @@ -173,8 +170,10 @@ public void add (Region region) {
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (region == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
if (region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
final Operation operation = new OperationWithRegion(Operation::add, region);
storeAndApplyOperationForAllHandles(operation);
if (!region.operations.isEmpty()) {
final Operation operation = new OperationWithRegion(Operation::add, region.operations);
storeAndApplyOperationForAllHandles(operation);
}
}

/**
Expand All @@ -192,11 +191,16 @@ public void add (Region region) {
*/
public boolean contains (int x, int y) {
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
return containsInPixels(DPIUtil.scaleUp(x, initialZoom), DPIUtil.scaleUp(y, initialZoom));
return applyUsingAnyHandle(regionHandle -> {
int zoom = regionHandle.zoom();
int xInPixels = DPIUtil.scaleUp(x, zoom);
int yInPixels = DPIUtil.scaleUp(y, zoom);
return containsInPixels(regionHandle.handle(), xInPixels, yInPixels);
});
}

boolean containsInPixels (int x, int y) {
return OS.PtInRegion (getHandleForInitialZoom(), x, y);
boolean containsInPixels (long handle, int x, int y) {
return OS.PtInRegion (handle, x, y);
}

/**
Expand All @@ -217,24 +221,28 @@ boolean containsInPixels (int x, int y) {
public boolean contains (Point pt) {
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (pt == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
Point p = DPIUtil.scaleUp(pt, initialZoom);
return containsInPixels(p.x, p.y);
return applyUsingAnyHandle(regionHandle -> {
int zoom = regionHandle.zoom();
Point p = DPIUtil.scaleUp(pt, zoom);
return containsInPixels(regionHandle.handle(), p.x, p.y);
});
}

@Override
void destroy () {
device.deregisterResourceWithZoomSupport(this);
zoomToHandle.values().forEach(handle -> OS.DeleteObject(handle));
zoomToHandle.values().forEach(RegionHandle::destroy);
zoomToHandle.clear();
operations.clear();
this.isDestroyed = true;
}

@Override
void destroyHandlesExcept(Set<Integer> zoomLevels) {
zoomToHandle.entrySet().removeIf(entry -> {
final Integer zoom = entry.getKey();
if (!zoomLevels.contains(zoom) && zoom != initialZoom) {
OS.DeleteObject(entry.getValue());
if (!zoomLevels.contains(zoom)) {
entry.getValue().destroy();
return true;
}
return false;
Expand Down Expand Up @@ -271,12 +279,14 @@ public boolean equals (Object object) {
*/
public Rectangle getBounds () {
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
return DPIUtil.scaleDown(getBoundsInPixels(), initialZoom);
return applyUsingAnyHandle(regionHandle -> {
return DPIUtil.scaleDown(getBoundsInPixels(regionHandle.handle()), regionHandle.zoom());
});
}

Rectangle getBoundsInPixels() {
private Rectangle getBoundsInPixels(long handle) {
RECT rect = new RECT();
OS.GetRgnBox(getHandleForInitialZoom(), rect);
OS.GetRgnBox(handle, rect);
return new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
}

Expand All @@ -294,7 +304,6 @@ Rectangle getBoundsInPixels() {
public int hashCode () {
return super.hashCode();
}

/**
* Intersects the given rectangle to the collection of polygons
* the receiver maintains to describe its area.
Expand Down Expand Up @@ -363,8 +372,10 @@ public void intersect (Region region) {
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (region == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
if (region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
final Operation operation = new OperationWithRegion(Operation::intersect, region);
storeAndApplyOperationForAllHandles(operation);
if (!region.operations.isEmpty()) {
final Operation operation = new OperationWithRegion(Operation::intersect, region.operations);
storeAndApplyOperationForAllHandles(operation);
}
}

/**
Expand All @@ -389,10 +400,10 @@ public boolean intersects (int x, int y, int width, int height) {
return intersects(new Rectangle(x, y, width, height));
}

boolean intersectsInPixels (int x, int y, int width, int height) {
boolean intersectsInPixels (long handle, int x, int y, int width, int height) {
RECT r = new RECT ();
OS.SetRect (r, x, y, x + width, y + height);
return OS.RectInRegion (getHandleForInitialZoom(), r);
return OS.RectInRegion(handle, r);
}

/**
Expand All @@ -415,8 +426,10 @@ boolean intersectsInPixels (int x, int y, int width, int height) {
public boolean intersects (Rectangle rect) {
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
Rectangle r = DPIUtil.scaleUp(rect, initialZoom);
return intersectsInPixels(r.x, r.y, r.width, r.height);
return applyUsingAnyHandle(regionHandle -> {
Rectangle r = DPIUtil.scaleUp(rect, regionHandle.zoom());
return intersectsInPixels(regionHandle.handle(), r.x, r.y, r.width, r.height);
});
}

/**
Expand All @@ -431,7 +444,7 @@ public boolean intersects (Rectangle rect) {
*/
@Override
public boolean isDisposed() {
return zoomToHandle.isEmpty();
return isDestroyed;
}

/**
Expand All @@ -448,9 +461,11 @@ public boolean isDisposed() {
public boolean isEmpty () {
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
RECT rect = new RECT ();
int result = OS.GetRgnBox (getHandleForInitialZoom(), rect);
if (result == OS.NULLREGION) return true;
return ((rect.right - rect.left) <= 0) || ((rect.bottom - rect.top) <= 0);
return applyUsingAnyHandle(regionHandle -> {
int result = OS.GetRgnBox(regionHandle.handle(), rect);
if (result == OS.NULLREGION) return true;
return ((rect.right - rect.left) <= 0) || ((rect.bottom - rect.top) <= 0);
});
}

/**
Expand Down Expand Up @@ -543,8 +558,10 @@ public void subtract (Region region) {
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (region == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
if (region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
final Operation operation = new OperationWithRegion(Operation::subtract, region);
storeAndApplyOperationForAllHandles(operation);
if (!region.operations.isEmpty()) {
final Operation operation = new OperationWithRegion(Operation::subtract, region.operations);
storeAndApplyOperationForAllHandles(operation);
}
}

/**
Expand Down Expand Up @@ -588,36 +605,43 @@ public void translate (Point pt) {
storeAndApplyOperationForAllHandles(operation);
}

private long getHandleForInitialZoom() {
return win32_getHandle(this, initialZoom);
}

private void storeAndApplyOperationForAllHandles(Operation operation) {
operations.add(operation);
zoomToHandle.forEach((zoom, handle) -> operation.apply(handle, zoom));
zoomToHandle.forEach((zoom, handle) -> operation.apply(handle));
}

private <T> T applyUsingAnyHandle(Function<RegionHandle, T> function) {
if (zoomToHandle.isEmpty()) {
return applyUsingTemporaryHandle(device.getDeviceZoom(), operations, function);
}
return function.apply(zoomToHandle.values().iterator().next());
}

private static <T> T applyUsingTemporaryHandle(int zoom, List<Operation> operations, Function<Long, T> function) {
long temporaryHandle = newRegionHandle(operations, zoom);
private static <T> T applyUsingTemporaryHandle(int zoom, List<Operation> operations, Function<RegionHandle, T> function) {
RegionHandle temporaryHandle = newRegionHandle(zoom, operations);
try {
return function.apply(temporaryHandle);
} finally {
OS.DeleteObject(temporaryHandle);
temporaryHandle.destroy();
}
}

private static long newEmptyRegionHandle() {
private static RegionHandle newRegionHandle(int zoom, List<Operation> operations) {
long newHandle = OS.CreateRectRgn (0, 0, 0, 0);
if (newHandle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
return newHandle;
RegionHandle newRegionHandle = new RegionHandle(newHandle, zoom);
for (Operation operation : operations) {
operation.apply(newRegionHandle);
}
return newRegionHandle;
}

private static long newRegionHandle(List<Operation> operations, int zoom) {
long newHandle = newEmptyRegionHandle();
for (Operation operation : operations) {
operation.apply(newHandle, zoom);
private RegionHandle getRegionHandle(int zoom) {
if (!zoomToHandle.containsKey(zoom)) {
RegionHandle regionHandle = newRegionHandle(zoom, operations);
zoomToHandle.put(zoom, regionHandle);
}
return newHandle;
return zoomToHandle.get(zoom);
}

/**
Expand All @@ -638,14 +662,7 @@ private static long newRegionHandle(List<Operation> operations, int zoom) {
* @noreference This method is not intended to be referenced by clients.
*/
public static long win32_getHandle(Region region, int zoom) {
if (!region.zoomToHandle.containsKey(zoom)) {
long handle = newEmptyRegionHandle();
for (Operation operation : region.operations) {
operation.apply(handle, zoom);
}
region.zoomToHandle.put(zoom, handle);
}
return region.zoomToHandle.get(zoom);
return region.getRegionHandle(zoom).handle();
}

/**
Expand All @@ -660,20 +677,26 @@ public String toString () {
return "Region {" + zoomToHandle.entrySet().stream().map(entry -> entry.getValue() + "(zoom:" + entry.getKey() + ")").collect(Collectors.joining(","));
}

private record RegionHandle(long handle, int zoom) {
void destroy() {
OS.DeleteObject(handle());
}
}

@FunctionalInterface
private interface OperationStrategy {
void apply(Operation operation, long handle, int zoom);
}

private abstract static class Operation {
private OperationStrategy operationStrategy;
private final OperationStrategy operationStrategy;

Operation(OperationStrategy operationStrategy) {
this.operationStrategy = operationStrategy;
}

void apply(long handle, int zoom) {
operationStrategy.apply(this, handle, zoom);
void apply(RegionHandle regionHandle) {
operationStrategy.apply(this, regionHandle.handle(), regionHandle.zoom());
}

abstract void add(long handle, int zoom);
Expand All @@ -686,8 +709,7 @@ void apply(long handle, int zoom) {
}

private static class OperationWithRectangle extends Operation {

Rectangle data;
private final Rectangle data;

OperationWithRectangle(OperationStrategy operationStrategy, Rectangle data) {
super(operationStrategy);
Expand Down Expand Up @@ -745,8 +767,7 @@ private Rectangle getScaledRectangle(int zoom) {
}

private static class OperationWithArray extends Operation {

int[] data;
private final int[] data;

public OperationWithArray(OperationStrategy operationStrategy, int[] data) {
super(operationStrategy);
Expand Down Expand Up @@ -793,8 +814,7 @@ private int[] getScaledPoints(int zoom) {
}

private static class OperationWithPoint extends Operation {

Point data;
private final Point data;

public OperationWithPoint(OperationStrategy operationStrategy, Point data) {
super(operationStrategy);
Expand Down Expand Up @@ -827,29 +847,29 @@ void translate(long handle, int zoom) {
private static class OperationWithRegion extends Operation {
private final List<Operation> operations;

OperationWithRegion(OperationStrategy operationStrategy, Region data) {
OperationWithRegion(OperationStrategy operationStrategy, List<Operation> operations) {
super(operationStrategy);
this.operations = data.operations;
this.operations = List.copyOf(operations);
}

@Override
void add(long handle, int zoom) {
applyUsingTemporaryHandle(zoom, operations, regionHandle -> {
return OS.CombineRgn (handle, handle, regionHandle, OS.RGN_OR);
return OS.CombineRgn (handle, handle, regionHandle.handle(), OS.RGN_OR);
});
}

@Override
void subtract(long handle, int zoom) {
applyUsingTemporaryHandle(zoom, operations, regionHandle -> {
return OS.CombineRgn (handle, handle, regionHandle, OS.RGN_DIFF);
return OS.CombineRgn (handle, handle, regionHandle.handle(), OS.RGN_DIFF);
});
}

@Override
void intersect(long handle, int zoom) {
applyUsingTemporaryHandle(zoom, operations, regionHandle -> {
return OS.CombineRgn (handle, handle, regionHandle, OS.RGN_AND);
return OS.CombineRgn (handle, handle, regionHandle.handle(), OS.RGN_AND);
});
}

Expand Down
Loading