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);