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);