diff --git a/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/graphics/ImagesWin32Tests.java b/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/graphics/ImagesWin32Tests.java index 6b60c2a20df..a7559354653 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/graphics/ImagesWin32Tests.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/graphics/ImagesWin32Tests.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2024 Yatta Solutions + * Copyright (c) 2024, 2026 Yatta Solutions * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -13,13 +13,18 @@ *******************************************************************************/ package org.eclipse.swt.graphics; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.*; +import java.util.stream.*; import org.eclipse.swt.*; import org.eclipse.swt.internal.*; import org.eclipse.swt.widgets.*; import org.junit.jupiter.api.*; import org.junit.jupiter.api.extension.*; +import org.junit.jupiter.params.*; +import org.junit.jupiter.params.provider.*; @ExtendWith(PlatformSpecificExecutionExtension.class) @ExtendWith(WithMonitorSpecificScalingExtension.class) @@ -30,9 +35,52 @@ public void testImageIconTypeShouldNotChangeAfterCallingGetHandleForDifferentZoo Image icon = Display.getDefault().getSystemImage(SWT.ICON_ERROR); try { Image.win32_getHandle(icon, 200); - assertEquals("Image type should stay to SWT.ICON", SWT.ICON, icon.type); + assertEquals(SWT.ICON, icon.type, "Image type should stay to SWT.ICON"); } finally { icon.dispose(); } } + + /** + * For images with very different width and height (e.g. 500x2), independent + * integer division when computing the zoom from each axis's pixel hint can make the + * height-derived zoom larger than the width-derived zoom. The correct fix is to + * derive the zoom from the axis with the larger pixel hint, which has more pixels + * and therefore a proportionally smaller rounding error. + *

+ * Verifies that for a wide (500-pixel) image at standard display zoom levels, the + * selected handle width matches the expected width at the requested zoom, across a + * range of image heights where integer-division rounding divergence is most extreme. + */ + @ParameterizedTest + @MethodSource("provideZoomAndHeightCombinations") + public void getImageHandle_asymmetricDimensions_selectsCorrectZoom(int displayZoom, int logicalHeight) { + Display display = Display.getDefault(); + int logicalWidth = 500; + PaletteData palette = new PaletteData(0xFF0000, 0xFF00, 0xFF); + ImageDataProvider provider = zoom -> new ImageData( + Math.max(1, Math.round(logicalWidth * zoom / 100f)), + Math.max(1, Math.round(logicalHeight * zoom / 100f)), + 32, palette); + Image image = new Image(display, provider); + int widthHint = Math.round(logicalWidth * displayZoom / 100f); + int heightHint = Math.round(logicalHeight * displayZoom / 100f); + int[] capturedWidth = {-1}; + try { + image.executeOnImageHandleAtBestFittingSize(h -> capturedWidth[0] = h.width(), widthHint, heightHint); + assertEquals(widthHint, capturedWidth[0], + "Handle width should match widthHint for a " + logicalWidth + "x" + logicalHeight + + " image at display zoom " + displayZoom + "%: expected " + widthHint + + " but got " + capturedWidth[0]); + } finally { + image.dispose(); + } + } + + private static Stream provideZoomAndHeightCombinations() { + int[] zooms = { 100, 125, 150, 175, 200 }; + int[] heights = IntStream.rangeClosed(1, 20).toArray(); + return Arrays.stream(zooms).boxed() + .flatMap(zoom -> Arrays.stream(heights).mapToObj(height -> Arguments.of(zoom, height))); + } } 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 12a78ed8464..e229adfe8f0 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 @@ -248,7 +248,7 @@ private InternalImageHandle getOrCreateImageHandleAtClosestSize(int widthHint, i Rectangle bounds = getBounds(100); int imageZoomForWidth = 100 * widthHint / bounds.width; int imageZoomForHeight = 100 * heightHint / bounds.height; - int imageZoom = DPIUtil.getZoomForAutoscaleProperty(Math.max(imageZoomForWidth, imageZoomForHeight)); + int imageZoom = DPIUtil.getZoomForAutoscaleProperty(widthHint > heightHint ? imageZoomForWidth : imageZoomForHeight); InternalImageHandle bestFittingHandle = imageHandleManager.get(imageZoom); if (bestFittingHandle == null) { ImageData bestFittingImageData = imageProvider.loadImageData(imageZoom).element();