@@ -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,123 @@ 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+ public 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+
2072+ @ Override
2073+ protected Rectangle getBounds (int zoom ) {
2074+ Rectangle rectangle = new Rectangle (0 , 0 , width , height );
2075+ return DPIUtil .scaleUp (rectangle , zoom );
2076+ }
2077+
2078+ @ Override
2079+ ImageData getImageData (int zoom ) {
2080+ if (zoomLevelToImageHandle .isEmpty () || zoomLevelToImageHandle .containsKey (zoom )) {
2081+ return getImageMetadata (zoom ).getImageData ();
2082+ }
2083+ // if a GC is initialized with an Image (memGC != null), the image data must not be resized, because it would
2084+ // be a destructive operation. Therefor, always the current image data must be returned
2085+ if (memGC != null ) {
2086+ return getImageDataAtCurrentZoom ();
2087+ }
2088+ TreeSet <Integer > availableZooms = new TreeSet <>(zoomLevelToImageHandle .keySet ());
2089+ int bestAvailableZoom = Optional .ofNullable (availableZooms .higher (zoom )).orElse (availableZooms .lower (zoom ));
2090+ return DPIUtil .scaleImageData (device , getImageMetadata (bestAvailableZoom ).getImageData (), zoom , bestAvailableZoom );
2091+ }
2092+
2093+ @ Override
2094+ ImageHandle getImageMetadata (int zoom ) {
2095+ if (zoomLevelToImageHandle .isEmpty ()) {
2096+ long handle = initBaseHandle (zoom );
2097+ ImageHandle imageHandle = new ImageHandle (handle , zoom );
2098+ zoomLevelToImageHandle .put (zoom , imageHandle );
2099+ return imageHandle ;
2100+ } else if (zoomLevelToImageHandle .containsKey (zoom )) {
2101+ return zoomLevelToImageHandle .get (zoom );
2102+ } else {
2103+ ImageData resizedData = getImageData (zoom );
2104+ ImageData newData = adaptImageDataIfDisabledOrGray (resizedData );
2105+ init (newData , zoom );
2106+ return zoomLevelToImageHandle .get (zoom );
2107+ }
2108+ }
2109+
2110+ private long initBaseHandle (int zoom ) {
2111+ if (isDisposed ()) SWT .error (SWT .ERROR_GRAPHIC_DISPOSED );
2112+ int scaledWidth = DPIUtil .scaleUp (width , zoom );
2113+ int scaledHeight = DPIUtil .scaleUp (height , zoom );
2114+ long hDC = device .internal_new_GC (null );
2115+ long newHandle ;
2116+ newHandle = OS .CreateCompatibleBitmap (hDC , scaledWidth , scaledHeight );
2117+ /*
2118+ * Feature in Windows. CreateCompatibleBitmap() may fail
2119+ * for large images. The fix is to create a DIB section
2120+ * in that case.
2121+ */
2122+ if (newHandle == 0 ) {
2123+ int bits = OS .GetDeviceCaps (hDC , OS .BITSPIXEL );
2124+ int planes = OS .GetDeviceCaps (hDC , OS .PLANES );
2125+ int depth = bits * planes ;
2126+ if (depth < 16 ) depth = 16 ;
2127+ if (depth > 24 ) depth = 24 ;
2128+ newHandle = createDIB (scaledWidth , scaledHeight , depth );
2129+ }
2130+ if (newHandle != 0 ) {
2131+ long memDC = OS .CreateCompatibleDC (hDC );
2132+ long hOldBitmap = OS .SelectObject (memDC , newHandle );
2133+ OS .PatBlt (memDC , 0 , 0 , scaledWidth , scaledHeight , OS .PATCOPY );
2134+ OS .SelectObject (memDC , hOldBitmap );
2135+ OS .DeleteDC (memDC );
2136+ }
2137+ device .internal_dispose_GC (hDC , null );
2138+ if (newHandle == 0 ) {
2139+ SWT .error (SWT .ERROR_NO_HANDLES , null , device .getLastError ());
2140+ }
2141+ return newHandle ;
2142+ }
2143+
2144+ @ Override
2145+ AbstractImageProviderWrapper createCopy (Image image ) {
2146+ return image .new PlainImageProviderWrapper (width , height );
2147+ }
2148+
2149+ @ Override
2150+ protected void destroy () {
2151+ this .isDestroyed = true ;
2152+ }
2153+
2154+ @ Override
2155+ boolean isDisposed () {
2156+ return isDestroyed ;
2157+ }
2158+ }
2159+
2160+
2161+ private abstract class DynamicImageProviderWrapper extends AbstractImageProviderWrapper {
2162+ abstract Object getProvider ();
2163+
20912164 protected void checkProvider (Object provider , Class <?> expectedClass ) {
20922165 if (provider == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
20932166 if (!expectedClass .isAssignableFrom (provider .getClass ())) SWT .error (SWT .ERROR_INVALID_ARGUMENT );
@@ -2100,15 +2173,12 @@ public int hashCode() {
21002173
21012174 @ Override
21022175 public boolean equals (Object otherProvider ) {
2103- return otherProvider instanceof AbstractImageProviderWrapper aip //
2104- && getProvider ().equals (aip .getProvider ());
2105- }
2106-
2107- protected void destroy () {
2176+ return otherProvider instanceof DynamicImageProviderWrapper aip //
2177+ && getProvider () != null && getProvider ().equals (aip .getProvider ());
21082178 }
21092179}
21102180
2111- private class ImageFileNameProviderWrapper extends AbstractImageProviderWrapper {
2181+ private class ImageFileNameProviderWrapper extends DynamicImageProviderWrapper {
21122182
21132183 /**
21142184 * ImageFileNameProvider to provide file names at various Zoom levels
@@ -2172,7 +2242,7 @@ ImageFileNameProviderWrapper createCopy(Image image) {
21722242 }
21732243}
21742244
2175- private class ImageDataProviderWrapper extends AbstractImageProviderWrapper {
2245+ private class ImageDataProviderWrapper extends DynamicImageProviderWrapper {
21762246
21772247 /**
21782248 * ImageDataProvider to provide ImageData at various Zoom levels
@@ -2222,7 +2292,7 @@ ImageDataProviderWrapper createCopy(Image image) {
22222292 }
22232293}
22242294
2225- private class ImageGcDrawerWrapper extends AbstractImageProviderWrapper {
2295+ private class ImageGcDrawerWrapper extends DynamicImageProviderWrapper {
22262296 private ImageGcDrawer drawer ;
22272297 private int width ;
22282298 private int height ;
0 commit comments