Skip to content

Commit e05d988

Browse files
committed
Add strict check 200% image data is double the size of 100% image data
A strict check to be used only for debugging means, this ensures the imageData is scaled linearly for 100 and 200 zooms.
1 parent 7100fa5 commit e05d988

File tree

5 files changed

+101
-55
lines changed

5 files changed

+101
-55
lines changed

bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/DPIUtil.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,9 +290,10 @@ private static ImageData autoScaleImageData (Device device, final ImageData imag
290290
int height = imageData.height;
291291
int scaledWidth = Math.round (width * scaleFactor);
292292
int scaledHeight = Math.round (height * scaleFactor);
293+
int defaultZoomLevel = 100;
293294
boolean useSmoothScaling = isSmoothScalingEnabled() && imageData.getTransparencyType() != SWT.TRANSPARENCY_MASK;
294295
if (useSmoothScaling) {
295-
Image original = new Image (device, (ImageDataProvider) zoom -> imageData);
296+
Image original = new Image(device, (ImageDataProvider) zoom -> (zoom == defaultZoomLevel) ? imageData : null);
296297
ImageGcDrawer drawer = new ImageGcDrawer() {
297298
@Override
298299
public void drawOn(GC gc, int imageWidth, int imageHeight) {
@@ -306,7 +307,7 @@ public int getGcStyle() {
306307
}
307308
};
308309
Image resultImage = new Image (device, drawer, scaledWidth, scaledHeight);
309-
ImageData result = resultImage.getImageData (100);
310+
ImageData result = resultImage.getImageData (defaultZoomLevel);
310311
original.dispose ();
311312
resultImage.dispose ();
312313
return result;

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

Lines changed: 49 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -610,10 +610,29 @@ public Image(Device device, ImageDataProvider imageDataProvider) {
610610
SWT.error(SWT.ERROR_INVALID_ARGUMENT, null,
611611
": ImageDataProvider [" + imageDataProvider + "] returns null ImageData at 100% zoom.");
612612
}
613+
if (Device.strictChecks) {
614+
validateLinearScaling(imageDataProvider);
615+
}
613616
init();
614617
this.device.registerResourceWithZoomSupport(this);
615618
}
616619

620+
private void validateLinearScaling(ImageDataProvider provider) {
621+
final int baseZoom = 100;
622+
final int scaledZoom = 200;
623+
final int scaleFactor = scaledZoom / baseZoom;
624+
ImageData baseImageData = provider.getImageData(baseZoom);
625+
ImageData scaledImageData = provider.getImageData(scaledZoom);
626+
627+
if (scaledImageData == null) {
628+
return;
629+
}
630+
631+
if (scaledImageData.width != scaleFactor * baseImageData.width || scaledImageData.height != scaleFactor * baseImageData.height) {
632+
System.err.println("ImageData should be linearly scaled across zooms.");
633+
}
634+
}
635+
617636
/**
618637
* The provided ImageGcDrawer will be called on demand whenever a new variant of the
619638
* Image for an additional zoom is required. Depending on the OS-specific implementation
@@ -1707,7 +1726,7 @@ private long configureGC(GCData data, int zoom) {
17071726
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
17081727
}
17091728

1710-
if (Device.strictChecks) {
1729+
if(Device.strictChecks) {
17111730
checkImageTypeForValidCustomDrawing(zoom);
17121731
}
17131732
/* Create a compatible HDC for the device */
@@ -1885,6 +1904,11 @@ public Collection<Integer> getPreservedZoomLevels() {
18851904
abstract AbstractImageProviderWrapper createCopy(Image image);
18861905

18871906
ImageData getScaledImageData (int zoom) {
1907+
// if a GC is initialized with an Image (memGC != null), the image data must not be resized, because it would
1908+
// be a destructive operation. Therefor, always the current image data must be returned
1909+
if (memGC != null) {
1910+
return getImageDataAtCurrentZoom();
1911+
}
18881912
TreeSet<Integer> availableZooms = new TreeSet<>(zoomLevelToImageHandle.keySet());
18891913
int closestZoom = Optional.ofNullable(availableZooms.higher(zoom)).orElse(availableZooms.lower(zoom));
18901914
return DPIUtil.scaleImageData(device, getImageMetadata(closestZoom).getImageData(), zoom, closestZoom);
@@ -2118,11 +2142,6 @@ ImageData newImageData(int zoom) {
21182142
if (zoomLevelToImageHandle.isEmpty()) {
21192143
return createBaseHandle(zoom).getImageData();
21202144
}
2121-
// if a GC is initialized with an Image (memGC != null), the image data must not be resized, because it would
2122-
// be a destructive operation. Therefor, a new handle is created for the requested zoom
2123-
if (memGC != null) {
2124-
return newImageHandle(zoom).getImageData();
2125-
}
21262145
return getScaledImageData(zoom);
21272146
}
21282147

@@ -2131,28 +2150,18 @@ protected ImageHandle newImageHandle(int zoom) {
21312150
if (zoomLevelToImageHandle.isEmpty()) {
21322151
return createBaseHandle(zoom);
21332152
}
2134-
if (memGC != null) {
2135-
GC currentGC = memGC;
2136-
memGC = null;
2137-
createHandle(zoom);
2138-
currentGC.refreshFor(new DrawableWrapper(Image.this, zoom), zoom);
2139-
return zoomLevelToImageHandle.get(zoom);
2140-
}
21412153
return super.newImageHandle(zoom);
21422154
}
2155+
21432156
private ImageHandle createBaseHandle(int zoom) {
2157+
long handle = initBaseHandle(zoom);
21442158
baseZoom = zoom;
2145-
return createHandle(zoom);
2146-
}
2147-
2148-
private ImageHandle createHandle(int zoom) {
2149-
long handle = initHandle(zoom);
21502159
ImageHandle imageHandle = new ImageHandle(handle, zoom);
21512160
zoomLevelToImageHandle.put(zoom, imageHandle);
21522161
return imageHandle;
21532162
}
21542163

2155-
private long initHandle(int zoom) {
2164+
private long initBaseHandle(int zoom) {
21562165
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
21572166
int scaledWidth = DPIUtil.scaleUp (width, zoom);
21582167
int scaledHeight = DPIUtil.scaleUp (height, zoom);
@@ -2564,6 +2573,7 @@ protected ImageHandle newImageHandle(int zoom) {
25642573
}
25652574
GC gc = new GC(new DrawableWrapper(image, zoom), gcStyle);
25662575
try {
2576+
gc.data.nativeZoom = zoom;
25672577
drawer.drawOn(gc, width, height);
25682578
ImageData imageData = image.getImageMetadata(zoom).getImageData();
25692579
drawer.postProcess(imageData);
@@ -2575,6 +2585,26 @@ protected ImageHandle newImageHandle(int zoom) {
25752585
}
25762586
}
25772587

2588+
private class DrawableWrapper implements Drawable {
2589+
private final Image image;
2590+
private final int zoom;
2591+
2592+
public DrawableWrapper(Image image, int zoom) {
2593+
this.image = image;
2594+
this.zoom = zoom;
2595+
}
2596+
2597+
@Override
2598+
public long internal_new_GC(GCData data) {
2599+
return this.image.configureGC(data, zoom);
2600+
}
2601+
2602+
@Override
2603+
public void internal_dispose_GC(long handle, GCData data) {
2604+
this.image.internal_dispose_GC(handle, data);
2605+
}
2606+
}
2607+
25782608
@Override
25792609
Object getProvider() {
25802610
return drawer;
@@ -2597,26 +2627,6 @@ public boolean equals(Object otherProvider) {
25972627
}
25982628
}
25992629

2600-
private static class DrawableWrapper implements Drawable {
2601-
private final Image image;
2602-
private final int zoom;
2603-
2604-
public DrawableWrapper(Image image, int zoom) {
2605-
this.image = image;
2606-
this.zoom = zoom;
2607-
}
2608-
2609-
@Override
2610-
public long internal_new_GC(GCData data) {
2611-
return this.image.configureGC(data, zoom);
2612-
}
2613-
2614-
@Override
2615-
public void internal_dispose_GC(long handle, GCData data) {
2616-
this.image.internal_dispose_GC(handle, data);
2617-
}
2618-
}
2619-
26202630
private class ImageHandle {
26212631
private long handle;
26222632
private final int zoom;

tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_Image.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,13 +1043,15 @@ public void test_imageDataIsCached() {
10431043
public void test_imageDataSameViaDifferentProviders() {
10441044
assumeFalse("Cocoa generates inconsistent image data", SwtTestUtil.isCocoa);
10451045
String imagePath = getPath("collapseall.png");
1046-
ImageFileNameProvider imageFileNameProvider = __ -> {
1047-
return imagePath;
1046+
ImageFileNameProvider imageFileNameProvider = zoom -> {
1047+
return (zoom == 100) ? imagePath : null;
10481048
};
1049-
ImageDataProvider dataProvider = __ -> {
1050-
try (InputStream imageStream = Files.newInputStream(Path.of(imagePath))) {
1051-
return new ImageData(imageStream);
1052-
} catch (IOException e) {
1049+
ImageDataProvider dataProvider = zoom -> {
1050+
if (zoom == 100) {
1051+
try (InputStream imageStream = Files.newInputStream(Path.of(imagePath))) {
1052+
return new ImageData(imageStream);
1053+
} catch (IOException e) {
1054+
}
10531055
}
10541056
return null;
10551057
};

tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_ImageData.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
import static org.junit.Assert.assertNotNull;
2525
import static org.junit.Assert.assertNull;
2626
import static org.junit.Assert.assertThrows;
27+
import static org.junit.Assert.fail;
28+
import static org.junit.Assume.assumeNotNull;
29+
import static org.junit.Assume.assumeTrue;
2730

2831
import java.io.IOException;
2932
import java.io.InputStream;
@@ -32,8 +35,10 @@
3235

3336
import org.eclipse.swt.SWT;
3437
import org.eclipse.swt.SWTException;
38+
import org.eclipse.swt.graphics.GC;
3539
import org.eclipse.swt.graphics.Image;
3640
import org.eclipse.swt.graphics.ImageData;
41+
import org.eclipse.swt.graphics.ImageDataProvider;
3742
import org.eclipse.swt.graphics.PaletteData;
3843
import org.eclipse.swt.graphics.RGB;
3944
import org.eclipse.swt.tests.graphics.ImageDataTestHelper;
@@ -799,6 +804,40 @@ public void test_setAlphaIII() {
799804
assertSWTProblem("Incorrect exception thrown for putWidth < 0", SWT.ERROR_INVALID_ARGUMENT, ex);
800805
}
801806

807+
@Test
808+
public void test_ImageCreationFailsWithNonScalingImageDataProviderWhenStrictCheckIsEnabled() {
809+
assumeNotNull(System.getProperty("org.eclipse.swt.internal.enableStrictChecks"));
810+
Display display = Display.getDefault();
811+
GC gc = new GC(display);
812+
try {
813+
ImageDataProvider wrongDataProvider = (zoom) -> new ImageData(16, 16, 32, new PaletteData());
814+
Image image = new Image(display, wrongDataProvider);
815+
image.dispose();
816+
fail("Expected an exception due to non-linearly scaled image data provider");
817+
} catch (IllegalArgumentException | SWTException e) {
818+
} finally {
819+
gc.dispose();
820+
display.dispose();
821+
}
822+
}
823+
824+
@Test
825+
public void test_ImageCreationSucceedsWithNonScalingImageDataProviderWhenStrictCheckIsDisabled() {
826+
assumeTrue(System.getProperty("org.eclipse.swt.internal.enableStrictChecks") == null);
827+
Display display = Display.getDefault();
828+
GC gc = new GC(display);
829+
try {
830+
ImageDataProvider wrongDataProvider = (zoom) -> new ImageData(16, 16, 32, new PaletteData());
831+
Image image = new Image(display, wrongDataProvider);
832+
image.dispose();
833+
} catch (IllegalArgumentException | SWTException e) {
834+
fail("Image creation is expected to succeed without strict checks, even for a non-scaling ImageDataProvider.");
835+
} finally {
836+
gc.dispose();
837+
display.dispose();
838+
}
839+
}
840+
802841
@Test
803842
public void test_setPixelIII() {
804843
int value;

tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_internal_SVGRasterizer.java

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,17 +54,11 @@ public void test_ConstructorLorg_eclipse_swt_graphics_Device_ImageFileNameProvid
5454

5555
@Test
5656
public void test_ConstructorLorg_eclipse_swt_graphics_Device_ImageDataProvider() {
57-
ImageDataProvider validImageDataProvider = zoom -> {
58-
String fileName = "collapseall.svg";
59-
return new ImageData(getPath(fileName));
60-
};
57+
ImageDataProvider validImageDataProvider = zoom -> (zoom == 100) ? new ImageData(getPath("collapseall.svg")) : null;
6158
Image image = new Image(Display.getDefault(), validImageDataProvider);
6259
image.dispose();
6360

64-
ImageDataProvider corruptImageDataProvider = zoom -> {
65-
String fileName = "corrupt.svg";
66-
return new ImageData(getPath(fileName));
67-
};
61+
ImageDataProvider corruptImageDataProvider = zoom -> (zoom == 100) ? new ImageData(getPath("corrupt.svg")) : null;
6862
SWTException e = assertThrows(SWTException.class,
6963
() -> new Image(Display.getDefault(), corruptImageDataProvider));
7064
assertSWTProblem("Incorrect exception thrown for provider with corrupt images", SWT.ERROR_INVALID_IMAGE, e);

0 commit comments

Comments
 (0)