From 6d41adef733f688dbd7d95c1b2e70b4b82226a70 Mon Sep 17 00:00:00 2001 From: Amartya Parijat Date: Fri, 12 Apr 2024 16:30:03 +0200 Subject: [PATCH] Implementation of GC to enable multi zoom level support for win32 which can be extended by other resources and widgets. Contributes to https://github.com/eclipse-platform/eclipse.platform.swt/issues/62 and https://github.com/eclipse-platform/eclipse.platform.swt/issues/131 --- .../win32/org/eclipse/swt/graphics/GC.java | 227 ++++++++++-------- .../org/eclipse/swt/graphics/GCData.java | 1 + .../win32/org/eclipse/swt/graphics/Image.java | 1 + .../org/eclipse/swt/widgets/Control.java | 6 + .../win32/org/eclipse/swt/widgets/Label.java | 1 + .../eclipse/swt/graphics/GCWin32Tests.java | 101 ++++++++ 6 files changed, 240 insertions(+), 97 deletions(-) create mode 100644 tests/org.eclipse.swt.tests.win32/JUnit Tests/org/eclipse/swt/graphics/GCWin32Tests.java 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 8d779a891de..682521bf528 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 @@ -455,8 +455,9 @@ void checkGC(int mask) { * */ public void copyArea (Image image, int x, int y) { - x = DPIUtil.autoScaleUp(drawable, x); - y = DPIUtil.autoScaleUp(drawable, y); + int deviceZoom = getDeviceZoom(); + x = DPIUtil.autoScaleUp(drawable, x, deviceZoom); + y = DPIUtil.autoScaleUp(drawable, y, deviceZoom); copyAreaInPixels(image, x, y); } @@ -511,12 +512,13 @@ public void copyArea (int srcX, int srcY, int width, int height, int destX, int * @since 3.1 */ public void copyArea (int srcX, int srcY, int width, int height, int destX, int destY, boolean paint) { - srcX = DPIUtil.autoScaleUp(drawable, srcX); - srcY = DPIUtil.autoScaleUp(drawable, srcY); - width = DPIUtil.autoScaleUp(drawable, width); - height = DPIUtil.autoScaleUp(drawable, height); - destX = DPIUtil.autoScaleUp(drawable, destX); - destY = DPIUtil.autoScaleUp(drawable, destY); + int deviceZoom = getDeviceZoom(); + srcX = DPIUtil.autoScaleUp(drawable, srcX, deviceZoom); + srcY = DPIUtil.autoScaleUp(drawable, srcY, deviceZoom); + width = DPIUtil.autoScaleUp(drawable, width, deviceZoom); + height = DPIUtil.autoScaleUp(drawable, height, deviceZoom); + destX = DPIUtil.autoScaleUp(drawable, destX, deviceZoom); + destY = DPIUtil.autoScaleUp(drawable, destY, deviceZoom); copyAreaInPixels(srcX, srcY, width, height, destX, destY, paint); } @@ -757,10 +759,11 @@ void disposeGdip() { * */ public void drawArc (int x, int y, int width, int height, int startAngle, int arcAngle) { - x = DPIUtil.autoScaleUp(drawable, x); - y = DPIUtil.autoScaleUp(drawable, y); - width = DPIUtil.autoScaleUp(drawable, width); - height = DPIUtil.autoScaleUp(drawable, height); + int deviceZoom = getDeviceZoom(); + x = DPIUtil.autoScaleUp(drawable, x, deviceZoom); + y = DPIUtil.autoScaleUp(drawable, y, deviceZoom); + width = DPIUtil.autoScaleUp(drawable, width, deviceZoom); + height = DPIUtil.autoScaleUp(drawable, height, deviceZoom); drawArcInPixels(x, y, width, height, startAngle, arcAngle); } @@ -840,10 +843,11 @@ void drawArcInPixels (int x, int y, int width, int height, int startAngle, int a * @see #drawRectangle(int, int, int, int) */ public void drawFocus (int x, int y, int width, int height) { - x = DPIUtil.autoScaleUp (drawable, x); - y = DPIUtil.autoScaleUp (drawable, y); - width = DPIUtil.autoScaleUp (drawable, width); - height = DPIUtil.autoScaleUp (drawable, height); + int deviceZoom = getDeviceZoom(); + x = DPIUtil.autoScaleUp (drawable, x, deviceZoom); + y = DPIUtil.autoScaleUp (drawable, y, deviceZoom); + width = DPIUtil.autoScaleUp (drawable, width, deviceZoom); + height = DPIUtil.autoScaleUp (drawable, height, deviceZoom); drawFocusInPixels(x, y, width, height); } @@ -918,8 +922,9 @@ void drawFocusInPixels (int x, int y, int width, int height) { * */ public void drawImage (Image image, int x, int y) { - x = DPIUtil.autoScaleUp(drawable, x); - y = DPIUtil.autoScaleUp(drawable, y); + int deviceZoom = getDeviceZoom(); + x = DPIUtil.autoScaleUp(drawable, x, deviceZoom); + y = DPIUtil.autoScaleUp(drawable, y, deviceZoom); drawImageInPixels(image, x, y); } @@ -971,9 +976,9 @@ public void drawImage (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); - Rectangle src = DPIUtil.autoScaleUp(drawable, new Rectangle(srcX, srcY, srcWidth, srcHeight)); - Rectangle dest = DPIUtil.autoScaleUp(drawable, new Rectangle(destX, destY, destWidth, destHeight)); - int deviceZoom = DPIUtil.getDeviceZoom(); + int deviceZoom = getDeviceZoom(); + Rectangle src = DPIUtil.autoScaleUp(drawable, new Rectangle(srcX, srcY, srcWidth, srcHeight), deviceZoom); + Rectangle dest = DPIUtil.autoScaleUp(drawable, new Rectangle(destX, destY, destWidth, destHeight), deviceZoom); if (deviceZoom != 100) { /* * This is a HACK! Due to rounding errors at fractional scale factors, @@ -1640,10 +1645,11 @@ void drawBitmapColor(Image srcImage, int srcX, int srcY, int srcWidth, int srcHe * */ public void drawLine (int x1, int y1, int x2, int y2) { - x1 = DPIUtil.autoScaleUp (drawable, x1); - x2 = DPIUtil.autoScaleUp (drawable, x2); - y1 = DPIUtil.autoScaleUp (drawable, y1); - y2 = DPIUtil.autoScaleUp (drawable, y2); + int deviceZoom = getDeviceZoom(); + x1 = DPIUtil.autoScaleUp (drawable, x1, deviceZoom); + x2 = DPIUtil.autoScaleUp (drawable, x2, deviceZoom); + y1 = DPIUtil.autoScaleUp (drawable, y1, deviceZoom); + y2 = DPIUtil.autoScaleUp (drawable, y2, deviceZoom); drawLineInPixels(x1, y1, x2, y2); } @@ -1692,10 +1698,11 @@ void drawLineInPixels (int x1, int y1, int x2, int y2) { * */ public void drawOval (int x, int y, int width, int height) { - x = DPIUtil.autoScaleUp (drawable, x); - y = DPIUtil.autoScaleUp (drawable, y); - width = DPIUtil.autoScaleUp (drawable, width); - height = DPIUtil.autoScaleUp (drawable, height); + int deviceZoom = getDeviceZoom(); + x = DPIUtil.autoScaleUp (drawable, x, deviceZoom); + y = DPIUtil.autoScaleUp (drawable, y, deviceZoom); + width = DPIUtil.autoScaleUp (drawable, width, deviceZoom); + height = DPIUtil.autoScaleUp (drawable, height, deviceZoom); drawOvalInPixels(x, y, width, height); } @@ -1768,8 +1775,9 @@ public void drawPath (Path path) { * @since 3.0 */ public void drawPoint (int x, int y) { - x = DPIUtil.autoScaleUp (drawable, x); - y = DPIUtil.autoScaleUp (drawable, y); + int deviceZoom = getDeviceZoom(); + x = DPIUtil.autoScaleUp (drawable, x, deviceZoom); + y = DPIUtil.autoScaleUp (drawable, y, deviceZoom); drawPointInPixels(x, y); } @@ -1802,7 +1810,7 @@ void drawPointInPixels (int x, int y) { */ public void drawPolygon (int[] pointArray) { if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - drawPolygonInPixels(DPIUtil.autoScaleUp(drawable, pointArray)); + drawPolygonInPixels(DPIUtil.autoScaleUp(drawable, pointArray, getDeviceZoom())); } void drawPolygonInPixels(int[] pointArray) { @@ -1850,7 +1858,7 @@ void drawPolygonInPixels(int[] pointArray) { * */ public void drawPolyline (int[] pointArray) { - drawPolylineInPixels(DPIUtil.autoScaleUp(drawable, pointArray)); + drawPolylineInPixels(DPIUtil.autoScaleUp(drawable, pointArray, getDeviceZoom())); } void drawPolylineInPixels(int[] pointArray) { @@ -1903,10 +1911,11 @@ void drawPolylineInPixels(int[] pointArray) { * */ public void drawRectangle (int x, int y, int width, int height) { - x = DPIUtil.autoScaleUp (drawable, x); - y = DPIUtil.autoScaleUp (drawable, y); - width = DPIUtil.autoScaleUp (drawable, width); - height = DPIUtil.autoScaleUp (drawable, height); + int deviceZoom = getDeviceZoom(); + x = DPIUtil.autoScaleUp (drawable, x, deviceZoom); + y = DPIUtil.autoScaleUp (drawable, y, deviceZoom); + width = DPIUtil.autoScaleUp (drawable, width, deviceZoom); + height = DPIUtil.autoScaleUp (drawable, height, deviceZoom); drawRectangleInPixels(x, y, width, height); } @@ -1962,7 +1971,7 @@ void drawRectangleInPixels (int x, int y, int width, int height) { */ public void drawRectangle (Rectangle rect) { if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - rect = DPIUtil.autoScaleUp(drawable, rect); + rect = DPIUtil.autoScaleUp(drawable, rect, getDeviceZoom()); drawRectangleInPixels(rect.x, rect.y, rect.width, rect.height); } @@ -1988,12 +1997,13 @@ public void drawRectangle (Rectangle rect) { * */ public void drawRoundRectangle (int x, int y, int width, int height, int arcWidth, int arcHeight) { - x = DPIUtil.autoScaleUp (drawable, x); - y = DPIUtil.autoScaleUp (drawable, y); - width = DPIUtil.autoScaleUp (drawable, width); - height = DPIUtil.autoScaleUp (drawable, height); - arcWidth = DPIUtil.autoScaleUp (drawable, arcWidth); - arcHeight = DPIUtil.autoScaleUp (drawable, arcHeight); + int deviceZoom = getDeviceZoom(); + x = DPIUtil.autoScaleUp (drawable, x, deviceZoom); + y = DPIUtil.autoScaleUp (drawable, y, deviceZoom); + width = DPIUtil.autoScaleUp (drawable, width, deviceZoom); + height = DPIUtil.autoScaleUp (drawable, height, deviceZoom); + arcWidth = DPIUtil.autoScaleUp (drawable, arcWidth, deviceZoom); + arcHeight = DPIUtil.autoScaleUp (drawable, arcHeight, deviceZoom); drawRoundRectangleInPixels(x, y, width, height, arcWidth, arcHeight); } @@ -2085,8 +2095,9 @@ void drawRoundRectangleGdip (long gdipGraphics, long pen, int x, int y, int widt * */ public void drawString (String string, int x, int y) { - x = DPIUtil.autoScaleUp(drawable, x); - y = DPIUtil.autoScaleUp(drawable, y); + int deviceZoom = getDeviceZoom(); + x = DPIUtil.autoScaleUp(drawable, x, deviceZoom); + y = DPIUtil.autoScaleUp(drawable, y, deviceZoom); drawStringInPixels(string, x, y, false); } @@ -2118,8 +2129,9 @@ public void drawString (String string, int x, int y) { * */ public void drawString (String string, int x, int y, boolean isTransparent) { - x = DPIUtil.autoScaleUp(drawable, x); - y = DPIUtil.autoScaleUp(drawable, y); + int deviceZoom = getDeviceZoom(); + x = DPIUtil.autoScaleUp(drawable, x, deviceZoom); + y = DPIUtil.autoScaleUp(drawable, y, deviceZoom); drawStringInPixels(string, x, y, isTransparent); } @@ -2209,8 +2221,9 @@ void drawStringInPixels (String string, int x, int y, boolean isTransparent) { * */ public void drawText (String string, int x, int y) { - x = DPIUtil.autoScaleUp(drawable, x); - y = DPIUtil.autoScaleUp(drawable, y); + int deviceZoom = getDeviceZoom(); + x = DPIUtil.autoScaleUp(drawable, x, deviceZoom); + y = DPIUtil.autoScaleUp(drawable, y, deviceZoom); drawTextInPixels(string, x, y); } @@ -2243,8 +2256,9 @@ void drawTextInPixels (String string, int x, int y) { * */ public void drawText (String string, int x, int y, boolean isTransparent) { - x = DPIUtil.autoScaleUp(drawable, x); - y = DPIUtil.autoScaleUp(drawable, y); + int deviceZoom = getDeviceZoom(); + x = DPIUtil.autoScaleUp(drawable, x, deviceZoom); + y = DPIUtil.autoScaleUp(drawable, y, deviceZoom); drawTextInPixels(string, x, y, isTransparent); } @@ -2294,8 +2308,9 @@ void drawTextInPixels (String string, int x, int y, boolean isTransparent) { * */ public void drawText (String string, int x, int y, int flags) { - x = DPIUtil.autoScaleUp(drawable, x); - y = DPIUtil.autoScaleUp(drawable, y); + int deviceZoom = getDeviceZoom(); + x = DPIUtil.autoScaleUp(drawable, x, deviceZoom); + y = DPIUtil.autoScaleUp(drawable, y, deviceZoom); drawTextInPixels(string, x, y, flags); } @@ -2673,10 +2688,11 @@ public boolean equals (Object object) { * @see #drawArc */ public void fillArc (int x, int y, int width, int height, int startAngle, int arcAngle) { - x = DPIUtil.autoScaleUp (drawable, x); - y = DPIUtil.autoScaleUp (drawable, y); - width = DPIUtil.autoScaleUp (drawable, width); - height = DPIUtil.autoScaleUp (drawable, height); + int deviceZoom = getDeviceZoom(); + x = DPIUtil.autoScaleUp (drawable, x, deviceZoom); + y = DPIUtil.autoScaleUp (drawable, y, deviceZoom); + width = DPIUtil.autoScaleUp (drawable, width, deviceZoom); + height = DPIUtil.autoScaleUp (drawable, height, deviceZoom); fillArcInPixels(x, y, width, height, startAngle, arcAngle); } @@ -2752,10 +2768,11 @@ void fillArcInPixels (int x, int y, int width, int height, int startAngle, int a * @see #drawRectangle(int, int, int, int) */ public void fillGradientRectangle (int x, int y, int width, int height, boolean vertical) { - x = DPIUtil.autoScaleUp (drawable, x); - y = DPIUtil.autoScaleUp (drawable, y); - width = DPIUtil.autoScaleUp (drawable, width); - height = DPIUtil.autoScaleUp (drawable, height); + int deviceZoom = getDeviceZoom(); + x = DPIUtil.autoScaleUp (drawable, x, deviceZoom); + y = DPIUtil.autoScaleUp (drawable, y, deviceZoom); + width = DPIUtil.autoScaleUp (drawable, width, deviceZoom); + height = DPIUtil.autoScaleUp (drawable, height, deviceZoom); fillGradientRectangleInPixels(x, y, width, height, vertical); } @@ -2870,10 +2887,11 @@ void fillGradientRectangleInPixels(int x, int y, int width, int height, boolean * @see #drawOval */ public void fillOval (int x, int y, int width, int height) { - x = DPIUtil.autoScaleUp (drawable, x); - y = DPIUtil.autoScaleUp (drawable, y); - width = DPIUtil.autoScaleUp (drawable, width); - height = DPIUtil.autoScaleUp (drawable, height); + int deviceZoom = getDeviceZoom(); + x = DPIUtil.autoScaleUp (drawable, x, deviceZoom); + y = DPIUtil.autoScaleUp (drawable, y, deviceZoom); + width = DPIUtil.autoScaleUp (drawable, width, deviceZoom); + height = DPIUtil.autoScaleUp (drawable, height, deviceZoom); fillOvalInPixels(x, y, width, height); } @@ -2943,7 +2961,7 @@ public void fillPath (Path path) { */ public void fillPolygon (int[] pointArray) { if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - fillPolygonInPixels(DPIUtil.autoScaleUp(drawable, pointArray)); + fillPolygonInPixels(DPIUtil.autoScaleUp(drawable, pointArray, getDeviceZoom())); } void fillPolygonInPixels (int[] pointArray) { @@ -2992,10 +3010,11 @@ void fillPolygonInPixels (int[] pointArray) { * @see #drawRectangle(int, int, int, int) */ public void fillRectangle (int x, int y, int width, int height) { - x = DPIUtil.autoScaleUp (drawable, x); - y = DPIUtil.autoScaleUp (drawable, y); - width = DPIUtil.autoScaleUp (drawable, width); - height = DPIUtil.autoScaleUp (drawable, height); + int deviceZoom = getDeviceZoom(); + x = DPIUtil.autoScaleUp (drawable, x, deviceZoom); + y = DPIUtil.autoScaleUp (drawable, y, deviceZoom); + width = DPIUtil.autoScaleUp (drawable, width, deviceZoom); + height = DPIUtil.autoScaleUp (drawable, height, deviceZoom); fillRectangleInPixels(x, y, width, height); } @@ -3035,7 +3054,7 @@ void fillRectangleInPixels (int x, int y, int width, int height) { */ public void fillRectangle (Rectangle rect) { if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - rect = DPIUtil.autoScaleUp(drawable, rect); + rect = DPIUtil.autoScaleUp(drawable, rect, getDeviceZoom()); fillRectangleInPixels(rect.x, rect.y, rect.width, rect.height); } @@ -3057,12 +3076,13 @@ public void fillRectangle (Rectangle rect) { * @see #drawRoundRectangle */ public void fillRoundRectangle (int x, int y, int width, int height, int arcWidth, int arcHeight) { - x = DPIUtil.autoScaleUp (drawable, x); - y = DPIUtil.autoScaleUp (drawable, y); - width = DPIUtil.autoScaleUp (drawable, width); - height = DPIUtil.autoScaleUp (drawable, height); - arcWidth = DPIUtil.autoScaleUp (drawable, arcWidth); - arcHeight = DPIUtil.autoScaleUp (drawable, arcHeight); + int deviceZoom = getDeviceZoom(); + x = DPIUtil.autoScaleUp (drawable, x, deviceZoom); + y = DPIUtil.autoScaleUp (drawable, y, deviceZoom); + width = DPIUtil.autoScaleUp (drawable, width, deviceZoom); + height = DPIUtil.autoScaleUp (drawable, height, deviceZoom); + arcWidth = DPIUtil.autoScaleUp (drawable, arcWidth, deviceZoom); + arcHeight = DPIUtil.autoScaleUp (drawable, arcHeight, deviceZoom); fillRoundRectangleInPixels(x, y, width, height, arcWidth, arcHeight); } @@ -3321,7 +3341,7 @@ public int getCharWidth(char ch) { * */ public Rectangle getClipping () { - return DPIUtil.autoScaleDown(drawable, getClippingInPixels()); + return DPIUtil.scaleDown(drawable, getClippingInPixels(), getDeviceZoom()); } Rectangle getClippingInPixels() { @@ -3579,9 +3599,10 @@ public int getInterpolation() { */ public LineAttributes getLineAttributes () { LineAttributes attributes = getLineAttributesInPixels(); - attributes.width = DPIUtil.autoScaleDown(drawable, attributes.width); + int deviceZoom = getDeviceZoom(); + attributes.width = DPIUtil.scaleDown(drawable, attributes.width, deviceZoom); if(attributes.dash != null) { - attributes.dash = DPIUtil.autoScaleDown(drawable, attributes.dash); + attributes.dash = DPIUtil.scaleDown(drawable, attributes.dash, deviceZoom); } return attributes; } @@ -3630,8 +3651,9 @@ public int[] getLineDash() { if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (data.lineDashes == null) return null; int[] lineDashes = new int[data.lineDashes.length]; + int deviceZoom = getDeviceZoom(); for (int i = 0; i < lineDashes.length; i++) { - lineDashes[i] = DPIUtil.autoScaleDown(drawable, (int)data.lineDashes[i]); + lineDashes[i] = DPIUtil.scaleDown(drawable, (int)data.lineDashes[i], deviceZoom); } return lineDashes; } @@ -3684,7 +3706,7 @@ public int getLineStyle() { * */ public int getLineWidth () { - return DPIUtil.autoScaleDown(drawable, getLineWidthInPixels()); + return DPIUtil.scaleDown(drawable, getLineWidthInPixels(), getDeviceZoom()); } int getLineWidthInPixels() { @@ -3887,6 +3909,7 @@ long identity() { void init(Drawable drawable, GCData data, long hDC) { int foreground = data.foreground; + this.data = data; if (foreground != -1) { data.state &= ~(FOREGROUND | FOREGROUND_TEXT | PEN); } else { @@ -3920,7 +3943,6 @@ void init(Drawable drawable, GCData data, long hDC) { if ((data.style & SWT.RIGHT_TO_LEFT) != 0) data.style |= SWT.MIRRORED; } this.drawable = drawable; - this.data = data; handle = hDC; } @@ -4242,10 +4264,11 @@ void setClipping(long clipRgn) { * */ public void setClipping (int x, int y, int width, int height) { - x = DPIUtil.autoScaleUp(drawable, x); - y = DPIUtil.autoScaleUp(drawable, y); - width = DPIUtil.autoScaleUp(drawable, width); - height = DPIUtil.autoScaleUp(drawable, height); + int deviceZoom = getDeviceZoom(); + x = DPIUtil.autoScaleUp(drawable, x, deviceZoom); + y = DPIUtil.autoScaleUp(drawable, y, deviceZoom); + width = DPIUtil.autoScaleUp(drawable, width, deviceZoom); + height = DPIUtil.autoScaleUp(drawable, height, deviceZoom); setClippingInPixels(x, y, width, height); } @@ -4313,7 +4336,7 @@ public void setClipping (Rectangle rect) { setClipping(0); } else { - rect = DPIUtil.autoScaleUp(drawable, rect); + rect = DPIUtil.autoScaleUp(drawable, rect, getDeviceZoom()); setClippingInPixels(rect.x, rect.y, rect.width, rect.height); } } @@ -4386,7 +4409,7 @@ public void setFillRule(int rule) { public void setFont (Font font) { if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (font != null && font.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); - data.font = font != null ? Font.win32_new(font, DPIUtil.getNativeDeviceZoom()) : data.device.systemFont; + data.font = font != null ? Font.win32_new(font, getNativeDeviceZoom()) : data.device.systemFont; data.state &= ~FONT; } @@ -4519,7 +4542,7 @@ public void setInterpolation(int interpolation) { */ public void setLineAttributes (LineAttributes attributes) { if (attributes == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); - attributes.width = DPIUtil.autoScaleUp(drawable, attributes.width); + attributes.width = DPIUtil.autoScaleUp(drawable, attributes.width, getDeviceZoom()); setLineAttributesInPixels(attributes); } @@ -4582,8 +4605,9 @@ void setLineAttributesInPixels (LineAttributes attributes) { } if (changed) { float[] newDashes = new float[dashes.length]; + int deviceZoom = getDeviceZoom(); for (int i = 0; i < newDashes.length; i++) { - newDashes[i] = DPIUtil.autoScaleUp(drawable, dashes[i]); + newDashes[i] = DPIUtil.autoScaleUp(drawable, dashes[i], deviceZoom); } dashes = newDashes; mask |= LINE_STYLE; @@ -4671,9 +4695,10 @@ public void setLineDash(int[] dashes) { if (dashes != null && dashes.length > 0) { boolean changed = data.lineStyle != SWT.LINE_CUSTOM || lineDashes == null || lineDashes.length != dashes.length; float[] newDashes = new float[dashes.length]; + int deviceZoom = getDeviceZoom(); for (int i = 0; i < dashes.length; i++) { if (dashes[i] <= 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); - newDashes[i] = DPIUtil.autoScaleUp(drawable, (float) dashes[i]); + newDashes[i] = DPIUtil.autoScaleUp(drawable, (float) dashes[i], deviceZoom); if (!changed && lineDashes[i] != newDashes[i]) changed = true; } if (!changed) return; @@ -4774,7 +4799,7 @@ public void setLineStyle(int lineStyle) { * */ public void setLineWidth(int lineWidth) { - lineWidth = DPIUtil.autoScaleUp (drawable, lineWidth); + lineWidth = DPIUtil.autoScaleUp (drawable, lineWidth, getDeviceZoom()); setLineWidthInPixels(lineWidth); } @@ -4920,7 +4945,7 @@ public void setTransform(Transform transform) { */ public Point stringExtent (String string) { if (string == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); - return DPIUtil.autoScaleDown(drawable, stringExtentInPixels(string)); + return DPIUtil.scaleDown(drawable, stringExtentInPixels(string), getDeviceZoom()); } Point stringExtentInPixels (String string) { @@ -4965,7 +4990,7 @@ Point stringExtentInPixels (String string) { * */ public Point textExtent (String string) { - return DPIUtil.autoScaleDown(drawable, textExtentInPixels(string, SWT.DRAW_DELIMITER | SWT.DRAW_TAB)); + return DPIUtil.scaleDown(drawable, textExtentInPixels(string, SWT.DRAW_DELIMITER | SWT.DRAW_TAB), getDeviceZoom()); } /** @@ -5000,7 +5025,7 @@ public Point textExtent (String string) { * */ public Point textExtent (String string, int flags) { - return DPIUtil.autoScaleDown(drawable, textExtentInPixels(string, flags)); + return DPIUtil.scaleDown(drawable, textExtentInPixels(string, flags), getDeviceZoom()); } Point textExtentInPixels(String string, int flags) { @@ -5120,4 +5145,12 @@ private static int sin(int angle, int length) { return (int)(Math.sin(angle * (Math.PI/180)) * length); } +private int getNativeDeviceZoom() { + return data.nativeDeviceZoom != 0 ? data.nativeDeviceZoom : DPIUtil.getNativeDeviceZoom(); +} + +private int getDeviceZoom() { + return DPIUtil.getZoomForAutoscaleProperty(getNativeDeviceZoom()); +} + } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GCData.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GCData.java index fa177db2c83..959f0617ed6 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GCData.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GCData.java @@ -47,6 +47,7 @@ public final class GCData { public float[] lineDashes; public float lineMiterLimit = 10; public int alpha = 0xFF; + public int nativeDeviceZoom; public Image image; public PAINTSTRUCT ps; 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 c95a3066bfd..4930c866fd5 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 @@ -2154,6 +2154,7 @@ public long internal_new_GC (GCData data) { data.style |= SWT.LEFT_TO_RIGHT; } data.device = device; + data.nativeDeviceZoom = currentNativeZoom; data.image = this; data.font = Font.win32_new(device.getSystemFont(), DPIUtil.getNativeDeviceZoom()); } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java index 1f5dfc80d0c..d59f9914fa9 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java @@ -1742,6 +1742,7 @@ public long internal_new_GC (GCData data) { } } data.device = display; + data.nativeDeviceZoom = getNativeZoom(); int foreground = getForegroundPixel (); if (foreground != OS.GetTextColor (hDC)) data.foreground = foreground; Control control = findBackgroundControl (); @@ -3657,6 +3658,11 @@ public void setRedraw (boolean redraw) { } } +@Override +void sendEvent(int eventType, Event event, boolean send) { + super.sendEvent(eventType, event, send); +} + /** * Sets the shape of the control to the region specified * by the argument. When the argument is null, the diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Label.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Label.java index 4265a2eb6a4..32029f6eaff 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Label.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Label.java @@ -563,6 +563,7 @@ void wmDrawChildImage(DRAWITEMSTRUCT struct) { } GCData data = new GCData(); + data.nativeDeviceZoom = getNativeZoom(); data.device = display; GC gc = GC.win32_new (struct.hDC, data); Image image = getEnabled () ? this.image : new Image (display, this.image, SWT.IMAGE_DISABLE); diff --git a/tests/org.eclipse.swt.tests.win32/JUnit Tests/org/eclipse/swt/graphics/GCWin32Tests.java b/tests/org.eclipse.swt.tests.win32/JUnit Tests/org/eclipse/swt/graphics/GCWin32Tests.java new file mode 100644 index 00000000000..fb8879b76fe --- /dev/null +++ b/tests/org.eclipse.swt.tests.win32/JUnit Tests/org/eclipse/swt/graphics/GCWin32Tests.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (c) 2024 Yatta Solutions + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Yatta Solutions - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.graphics; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.lang.reflect.Field; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.internal.DPIUtil; +import org.eclipse.swt.internal.SWTFontProvider; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Shell; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class GCWin32Tests { + private Display display; + + @Before + public void setUp() { + changeAutoScaleOnRuntime(true); + display = Display.getDefault(); + } + + @After + public void tearDown() { + changeAutoScaleOnRuntime(false); + } + + @Test + public void gcZoomLevelMustChangeOnShellZoomChange() { + CompletableFuture gcNativeZoom = new CompletableFuture<>(); + CompletableFuture scaledGcNativeZoom = new CompletableFuture<>(); + int zoom = DPIUtil.getDeviceZoom(); + AtomicBoolean isScaled = new AtomicBoolean(false); + Shell shell = new Shell(display); + shell.addListener(SWT.Paint, event -> { + if (isScaled.get()) { + scaledGcNativeZoom.complete(event.gc.getGCData().nativeDeviceZoom); + } else { + gcNativeZoom.complete(event.gc.getGCData().nativeDeviceZoom); + } + }); + + shell.open(); + assertEquals("GCData must have a zoom level equal to the actual zoom level of the widget/shell", DPIUtil.getNativeDeviceZoom(), (int) gcNativeZoom.join()); + + int newSWTZoom = zoom * 2; + Event swtEvent = new Event(); + swtEvent.type = SWT.ZoomChanged; + swtEvent.widget = shell; + swtEvent.detail = newSWTZoom; + shell.notifyListeners(SWT.ZoomChanged, swtEvent); + isScaled.set(true); + shell.setVisible(false); + shell.setVisible(true); + + assertEquals("GCData must have a zoom level equal to the actual zoom level of the widget/shell on zoomChanged event", newSWTZoom, (int) scaledGcNativeZoom.join()); + } + + @Test + public void drawnElementsShouldScaleUpToTheRightZoomLevel() { + int zoom = DPIUtil.getDeviceZoom(); + int scalingFactor = 2; + Shell shell = new Shell(display); + GC gc = GC.win32_new(shell, new GCData()); + gc.getGCData().nativeDeviceZoom = zoom * scalingFactor; + gc.getGCData().lineWidth = 10; + assertEquals("DPIUtil calls with getDeviceZoom should scale to the right value", gc.getGCData().lineWidth, gc.getLineWidth() * scalingFactor, 0); + } + + void changeAutoScaleOnRuntime(boolean value) { + try { + Field autoScaleOnRuntimeField = DPIUtil.class.getDeclaredField("autoScaleOnRuntime"); + autoScaleOnRuntimeField.setAccessible(true); + autoScaleOnRuntimeField.setBoolean(null, value); + autoScaleOnRuntimeField.setAccessible(false); + // dispose a probably existing font registry for the default display + SWTFontProvider.disposeFontRegistry(display); + } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { + fail("Value for DPI::autoScaleOnRuntime could not be changed"); + } + } +}