From 00a867e8fab04fa7e2961da58a672d022968e78a Mon Sep 17 00:00:00 2001 From: Andreas Koch Date: Fri, 9 May 2025 13:01:26 +0200 Subject: [PATCH] [win32] Choose best Image handle drawing with GC This commit adapts the drawImage method in GC in the windows implementation for copying and (probably) scaling an area from a source image into the GC target. With the Image supporting multiple handles now, the handle from the source image is no longer chosen by the zoom context of the GC but from the target size, e.g. if an image should be drawn with a scale of 2 on a 100% monitor, it might provide better results to use an image handle fitting for 200%. --- .../win32/org/eclipse/swt/graphics/GC.java | 57 ++++++++++++++++--- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java index ddaa6da5964..9edadddfacf 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java @@ -14,10 +14,14 @@ package org.eclipse.swt.graphics; +import java.util.*; +import java.util.stream.*; + import org.eclipse.swt.*; import org.eclipse.swt.internal.*; import org.eclipse.swt.internal.gdip.*; import org.eclipse.swt.internal.win32.*; +import org.eclipse.swt.widgets.*; /** * Class GC is where all of the drawing capabilities that are @@ -985,31 +989,70 @@ public void drawImage (Image image, int srcX, int srcY, int srcWidth, int srcHei if (image == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); if (image.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); - int imageZoom = getZoom(); - Rectangle src = DPIUtil.scaleUp(drawable, new Rectangle(srcX, srcY, srcWidth, srcHeight), imageZoom); + int gcZoom = getZoom(); + int srcImageZoom = calculateZoomForImage(gcZoom, srcWidth, srcHeight, destWidth, destHeight); + drawImage(image, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, gcZoom, srcImageZoom); +} + +private Collection getAllCurrentMonitorZooms() { + if (device instanceof Display display) { + return Arrays.stream(display.getMonitors()) + .map(Monitor::getZoom) + .collect(Collectors.toSet()); + } + return Collections.emptySet(); +} + +private int calculateZoomForImage(int gcZoom, int srcWidth, int srcHeight, int destWidth, int destHeight) { + if (srcWidth == 1 && srcHeight == 1) { + // One pixel images can use the GC zoom + return gcZoom; + } + if (destWidth == srcWidth && destHeight == srcHeight) { + // unscaled images can use the GC zoom + return gcZoom; + } + + float imageScaleFactor = 1f * destWidth / srcWidth; + int imageZoom = Math.round(gcZoom * imageScaleFactor); + if (getAllCurrentMonitorZooms().contains(imageZoom)) { + return imageZoom; + } + if (imageZoom > 150) { + return 200; + } + return 100; +} + +private void drawImage(Image image, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, + int destWidth, int destHeight, int imageZoom, int scaledImageZoom) { + Rectangle src = DPIUtil.scaleUp(drawable, new Rectangle(srcX, srcY, srcWidth, srcHeight), scaledImageZoom); Rectangle dest = DPIUtil.scaleUp(drawable, new Rectangle(destX, destY, destWidth, destHeight), imageZoom); - if (imageZoom != 100) { + if (scaledImageZoom != 100) { /* * This is a HACK! Due to rounding errors at fractional scale factors, * the coordinates may be slightly off. The workaround is to restrict * coordinates to the allowed bounds. */ - Rectangle b = image.getBounds(imageZoom); + Rectangle b = image.getBounds(scaledImageZoom); int errX = src.x + src.width - b.width; int errY = src.y + src.height - b.height; if (errX != 0 || errY != 0) { - if (errX <= imageZoom / 100 && errY <= imageZoom / 100) { + if (errX <= scaledImageZoom / 100 && errY <= scaledImageZoom / 100) { src.intersect(b); } else { SWT.error (SWT.ERROR_INVALID_ARGUMENT); } } } - drawImage(image, src.x, src.y, src.width, src.height, dest.x, dest.y, dest.width, dest.height, false); + drawImage(image, src.x, src.y, src.width, src.height, dest.x, dest.y, dest.width, dest.height, false, scaledImageZoom); } void drawImage(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple) { - int imageZoom = getZoom(); + drawImage(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, getZoom()); +} + +void drawImage(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple, int imageZoom) { if (data.gdipGraphics != 0) { //TODO - cache bitmap long [] gdipImage = srcImage.createGdipImage(imageZoom);