@@ -177,11 +177,8 @@ public Image(Device device, int width, int height) {
177177
178178private Image (Device device , int width , int height , int nativeZoom ) {
179179 super (device );
180- initialNativeZoom = nativeZoom ;
181- final int zoom = getZoom ();
182- width = DPIUtil .scaleUp (width , zoom );
183- height = DPIUtil .scaleUp (height , zoom );
184- init (width , height );
180+ this .initialNativeZoom = nativeZoom ;
181+ this .imageProvider = new PlainImageProviderWrapper (width , height );
185182 init ();
186183 this .device .registerResourceWithZoomSupport (this );
187184}
@@ -330,8 +327,7 @@ public Image(Device device, Rectangle bounds) {
330327 super (device );
331328 if (bounds == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
332329 initialNativeZoom = DPIUtil .getNativeDeviceZoom ();
333- bounds = DPIUtil .scaleUp (bounds , getZoom ());
334- init (bounds .width , bounds .height );
330+ this .imageProvider = new PlainImageProviderWrapper (bounds .width , bounds .height );
335331 init ();
336332 this .device .registerResourceWithZoomSupport (this );
337333}
@@ -1457,39 +1453,6 @@ public int hashCode () {
14571453 return (int )win32_getHandle (this , getZoom ());
14581454}
14591455
1460- void init (int width , int height ) {
1461- if (width <= 0 || height <= 0 ) {
1462- SWT .error (SWT .ERROR_INVALID_ARGUMENT );
1463- }
1464- type = SWT .BITMAP ;
1465- long hDC = device .internal_new_GC (null );
1466- ImageHandle imageMetadata = new ImageHandle (OS .CreateCompatibleBitmap (hDC , width , height ), getZoom ());
1467- /*
1468- * Feature in Windows. CreateCompatibleBitmap() may fail
1469- * for large images. The fix is to create a DIB section
1470- * in that case.
1471- */
1472- if (imageMetadata .handle == 0 ) {
1473- int bits = OS .GetDeviceCaps (hDC , OS .BITSPIXEL );
1474- int planes = OS .GetDeviceCaps (hDC , OS .PLANES );
1475- int depth = bits * planes ;
1476- if (depth < 16 ) depth = 16 ;
1477- if (depth > 24 ) depth = 24 ;
1478- imageMetadata = new ImageHandle (createDIB (width , height , depth ), getZoom ());
1479- }
1480- if (imageMetadata .handle != 0 ) {
1481- long memDC = OS .CreateCompatibleDC (hDC );
1482- long hOldBitmap = OS .SelectObject (memDC , imageMetadata .handle );
1483- OS .PatBlt (memDC , 0 , 0 , width , height , OS .PATCOPY );
1484- OS .SelectObject (memDC , hOldBitmap );
1485- OS .DeleteDC (memDC );
1486- }
1487- device .internal_dispose_GC (hDC , null );
1488- if (imageMetadata .handle == 0 ) {
1489- SWT .error (SWT .ERROR_NO_HANDLES , null , device .getLastError ());
1490- }
1491- }
1492-
14931456static long createDIB (int width , int height , int depth ) {
14941457 BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER ();
14951458 bmiHeader .biSize = BITMAPINFOHEADER .sizeof ;
@@ -2081,13 +2044,121 @@ public static Image win32_new(Device device, int type, long handle, int nativeZo
20812044}
20822045
20832046private abstract class AbstractImageProviderWrapper {
2084- abstract Object getProvider ();
20852047 protected abstract Rectangle getBounds (int zoom );
20862048 abstract ImageData getImageData (int zoom );
20872049 abstract ImageHandle getImageMetadata (int zoom );
20882050 abstract AbstractImageProviderWrapper createCopy (Image image );
20892051 abstract boolean isDisposed ();
20902052
2053+ protected void destroy () {
2054+ }
2055+ }
2056+
2057+ private class PlainImageProviderWrapper extends AbstractImageProviderWrapper {
2058+ private boolean isDestroyed ;
2059+ private final int width ;
2060+ private final int height ;
2061+
2062+ PlainImageProviderWrapper (int width , int height ) {
2063+ if (width <= 0 || height <= 0 ) {
2064+ SWT .error (SWT .ERROR_INVALID_ARGUMENT );
2065+ }
2066+ this .width = width ;
2067+ this .height = height ;
2068+ type = SWT .BITMAP ;
2069+ }
2070+
2071+ @ Override
2072+ protected Rectangle getBounds (int zoom ) {
2073+ Rectangle rectangle = new Rectangle (0 , 0 , width , height );
2074+ return DPIUtil .scaleUp (rectangle , zoom );
2075+ }
2076+
2077+ @ Override
2078+ ImageData getImageData (int zoom ) {
2079+ if (zoomLevelToImageHandle .isEmpty () || zoomLevelToImageHandle .containsKey (zoom )) {
2080+ return getImageMetadata (zoom ).getImageData ();
2081+ }
2082+ // if a GC is initialized with an Image (memGC != null), the image data must not be resized, because it would
2083+ // be a destructive operation. Therefor, always the current image data must be returned
2084+ if (memGC != null ) {
2085+ return getImageDataAtCurrentZoom ();
2086+ }
2087+ TreeSet <Integer > availableZooms = new TreeSet <>(zoomLevelToImageHandle .keySet ());
2088+ int bestAvailableZoom = Optional .ofNullable (availableZooms .higher (zoom )).orElse (availableZooms .lower (zoom ));
2089+ return DPIUtil .scaleImageData (device , getImageMetadata (bestAvailableZoom ).getImageData (), zoom , bestAvailableZoom );
2090+ }
2091+
2092+ @ Override
2093+ ImageHandle getImageMetadata (int zoom ) {
2094+ if (zoomLevelToImageHandle .isEmpty ()) {
2095+ long handle = initBaseHandle (zoom );
2096+ ImageHandle imageHandle = new ImageHandle (handle , zoom );
2097+ zoomLevelToImageHandle .put (zoom , imageHandle );
2098+ return imageHandle ;
2099+ } else if (zoomLevelToImageHandle .containsKey (zoom )) {
2100+ return zoomLevelToImageHandle .get (zoom );
2101+ } else {
2102+ ImageData resizedData = getImageData (zoom );
2103+ ImageData newData = adaptImageDataIfDisabledOrGray (resizedData );
2104+ init (newData , zoom );
2105+ return zoomLevelToImageHandle .get (zoom );
2106+ }
2107+ }
2108+
2109+ private long initBaseHandle (int zoom ) {
2110+ if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
2111+ int scaledWidth = DPIUtil .scaleUp (width , zoom );
2112+ int scaledHeight = DPIUtil .scaleUp (height , zoom );
2113+ long hDC = device .internal_new_GC (null );
2114+ long newHandle ;
2115+ newHandle = OS .CreateCompatibleBitmap (hDC , scaledWidth , scaledHeight );
2116+ /*
2117+ * Feature in Windows. CreateCompatibleBitmap() may fail
2118+ * for large images. The fix is to create a DIB section
2119+ * in that case.
2120+ */
2121+ if (newHandle == 0 ) {
2122+ int bits = OS .GetDeviceCaps (hDC , OS .BITSPIXEL );
2123+ int planes = OS .GetDeviceCaps (hDC , OS .PLANES );
2124+ int depth = bits * planes ;
2125+ if (depth < 16 ) depth = 16 ;
2126+ if (depth > 24 ) depth = 24 ;
2127+ newHandle = createDIB (scaledWidth , scaledHeight , depth );
2128+ }
2129+ if (newHandle != 0 ) {
2130+ long memDC = OS .CreateCompatibleDC (hDC );
2131+ long hOldBitmap = OS .SelectObject (memDC , newHandle );
2132+ OS .PatBlt (memDC , 0 , 0 , scaledWidth , scaledHeight , OS .PATCOPY );
2133+ OS .SelectObject (memDC , hOldBitmap );
2134+ OS .DeleteDC (memDC );
2135+ }
2136+ device .internal_dispose_GC (hDC , null );
2137+ if (newHandle == 0 ) {
2138+ SWT .error (SWT .ERROR_NO_HANDLES , null , device .getLastError ());
2139+ }
2140+ return newHandle ;
2141+ }
2142+
2143+ @ Override
2144+ AbstractImageProviderWrapper createCopy (Image image ) {
2145+ return image .new PlainImageProviderWrapper (width , height );
2146+ }
2147+
2148+ @ Override
2149+ protected void destroy () {
2150+ this .isDestroyed = true ;
2151+ }
2152+
2153+ @ Override
2154+ boolean isDisposed () {
2155+ return isDestroyed ;
2156+ }
2157+ }
2158+
2159+ private abstract class DynamicImageProviderWrapper extends AbstractImageProviderWrapper {
2160+ abstract Object getProvider ();
2161+
20912162 protected void checkProvider (Object provider , Class <?> expectedClass ) {
20922163 if (provider == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
20932164 if (!expectedClass .isAssignableFrom (provider .getClass ())) SWT .error (SWT .ERROR_INVALID_ARGUMENT );
@@ -2100,15 +2171,12 @@ public int hashCode() {
21002171
21012172 @ Override
21022173 public boolean equals (Object otherProvider ) {
2103- return otherProvider instanceof AbstractImageProviderWrapper aip //
2104- && getProvider ().equals (aip .getProvider ());
2105- }
2106-
2107- protected void destroy () {
2174+ return otherProvider instanceof DynamicImageProviderWrapper aip
2175+ && Objects .equals (getProvider (), aip .getProvider ());
21082176 }
21092177}
21102178
2111- private class ImageFileNameProviderWrapper extends AbstractImageProviderWrapper {
2179+ private class ImageFileNameProviderWrapper extends DynamicImageProviderWrapper {
21122180
21132181 /**
21142182 * ImageFileNameProvider to provide file names at various Zoom levels
@@ -2172,7 +2240,7 @@ ImageFileNameProviderWrapper createCopy(Image image) {
21722240 }
21732241}
21742242
2175- private class ImageDataProviderWrapper extends AbstractImageProviderWrapper {
2243+ private class ImageDataProviderWrapper extends DynamicImageProviderWrapper {
21762244
21772245 /**
21782246 * ImageDataProvider to provide ImageData at various Zoom levels
@@ -2222,13 +2290,13 @@ ImageDataProviderWrapper createCopy(Image image) {
22222290 }
22232291}
22242292
2225- private class ImageGcDrawerWrapper extends AbstractImageProviderWrapper {
2293+ private class ImageGcDrawerWrapper extends DynamicImageProviderWrapper {
22262294 private ImageGcDrawer drawer ;
22272295 private int width ;
22282296 private int height ;
22292297 private boolean isDestroyed ;
22302298
2231- public ImageGcDrawerWrapper (ImageGcDrawer imageGcDrawer , int width , int height ) {
2299+ ImageGcDrawerWrapper (ImageGcDrawer imageGcDrawer , int width , int height ) {
22322300 checkProvider (imageGcDrawer , ImageGcDrawer .class );
22332301 this .drawer = imageGcDrawer ;
22342302 this .width = width ;
0 commit comments