diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java index 8e83e08b36c..d3b23074009 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java @@ -111,7 +111,7 @@ public final class Image extends Resource implements Drawable { /** * AbstractImageProvider to avail right ImageProvider (ImageDataProvider or ImageFileNameProvider) */ - private AbstractImageProviderWrapper imageProvider; + private final AbstractImageProviderWrapper imageProvider; /** * Style flag used to differentiate normal, gray-scale and disabled images based @@ -138,16 +138,13 @@ public final class Image extends Resource implements Drawable { private Map zoomLevelToImageHandle = new HashMap<>(); -/** - * Prevents uninitialized instances from being created outside the package. - */ -Image (Device device) { - this(device, DPIUtil.getNativeDeviceZoom()); -} - -private Image (Device device, int nativeZoom) { +private Image (Device device, int type, long handle, int nativeZoom) { super(device); initialNativeZoom = nativeZoom; + this.type = type; + this.imageProvider = new ExistingImageHandleProviderWrapper(handle, nativeZoom); + this.isInitialized = true; + this.device.registerResourceWithZoomSupport(this); } /** @@ -243,9 +240,7 @@ public Image(Device device, Image srcImage, int flag) { initialNativeZoom = srcImage.initialNativeZoom; Rectangle rect = srcImage.getBounds(getZoom()); this.type = srcImage.type; - if(srcImage.imageProvider != null) { - this.imageProvider = srcImage.imageProvider.createCopy(this); - } + this.imageProvider = srcImage.imageProvider.createCopy(this); this.styleFlag = srcImage.styleFlag | flag; long srcImageHandle = win32_getHandle(srcImage, getZoom()); switch (flag) { @@ -1916,11 +1911,7 @@ public String toString () { * @noreference This method is not intended to be referenced by clients. */ public static Image win32_new(Device device, int type, long handle, int nativeZoom) { - Image image = new Image(device, nativeZoom); - image.type = type; - image.new ImageHandle(handle, nativeZoom); - image.device.registerResourceWithZoomSupport(image); - return image; + return new Image(device, type, handle, nativeZoom); } private abstract class AbstractImageProviderWrapper { @@ -1940,6 +1931,63 @@ protected void destroy() { } } +private class ExistingImageHandleProviderWrapper extends AbstractImageProviderWrapper { + + private final int width; + private final int height; + private final long handle; + private final int zoomForHandle; + + public ExistingImageHandleProviderWrapper(long handle, int zoomForHandle) { + this.handle = handle; + this.zoomForHandle = zoomForHandle; + ImageHandle imageHandle = new ImageHandle(handle, zoomForHandle); + + ImageData baseData = imageHandle.getImageData(); + this.width = DPIUtil.scaleDown(baseData.width, zoomForHandle); + this.height = DPIUtil.scaleDown(baseData.height, zoomForHandle); + } + + @Override + protected Rectangle getBounds(int zoom) { + Rectangle rectangle = new Rectangle(0, 0, width, height); + return DPIUtil.scaleUp(rectangle, zoom); + } + + @Override + ImageData getImageData(int zoom) { + if (zoomLevelToImageHandle.isEmpty() || zoomLevelToImageHandle.containsKey(zoom)) { + return getImageMetadata(zoom).getImageData(); + } + + return getScaledImageData(zoom); + } + + @Override + ImageHandle getImageMetadata(int zoom) { + if (zoomLevelToImageHandle.containsKey(zoom)) { + return zoomLevelToImageHandle.get(zoom); + } else { + ImageData resizedData = getImageData(zoom); + ImageData newData = adaptImageDataIfDisabledOrGray(resizedData); + if (type == SWT.ICON && newData.getTransparencyType() != SWT.TRANSPARENCY_MASK) { + // If the original type was an icon with transparency mask and re-scaling leads + // to image data without transparency mask, this will create invalid images + // so this fallback will "repair" the image data by explicitly passing + // the transparency mask created from the scaled image data + return initIconHandle(device, newData, newData.getTransparencyMask(), zoom); + } else { + return init(newData, zoom); + } + } + } + + @Override + AbstractImageProviderWrapper createCopy(Image image) { + return image.new ExistingImageHandleProviderWrapper(handle, zoomForHandle); + } +} + private abstract class ImageFromImageDataProviderWrapper extends AbstractImageProviderWrapper { protected abstract ElementAtZoom loadImageData(int zoom);