Skip to content

Commit b3bcd2e

Browse files
committed
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 0f21a6e commit b3bcd2e

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
@@ -2212,13 +2212,20 @@ private class ImageFileNameProviderWrapper extends BaseImageProviderWrapper<Imag
22122212
@Override
22132213
ImageData getImageData(int zoom) {
22142214
ElementAtZoom<String> fileForZoom = DPIUtil.validateAndGetImagePathAtZoom(provider, zoom);
2215+
2216+
// Load at appropriate zoom via loader
2217+
if (fileForZoom.zoom() != zoom && ImageDataLoader.canLoadAtZoom(fileForZoom.element(), fileForZoom.zoom(), zoom)) {
2218+
ElementAtZoom<ImageData> imageDataAtZoom = ImageDataLoader.load(fileForZoom.element(), fileForZoom.zoom(), zoom);
2219+
return adaptImageDataIfDisabledOrGray(imageDataAtZoom.element());
2220+
}
2221+
2222+
// Load at file zoom (native or via loader) and rescale
22152223
ImageHandle nativeInitializedImage;
22162224
if (zoomLevelToImageHandle.containsKey(fileForZoom.zoom())) {
22172225
nativeInitializedImage = zoomLevelToImageHandle.get(fileForZoom.zoom());
22182226
} else {
22192227
nativeInitializedImage = initNative(fileForZoom.element(), fileForZoom.zoom());
22202228
}
2221-
22222229
ElementAtZoom<ImageData> imageDataAtZoom;
22232230
if (nativeInitializedImage == null) {
22242231
imageDataAtZoom = ImageDataLoader.load(fileForZoom.element(), fileForZoom.zoom(), zoom);

0 commit comments

Comments
 (0)