From 512c3a910529126b96ea791df763a840db7d7bae Mon Sep 17 00:00:00 2001 From: Andreas Koch Date: Thu, 8 May 2025 11:10:31 +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 | 47 +++++++++++-------- .../win32/org/eclipse/swt/graphics/Image.java | 16 +++++++ 2 files changed, 44 insertions(+), 19 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..70f648acab0 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 @@ -986,30 +986,39 @@ public void drawImage (Image image, int srcX, int srcY, int srcWidth, int srcHei if (image.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); int imageZoom = getZoom(); - Rectangle src = DPIUtil.scaleUp(drawable, new Rectangle(srcX, srcY, srcWidth, srcHeight), imageZoom); - Rectangle dest = DPIUtil.scaleUp(drawable, new Rectangle(destX, destY, destWidth, destHeight), imageZoom); - if (imageZoom != 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); - 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) { - src.intersect(b); - } else { - SWT.error (SWT.ERROR_INVALID_ARGUMENT); + float imageScaleFactor = 1f*destWidth/srcWidth; + int scaledImageZoom = Math.round(imageZoom*imageScaleFactor); + + image.applyUsingAnyHandle(scaledImageZoom, (imageHandle) -> { + 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 (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); + 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); 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 272cedb319f..913aae033d7 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 @@ -1832,6 +1832,22 @@ T applyUsingAnyHandle(Function function) { return function.apply(zoomLevelToImageHandle.values().iterator().next()); } +void applyUsingAnyHandle(int zoom, Consumer consumer) { + ImageHandle imageHandle = zoomLevelToImageHandle.get(zoom); + if (imageHandle!= null) { + consumer.accept(imageHandle.handle); + return; + } + + ImageHandle temporaryHandle = this.imageProvider.newImageHandle(zoom); + try { + consumer.accept(temporaryHandle.handle); + return; + } finally { + temporaryHandle.destroy(); + } +} + /** * Invokes platform specific functionality to allocate a new image. *