From 3cd4ddff583f8c1b72e9c599536a27fe59b64c76 Mon Sep 17 00:00:00 2001 From: Andreas Koch Date: Fri, 17 Jan 2025 09:41:21 +0100 Subject: [PATCH] WIP --- .../cocoa/org/eclipse/swt/graphics/Image.java | 68 +++++++++++++++++- .../gtk/org/eclipse/swt/graphics/Image.java | 71 +++++++++++++++++++ 2 files changed, 138 insertions(+), 1 deletion(-) diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Image.java index f20ab4fc55c..b1d1c8b26ec 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Image.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Image.java @@ -135,6 +135,11 @@ public final class Image extends Resource implements Drawable { */ private ImageDataProvider imageDataProvider; + /** + * ImageGcDrawer to provide a callback to draw on a GC for various zoom levels + */ + private ImageGcDrawer imageGcDrawer; + /** * Style flag used to differentiate normal, gray-scale and disabled images based * on image data providers. Without this, a normal and a disabled image of the @@ -384,8 +389,9 @@ public Image(Device device, Image srcImage, int flag) { imageFileNameProvider = srcImage.imageFileNameProvider; imageDataProvider = srcImage.imageDataProvider; + imageGcDrawer = srcImage.imageGcDrawer; this.styleFlag = srcImage.styleFlag | flag; - if (imageFileNameProvider != null || imageDataProvider != null) { + if (imageFileNameProvider != null || imageDataProvider != null ||srcImage.imageGcDrawer != null) { /* If source image has 200% representation then create the 200% representation for the new image & apply flag */ NSBitmapImageRep rep200 = srcImage.getRepresentation (200); if (rep200 != null) createRepFromSourceAndApplyFlag(rep200, srcWidth * 2, srcHeight * 2, flag); @@ -843,6 +849,62 @@ public Image(Device device, ImageDataProvider imageDataProvider) { } } +/** + * The provided ImageGcDrawer will be called on demand whenever a new variant of the + * Image for an additional zoom is required. Depending on the OS specific implementation + * these calls will be done during the instantiation or later when a new variant is + * requested + *

+ * + * @param device the device on which to create the image + * @param imageGcDrawer the ImageGcDrawer object to be called when a new image variant + * for another zoom is required. + * @param width the width of the new image in points + * @param height the height of the new image in points + * + * @exception IllegalArgumentException

+ * @since 3.129 + */ +public Image(Device device, ImageGcDrawer imageGcDrawer, int width, int height) { + super(device); + if (imageGcDrawer == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + this.imageGcDrawer = imageGcDrawer; + ImageData data = drawWithImageGcDrawer(imageGcDrawer, width, height, 100); + if (data == null) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + NSAutoreleasePool pool = null; + if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); + try { + init (data); + init (); + ImageData data2x = drawWithImageGcDrawer(imageGcDrawer, width, height, 200); + if (data2x != null) { + alphaInfo_200 = new AlphaInfo(); + NSBitmapImageRep rep = createRepresentation (data2x, alphaInfo_200); + handle.addRepresentation(rep); + rep.release(); + } + } finally { + if (pool != null) pool.release(); + } +} + +private ImageData drawWithImageGcDrawer(ImageGcDrawer imageGcDrawer, int width, int height, int zoom) { + Image image = new Image(device, width, height); + GC gc = new GC(image); + try { + imageGcDrawer.drawOn(gc); + ImageData imageData = image.getImageData(zoom); + imageGcDrawer.postProcess(imageData); + return imageData; + } finally { + gc.dispose(); + image.dispose(); + } +} + private AlphaInfo _getAlphaInfoAtCurrentZoom (NSBitmapImageRep rep) { int deviceZoom = DPIUtil.getDeviceZoom(); if (deviceZoom != 100 && (imageFileNameProvider != null || imageDataProvider != null)) { @@ -1121,6 +1183,8 @@ public boolean equals (Object object) { return styleFlag == image.styleFlag && imageDataProvider.equals (image.imageDataProvider); } else if (imageFileNameProvider != null && image.imageFileNameProvider != null) { return styleFlag == image.styleFlag && imageFileNameProvider.equals (image.imageFileNameProvider); + } else if (imageGcDrawer != null && image.imageGcDrawer != null) { + return styleFlag == image.styleFlag && imageGcDrawer.equals (image.imageGcDrawer); } else { return handle == image.handle; } @@ -1357,6 +1421,8 @@ public int hashCode () { return imageDataProvider.hashCode(); } else if (imageFileNameProvider != null) { return imageFileNameProvider.hashCode(); + } else if (imageGcDrawer != null) { + return imageGcDrawer.hashCode(); } else { return handle != null ? (int)handle.id : 0; } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java index 2b48e4b34a5..f5ee7b2bcf1 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java @@ -151,6 +151,11 @@ public final class Image extends Resource implements Drawable { */ private ImageDataProvider imageDataProvider; + /** + * ImageGcDrawer to provide a callback to draw on a GC for various zoom levels + */ + private ImageGcDrawer imageGcDrawer; + /** * Style flag used to differentiate normal, gray-scale and disabled images based * on image data providers. Without this, a normal and a disabled image of the @@ -263,6 +268,7 @@ public Image(Device device, Image srcImage, int flag) { this.type = srcImage.type; this.imageDataProvider = srcImage.imageDataProvider; this.imageFileNameProvider = srcImage.imageFileNameProvider; + this.imageGcDrawer = srcImage.imageGcDrawer; this.styleFlag = srcImage.styleFlag | flag; this.currentDeviceZoom = srcImage.currentDeviceZoom; @@ -661,6 +667,34 @@ public Image(Device device, ImageDataProvider imageDataProvider) { init (); } +/** + * The provided ImageGcDrawer will be called on demand whenever a new variant of the + * Image for an additional zoom is required. Depending on the OS specific implementation + * these calls will be done during the instantiation or later when a new variant is + * requested + *

+ * + * @param device the device on which to create the image + * @param imageGcDrawer the ImageGcDrawer object to be called when a new image variant + * for another zoom is required. + * @param width the width of the new image in points + * @param height the height of the new image in points + * + * @exception IllegalArgumentException

+ * @since 3.129 + */ +public Image(Device device, ImageGcDrawer imageGcDrawer, int width, int height) { + super(device); + this.imageGcDrawer = imageGcDrawer; + currentDeviceZoom = DPIUtil.getDeviceZoom(); + ImageData imageData = drawWithImageGcDrawer(currentDeviceZoom); + init (imageData); + init (); +} + /** * Refreshes the image for the current device scale factor. *

@@ -722,6 +756,17 @@ boolean refreshImageForZoom () { refreshed = true; currentDeviceZoom = deviceZoomLevel; } + } else if (imageGcDrawer != null) { + int deviceZoomLevel = deviceZoom; + if (deviceZoomLevel != currentDeviceZoom) { + ImageData data = drawWithImageGcDrawer(deviceZoomLevel); + /* Release current native resources */ + destroy (); + init(data); + init(); + refreshed = true; + currentDeviceZoom = deviceZoomLevel; + } } else { if (!DPIUtil.useCairoAutoScale()) { int deviceZoomLevel = deviceZoom; @@ -904,6 +949,8 @@ public boolean equals (Object object) { return (styleFlag == image.styleFlag) && imageDataProvider.equals (image.imageDataProvider); } else if (imageFileNameProvider != null && image.imageFileNameProvider != null) { return (styleFlag == image.styleFlag) && imageFileNameProvider.equals (image.imageFileNameProvider); + } else if (imageGcDrawer != null && image.imageGcDrawer != null) { + return styleFlag == image.styleFlag && imageGcDrawer.equals (image.imageGcDrawer); } else { return surface == image.surface; } @@ -1110,11 +1157,33 @@ public ImageData getImageData (int zoom) { } else if (imageFileNameProvider != null) { ElementAtZoom fileName = DPIUtil.validateAndGetImagePathAtZoom (imageFileNameProvider, zoom); return DPIUtil.scaleImageData (device, new ImageData (fileName.element()), zoom, fileName.zoom()); + } else if (imageGcDrawer != null) { + return drawWithImageGcDrawer(zoom); } else { return DPIUtil.scaleImageData (device, getImageDataAtCurrentZoom (), zoom, currentDeviceZoom); } } + + +private ImageData drawWithImageGcDrawer(int zoom) { + if (this.imageGcDrawer != null) { + Image image = new Image(device, width, height); + GC gc = new GC(image); + try { + imageGcDrawer.drawOn(gc); + ImageData imageData = image.getImageData(zoom); + imageGcDrawer.postProcess(imageData); + return imageData; + } finally { + gc.dispose(); + image.dispose(); + } + } + SWT.error(SWT.ERROR_INVALID_ARGUMENT, null, ": ImageGcDrawer [" + imageGcDrawer + "] is null."); + return null; +} + /** * Invokes platform specific functionality to allocate a new image. *

@@ -1179,6 +1248,8 @@ public int hashCode () { return imageDataProvider.hashCode(); } else if (imageFileNameProvider != null) { return imageFileNameProvider.hashCode(); + } else if (imageGcDrawer != null) { + return imageGcDrawer.hashCode(); } else { return (int)surface; }