@@ -172,8 +172,13 @@ private Image (Device device, int nativeZoom) {
172172 * @see #dispose()
173173 */
174174public Image (Device device , int width , int height ) {
175+ this (device , width , height , DPIUtil .getNativeDeviceZoom ());
176+ }
177+
178+
179+ private Image (Device device , int width , int height , int nativeZoom ) {
175180 super (device );
176- initialNativeZoom = DPIUtil . getNativeDeviceZoom () ;
181+ initialNativeZoom = nativeZoom ;
177182 final int zoom = getZoom ();
178183 width = DPIUtil .scaleUp (width , zoom );
179184 height = DPIUtil .scaleUp (height , zoom );
@@ -602,6 +607,32 @@ public Image(Device device, ImageDataProvider imageDataProvider) {
602607 this .device .registerResourceWithZoomSupport (this );
603608}
604609
610+ /**
611+ * The provided ImageGcDrawer will be called on demand whenever a new variant of the
612+ * Image for an additional zoom is required. Depending on the OS specific implementation
613+ * these calls will be done during the instantiation or later when a new variant is
614+ * requested
615+ * <p>
616+ *
617+ * @param device the device on which to create the image
618+ * @param imageGcDrawer the ImageGcDrawer object to be called when a new image variant
619+ * for another zoom is required.
620+ * @param width the width of the new image in points
621+ * @param height the height of the new image in points
622+ *
623+ * @exception IllegalArgumentException <ul>
624+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
625+ * <li>ERROR_NULL_ARGUMENT - if the ImageGcDrawer is null</li>
626+ * </ul>
627+ * @since 3.129
628+ */
629+ public Image (Device device , ImageGcDrawer imageGcDrawer , int width , int height ) {
630+ super (device );
631+ this .imageProvider = new ImageGcDrawerWrapper (imageGcDrawer , width , height );
632+ initialNativeZoom = DPIUtil .getNativeDeviceZoom ();
633+ init ();
634+ }
635+
605636private ImageData adaptImageDataIfDisabledOrGray (ImageData data ) {
606637 ImageData returnImageData = null ;
607638 switch (this .styleFlag ) {
@@ -1140,6 +1171,9 @@ ImageHandle initNative(String filename, int zoom) {
11401171void destroy () {
11411172 device .deregisterResourceWithZoomSupport (this );
11421173 if (memGC != null ) memGC .dispose ();
1174+ if (this .imageProvider != null ) {
1175+ this .imageProvider .destroy ();
1176+ }
11431177 destroyHandle ();
11441178 memGC = null ;
11451179}
@@ -1282,14 +1316,17 @@ public Rectangle getBounds() {
12821316
12831317Rectangle getBounds (int zoom ) {
12841318 if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
1285- ImageHandle imageMetadata ;
12861319 if (zoomLevelToImageHandle .containsKey (zoom )) {
1287- imageMetadata = zoomLevelToImageHandle .get (zoom );
1320+ ImageHandle imageMetadata = zoomLevelToImageHandle .get (zoom );
1321+ Rectangle rectangle = new Rectangle (0 , 0 , imageMetadata .width , imageMetadata .height );
1322+ return DPIUtil .scaleBounds (rectangle , zoom , imageMetadata .zoom );
1323+ } else if (this .imageProvider != null ) {
1324+ return this .imageProvider .getBounds (zoom );
12881325 } else {
1289- imageMetadata = zoomLevelToImageHandle .values ().iterator ().next ();
1326+ ImageHandle imageMetadata = zoomLevelToImageHandle .values ().iterator ().next ();
1327+ Rectangle rectangle = new Rectangle (0 , 0 , imageMetadata .width , imageMetadata .height );
1328+ return DPIUtil .scaleBounds (rectangle , zoom , imageMetadata .zoom );
12901329 }
1291- Rectangle rectangle = new Rectangle (0 , 0 , imageMetadata .width , imageMetadata .height );
1292- return DPIUtil .scaleBounds (rectangle , zoom , imageMetadata .zoom );
12931330}
12941331
12951332/**
@@ -1932,6 +1969,9 @@ public void internal_dispose_GC (long hDC, GCData data) {
19321969 */
19331970@ Override
19341971public boolean isDisposed () {
1972+ if (this .imageProvider != null ) {
1973+ return this .imageProvider .isDisposed ();
1974+ }
19351975 return zoomLevelToImageHandle .isEmpty ();
19361976}
19371977
@@ -2043,9 +2083,11 @@ public static Image win32_new(Device device, int type, long handle, int nativeZo
20432083
20442084private abstract class AbstractImageProviderWrapper {
20452085 abstract Object getProvider ();
2086+ protected abstract Rectangle getBounds (int zoom );
20462087 abstract ImageData getImageData (int zoom );
20472088 abstract ImageHandle getImageMetadata (int zoom );
20482089 abstract AbstractImageProviderWrapper createCopy (Image image );
2090+ abstract boolean isDisposed ();
20492091
20502092 protected void checkProvider (Object provider , Class <?> expectedClass ) {
20512093 if (provider == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
@@ -2062,6 +2104,9 @@ public boolean equals(Object otherProvider) {
20622104 return otherProvider instanceof AbstractImageProviderWrapper aip //
20632105 && getProvider ().equals (aip .getProvider ());
20642106 }
2107+
2108+ protected void destroy () {
2109+ }
20652110}
20662111
20672112private class ImageFileNameProviderWrapper extends AbstractImageProviderWrapper {
@@ -2076,6 +2121,13 @@ private class ImageFileNameProviderWrapper extends AbstractImageProviderWrapper
20762121 this .provider = provider ;
20772122 }
20782123
2124+ @ Override
2125+ protected Rectangle getBounds (int zoom ) {
2126+ ImageHandle imageHandle = zoomLevelToImageHandle .values ().iterator ().next ();
2127+ Rectangle rectangle = new Rectangle (0 , 0 , imageHandle .width , imageHandle .height );
2128+ return DPIUtil .scaleBounds (rectangle , zoom , imageHandle .zoom );
2129+ }
2130+
20792131 @ Override
20802132 ImageData getImageData (int zoom ) {
20812133 ElementAtZoom <String > fileName = DPIUtil .validateAndGetImagePathAtZoom (provider , zoom );
@@ -2099,6 +2151,11 @@ ImageHandle getImageMetadata(int zoom) {
20992151 return zoomLevelToImageHandle .get (zoom );
21002152 }
21012153
2154+ @ Override
2155+ boolean isDisposed () {
2156+ return zoomLevelToImageHandle .isEmpty ();
2157+ }
2158+
21022159 @ Override
21032160 Object getProvider () {
21042161 return provider ;
@@ -2127,6 +2184,13 @@ private class ImageDataProviderWrapper extends AbstractImageProviderWrapper {
21272184 this .provider = provider ;
21282185 }
21292186
2187+ @ Override
2188+ protected Rectangle getBounds (int zoom ) {
2189+ ElementAtZoom <ImageData > data = DPIUtil .validateAndGetImageDataAtZoom (provider , zoom );
2190+ Rectangle rectangle = new Rectangle (0 , 0 , data .element ().width , data .element ().height );
2191+ return DPIUtil .scaleBounds (rectangle , zoom , data .zoom ());
2192+ }
2193+
21302194 @ Override
21312195 ImageData getImageData (int zoom ) {
21322196 ElementAtZoom <ImageData > data = DPIUtil .validateAndGetImageDataAtZoom (provider , zoom );
@@ -2143,6 +2207,11 @@ ImageHandle getImageMetadata(int zoom) {
21432207 return zoomLevelToImageHandle .get (zoom );
21442208 }
21452209
2210+ @ Override
2211+ boolean isDisposed () {
2212+ return zoomLevelToImageHandle .isEmpty ();
2213+ }
2214+
21462215 @ Override
21472216 Object getProvider () {
21482217 return provider ;
@@ -2154,6 +2223,70 @@ ImageDataProviderWrapper createCopy(Image image) {
21542223 }
21552224}
21562225
2226+ private class ImageGcDrawerWrapper extends AbstractImageProviderWrapper {
2227+ private ImageGcDrawer drawer ;
2228+ private int width ;
2229+ private int height ;
2230+ private boolean isDestroyed = false ;
2231+
2232+ public ImageGcDrawerWrapper (ImageGcDrawer imageGcDrawer , int width , int height ) {
2233+ checkProvider (imageGcDrawer , ImageGcDrawer .class );
2234+ this .drawer = imageGcDrawer ;
2235+ this .width = width ;
2236+ this .height = height ;
2237+ }
2238+
2239+ @ Override
2240+ protected Rectangle getBounds (int zoom ) {
2241+ Rectangle rectangle = new Rectangle (0 , 0 , width , height );
2242+ return DPIUtil .scaleBounds (rectangle , zoom , 100 );
2243+ }
2244+
2245+ @ Override
2246+ ImageData getImageData (int zoom ) {
2247+ return getImageMetadata (zoom ).getImageData ();
2248+ }
2249+
2250+ @ Override
2251+ ImageHandle getImageMetadata (int zoom ) {
2252+ initialNativeZoom = zoom ;
2253+ Image image = new Image (device , width , height , zoom );
2254+ GC gc = new GC (image );
2255+ try {
2256+ gc .data .nativeZoom = zoom ;
2257+ drawer .drawOn (gc );
2258+ ImageData imageData = image .getImageMetadata (zoom ).getImageData ();
2259+ drawer .postProcess (imageData );
2260+ ImageData newData = adaptImageDataIfDisabledOrGray (imageData );
2261+ init (newData , zoom );
2262+ } finally {
2263+ gc .dispose ();
2264+ image .dispose ();
2265+ }
2266+ return zoomLevelToImageHandle .get (zoom );
2267+ }
2268+
2269+ @ Override
2270+ protected void destroy () {
2271+ isDestroyed = true ;
2272+ }
2273+
2274+ @ Override
2275+ boolean isDisposed () {
2276+ return isDestroyed ;
2277+ }
2278+
2279+ @ Override
2280+ Object getProvider () {
2281+ return drawer ;
2282+ }
2283+
2284+ @ Override
2285+ ImageGcDrawerWrapper createCopy (Image image ) {
2286+ return image .new ImageGcDrawerWrapper (drawer , width , height );
2287+ }
2288+ }
2289+
21572290private class ImageHandle {
21582291 private final long handle ;
21592292 private final int zoom ;
0 commit comments