From 3d1c6f408328a8abf74de5feaeff3c617fd5aa6c Mon Sep 17 00:00:00 2001 From: Heiko Klare Date: Tue, 14 Oct 2025 11:25:02 +0200 Subject: [PATCH] [Win32] Reuse zoom handle for drawing image at size if appropriate When drawing an image at a specified size, currently a new image handle is always created based on on-demand loaded image data. In case the fallback to loading image data for the best fitting zoom is used, a handle for that zoom may already exist and could be reused but is currently not considered. With this change, an existing handle is used if appropriate instead of unnecessarily creating a temporary handle. --- .../win32/org/eclipse/swt/graphics/Image.java | 82 +++++++++++-------- 1 file changed, 48 insertions(+), 34 deletions(-) diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java index 52d6c2219d..710a80623c 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java @@ -136,30 +136,66 @@ public final class Image extends Resource implements Drawable { private List> onDisposeListeners; - private record CachedHandle(ImageHandle handleContainer, int requestedWidth, int requestedHeight) { + private class HandleAtSize { + private ImageHandle handleContainer = null; + private int requestedWidth = -1; + private int requestedHeight = -1; public void destroy() { - if (handleContainer != null) { + if (handleContainer != null && !zoomLevelToImageHandle.containsValue(handleContainer)) { handleContainer.destroy(); } + handleContainer = null; + requestedWidth = -1; + requestedHeight = -1; } - public boolean isReusable(int height, int width) { - if(handleContainer == null) { + public ImageHandle refresh(int width, int height) { + if (!isReusable(width, height)) { + destroy(); + requestedWidth = width; + requestedHeight = height; + handleContainer = createHandleAtExactSize(width, height) + .orElseGet(() -> getOrCreateImageHandleAtClosestSize(width, height)); + } + return handleContainer; + } + + private boolean isReusable(int width, int height) { + if (handleContainer == null || handleContainer.isDisposed()) { return false; } return (requestedHeight == height && requestedWidth == width) || (handleContainer.height == height && handleContainer.width == width); + } + private Optional createHandleAtExactSize(int width, int height) { + Optional imageData = imageProvider.loadImageDataAtExactSize(width, height); + if (imageData.isPresent()) { + ImageData adaptedData = adaptImageDataIfDisabledOrGray(imageData.get()); + ImageHandle imageHandle = init(adaptedData, -1); + return Optional.of(imageHandle); + } + return Optional.empty(); } - public ImageHandle getHandle() { - return handleContainer; + private ImageHandle getOrCreateImageHandleAtClosestSize(int widthHint, int heightHint) { + Rectangle bounds = getBounds(100); + int imageZoomForWidth = 100 * widthHint / bounds.width; + int imageZoomForHeight = 100 * heightHint / bounds.height; + int imageZoom = DPIUtil.getZoomForAutoscaleProperty(Math.max(imageZoomForWidth, imageZoomForHeight)); + ImageHandle bestFittingHandle = zoomLevelToImageHandle.get(imageZoom); + if (bestFittingHandle == null) { + ImageData bestFittingImageData = imageProvider.loadImageData(imageZoom).element(); + ImageData adaptedData = adaptImageDataIfDisabledOrGray(bestFittingImageData); + bestFittingHandle = init(adaptedData, -1); + } + return bestFittingHandle; } - }; - // Initialize lastRequestedHandle with -1 for size-related fields to indicate uninitialized values - CachedHandle lastRequestedHandle = new CachedHandle(null, -1, -1); + } + + private final HandleAtSize lastRequestedHandle = new HandleAtSize(); private Image (Device device, int type, long handle, int nativeZoom) { super(device); @@ -840,14 +876,8 @@ ImageHandle getHandle (int targetZoom, int nativeZoom) { } void executeOnImageHandleAtBestFittingSize(Consumer handleAtSizeConsumer, int widthHint, int heightHint) { - if (!lastRequestedHandle.isReusable(heightHint, widthHint)) { - ImageData imageData; - imageData = this.imageProvider.loadImageDataAtSize(widthHint, heightHint); - lastRequestedHandle.destroy(); - ImageHandle handleContainer = init(imageData, -1); - lastRequestedHandle = new CachedHandle(handleContainer, widthHint, heightHint); - } - handleAtSizeConsumer.accept(lastRequestedHandle.getHandle()); + ImageHandle imageHandle = lastRequestedHandle.refresh(widthHint, heightHint); + handleAtSizeConsumer.accept(imageHandle); } /** @@ -1083,8 +1113,8 @@ void destroy () { } private void destroyHandles() { - destroyHandles(__ -> true); lastRequestedHandle.destroy(); + destroyHandles(__ -> true); } @Override @@ -1992,22 +2022,6 @@ ElementAtZoom getClosestAvailableImageData(int zoom) { return new ElementAtZoom<>(getImageMetadata(new ZoomContext(closestZoom)).getImageData(), closestZoom); } - public ImageData loadImageDataAtSize(int widthHint, int heightHint) { - Optional exact = loadImageDataAtExactSize(widthHint, heightHint); - if (exact.isPresent()) { - return adaptImageDataIfDisabledOrGray(exact.get()); - } - return loadImageDataClosestTo(widthHint, heightHint); - } - - private ImageData loadImageDataClosestTo(int targetWidth, int targetHeight) { - Rectangle bounds = getBounds(100); - int imageZoomForWidth = 100 * targetWidth / bounds.width; - int imageZoomForHeight = 100 * targetHeight / bounds.height; - int imageZoom = DPIUtil.getZoomForAutoscaleProperty(Math.max(imageZoomForWidth, imageZoomForHeight)); - return loadImageData(imageZoom).element(); - } - protected Optional loadImageDataAtExactSize(int width, int height) { return Optional.empty(); // exact size not available }