Skip to content

Commit 83257cc

Browse files
HeikoKlareHannesWell
authored andcommitted
Allow to test for loading image at zoom and fix faulty Win32 image load
The ImageLoader and FileFormat implementations currently combine the check whether an image can be provided at a specific scale value and the provision of an image in the scale itself. In case a consumer wants to only test whether an image can be provided at a specific scale, it needs to request that image at that scale, even if it will not be used later one, e.g., because it cannot be provided in the required scale. With this change, ImageLoader and FileFormat provide separate methods for validating whether an image can be retrieved at a specific zoom (such as from an SVG) and the retrieval of the image itself. This is employed by the Cocoa Image implementation to avoid unnecessary load operations and in the Win32 Image implementation to correct erroneous scaling from an already initialized handle instead of loading at proper zoom (such as for an SVG). In addition, this fixes a faulty reuse of the same stream in the Cocoa Image implementation at the same place.
1 parent 6a2b931 commit 83257cc

File tree

5 files changed

+58
-23
lines changed

5 files changed

+58
-23
lines changed

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

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020

2121
import org.eclipse.swt.*;
2222
import org.eclipse.swt.internal.*;
23-
import org.eclipse.swt.internal.DPIUtil.*;
2423
import org.eclipse.swt.internal.cocoa.*;
2524
import org.eclipse.swt.internal.graphics.*;
2625
import org.eclipse.swt.internal.image.*;
@@ -692,11 +691,18 @@ public Image(Device device, ImageData source, ImageData mask) {
692691
*/
693692
public Image(Device device, InputStream stream) {
694693
super(device);
694+
if (stream == null) {
695+
SWT.error(SWT.ERROR_NULL_ARGUMENT);
696+
}
695697
NSAutoreleasePool pool = null;
696698
if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
697699
try {
698-
initWithSupplier(zoom -> ImageDataLoader.load(stream, FileFormat.DEFAULT_ZOOM, zoom));
700+
byte[] input = stream.readAllBytes();
701+
initWithSupplier(zoom -> ImageDataLoader.canLoadAtZoom(new ByteArrayInputStream(input), FileFormat.DEFAULT_ZOOM, zoom),
702+
zoom -> ImageDataLoader.load(new ByteArrayInputStream(input), FileFormat.DEFAULT_ZOOM, zoom).element());
699703
init();
704+
} catch (IOException e) {
705+
SWT.error(SWT.ERROR_INVALID_ARGUMENT, e);
700706
} finally {
701707
if (pool != null) pool.release();
702708
}
@@ -741,7 +747,10 @@ public Image(Device device, String filename) {
741747
try {
742748
if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
743749
initNative(filename);
744-
if (this.handle == null) initWithSupplier(zoom -> ImageDataLoader.load(filename, FileFormat.DEFAULT_ZOOM, zoom));
750+
if (this.handle == null) {
751+
initWithSupplier(zoom -> ImageDataLoader.canLoadAtZoom(filename, FileFormat.DEFAULT_ZOOM, zoom),
752+
zoom -> ImageDataLoader.load(filename, FileFormat.DEFAULT_ZOOM, zoom).element());
753+
}
745754
init();
746755
} finally {
747756
if (pool != null) pool.release();
@@ -795,15 +804,13 @@ public Image(Device device, ImageFileNameProvider imageFileNameProvider) {
795804
id id = NSImageRep.imageRepWithContentsOfFile(NSString.stringWith(filename2x));
796805
NSImageRep rep = new NSImageRep(id);
797806
handle.addRepresentation(rep);
798-
} else {
807+
} else if (ImageDataLoader.canLoadAtZoom(filename, 100, 200)) {
799808
// Try to natively scale up the image (e.g. possible if it's an SVG)
800-
ElementAtZoom<ImageData> imageData2x = ImageDataLoader.load(filename, 100, 200);
801-
if (imageData2x.zoom() == 200) {
802-
alphaInfo_200 = new AlphaInfo();
803-
NSBitmapImageRep rep = createRepresentation (imageData2x.element(), alphaInfo_200);
804-
handle.addRepresentation(rep);
805-
rep.release();
806-
}
809+
ImageData imageData2x = ImageDataLoader.load(filename, 100, 200).element();
810+
alphaInfo_200 = new AlphaInfo();
811+
NSBitmapImageRep rep = createRepresentation (imageData2x, alphaInfo_200);
812+
handle.addRepresentation(rep);
813+
rep.release();
807814
}
808815
} finally {
809816
if (pool != null) pool.release();
@@ -1484,17 +1491,11 @@ void init(ImageData image) {
14841491
handle.setCacheMode(OS.NSImageCacheNever);
14851492
}
14861493

1487-
private void initWithSupplier(Function<Integer, ElementAtZoom<ImageData>> zoomToImageData) {
1488-
ElementAtZoom<ImageData> imageData = zoomToImageData.apply(DPIUtil.getDeviceZoom());
1489-
ImageData imageData2x = null;
1490-
if (imageData.zoom() == 200) {
1491-
imageData2x = imageData.element();
1492-
}
1493-
if (imageData.zoom() != 100) {
1494-
imageData = zoomToImageData.apply(100);
1495-
}
1496-
init(imageData.element());
1497-
if (imageData2x != null) {
1494+
private void initWithSupplier(Function<Integer, Boolean> canLoadAtZoom, Function<Integer, ImageData> zoomToImageData) {
1495+
ImageData imageData = zoomToImageData.apply(100);
1496+
init(imageData);
1497+
if (canLoadAtZoom.apply(200)) {
1498+
ImageData imageData2x = zoomToImageData.apply(200);
14981499
alphaInfo_200 = new AlphaInfo();
14991500
NSBitmapImageRep rep = createRepresentation (imageData2x, alphaInfo_200);
15001501
handle.addRepresentation(rep);

bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageDataLoader.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,20 @@ public static ImageData load(String filename) {
3737
return data[0];
3838
}
3939

40+
public static boolean canLoadAtZoom(InputStream stream, int fileZoom, int targetZoom) {
41+
return ImageLoader.canLoadAtZoom(stream, fileZoom, targetZoom);
42+
}
43+
4044
public static ElementAtZoom<ImageData> load(InputStream stream, int fileZoom, int targetZoom) {
4145
List<ElementAtZoom<ImageData>> data = new ImageLoader().load(stream, fileZoom, targetZoom);
4246
if (data.isEmpty()) SWT.error(SWT.ERROR_INVALID_IMAGE);
4347
return data.get(0);
4448
}
4549

50+
public static boolean canLoadAtZoom(String filename, int fileZoom, int targetZoom) {
51+
return ImageLoader.canLoadAtZoom(filename, fileZoom, targetZoom);
52+
}
53+
4654
public static ElementAtZoom<ImageData> load(String filename, int fileZoom, int targetZoom) {
4755
List<ElementAtZoom<ImageData>> data = new ImageLoader().load(filename, fileZoom, targetZoom);
4856
if (data.isEmpty()) SWT.error(SWT.ERROR_INVALID_IMAGE);

bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageLoader.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,11 @@ List<ElementAtZoom<ImageData>> load(InputStream stream, int fileZoom, int target
163163
return images;
164164
}
165165

166+
static boolean canLoadAtZoom(InputStream stream, int fileZoom, int targetZoom) {
167+
if (stream == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
168+
return FileFormat.canLoadAtZoom(new ElementAtZoom<>(stream, fileZoom), targetZoom);
169+
}
170+
166171
/**
167172
* Loads an array of <code>ImageData</code> objects from the
168173
* file with the specified name. Throws an error if either
@@ -196,6 +201,16 @@ List<ElementAtZoom<ImageData>> load(String filename, int fileZoom, int targetZoo
196201
return null;
197202
}
198203

204+
static boolean canLoadAtZoom(String filename, int fileZoom, int targetZoom) {
205+
if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
206+
try (InputStream stream = new FileInputStream(filename)) {
207+
return canLoadAtZoom(stream, fileZoom, targetZoom);
208+
} catch (IOException e) {
209+
SWT.error(SWT.ERROR_IO, e);
210+
}
211+
return false;
212+
}
213+
199214
/**
200215
* Saves the image data in this ImageLoader to the specified stream.
201216
* The format parameter can have one of the following values:

bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/FileFormat.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ public static List<ElementAtZoom<ImageData>> load(ElementAtZoom<InputStream> is,
136136
return fileFormat.loadFromStream(stream, is.zoom(), targetZoom);
137137
}
138138

139+
public static boolean canLoadAtZoom(ElementAtZoom<InputStream> is, int targetZoom) {
140+
return is.zoom() == targetZoom || isDynamicallySizableFormat(is.element());
141+
}
142+
139143
/**
140144
* Write the device independent image array stored in the specified loader
141145
* to the specified output stream using the specified file format.

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2235,13 +2235,20 @@ private class ImageFileNameProviderWrapper extends BaseImageProviderWrapper<Imag
22352235
@Override
22362236
protected ElementAtZoom<ImageData> loadImageData(int zoom) {
22372237
ElementAtZoom<String> fileForZoom = DPIUtil.validateAndGetImagePathAtZoom(provider, zoom);
2238+
2239+
// Load at appropriate zoom via loader
2240+
if (fileForZoom.zoom() != zoom && ImageDataLoader.canLoadAtZoom(fileForZoom.element(), fileForZoom.zoom(), zoom)) {
2241+
ElementAtZoom<ImageData> imageDataAtZoom = ImageDataLoader.load(fileForZoom.element(), fileForZoom.zoom(), zoom);
2242+
return new ElementAtZoom<>(adaptImageDataIfDisabledOrGray(imageDataAtZoom.element()), zoom);
2243+
}
2244+
2245+
// Load at file zoom (native or via loader) and rescale
22382246
ImageHandle nativeInitializedImage;
22392247
if (zoomLevelToImageHandle.containsKey(fileForZoom.zoom())) {
22402248
nativeInitializedImage = zoomLevelToImageHandle.get(fileForZoom.zoom());
22412249
} else {
22422250
nativeInitializedImage = initNative(fileForZoom.element(), fileForZoom.zoom());
22432251
}
2244-
22452252
ElementAtZoom<ImageData> imageDataAtZoom;
22462253
if (nativeInitializedImage == null) {
22472254
imageDataAtZoom = ImageDataLoader.load(fileForZoom.element(), fileForZoom.zoom(), zoom);

0 commit comments

Comments
 (0)