From f07d4e19cb839f980e9a1b52c1b67766f7b5ad75 Mon Sep 17 00:00:00 2001 From: Heiko Klare Date: Thu, 16 Apr 2026 23:21:41 +0200 Subject: [PATCH] [macOS] Consider transformation scale in GC.drawImage(image, x, y) #2919 With e97143c7b058d66315d22d67f778188530af32ab, support was added on Windows to take the Transform scaling into consideration when calling drawImage(image, x, y). Especially when used in combination with an SVG-based image, this leads to better results as the best-fitting image representation is used for painting, rather than relying on interpolation. This change follows the same logic for Cocoa/macOS, equivalent to what has already been done for Windows and Linux. When a Transform is active on the GC, the call to drawImage(image, x, y) is delegated to drawImage(image, x, y, w, h), using the image's natural bounds as the destination size. Within that method, the destination dimensions are multiplied by the effective transformation scale before being passed to executeOnImageAtSizeBestFittingSize(), so that the higher-resolution image representation is selected and rendered at its full quality rather than being upscaled from a lower-resolution variant. The effective scale is derived from the active NSAffineTransform via Math.hypot() on the matrix columns, which correctly handles transforms that combine scaling with rotation. The existing test test_drawImageLorg_eclipse_swt_graphics_ImageIIII_withTransform, which was previously restricted to Windows and Linux, is now enabled on all platforms (the @DisabledOnOs(OS.MACOS) guard and its now-unused imports are removed). Contributes to https://github.com/eclipse-platform/eclipse.platform.swt/issues/2919 --- .../cocoa/org/eclipse/swt/graphics/GC.java | 25 +++++++++++++++++-- .../Test_org_eclipse_swt_graphics_GC.java | 3 --- 2 files changed, 23 insertions(+), 5 deletions(-) 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 8d619bd4eb5..cce24a1107f 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 @@ -281,6 +281,19 @@ static int checkStyle (int style) { return style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT); } +private float calculateTransformationScale() { + if (data.transform == null) { + return 1.0f; + } + // this calculates the effective length in x and y + // direction without being affected by the rotation + // of the transformation + NSAffineTransformStruct struct = data.transform.transformStruct(); + float scaleWidth = (float) Math.hypot(struct.m11, struct.m21); + float scaleHeight = (float) Math.hypot(struct.m12, struct.m22); + return Math.max(scaleWidth, scaleHeight); +} + /** * Invokes platform specific functionality to allocate a new graphics context. *

@@ -1143,7 +1156,12 @@ public void drawImage(Image image, int x, int y) { if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (image == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); if (image.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); - drawImage(image, 0, 0, -1, -1, x, y, -1, -1, true); + if (data.transform != null) { + Rectangle imageBounds = image.getBounds(); + drawImage(image, x, y, imageBounds.width, imageBounds.height); + } else { + drawImage(image, 0, 0, -1, -1, x, y, -1, -1, true); + } } /** @@ -1238,9 +1256,12 @@ public void drawImage(Image image, int destX, int destY, int destWidth, int dest if (image.isDisposed()) { SWT.error(SWT.ERROR_INVALID_ARGUMENT); } + float transformationScale = calculateTransformationScale(); + int scaledWidth = Math.round(destWidth * transformationScale); + int scaledHeight = Math.round(destHeight * transformationScale); image.executeOnImageAtSizeBestFittingSize(imageAtSize -> { drawImage(imageAtSize, 0, 0, imageAtSize.width, imageAtSize.height, destX, destY, destWidth, destHeight, false); - }, destWidth, destHeight); + }, scaledWidth, scaledHeight); } 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/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 e2760ab9d0c..cafb4f91468 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 @@ -58,8 +58,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; @@ -395,7 +393,6 @@ public void test_drawImageLorg_eclipse_swt_graphics_ImageIIII() { } @Test -@DisabledOnOs(OS.MAC) public void test_drawImageLorg_eclipse_swt_graphics_ImageIIII_withTransform() throws IOException { Image image = null; try (InputStream is = getClass().getResourceAsStream("collapseall.svg")) {