Skip to content

Commit fdb2dc7

Browse files
committed
Update ImageDataProvider contract
Clarify in the contract that ImageDataProvider implementations are expected to return linearly scaled ImageData based on the zoom level. This commit also extends the strict checks for verifying linear scaling to GTK and Cocoa implementations.
1 parent 9eea8f6 commit fdb2dc7

File tree

10 files changed

+82
-39
lines changed

10 files changed

+82
-39
lines changed

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -850,6 +850,9 @@ public Image(Device device, ImageDataProvider imageDataProvider) {
850850
try {
851851
init (data, 100);
852852
init ();
853+
if (SWTInternalConstants.strictChecks) {
854+
DPIUtil.validateLinearScaling(imageDataProvider);
855+
}
853856
ImageData data2x = imageDataProvider.getImageData (200);
854857
if (data2x != null) {
855858
alphaInfo_200 = new AlphaInfo();
@@ -1822,12 +1825,15 @@ public String toString () {
18221825
* @noreference This method is not intended to be referenced by clients.
18231826
*/
18241827
public static void drawScaled(GC gc, ImageData imageData, int width, int height, float scaleFactor) {
1828+
boolean originalStrictChecks = SWTInternalConstants.strictChecks;
1829+
SWTInternalConstants.strictChecks = false;
18251830
Image imageToDraw = new Image(gc.device, (ImageDataProvider) zoom -> imageData);
18261831
gc.drawImage (imageToDraw, 0, 0, CocoaDPIUtil.pixelToPoint (width), CocoaDPIUtil.pixelToPoint (height),
18271832
/* E.g. destWidth here is effectively DPIUtil.autoScaleDown (scaledWidth), but avoiding rounding errors.
18281833
* Nevertheless, we still have some rounding errors due to the point-based API GC#drawImage(..).
18291834
*/
18301835
0, 0, Math.round (CocoaDPIUtil.pixelToPoint (width * scaleFactor)), Math.round (CocoaDPIUtil.pixelToPoint (height * scaleFactor)));
1836+
SWTInternalConstants.strictChecks = originalStrictChecks;
18311837
imageToDraw.dispose();
18321838
}
18331839

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

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,31 @@ public interface ImageDataProvider {
2828

2929
/**
3030
* Returns the image data for the given zoom level.
31-
* <p>
32-
* If no image is available for a particular zoom level, this method should
33-
* return <code>null</code>. For <code>zoom == 100</code>, returning
34-
* <code>null</code> is not allowed, and SWT will throw an exception.
31+
*
32+
* <ul>
33+
* <li>
34+
* If no image is available for a particular zoom level, this method should
35+
* return <code>null</code>. For <code>zoom == 100</code>, returning
36+
* <code>null</code> is not allowed, and SWT will throw an exception.
37+
* </li>
38+
* <li>
39+
* Implementations are expected to return {@link ImageData} that is
40+
* <b>linearly scaled</b> with respect to the zoom level.
41+
* For example, if <code>getImageData(100)</code> returns an image of
42+
* width <code>w</code> and height <code>h</code>, then
43+
* <code>getImageData(200)</code> must return an {@link ImageData}
44+
* of width <code>2 * w</code> and height <code>2 * h</code>,
45+
* if a non-{@code null} result is returned.
46+
* </li>
47+
* </ul>
48+
*
3549
*
3650
* @param zoom
3751
* The zoom level in % of the standard resolution (which is 1
3852
* physical monitor pixel == 1 SWT logical point). Typically 100,
3953
* 150, or 200.
40-
* @return the image data, or <code>null</code> if <code>zoom != 100</code>
54+
* @return the linearly scaled image data for the given zoom level,
55+
* or <code>null</code> if <code>zoom != 100</code>
4156
* and no image is available for the given zoom level.
4257
* @since 3.104
4358
*/

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,26 @@ public static int mapZoomToDPI (int zoom) {
223223
return roundedDpi;
224224
}
225225

226+
public static void validateLinearScaling(ImageDataProvider provider) {
227+
final int baseZoom = 100;
228+
final int scaledZoom = 200;
229+
final int scaleFactor = scaledZoom / baseZoom;
230+
ImageData baseImageData = provider.getImageData(baseZoom);
231+
ImageData scaledImageData = provider.getImageData(scaledZoom);
232+
233+
if (scaledImageData == null) {
234+
return;
235+
}
236+
237+
if (scaledImageData.width != scaleFactor * baseImageData.width
238+
|| scaledImageData.height != scaleFactor * baseImageData.height) {
239+
System.err.println(String.format(
240+
"***WARNING: ImageData should be linearly scaled across zooms but size is (%d, %d) at 100%% and (%d, %d) at 200%%.",
241+
baseImageData.width, baseImageData.height, scaledImageData.width, scaledImageData.height));
242+
new Error().printStackTrace(System.err);
243+
}
244+
}
245+
226246
/**
227247
* Represents an element, such as some image data, at a specific zoom level.
228248
*
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Yatta Solutions
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*
11+
* Contributors:
12+
* Yatta Solutions - initial API and implementation
13+
*******************************************************************************/
14+
package org.eclipse.swt.internal;
15+
16+
public class SWTInternalConstants {
17+
18+
public static boolean strictChecks = System.getProperty("org.eclipse.swt.internal.enableStrictChecks") != null;
19+
20+
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,9 @@ public Image(Device device, ImageDataProvider imageDataProvider) {
672672
currentDeviceZoom = DPIUtil.getDeviceZoom();
673673
initFromImageDataProvider(currentDeviceZoom);
674674
init ();
675+
if (SWTInternalConstants.strictChecks) {
676+
DPIUtil.validateLinearScaling(imageDataProvider);
677+
}
675678
}
676679

677680
/**
@@ -1583,12 +1586,15 @@ public String toString () {
15831586
* @noreference This method is not intended to be referenced by clients.
15841587
*/
15851588
public static void drawScaled(GC gc, ImageData imageData, int width, int height, float scaleFactor) {
1589+
boolean originalStrictChecks = SWTInternalConstants.strictChecks;
1590+
SWTInternalConstants.strictChecks = false;
15861591
Image imageToDraw = new Image(gc.device, (ImageDataProvider) zoom -> imageData);
15871592
gc.drawImage (imageToDraw, 0, 0, width, height,
15881593
/* E.g. destWidth here is effectively DPIUtil.autoScaleDown (scaledWidth), but avoiding rounding errors.
15891594
* Nevertheless, we still have some rounding errors due to the point-based API GC#drawImage(..).
15901595
*/
15911596
0, 0, Math.round (width * scaleFactor), Math.round (height * scaleFactor));
1597+
SWTInternalConstants.strictChecks = originalStrictChecks;
15921598
imageToDraw.dispose();
15931599
}
15941600

bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,6 @@
116116
*/
117117
public class Display extends Device implements Executor {
118118

119-
static boolean strictChecks = System.getProperty("org.eclipse.swt.internal.enableStrictChecks") != null;
120-
121119
private static final int SLOT_IN_USE = -2;
122120
private static final int LAST_TABLE_INDEX = -1;
123121

@@ -880,7 +878,7 @@ void addWidget (long handle, Widget widget) {
880878
widgetTable = newWidgetTable;
881879
}
882880
int index = freeSlot + 1;
883-
if(strictChecks) {
881+
if(SWTInternalConstants.strictChecks) {
884882
long data = OS.g_object_get_qdata (handle, SWT_OBJECT_INDEX);
885883
if(data > 0 && data != index) {
886884
SWT.error(SWT.ERROR_INVALID_ARGUMENT, null, ". Potential leak of " + widget + debugInfoForIndex(data - 1));

bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Shell.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3258,7 +3258,7 @@ void deregister () {
32583258
if(shellHandle != 0 && !(disposed instanceof Shell)) {
32593259
SWT.error(SWT.ERROR_INVALID_RETURN_VALUE, null, ". Wrong widgetTable entry: " + disposed + " removed for shell: " + this + display.dumpWidgetTableInfo());
32603260
}
3261-
if(Display.strictChecks) {
3261+
if(SWTInternalConstants.strictChecks) {
32623262
Shell[] shells = display.getShells();
32633263
for (Shell shell : shells) {
32643264
if(shell == this) {

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@
3434
*/
3535
public abstract class Device implements Drawable {
3636

37-
static boolean strictChecks = System.getProperty("org.eclipse.swt.internal.enableStrictChecks") != null;
38-
3937
/* Debugging */
4038
public static boolean DEBUG;
4139
boolean debug = DEBUG;

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ private void validateGCState() {
210210
}
211211

212212
void checkGC(int mask) {
213-
if (Device.strictChecks) {
213+
if (SWTInternalConstants.strictChecks) {
214214
validateGCState();
215215
}
216216
int state = data.state;
@@ -4402,7 +4402,7 @@ private void init(Drawable drawable, GCData data, long hDC) {
44024402
}
44034403

44044404
private static int extractZoom(long hDC) {
4405-
if (Device.strictChecks) {
4405+
if (SWTInternalConstants.strictChecks) {
44064406
System.err.println("***WARNING: GC is initialized with a missing zoom. This indicates an "
44074407
+ "incompatible custom Drawable implementation.");
44084408
}

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

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -612,33 +612,13 @@ public Image(Device device, ImageDataProvider imageDataProvider) {
612612
SWT.error(SWT.ERROR_INVALID_ARGUMENT, null,
613613
": ImageDataProvider [" + imageDataProvider + "] returns null ImageData at 100% zoom.");
614614
}
615-
if (Device.strictChecks) {
616-
validateLinearScaling(imageDataProvider);
615+
if (SWTInternalConstants.strictChecks) {
616+
DPIUtil.validateLinearScaling(imageDataProvider);
617617
}
618618
init();
619619
this.device.registerResourceWithZoomSupport(this);
620620
}
621621

622-
private void validateLinearScaling(ImageDataProvider provider) {
623-
final int baseZoom = 100;
624-
final int scaledZoom = 200;
625-
final int scaleFactor = scaledZoom / baseZoom;
626-
ImageData baseImageData = provider.getImageData(baseZoom);
627-
ImageData scaledImageData = provider.getImageData(scaledZoom);
628-
629-
if (scaledImageData == null) {
630-
return;
631-
}
632-
633-
if (scaledImageData.width != scaleFactor * baseImageData.width
634-
|| scaledImageData.height != scaleFactor * baseImageData.height) {
635-
System.err.println(String.format(
636-
"***WARNING: ImageData should be linearly scaled across zooms but size is (%d, %d) at 100%% and (%d, %d) at 200%%.",
637-
baseImageData.width, baseImageData.height, scaledImageData.width, scaledImageData.height));
638-
new Error().printStackTrace(System.err);
639-
}
640-
}
641-
642622
/**
643623
* The provided ImageGcDrawer will be called on demand whenever a new variant of the
644624
* Image for an additional zoom is required. Depending on the OS-specific implementation
@@ -850,12 +830,12 @@ public static long win32_getHandle (Image image, int zoom) {
850830
* @noreference This method is not intended to be referenced by clients.
851831
*/
852832
public static void drawScaled(GC gc, ImageData imageData, int width, int height, float scaleFactor) {
853-
boolean originalStrictChecks = Device.strictChecks;
854-
Device.strictChecks = false;
833+
boolean originalStrictChecks = SWTInternalConstants.strictChecks;
834+
SWTInternalConstants.strictChecks = false;
855835
Image imageToDraw = new Image(gc.device, (ImageDataProvider) zoom -> imageData);
856836
gc.drawImage (imageToDraw, 0, 0, width, height,
857837
0, 0, Math.round (width * scaleFactor), Math.round (height * scaleFactor), false);
858-
Device.strictChecks = originalStrictChecks;
838+
SWTInternalConstants.strictChecks = originalStrictChecks;
859839
imageToDraw.dispose();
860840
}
861841

@@ -1752,7 +1732,7 @@ private long configureGC(GCData data, int zoom) {
17521732
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
17531733
}
17541734

1755-
if (Device.strictChecks) {
1735+
if (SWTInternalConstants.strictChecks) {
17561736
checkImageTypeForValidCustomDrawing(zoom);
17571737
}
17581738
/* Create a compatible HDC for the device */

0 commit comments

Comments
 (0)