From 583bf9bb5121da0168a81d76c961ec5646f79dfa Mon Sep 17 00:00:00 2001 From: arunjose696 Date: Tue, 14 Oct 2025 10:31:50 +0200 Subject: [PATCH] [GTK] Support loading and drawing images at desired size This change introduces support for loading and drawing images at custom sizes in the GTK versions of GC and Image. The GC#drawImage() method, which only accepts the destination position and size, now attempts to load image at the destination size in case if it is provided by ImageFilenameProvider returning svgs or if the image is created with a imageDataAtSizeProvider. --- .../gtk/org/eclipse/swt/graphics/GC.java | 2 +- .../gtk/org/eclipse/swt/graphics/Image.java | 69 +++++++++++++++++++ .../Test_org_eclipse_swt_graphics_GC.java | 6 +- 3 files changed, 71 insertions(+), 6 deletions(-) diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/GC.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/GC.java index 1e70b7254c..6ee298079e 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/GC.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/GC.java @@ -913,7 +913,7 @@ public void drawImage(Image image, int destX, int destY, int destWidth, int dest if (image.isDisposed()) { SWT.error(SWT.ERROR_INVALID_ARGUMENT); } - drawImage(image, 0, 0, 0, 0, destX, destY, destWidth, destHeight, false); + image.executeOnImageAtSize(imageAtSize -> drawImage(imageAtSize, 0, 0, 0, 0, destX, destY, destWidth, destHeight, false), destWidth, destHeight); } void drawImage(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple) { diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java index e17ab95161..2dda532542 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java @@ -18,6 +18,7 @@ import java.io.*; import java.util.*; +import java.util.function.*; import org.eclipse.swt.*; import org.eclipse.swt.internal.*; @@ -929,6 +930,74 @@ void destroy() { memGC = null; } +private CachedImageAtSize cachedImageAtSize = new CachedImageAtSize(); + +private class CachedImageAtSize { + private Image image; + + public void destroy() { + if (image != null) { + image.dispose(); + image = null; + } + } + + private Optional refresh(int destWidth, int destHeight) { + int scaledWidth = DPIUtil.pointToPixel(destWidth, DPIUtil.getDeviceZoom()); + int scaledHeight = DPIUtil.pointToPixel(destHeight, DPIUtil.getDeviceZoom()); + if (isReusable(scaledWidth, scaledHeight)) { + return Optional.of(image); + } else { + destroy(); + Optional imageAtSize = loadImageAtSize(scaledWidth, scaledHeight); + image = imageAtSize.orElse(null); + return imageAtSize; + } + } + + private boolean isReusable(int width, int height) { + return image != null && image.height == height && image.width == width; + } + + private Optional loadImageAtSize(int destWidth, int destHeight) { + Optional imageData = loadImageDataAtExactSize(destWidth, destHeight); + if (imageData.isEmpty()) { + return Optional.empty(); + } + Image image = new Image(device, imageData.get(), DPIUtil.getDeviceZoom()); + if (styleFlag != SWT.IMAGE_COPY) { + Image styledImage = new Image(device, image, styleFlag); + image.dispose(); + image = styledImage; + } + return Optional.of(image); + } + + private Optional loadImageDataAtExactSize(int targetWidth, int targetHeight) { + if (imageDataProvider instanceof ImageDataAtSizeProvider imageDataAtSizeProvider) { + ImageData imageData = imageDataAtSizeProvider.getImageData(targetWidth, targetHeight); + if (imageData == null) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT, null, + " ImageDataAtSizeProvider returned null for width=" + targetWidth + ", height=" + targetHeight); + } + return Optional.of(imageData); + } + if (imageFileNameProvider != null) { + String fileName = DPIUtil.validateAndGetImagePathAtZoom(imageFileNameProvider, 100).element(); + if (ImageDataLoader.isDynamicallySizable(fileName)) { + ImageData imageDataAtSize = ImageDataLoader.loadBySize(fileName, targetWidth, targetHeight); + return Optional.of(imageDataAtSize); + } + } + return Optional.empty(); + } +} + +void executeOnImageAtSize(Consumer imageAtBestFittingSizeConsumer, int destWidth, int destHeight) { + Optional imageAtSize = cachedImageAtSize.refresh(destWidth, destHeight); + imageAtBestFittingSizeConsumer.accept(imageAtSize.orElse(this)); +} + /** * Compares the argument to the receiver, and returns true * if they represent the same object using a class diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_GC.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_GC.java index 2e40ee0034..dfb764d5a9 100644 --- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_GC.java +++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_GC.java @@ -54,8 +54,6 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledOnOs; -import org.junit.jupiter.api.condition.OS; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -442,7 +440,6 @@ public void test_drawImageLorg_eclipse_swt_graphics_ImageIIII_ImageDataProvider( } @Test -@DisabledOnOs(value = OS.LINUX) public void test_drawImageLorg_eclipse_swt_graphics_ImageIIII_ImageDataAtSizeProvider_invalid() { ImageDataAtSizeProvider provider = new ImageDataAtSizeProvider() { @Override @@ -469,11 +466,10 @@ public ImageData getImageData(int width, int height) { @ParameterizedTest @ValueSource(ints = {SWT.IMAGE_COPY, SWT.IMAGE_DISABLE, SWT.IMAGE_GRAY, -1}) -@DisabledOnOs(value = OS.LINUX) public void test_drawImageLorg_eclipse_swt_graphics_ImageIIII_ImageDataAtSizeProvider(int styleFlag) { int width = 50; int height = 70; - Image drawToImage = new Image(display, width, height); + Image drawToImage = new Image(display, new ImageData(width, height, 32, new PaletteData(0xFF0000, 0xFF00, 0xFF))); GC gc = new GC(drawToImage); gc.setAntialias(SWT.OFF); RGB drawnRgb = new RGB(255, 255, 255);