diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/GC.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/GC.java index 31d122d55c..aa4818e9c1 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/GC.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/GC.java @@ -1238,7 +1238,9 @@ 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.executeOnImageAtSizeBestFittingSize(imageAtSize -> { + drawImage(imageAtSize, 0, 0, imageAtSize.width, imageAtSize.height, 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/cocoa/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Image.java index 29eb789f6d..981e943a08 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Image.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Image.java @@ -14,6 +14,7 @@ package org.eclipse.swt.graphics; +import static org.eclipse.swt.internal.DPIUtil.pointToPixel; import static org.eclipse.swt.internal.image.ImageColorTransformer.DEFAULT_DISABLED_IMAGE_TRANSFORMER; import java.io.*; @@ -1177,6 +1178,7 @@ private NSBitmapImageRep createRepresentation(ImageData imageData, AlphaInfo alp @Override void destroy() { + cachedImageAtSize.destroy(); if (memGC != null) memGC.dispose(); handle.release(); handle = null; @@ -1837,5 +1839,73 @@ public static void drawAtSize(GC gc, ImageData imageData, int width, int height) }); } +void executeOnImageAtSizeBestFittingSize(Consumer imageAtBestFittingSizeConsumer, int destWidth, int destHeight) { + Optional imageAtSize = cachedImageAtSize.refresh(destWidth, destHeight); + imageAtBestFittingSizeConsumer.accept(imageAtSize.orElse(this)); +} + +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 = pointToPixel(destWidth, DPIUtil.getDeviceZoom()); + int scaledHeight = 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()); + if (styleFlag != SWT.IMAGE_COPY) { + NSBitmapImageRep representation = image.getRepresentation(100); + image.createRepFromSourceAndApplyFlag(representation, destWidth, destHeight, styleFlag); + image.handle.removeRepresentation(representation); + } + 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(); + } +} + } 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 6400e28771..2e40ee0034 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,7 +54,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.EnabledOnOs; +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 +442,7 @@ public void test_drawImageLorg_eclipse_swt_graphics_ImageIIII_ImageDataProvider( } @Test -@EnabledOnOs(value = OS.WINDOWS) +@DisabledOnOs(value = OS.LINUX) public void test_drawImageLorg_eclipse_swt_graphics_ImageIIII_ImageDataAtSizeProvider_invalid() { ImageDataAtSizeProvider provider = new ImageDataAtSizeProvider() { @Override @@ -469,7 +469,7 @@ public ImageData getImageData(int width, int height) { @ParameterizedTest @ValueSource(ints = {SWT.IMAGE_COPY, SWT.IMAGE_DISABLE, SWT.IMAGE_GRAY, -1}) -@EnabledOnOs(value = OS.WINDOWS) +@DisabledOnOs(value = OS.LINUX) public void test_drawImageLorg_eclipse_swt_graphics_ImageIIII_ImageDataAtSizeProvider(int styleFlag) { int width = 50; int height = 70;