From b9e9aefc0f5a37e1623b4b2e3a8ca0229551fdfa Mon Sep 17 00:00:00 2001 From: Heiko Klare Date: Tue, 21 Oct 2025 19:28:42 +0200 Subject: [PATCH] [Win32] Fix cut off controls #2641 In HiDPI scenarios with fractional monitor scales (such as 125% and 175%), some controls appear slightly cut off. The reason for this is inconsistent rounding of control sizes. The rounding is necessary during pixel/point conversion and leads to added or lost single pixels. One controls which obviously shows the behavior is the border of CTabFolders. This change adapts the calculation in the following way: - It ensures that pixelToPoint and pointToPixel conversions for sizes round in opposite ways instead of rounding up in both directions as currently done. This ensures that sizes being set (via pointToPixel) are rounded up while sizes being retrieved (via pixelToPoint) are rounded down. - It extracts the pixelToPoint conversion for sizes that are calculated based on pixel values and are supposed to represent a conservative size (i.e., better be to high than to low). - It ensures that also the pixelToPoint conversion of rectangles takes the proper rounding method for sizes into account. Fixes https://github.com/eclipse-platform/eclipse.platform.swt/issues/2641 --- .../common/org/eclipse/swt/graphics/RoundingMode.java | 5 ++++- .../win32/org/eclipse/swt/internal/Win32DPIUtils.java | 8 ++++++-- .../win32/org/eclipse/swt/widgets/Control.java | 2 +- .../win32/org/eclipse/swt/widgets/CoolItem.java | 2 +- .../org/eclipse/swt/tests/win32/Win32DPIUtilTests.java | 2 +- 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/RoundingMode.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/RoundingMode.java index 55f7afb506..ad15c7ff93 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/RoundingMode.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/RoundingMode.java @@ -3,7 +3,7 @@ * @noreference This class is not intended to be referenced by clients */ public enum RoundingMode { - ROUND, UP; + ROUND, UP, DOWN; public int round(float x) { if (this == ROUND) { @@ -12,6 +12,9 @@ public int round(float x) { if (this == UP) { return (int) Math.ceil(x); } + if (this == DOWN) { + return (int) Math.floor(x); + } return (int) x; } } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/Win32DPIUtils.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/Win32DPIUtils.java index d01fd7108e..078e81ac02 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/Win32DPIUtils.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/Win32DPIUtils.java @@ -124,13 +124,17 @@ public static Point pixelToPointAsLocation(Drawable drawable, Point point, int z } public static Point pixelToPointAsSize(Point point, int zoom) { - return pixelToPoint(point, zoom, RoundingMode.UP); + return pixelToPoint(point, zoom, RoundingMode.DOWN); } public static Point pixelToPointAsLocation(Point point, int zoom) { return pixelToPoint(point, zoom, RoundingMode.ROUND); } + public static Point pixelToPointAsConservativeSize(Point point, int zoom) { + return pixelToPoint(point, zoom, RoundingMode.UP); + } + private static Point pixelToPoint(Point point, int zoom, RoundingMode mode) { if (zoom == 100 || point == null) return point; Point.OfFloat fPoint = Point.OfFloat.from(point); @@ -145,7 +149,7 @@ public static Rectangle pixelToPoint(Rectangle rect, int zoom) { if (rect instanceof Rectangle.OfFloat rectOfFloat) return pixelToPoint(rectOfFloat, zoom); Rectangle scaledRect = new Rectangle.OfFloat (0,0,0,0); Point scaledTopLeft = pixelToPointAsLocation(new Point (rect.x, rect.y), zoom); - Point scaledBottomRight = pixelToPointAsLocation(new Point (rect.x + rect.width, rect.y + rect.height), zoom); + Point scaledBottomRight = pixelToPointAsSize(new Point (rect.x + rect.width, rect.y + rect.height), zoom); scaledRect.x = scaledTopLeft.x; scaledRect.y = scaledTopLeft.y; diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java index 9eeed2a76d..a5f1012a56 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java @@ -623,7 +623,7 @@ public Point computeSize (int wHint, int hHint, boolean changed){ hHint = (hHint != SWT.DEFAULT ? DPIUtil.pointToPixel(hHint, zoom) : hHint); //We should never return a size that is to small, RoundingMode.UP ensures we at worst case report //a size that is a bit too large by half a point - return Win32DPIUtils.pixelToPointAsSize(computeSizeInPixels(wHint, hHint, changed), zoom); + return Win32DPIUtils.pixelToPointAsConservativeSize(computeSizeInPixels(wHint, hHint, changed), zoom); } Point computeSizeInPixels (int wHint, int hHint, boolean changed) { diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/CoolItem.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/CoolItem.java index 5a882a7dbd..9ab4554be4 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/CoolItem.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/CoolItem.java @@ -188,7 +188,7 @@ public Point computeSize (int wHint, int hHint) { int zoom = getZoom(); wHint = (wHint != SWT.DEFAULT ? DPIUtil.pointToPixel(wHint, zoom) : wHint); hHint = (hHint != SWT.DEFAULT ? DPIUtil.pointToPixel(hHint, zoom) : hHint); - return Win32DPIUtils.pixelToPointAsSize(computeSizeInPixels(wHint, hHint), zoom); + return Win32DPIUtils.pixelToPointAsConservativeSize(computeSizeInPixels(wHint, hHint), zoom); } Point computeSizeInPixels (int wHint, int hHint) { int index = parent.indexOf (this); diff --git a/tests/org.eclipse.swt.tests.win32/JUnit Tests/org/eclipse/swt/tests/win32/Win32DPIUtilTests.java b/tests/org.eclipse.swt.tests.win32/JUnit Tests/org/eclipse/swt/tests/win32/Win32DPIUtilTests.java index 38dc20fc76..e570041340 100644 --- a/tests/org.eclipse.swt.tests.win32/JUnit Tests/org/eclipse/swt/tests/win32/Win32DPIUtilTests.java +++ b/tests/org.eclipse.swt.tests.win32/JUnit Tests/org/eclipse/swt/tests/win32/Win32DPIUtilTests.java @@ -103,7 +103,7 @@ public void scaleDownPoint() { @Test public void scaleDownRectangle() { Rectangle valueAt200 = new Rectangle(100, 150, 10, 14); - Rectangle valueAt150 = new Rectangle(75, 113, 7, 10); + Rectangle valueAt150 = new Rectangle(75, 113, 8, 10); Rectangle valueAt100 = new Rectangle(50, 75, 5, 7); Rectangle scaledValue = Win32DPIUtils.pixelToPoint(valueAt200, 200);