Skip to content

Commit eae19e4

Browse files
committed
[win32] Create plain image handles on demand
This commit refactors the Image constructor using width and height to create a bitmap to create handles on demand instead of creating a first handle in the constructor.
1 parent 2974864 commit eae19e4

File tree

1 file changed

+119
-49
lines changed
  • bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics

1 file changed

+119
-49
lines changed

bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java

Lines changed: 119 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,8 @@ public Image(Device device, int width, int height) {
177177

178178
private 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-
14931456
static 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

20832046
private 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

Comments
 (0)