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 1c85beb57d..4894a5de70 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 @@ -15,16 +15,13 @@ import java.util.*; -import java.util.List; import java.util.function.*; -import java.util.stream.*; import org.eclipse.swt.*; import org.eclipse.swt.graphics.Image.*; 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 @@ -1178,18 +1175,52 @@ private class DrawScalingImageToImageOperation extends ImageOperation { @Override void apply() { + draw(getImage(), source.x, source.y, source.width, source.height, destination.x, destination.y, destination.width, destination.height); + } + + private void draw(Image image, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight) { int gcZoom = getZoom(); - int srcImageZoom = calculateZoomForImage(gcZoom, source.width, source.height, destination.width, destination.height); - drawImage(getImage(), source.x, source.y, source.width, source.height, destination.x, destination.y, destination.width, destination.height, gcZoom, srcImageZoom); + int requestedImageZoom = calculateZoomForImage(gcZoom, source.width, source.height, destination.width, destination.height); + + Rectangle src = new Rectangle(srcX, srcY, srcWidth, srcHeight); + Rectangle destPixels = Win32DPIUtils.pointToPixel(drawable, new Rectangle(destX, destY, destWidth, destHeight), gcZoom); + Rectangle fullImageBounds = image.getBounds(); + Rectangle requestedFullImageBoundsPixels = Win32DPIUtils.pointToPixel(drawable, fullImageBounds, requestedImageZoom); + + image.executeOnImageHandleAtBestFittingSize((tempHandle) -> { + Rectangle srcPixels = computeSourceRectangle(tempHandle, fullImageBounds, src); + drawImage(image, srcPixels.x, srcPixels.y, srcPixels.width, srcPixels.height, destPixels.x, destPixels.y, destPixels.width, + destPixels.height, false, tempHandle); + }, requestedFullImageBoundsPixels.width, requestedFullImageBoundsPixels.height); } - private Collection getAllCurrentMonitorZooms() { - if (device instanceof Display display) { - return Arrays.stream(display.getMonitors()) - .map(Monitor::getZoom) - .collect(Collectors.toSet()); + private Rectangle computeSourceRectangle(ImageHandle imageHandle, Rectangle fullImageBounds, Rectangle src) { + /* + * The point values (x, y, width, height) of the source "part" in points will be + * computed to pixels depending on the factor of the full image bounds to the + * actual OS handle size that will be used. + */ + float scaleFactor = Math.min(1f * imageHandle.width() / fullImageBounds.width, 1f * imageHandle.height() / fullImageBounds.height); + int closestZoomOfHandle = Math.round(scaleFactor * 100); + Rectangle srcPixels = Win32DPIUtils.pointToPixel(drawable, src, closestZoomOfHandle); + + if (closestZoomOfHandle != 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. + */ + int errX = srcPixels.x + srcPixels.width - imageHandle.width(); + int errY = srcPixels.y + srcPixels.height - imageHandle.height(); + if (errX != 0 || errY != 0) { + if (errX <= closestZoomOfHandle / 100 && errY <= closestZoomOfHandle / 100) { + srcPixels.intersect(new Rectangle(0, 0, imageHandle.width(), imageHandle.height())); + } else { + SWT.error (SWT.ERROR_INVALID_ARGUMENT); + } + } } - return Collections.emptySet(); + return srcPixels; } private int calculateZoomForImage(int gcZoom, int srcWidth, int srcHeight, int destWidth, int destHeight) { @@ -1205,15 +1236,9 @@ private int calculateZoomForImage(int gcZoom, int srcWidth, int srcHeight, int d return gcZoom; } - float imageScaleFactor = 1f * destWidth / srcWidth; + float imageScaleFactor = Math.max(1f * destWidth / srcWidth, 1f * destHeight / srcHeight); int imageZoom = Math.round(gcZoom * imageScaleFactor); - if (getAllCurrentMonitorZooms().contains(imageZoom)) { - return imageZoom; - } - if (imageZoom > 150) { - return 200; - } - return 100; + return imageZoom; } } @@ -1241,30 +1266,6 @@ private void drawImage(Image image, int destX, int destY, int destWidth, int des }, destPixels.width, destPixels.height); } -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 = Win32DPIUtils.pointToPixel(drawable, new Rectangle(srcX, srcY, srcWidth, srcHeight), scaledImageZoom); - Rectangle dest = Win32DPIUtils.pointToPixel(drawable, new Rectangle(destX, destY, destWidth, destHeight), imageZoom); - 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(scaledImageZoom); - int errX = src.x + src.width - b.width; - int errY = src.y + src.height - b.height; - if (errX != 0 || errY != 0) { - 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, image.getHandle(scaledImageZoom, data.nativeZoom)); -} - private class DrawImageToImageOperation extends ImageOperation { private final Rectangle source; private final Rectangle destination;