diff options
author | Markus Keller | 2016-04-11 18:46:37 +0000 |
---|---|---|
committer | Markus Keller | 2016-05-12 12:39:37 +0000 |
commit | 487efd11899ecb2796ce34f118afac7f29e65d2d (patch) | |
tree | b40c6144554665a0aa2a8a33a114a77e789dfd54 | |
parent | cc317774a8b42e5e9aaeebb2dc41cb9c38430a23 (diff) | |
download | eclipse.platform.swt-487efd11899ecb2796ce34f118afac7f29e65d2d.tar.gz eclipse.platform.swt-487efd11899ecb2796ce34f118afac7f29e65d2d.tar.xz eclipse.platform.swt-487efd11899ecb2796ce34f118afac7f29e65d2d.zip |
Bug 493462: [HiDPI] Improve autoScale method, default deviceZoom, and system properties
Change-Id: I5c87c4378092770abb8991936cd7ea6a51fcb2af
9 files changed, 202 insertions, 117 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java index 1054282ffc..43da3caf15 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java @@ -724,7 +724,7 @@ Image createButtonImage(Display display, int button) { final ImageData imageData = image.getImageDataAtCurrentZoom(); imageData.transparentPixel = imageData.palette.getPixel(transparent); image.dispose(); - image = new Image(display, new AutoScaleImageDataProvider(imageData, DPIUtil.getDeviceZoom())); + image = new Image(display, new AutoScaleImageDataProvider(display, imageData, DPIUtil.getDeviceZoom())); return image; } void createItem (CTabItem item, int index) { diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TableDragSourceEffect.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TableDragSourceEffect.java index 5eb5319d21..5774b4a04e 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TableDragSourceEffect.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TableDragSourceEffect.java @@ -144,7 +144,8 @@ public class TableDragSourceEffect extends DragSourceEffect { } else { data.transparentPixel = shdi.crColorKey << 8; } - dragSourceImage = new Image(control.getDisplay(), new AutoScaleImageDataProvider(data, DPIUtil.getDeviceZoom())); + Display display = control.getDisplay(); + dragSourceImage = new Image(display, new AutoScaleImageDataProvider(display, data, DPIUtil.getDeviceZoom())); OS.SelectObject (memHdc, oldMemBitmap); OS.DeleteDC (memHdc); OS.DeleteObject (memDib); diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TreeDragSourceEffect.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TreeDragSourceEffect.java index a0e6e99d0e..ea6f9ef13e 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TreeDragSourceEffect.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TreeDragSourceEffect.java @@ -143,7 +143,8 @@ public class TreeDragSourceEffect extends DragSourceEffect { } else { data.transparentPixel = shdi.crColorKey << 8; } - dragSourceImage = new Image (control.getDisplay (), new AutoScaleImageDataProvider(data, DPIUtil.getDeviceZoom())); + Display display = control.getDisplay (); + dragSourceImage = new Image (display, new AutoScaleImageDataProvider(display, data, DPIUtil.getDeviceZoom())); OS.SelectObject (memHdc, oldMemBitmap); OS.DeleteDC (memHdc); OS.DeleteObject (memDib); diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Image.java index b3320fc0f5..6e0df6a655 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Image.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Image.java @@ -971,7 +971,7 @@ public ImageData getImageDataAtCurrentZoom() { NSBitmapImageRep imageRep = getRepresentation(); return _getImageData(imageRep); } - return DPIUtil.autoScaleImageData(getImageData(), DPIUtil.getDeviceZoom(), 100); + return DPIUtil.autoScaleImageData(device, getImageData(), DPIUtil.getDeviceZoom(), 100); } finally { if (pool != null) pool.release(); } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/DPIUtil.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/DPIUtil.java index 60901a7bfc..90dca7fedf 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/DPIUtil.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/DPIUtil.java @@ -30,35 +30,68 @@ import org.eclipse.swt.graphics.*; */ public class DPIUtil { - /* DPI Constants */ - static final int DPI_ZOOM_100 = 96; - private static final double MIN_ZOOM_INTERVAL = 25; + private static final int DPI_ZOOM_100 = 96; - private static boolean autoScaleEnable = true; private static int deviceZoom = 100; - /* - * The AutoScale functionality is enabled by default on HighDPI monitors & - * can be disabled by setting below system property to "false"(Ignore case). + private static enum AutoScaleMethod { AUTO, NEAREST, SMOOTH } + private static AutoScaleMethod autoScaleMethodSetting = AutoScaleMethod.AUTO; + private static AutoScaleMethod autoScaleMethod = AutoScaleMethod.NEAREST; + + /** + * System property that controls the autoScale functionality. + * <ul> + * <li><b>false</b>: deviceZoom is set to 100%</li> + * <li><b>integer</b>: deviceZoom depends on the current display resolution, + * but only uses integer multiples of 100%. The detected native zoom is + * generally rounded down (e.g. at 150%, will use 100%), unless close to + * the next integer multiple (currently at 175%, will use 200%).</li> + * <li><b>quarter</b>: deviceZoom depends on the current display resolution, + * but only uses integer multiples of 25%. The detected native zoom is + * rounded to the closest permissible value.</li> + * <li><b>exact</b>: deviceZoom uses the native zoom (with 1% as minimal + * step).</li> + * <li><i><value></i>: deviceZoom uses the given integer value in + * percent as zoom level.</li> + * </ul> + * The current default is "integer". + */ + private static final String SWT_AUTOSCALE = "swt.autoScale"; + + /** + * System property that controls the method for scaling images: + * <ul> + * <li>"nearest": nearest-neighbor interpolation, may look jagged</li> + * <li>"smooth": smooth edges, may look blurry</li> + * </ul> + * The current default is to use "nearest", except on + * GTK when the deviceZoom is not an integer multiple of 100%. + * The smooth strategy currently doesn't work on Win32 and Cocoa, see + * <a href="https://bugs.eclipse.org/493455">bug 493455</a>. */ - static final String SWT_ENABLE_AUTOSCALE = "swt.enable.autoScale"; + private static final String SWT_AUTOSCALE_METHOD = "swt.autoScale.method"; static { - String value = System.getProperty (SWT_ENABLE_AUTOSCALE); - if (value != null && "false".equalsIgnoreCase (value)) - autoScaleEnable = false; + String value = System.getProperty (SWT_AUTOSCALE_METHOD); + if (value != null) { + if (AutoScaleMethod.NEAREST.name().equalsIgnoreCase(value)) { + autoScaleMethod = autoScaleMethodSetting = AutoScaleMethod.NEAREST; + } else if (AutoScaleMethod.SMOOTH.name().equalsIgnoreCase(value)) { + autoScaleMethod = autoScaleMethodSetting = AutoScaleMethod.SMOOTH; + } + } } /** * Auto-scale down ImageData */ -public static ImageData autoScaleDown (ImageData imageData) { - if (deviceZoom == 100 || !isAutoScaleEnable () || imageData == null) return imageData; - float scaleFactor = getScalingFactor (); - return imageData.scaledTo (Math.round ((float)imageData.width / scaleFactor), Math.round ((float)imageData.height / scaleFactor)); +public static ImageData autoScaleDown (Device device, final ImageData imageData) { + if (deviceZoom == 100 || imageData == null) return imageData; + float scaleFactor = 1.0f / getScalingFactor (); + return autoScaleImageData(device, imageData, scaleFactor); } public static int[] autoScaleDown(int[] pointArray) { - if (deviceZoom == 100 || !isAutoScaleEnable () || pointArray == null) return pointArray; + if (deviceZoom == 100 || pointArray == null) return pointArray; float scaleFactor = getScalingFactor (); int [] returnArray = new int[pointArray.length]; for (int i = 0; i < pointArray.length; i++) { @@ -71,7 +104,7 @@ public static int[] autoScaleDown(int[] pointArray) { * Auto-scale up float array dimensions. */ public static float[] autoScaleDown (float size[]) { - if (deviceZoom == 100 || !isAutoScaleEnable () || size == null) return size; + if (deviceZoom == 100 || size == null) return size; float scaleFactor = getScalingFactor (); float scaledSize[] = new float[size.length]; for (int i = 0; i < scaledSize.length; i++) { @@ -83,7 +116,7 @@ public static float[] autoScaleDown (float size[]) { * Auto-scale down int dimensions. */ public static int autoScaleDown (int size) { - if (deviceZoom == 100 || !isAutoScaleEnable ()||size == SWT.DEFAULT) return size; + if (deviceZoom == 100 || size == SWT.DEFAULT) return size; float scaleFactor = getScalingFactor (); return Math.round (size / scaleFactor); } @@ -91,7 +124,7 @@ public static int autoScaleDown (int size) { * Auto-scale down float dimensions. */ public static float autoScaleDown (float size) { - if (deviceZoom == 100 || !isAutoScaleEnable ()||size == SWT.DEFAULT) return size; + if (deviceZoom == 100 || size == SWT.DEFAULT) return size; float scaleFactor = getScalingFactor (); return (size / scaleFactor); } @@ -100,7 +133,7 @@ public static float autoScaleDown (float size) { * Returns a new scaled down Point. */ public static Point autoScaleDown (Point point) { - if (deviceZoom == 100 || !isAutoScaleEnable () || point == null) return point; + if (deviceZoom == 100 || point == null) return point; float scaleFactor = getScalingFactor (); Point scaledPoint = new Point (0,0); scaledPoint.x = Math.round (point.x / scaleFactor); @@ -112,7 +145,7 @@ public static Point autoScaleDown (Point point) { * Returns a new scaled down Rectangle. */ public static Rectangle autoScaleDown (Rectangle rect) { - if (deviceZoom == 100 || !isAutoScaleEnable () || rect == null) return rect; + if (deviceZoom == 100 || rect == null) return rect; Rectangle scaledRect = new Rectangle (0,0,0,0); Point scaledTopLeft = DPIUtil.autoScaleDown (new Point (rect.x, rect.y)); Point scaledBottomRight = DPIUtil.autoScaleDown (new Point (rect.x + rect.width, rect.y + rect.height)); @@ -127,17 +160,60 @@ public static Rectangle autoScaleDown (Rectangle rect) { /** * Auto-scale image with ImageData */ -public static ImageData autoScaleImageData (ImageData imageData, int targetZoom, int currentZoom) { - if (!isAutoScaleEnable () || imageData == null || targetZoom == currentZoom) return imageData; - float scaleFactor = ((float) targetZoom)/((float) currentZoom); - return imageData.scaledTo (Math.round ((float)imageData.width * scaleFactor), Math.round ((float)imageData.height * scaleFactor)); +public static ImageData autoScaleImageData (Device device, final ImageData imageData, int targetZoom, int currentZoom) { + if (deviceZoom == 100 || imageData == null || targetZoom == currentZoom) return imageData; + float scaleFactor = (float) targetZoom / (float) currentZoom; + return autoScaleImageData(device, imageData, scaleFactor); +} + +private static ImageData autoScaleImageData (Device device, final ImageData imageData, float scaleFactor) { + // Guards are already implemented in callers: if (deviceZoom == 100 || imageData == null || scaleFactor == 1.0f) return imageData; + int width = imageData.width; + int height = imageData.height; + int scaledWidth = Math.round ((float) width * scaleFactor); + int scaledHeight = Math.round ((float) height * scaleFactor); + switch (autoScaleMethod) { + case SMOOTH: + Image original = new Image (device, new ImageDataProvider () { + @Override + public ImageData getImageData (int zoom) { + return imageData; + } + }); + + /* Create a 24 bit image data with alpha channel */ + final ImageData resultData = new ImageData (scaledWidth, scaledHeight, 24, new PaletteData (0xFF, 0xFF00, 0xFF0000)); + resultData.alphaData = new byte [scaledWidth * scaledHeight]; + + Image resultImage = new Image (device, new ImageDataProvider () { + @Override + public ImageData getImageData (int zoom) { + return resultData; + } + }); + GC gc = new GC (resultImage); + gc.setAntialias (SWT.ON); + gc.drawImage (original, 0, 0, DPIUtil.autoScaleDown (width), DPIUtil.autoScaleDown (height), + /* E.g. destWidth here is effectively DPIUtil.autoScaleDown (scaledWidth), but avoiding rounding errors. + * Nevertheless, we still have some rounding errors due to the point-based API GC#drawImage(..). + */ + 0, 0, Math.round (DPIUtil.autoScaleDown ((float) width * scaleFactor)), Math.round (DPIUtil.autoScaleDown ((float) height * scaleFactor))); + gc.dispose (); + original.dispose (); + ImageData result = resultImage.getImageDataAtCurrentZoom (); + resultImage.dispose (); + return result; + case NEAREST: + default: + return imageData.scaledTo (scaledWidth, scaledHeight); + } } /** * Returns a new rectangle as per the scaleFactor. */ public static Rectangle autoScaleBounds (Rectangle rect, int targetZoom, int currentZoom) { - if (!isAutoScaleEnable () || rect == null || targetZoom == currentZoom) return rect; + if (deviceZoom == 100 || rect == null || targetZoom == currentZoom) return rect; float scaleFactor = ((float)targetZoom) / (float)currentZoom; Rectangle returnRect = new Rectangle (0,0,0,0); returnRect.x = Math.round (rect.x * scaleFactor); @@ -150,14 +226,14 @@ public static Rectangle autoScaleBounds (Rectangle rect, int targetZoom, int cur /** * Auto-scale up ImageData */ -public static ImageData autoScaleUp (ImageData imageData) { - if (deviceZoom == 100 || !isAutoScaleEnable () || imageData == null) return imageData; +public static ImageData autoScaleUp (Device device, final ImageData imageData) { + if (deviceZoom == 100 || imageData == null) return imageData; float scaleFactor = getScalingFactor (); - return imageData.scaledTo (Math.round ((float)imageData.width * scaleFactor), Math.round ((float)imageData.height * scaleFactor)); + return autoScaleImageData(device, imageData, scaleFactor); } public static int[] autoScaleUp(int[] pointArray) { - if (deviceZoom == 100 || !isAutoScaleEnable () || pointArray == null) return pointArray; + if (deviceZoom == 100 || pointArray == null) return pointArray; float scaleFactor = getScalingFactor (); int [] returnArray = new int[pointArray.length]; for (int i = 0; i < pointArray.length; i++) { @@ -170,13 +246,13 @@ public static int[] autoScaleUp(int[] pointArray) { * Auto-scale up int dimensions. */ public static int autoScaleUp (int size) { - if (deviceZoom == 100 || !isAutoScaleEnable ()||size == SWT.DEFAULT) return size; + if (deviceZoom == 100 || size == SWT.DEFAULT) return size; float scaleFactor = getScalingFactor (); return Math.round (size * scaleFactor); } public static float autoScaleUp(float size) { - if (deviceZoom == 100 || !isAutoScaleEnable ()||size == SWT.DEFAULT) return size; + if (deviceZoom == 100 || size == SWT.DEFAULT) return size; float scaleFactor = getScalingFactor (); return (size * scaleFactor); } @@ -185,7 +261,7 @@ public static float autoScaleUp(float size) { * Returns a new scaled up Point. */ public static Point autoScaleUp (Point point) { - if (deviceZoom == 100 || !isAutoScaleEnable () || point == null) return point; + if (deviceZoom == 100 || point == null) return point; float scaleFactor = getScalingFactor (); Point scaledPoint = new Point (0,0); scaledPoint.x = Math.round (point.x * scaleFactor); @@ -197,7 +273,7 @@ public static Point autoScaleUp (Point point) { * Returns a new scaled up Rectangle. */ public static Rectangle autoScaleUp (Rectangle rect) { - if (deviceZoom == 100 || !isAutoScaleEnable () || rect == null) return rect; + if (deviceZoom == 100 || rect == null) return rect; Rectangle scaledRect = new Rectangle (0,0,0,0); Point scaledTopLeft = DPIUtil.autoScaleUp (new Point (rect.x, rect.y)); Point scaledBottomRight = DPIUtil.autoScaleUp (new Point (rect.x + rect.width, rect.y + rect.height)); @@ -208,39 +284,24 @@ public static Rectangle autoScaleUp (Rectangle rect) { scaledRect.height = scaledBottomRight.y - scaledTopLeft.y; return scaledRect; } -public static boolean isAutoScaleEnable () { - return autoScaleEnable; -} /** * Returns Scaling factor from the display * @return float scaling factor */ private static float getScalingFactor () { - float scalingFactor = 1; - if (isAutoScaleEnable ()) { - scalingFactor = getDeviceZoom ()/100f; - } - return scalingFactor; + return deviceZoom / 100f; } /** - * Compute the zoom value based on the scaleFactor value. - * - * @return zoom - */ -public static int mapSFToZoom (float scaleFactor) { - return mapDPIToZoom ((int) (scaleFactor * DPI_ZOOM_100)); -} -/** * Compute the zoom value based on the DPI value. * * @return zoom */ public static int mapDPIToZoom (int dpi) { - double zoom = (double)dpi * 100 / DPI_ZOOM_100; //convert to percentage - int roundedZoom = (int) (Math.round (zoom / MIN_ZOOM_INTERVAL) * MIN_ZOOM_INTERVAL); //rounding to MIN_ZOOM_INTERVAL steps - return Math.max(100, roundedZoom); //We are setting the minimum zoom value as 100%. below that it causing too many problems + double zoom = (double) dpi * 100 / DPI_ZOOM_100; + int roundedZoom = (int) Math.round (zoom); + return roundedZoom; } /** * Gets Image data at specified zoom level, if image is missing then @@ -272,34 +333,59 @@ public static String validateAndGetImagePathAtZoom (ImageFileNameProvider provid return filename; } -/** - * @return the deviceZoom - */ public static int getDeviceZoom() { - return isAutoScaleEnable () ? deviceZoom : 100; + return deviceZoom; } -/** - * @param deviceZoom the deviceZoom to set - */ -public static void setDeviceZoom(int deviceZoom) { +public static void setDeviceZoom (int nativeDeviceZoom) { + int deviceZoom = 0; + String value = System.getProperty (SWT_AUTOSCALE); + if (value != null) { + if ("false".equalsIgnoreCase (value)) { + deviceZoom = 100; + } else if ("quarter".equalsIgnoreCase (value)) { + deviceZoom = (int) (Math.round (nativeDeviceZoom / 25f) * 25); + } else if ("exact".equalsIgnoreCase (value)) { + deviceZoom = nativeDeviceZoom; + } else { + try { + int zoom = Integer.parseInt (value); + deviceZoom = Math.max (Math.min (zoom, 1600), 25); + } catch (NumberFormatException e) { + // unsupported value, use default + } + } + } + if (deviceZoom == 0) { // || "integer".equalsIgnoreCase (value) + deviceZoom = Math.max ((nativeDeviceZoom + 25) / 100 * 100, 100); + } + DPIUtil.deviceZoom = deviceZoom; System.setProperty("org.eclipse.swt.internal.deviceZoom", Integer.toString(deviceZoom)); + if (deviceZoom != 100 && autoScaleMethodSetting == AutoScaleMethod.AUTO) { + if (deviceZoom / 100 * 100 == deviceZoom || !"gtk".equals(SWT.getPlatform())) { + autoScaleMethod = AutoScaleMethod.NEAREST; + } else { + autoScaleMethod = AutoScaleMethod.SMOOTH; + } + } } /** * AutoScale ImageDataProvider. */ public static final class AutoScaleImageDataProvider implements ImageDataProvider { + Device device; ImageData imageData; int currentZoom; - public AutoScaleImageDataProvider(ImageData data, int zoom){ + public AutoScaleImageDataProvider(Device device, ImageData data, int zoom){ + this.device = device; this.imageData = data; this.currentZoom = zoom; } @Override public ImageData getImageData(int zoom) { - return DPIUtil.autoScaleImageData(imageData, zoom, currentZoom); + return DPIUtil.autoScaleImageData(device, imageData, zoom, currentZoom); } } } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java index c593caa28d..25befb40e3 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java @@ -580,7 +580,7 @@ public Image(Device device, ImageData data) { super(device); if (data == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); currentDeviceZoom = DPIUtil.getDeviceZoom(); - data = DPIUtil.autoScaleUp (data); + data = DPIUtil.autoScaleUp (device, data); init(data); init(); } @@ -623,8 +623,8 @@ public Image(Device device, ImageData source, ImageData mask) { SWT.error(SWT.ERROR_INVALID_ARGUMENT); } currentDeviceZoom = DPIUtil.getDeviceZoom(); - source = DPIUtil.autoScaleUp (source); - mask = DPIUtil.autoScaleUp (mask); + source = DPIUtil.autoScaleUp (device, source); + mask = DPIUtil.autoScaleUp (device, mask); mask = ImageData.convertMask (mask); ImageData image = new ImageData(source.width, source.height, source.depth, source.palette, source.scanlinePad, source.data); image.maskPad = mask.scanlinePad; @@ -690,7 +690,7 @@ public Image(Device device, InputStream stream) { super(device); ImageData data = new ImageData(stream); currentDeviceZoom = DPIUtil.getDeviceZoom(); - data = DPIUtil.autoScaleUp (data); + data = DPIUtil.autoScaleUp (device, data); init(data); init(); } @@ -733,7 +733,7 @@ public Image(Device device, String filename) { ImageData data = new ImageData(filename); currentDeviceZoom = DPIUtil.getDeviceZoom(); - data = DPIUtil.autoScaleUp (data); + data = DPIUtil.autoScaleUp (device, data); init(data); init(); } @@ -781,7 +781,7 @@ public Image(Device device, ImageFileNameProvider imageFileNameProvider) { } } else { ImageData imageData = new ImageData (filename); - ImageData resizedData = DPIUtil.autoScaleUp (imageData); + ImageData resizedData = DPIUtil.autoScaleUp (device, imageData); init(resizedData); } init (); @@ -825,7 +825,7 @@ public Image(Device device, ImageDataProvider imageDataProvider) { if (found[0]) { init (data); } else { - ImageData resizedData = DPIUtil.autoScaleUp (data); + ImageData resizedData = DPIUtil.autoScaleUp (device, data); init (resizedData); } init (); @@ -860,7 +860,7 @@ boolean refreshImageForZoom () { /* Release current native resources */ destroy (); ImageData imageData = new ImageData (filename); - ImageData resizedData = DPIUtil.autoScaleUp (imageData); + ImageData resizedData = DPIUtil.autoScaleUp (device, imageData); init(resizedData); init (); refreshed = true; @@ -883,7 +883,7 @@ boolean refreshImageForZoom () { if (!found[0]) { /* Release current native resources */ destroy (); - ImageData resizedData = DPIUtil.autoScaleImageData(data, deviceZoomLevel, 100); + ImageData resizedData = DPIUtil.autoScaleImageData(device, data, deviceZoomLevel, 100); init(resizedData); init(); refreshed = true; @@ -895,7 +895,7 @@ boolean refreshImageForZoom () { if (deviceZoomLevel != currentDeviceZoom) { ImageData data = getImageDataAtCurrentZoom(); destroy (); - ImageData resizedData = DPIUtil.autoScaleImageData(data, deviceZoomLevel, currentDeviceZoom); + ImageData resizedData = DPIUtil.autoScaleImageData(device, data, deviceZoomLevel, currentDeviceZoom); init(resizedData); init(); refreshed = true; @@ -1520,7 +1520,7 @@ public ImageData getImageDataAtCurrentZoom () { */ ImageData getImageData (int zoom) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); - return DPIUtil.autoScaleImageData (getImageDataAtCurrentZoom (), zoom, currentDeviceZoom); + return DPIUtil.autoScaleImageData (device, getImageDataAtCurrentZoom (), zoom, currentDeviceZoom); } /** diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java index ad91150c4b..2c3f18a1b9 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java @@ -927,8 +927,8 @@ void drawFocusInPixels (int x, int y, int width, int height) { * </ul> */ public void drawImage (Image image, int x, int y) { - x = (x != SWT.DEFAULT ? DPIUtil.autoScaleUp(x) : x); - y = (y != SWT.DEFAULT ? DPIUtil.autoScaleUp(y) : y); + x = DPIUtil.autoScaleUp(x); + y = DPIUtil.autoScaleUp(y); drawImageInPixels(image, x, y); } @@ -972,18 +972,6 @@ void drawImageInPixels(Image image, int x, int y) { * </ul> */ public void drawImage (Image image, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight) { - srcX = (srcX != SWT.DEFAULT ? DPIUtil.autoScaleUp(srcX) : srcX); - srcY = (srcY != SWT.DEFAULT ? DPIUtil.autoScaleUp(srcY) : srcY); - srcWidth = (srcWidth != SWT.DEFAULT ? DPIUtil.autoScaleUp(srcWidth) : srcWidth); - srcHeight = (srcHeight != SWT.DEFAULT ? DPIUtil.autoScaleUp(srcHeight) : srcHeight); - destX = (destX != SWT.DEFAULT ? DPIUtil.autoScaleUp(destX) : destX); - destY = (destY != SWT.DEFAULT ? DPIUtil.autoScaleUp(destY) : destY); - destWidth = (destWidth != SWT.DEFAULT ? DPIUtil.autoScaleUp(destWidth) : destWidth); - destHeight = (destHeight != SWT.DEFAULT ? DPIUtil.autoScaleUp(destHeight) : destHeight); - drawImageInPixels(image, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight); -} - -void drawImageInPixels(Image image, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight) { if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (srcWidth == 0 || srcHeight == 0 || destWidth == 0 || destHeight == 0) return; if (srcX < 0 || srcY < 0 || srcWidth < 0 || srcHeight < 0 || destWidth < 0 || destHeight < 0) { @@ -991,7 +979,28 @@ void drawImageInPixels(Image image, int srcX, int srcY, int srcWidth, int srcHei } if (image == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); if (image.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); - drawImage(image, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, false); + + Rectangle src = DPIUtil.autoScaleUp(new Rectangle(srcX, srcY, srcWidth, srcHeight)); + Rectangle dest = DPIUtil.autoScaleUp(new Rectangle(destX, destY, destWidth, destHeight)); + int deviceZoom = DPIUtil.getDeviceZoom(); + if (deviceZoom != 100) { + /* + * This is a HACK! Due to rounding errors at fractional scale factors, + * the coordinates may be slightly off. The workaround is to restrict + * coordinates to the allowed bounds. + */ + Rectangle b = image.getBoundsInPixels(); + int errX = src.x + src.width - b.width; + int errY = src.y + src.height - b.height; + if (errX != 0 || errY != 0) { + if (errX <= deviceZoom / 100 && errY <= deviceZoom / 100) { + src.intersect(b); + } else { + SWT.error (SWT.ERROR_INVALID_ARGUMENT); + } + } + } + drawImage(image, src.x, src.y, src.width, src.height, dest.x, dest.y, dest.width, dest.height, false); } void drawImage(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple) { @@ -1213,18 +1222,7 @@ void drawBitmap(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, srcHeight = destHeight = imgHeight; } else { if (srcX + srcWidth > imgWidth || srcY + srcHeight > imgHeight) { - /* - * This is a HACK ! Due to auto-scale of dimensions at high DPI - * display(specifically 150% zoom), rounding error of 1 pixel - * gets introduced in srcX . Below check detects this particular - * scenario and adjusts the dimension for 1 pixel grace value. - */ - if (DPIUtil.isAutoScaleEnable() && DPIUtil.getDeviceZoom() > 100 && ((srcX + srcWidth - imgWidth) == 1)) { - srcX--; - } - else { - SWT.error(SWT.ERROR_INVALID_ARGUMENT); - } + SWT.error(SWT.ERROR_INVALID_ARGUMENT); } simple = srcX == 0 && srcY == 0 && srcWidth == destWidth && destWidth == imgWidth && 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 1fa7ee94d1..f6b68178bc 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 @@ -495,7 +495,7 @@ public Image(Device device, ImageData data) { super(device); if (data == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); currentDeviceZoom = DPIUtil.getDeviceZoom (); - data = DPIUtil.autoScaleUp (data); + data = DPIUtil.autoScaleUp (device, data); init(data); init(); } @@ -538,8 +538,8 @@ public Image(Device device, ImageData source, ImageData mask) { SWT.error(SWT.ERROR_INVALID_ARGUMENT); } currentDeviceZoom = DPIUtil.getDeviceZoom (); - source = DPIUtil.autoScaleUp(source); - mask = DPIUtil.autoScaleUp(mask); + source = DPIUtil.autoScaleUp(device, source); + mask = DPIUtil.autoScaleUp(device, mask); mask = ImageData.convertMask(mask); init(this.device, this, source, mask); init(); @@ -601,7 +601,7 @@ public Image(Device device, ImageData source, ImageData mask) { public Image (Device device, InputStream stream) { super(device); currentDeviceZoom = DPIUtil.getDeviceZoom (); - ImageData data = DPIUtil.autoScaleUp(new ImageData(stream)); + ImageData data = DPIUtil.autoScaleUp(device, new ImageData(stream)); init(data); init(); } @@ -642,7 +642,7 @@ public Image (Device device, String filename) { super(device); if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); currentDeviceZoom = DPIUtil.getDeviceZoom (); - ImageData data = DPIUtil.autoScaleUp(new ImageData(filename)); + ImageData data = DPIUtil.autoScaleUp(device, new ImageData(filename)); init(data); init(); } @@ -686,7 +686,7 @@ public Image(Device device, ImageFileNameProvider imageFileNameProvider) { initNative (fileName); if (this.handle == 0) init(new ImageData (fileName)); } else { - ImageData resizedData = DPIUtil.autoScaleUp (new ImageData (fileName)); + ImageData resizedData = DPIUtil.autoScaleUp (device, new ImageData (fileName)); init(resizedData); } init(); @@ -730,7 +730,7 @@ public Image(Device device, ImageDataProvider imageDataProvider) { if (found[0]) { init(data); } else { - ImageData resizedData = DPIUtil.autoScaleUp(data); + ImageData resizedData = DPIUtil.autoScaleUp(device, data); init (resizedData); } init(); @@ -760,7 +760,7 @@ boolean refreshImageForZoom () { if (!found[0]) { /* Release current native resources */ destroy (); - ImageData resizedData = DPIUtil.autoScaleUp (new ImageData (filename)); + ImageData resizedData = DPIUtil.autoScaleUp (device, new ImageData (filename)); init(resizedData); init (); refreshed = true; @@ -782,7 +782,7 @@ boolean refreshImageForZoom () { if (!found[0]) { /* Release current native resources */ destroy (); - ImageData resizedData = DPIUtil.autoScaleUp (data); + ImageData resizedData = DPIUtil.autoScaleUp (device, data); init(resizedData); init(); refreshed = true; @@ -793,7 +793,7 @@ boolean refreshImageForZoom () { if (deviceZoomLevel != currentDeviceZoom) { ImageData data = getImageDataAtCurrentZoom(); destroy (); - ImageData resizedData = DPIUtil.autoScaleImageData(data, deviceZoomLevel, currentDeviceZoom); + ImageData resizedData = DPIUtil.autoScaleImageData(device, data, deviceZoomLevel, currentDeviceZoom); init(resizedData); init(); refreshed = true; @@ -1470,7 +1470,7 @@ public ImageData getImageData() { } ImageData getImageData (int zoom) { - return DPIUtil.autoScaleImageData(this.getImageDataAtCurrentZoom(), zoom, currentDeviceZoom); + return DPIUtil.autoScaleImageData(device, this.getImageDataAtCurrentZoom(), zoom, currentDeviceZoom); } /** diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Display.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Display.java index cdf4c0cb28..a8d1dcd2fd 100644 --- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Display.java +++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Display.java @@ -48,7 +48,6 @@ private static final boolean BUG_492569 = SwtTestUtil.isCocoa || SwtTestUtil.isG @Test public void test_Constructor() { Display disp = new Display(); - System.out.println("org.eclipse.swt.internal.DPIUtil.isAutoScaleEnable(): " + DPIUtil.isAutoScaleEnable()); System.out.println("org.eclipse.swt.internal.DPIUtil.getDeviceZoom(): " + DPIUtil.getDeviceZoom()); disp.dispose(); if (SwtTestUtil.isGTK) { |