Skip to content

Commit d943889

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 709f323 commit d943889

File tree

1 file changed

+118
-54
lines changed
  • bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics

1 file changed

+118
-54
lines changed

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

+118-54
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
}
@@ -327,13 +324,7 @@ public Image(Device device, Image srcImage, int flag) {
327324
* @see #dispose()
328325
*/
329326
public Image(Device device, Rectangle bounds) {
330-
super(device);
331-
if (bounds == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
332-
initialNativeZoom = DPIUtil.getNativeDeviceZoom();
333-
bounds = DPIUtil.scaleUp (bounds, getZoom());
334-
init(bounds.width, bounds.height);
335-
init();
336-
this.device.registerResourceWithZoomSupport(this);
327+
this(device, bounds.width, bounds.height);
337328
}
338329

339330
/**
@@ -1465,39 +1456,6 @@ public int hashCode () {
14651456
return (int)win32_getHandle(this, getZoom());
14661457
}
14671458

1468-
void init(int width, int height) {
1469-
if (width <= 0 || height <= 0) {
1470-
SWT.error (SWT.ERROR_INVALID_ARGUMENT);
1471-
}
1472-
type = SWT.BITMAP;
1473-
long hDC = device.internal_new_GC(null);
1474-
ImageHandle imageMetadata = new ImageHandle(OS.CreateCompatibleBitmap(hDC, width, height), getZoom());
1475-
/*
1476-
* Feature in Windows. CreateCompatibleBitmap() may fail
1477-
* for large images. The fix is to create a DIB section
1478-
* in that case.
1479-
*/
1480-
if (imageMetadata.handle == 0) {
1481-
int bits = OS.GetDeviceCaps(hDC, OS.BITSPIXEL);
1482-
int planes = OS.GetDeviceCaps(hDC, OS.PLANES);
1483-
int depth = bits * planes;
1484-
if (depth < 16) depth = 16;
1485-
if (depth > 24) depth = 24;
1486-
imageMetadata = new ImageHandle(createDIB(width, height, depth), getZoom());
1487-
}
1488-
if (imageMetadata.handle != 0) {
1489-
long memDC = OS.CreateCompatibleDC(hDC);
1490-
long hOldBitmap = OS.SelectObject(memDC, imageMetadata.handle);
1491-
OS.PatBlt(memDC, 0, 0, width, height, OS.PATCOPY);
1492-
OS.SelectObject(memDC, hOldBitmap);
1493-
OS.DeleteDC(memDC);
1494-
}
1495-
device.internal_dispose_GC(hDC, null);
1496-
if (imageMetadata.handle == 0) {
1497-
SWT.error(SWT.ERROR_NO_HANDLES, null, device.getLastError());
1498-
}
1499-
}
1500-
15011459
static long createDIB(int width, int height, int depth) {
15021460
BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER();
15031461
bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
@@ -2089,13 +2047,122 @@ public static Image win32_new(Device device, int type, long handle, int nativeZo
20892047
}
20902048

20912049
private abstract class AbstractImageProviderWrapper {
2092-
abstract Object getProvider();
20932050
protected abstract Rectangle getBounds(int zoom);
20942051
abstract ImageData getImageData(int zoom);
20952052
abstract ImageHandle getImageMetadata(int zoom);
20962053
abstract AbstractImageProviderWrapper createCopy(Image image);
20972054
abstract boolean isDisposed();
20982055

2056+
protected void destroy() {
2057+
}
2058+
}
2059+
2060+
private class PlainImageProviderWrapper extends AbstractImageProviderWrapper {
2061+
private boolean isDestroyed;
2062+
private final int width;
2063+
private final int height;
2064+
2065+
public PlainImageProviderWrapper(int width, int height) {
2066+
if (width <= 0 || height <= 0) {
2067+
SWT.error (SWT.ERROR_INVALID_ARGUMENT);
2068+
}
2069+
this.width = width;
2070+
this.height = height;
2071+
type = SWT.BITMAP;
2072+
}
2073+
2074+
2075+
@Override
2076+
protected Rectangle getBounds(int zoom) {
2077+
Rectangle rectangle = new Rectangle(0, 0, width, height);
2078+
return DPIUtil.scaleUp(rectangle, zoom);
2079+
}
2080+
2081+
@Override
2082+
ImageData getImageData(int zoom) {
2083+
if (zoomLevelToImageHandle.isEmpty() || zoomLevelToImageHandle.containsKey(zoom)) {
2084+
return getImageMetadata(zoom).getImageData();
2085+
}
2086+
// if a GC is initialized with an Image (memGC != null), the image data must not be resized, because it would
2087+
// be a destructive operation. Therefor, always the current image data must be returned
2088+
if (memGC != null) {
2089+
return getImageDataAtCurrentZoom();
2090+
}
2091+
TreeSet<Integer> availableZooms = new TreeSet<>(zoomLevelToImageHandle.keySet());
2092+
int bestAvailableZoom = Optional.ofNullable(availableZooms.higher(zoom)).orElse(availableZooms.lower(zoom));
2093+
return DPIUtil.scaleImageData (device, getImageMetadata(bestAvailableZoom).getImageData(), zoom, bestAvailableZoom);
2094+
}
2095+
2096+
@Override
2097+
ImageHandle getImageMetadata(int zoom) {
2098+
if (zoomLevelToImageHandle.isEmpty()) {
2099+
long handle = initBaseHandle(zoom);
2100+
ImageHandle imageHandle = new ImageHandle(handle, zoom);
2101+
zoomLevelToImageHandle.put(zoom, imageHandle);
2102+
return imageHandle;
2103+
} else if(zoomLevelToImageHandle.containsKey(zoom)) {
2104+
return zoomLevelToImageHandle.get(zoom);
2105+
} else {
2106+
ImageData resizedData = getImageData(zoom);
2107+
ImageData newData = adaptImageDataIfDisabledOrGray(resizedData);
2108+
init(newData, zoom);
2109+
return zoomLevelToImageHandle.get(zoom);
2110+
}
2111+
}
2112+
2113+
private long initBaseHandle(int zoom) {
2114+
int scaledWidth = DPIUtil.scaleUp (width, zoom);
2115+
int scaledHeight = DPIUtil.scaleUp (height, zoom);
2116+
long hDC = device.internal_new_GC(null);
2117+
long newHandle;
2118+
newHandle = OS.CreateCompatibleBitmap(hDC, scaledWidth, scaledHeight);
2119+
/*
2120+
* Feature in Windows. CreateCompatibleBitmap() may fail
2121+
* for large images. The fix is to create a DIB section
2122+
* in that case.
2123+
*/
2124+
if (newHandle == 0) {
2125+
int bits = OS.GetDeviceCaps(hDC, OS.BITSPIXEL);
2126+
int planes = OS.GetDeviceCaps(hDC, OS.PLANES);
2127+
int depth = bits * planes;
2128+
if (depth < 16) depth = 16;
2129+
if (depth > 24) depth = 24;
2130+
newHandle = createDIB(scaledWidth, scaledHeight, depth);
2131+
}
2132+
if (newHandle != 0) {
2133+
long memDC = OS.CreateCompatibleDC(hDC);
2134+
long hOldBitmap = OS.SelectObject(memDC, newHandle);
2135+
OS.PatBlt(memDC, 0, 0, scaledWidth, scaledHeight, OS.PATCOPY);
2136+
OS.SelectObject(memDC, hOldBitmap);
2137+
OS.DeleteDC(memDC);
2138+
}
2139+
device.internal_dispose_GC(hDC, null);
2140+
if (newHandle == 0) {
2141+
SWT.error(SWT.ERROR_NO_HANDLES, null, device.getLastError());
2142+
}
2143+
return newHandle;
2144+
}
2145+
2146+
@Override
2147+
AbstractImageProviderWrapper createCopy(Image image) {
2148+
return image.new PlainImageProviderWrapper(width, height);
2149+
}
2150+
2151+
@Override
2152+
protected void destroy() {
2153+
this.isDestroyed = true;
2154+
}
2155+
2156+
@Override
2157+
boolean isDisposed() {
2158+
return isDestroyed;
2159+
}
2160+
}
2161+
2162+
2163+
private abstract class DynamicImageProviderWrapper extends AbstractImageProviderWrapper {
2164+
abstract Object getProvider();
2165+
20992166
protected void checkProvider(Object provider, Class<?> expectedClass) {
21002167
if (provider == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
21012168
if (!expectedClass.isAssignableFrom(provider.getClass())) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
@@ -2108,15 +2175,12 @@ public int hashCode() {
21082175

21092176
@Override
21102177
public boolean equals(Object otherProvider) {
2111-
return otherProvider instanceof AbstractImageProviderWrapper aip //
2112-
&& getProvider().equals(aip.getProvider());
2113-
}
2114-
2115-
protected void destroy() {
2178+
return otherProvider instanceof DynamicImageProviderWrapper aip //
2179+
&& getProvider() != null && getProvider().equals(aip.getProvider());
21162180
}
21172181
}
21182182

2119-
private class ImageFileNameProviderWrapper extends AbstractImageProviderWrapper {
2183+
private class ImageFileNameProviderWrapper extends DynamicImageProviderWrapper {
21202184

21212185
/**
21222186
* ImageFileNameProvider to provide file names at various Zoom levels
@@ -2179,7 +2243,7 @@ ImageFileNameProviderWrapper createCopy(Image image) {
21792243
}
21802244
}
21812245

2182-
private class ImageDataProviderWrapper extends AbstractImageProviderWrapper {
2246+
private class ImageDataProviderWrapper extends DynamicImageProviderWrapper {
21832247

21842248
/**
21852249
* ImageDataProvider to provide ImageData at various Zoom levels
@@ -2230,7 +2294,7 @@ ImageDataProviderWrapper createCopy(Image image) {
22302294
}
22312295
}
22322296

2233-
private class ImageGcDrawerWrapper extends AbstractImageProviderWrapper {
2297+
private class ImageGcDrawerWrapper extends DynamicImageProviderWrapper {
22342298
private ImageGcDrawer drawer;
22352299
private int width;
22362300
private int height;

0 commit comments

Comments
 (0)