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 3c2b278529d..3cbff0ea90a 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 @@ -198,9 +198,9 @@ void checkGC(int mask) { Pattern pattern = data.foregroundPattern; if (pattern != null) { if(data.alpha == 0xFF) { - brush = pattern.handle; + brush = pattern.getHandle(getZoom()); } else { - brush = data.gdipFgPatternBrushAlpha != 0 ? Gdip.Brush_Clone(data.gdipFgPatternBrushAlpha) : createAlphaTextureBrush(pattern.handle, data.alpha); + brush = data.gdipFgPatternBrushAlpha != 0 ? Gdip.Brush_Clone(data.gdipFgPatternBrushAlpha) : createAlphaTextureBrush(pattern.getHandle(getZoom()), data.alpha); data.gdipFgPatternBrushAlpha = brush; } if ((data.style & SWT.MIRRORED) != 0) { @@ -289,9 +289,9 @@ void checkGC(int mask) { Pattern pattern = data.backgroundPattern; if (pattern != null) { if(data.alpha == 0xFF) { - data.gdipBrush = pattern.handle; + data.gdipBrush = pattern.getHandle(getZoom()); } else { - long brush = data.gdipBgPatternBrushAlpha != 0 ? Gdip.Brush_Clone(data.gdipBgPatternBrushAlpha) : createAlphaTextureBrush(pattern.handle, data.alpha); + long brush = data.gdipBgPatternBrushAlpha != 0 ? Gdip.Brush_Clone(data.gdipBgPatternBrushAlpha) : createAlphaTextureBrush(pattern.getHandle(getZoom()), data.alpha); data.gdipBrush = data.gdipBgBrush /*= data.gdipBgPatternBrushAlpha */ = brush; } if ((data.style & SWT.MIRRORED) != 0) { @@ -3440,7 +3440,7 @@ public void getClipping (Region region) { } long getFgBrush() { - return data.foregroundPattern != null ? data.foregroundPattern.handle : data.gdipFgBrush; + return data.foregroundPattern != null ? data.foregroundPattern.getHandle(getZoom()) : data.gdipFgBrush; } /** diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Pattern.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Pattern.java index 38a9eb8629a..e4ed934cbf6 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Pattern.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Pattern.java @@ -13,6 +13,8 @@ *******************************************************************************/ package org.eclipse.swt.graphics; +import java.util.*; + import org.eclipse.swt.*; import org.eclipse.swt.internal.*; import org.eclipse.swt.internal.gdip.*; @@ -39,22 +41,19 @@ */ public class Pattern extends Resource { - /** - * the OS resource for the Pattern - * (Warning: This field is platform dependent) - *

- * IMPORTANT: This field is not part of the SWT - * public API. It is marked public only so that it can be shared - * within the packages provided by SWT. It is not available on all - * platforms and should never be accessed from application code. - *

- * - * @noreference This field is not intended to be referenced by clients. - */ - public long handle; + private int initialZoom; private Runnable bitmapDestructor; + private Image image; + + private float x1, y1, x2, y2; + private Color color1, color2; + private int alpha1, alpha2; + private final boolean isImagePattern; + + private HashMap handleMap = new HashMap<>(); + /** * Constructs a new Pattern given an image. Drawing with the resulting * pattern will cause the image to be tiled over the resulting area. @@ -85,14 +84,23 @@ public class Pattern extends Resource { */ public Pattern(Device device, Image image) { super(device); + isImagePattern = true; if (image == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); if (image.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); this.device.checkGDIP(); - long[] gdipImage = image.createGdipImage(); + this.image = image; + initialZoom = DPIUtil.getDeviceZoom(); + setImageHandle(image, initialZoom); + init(); +} + +void setImageHandle(Image image, int zoomLevel) { + long[] gdipImage = image.createGdipImage(zoomLevel); long img = gdipImage[0]; int width = Gdip.Image_GetWidth(img); int height = Gdip.Image_GetHeight(img); - handle = Gdip.TextureBrush_new(img, Gdip.WrapModeTile, 0, 0, width, height); + long handle = Gdip.TextureBrush_new(img, Gdip.WrapModeTile, 0, 0, width, height); + handleMap.put(zoomLevel, handle); bitmapDestructor = () -> { Gdip.Bitmap_delete(img); if (gdipImage[1] != 0) { @@ -104,7 +112,6 @@ public Pattern(Device device, Image image) { bitmapDestructor.run(); SWT.error(SWT.ERROR_NO_HANDLES); } - init(); } /** @@ -187,10 +194,37 @@ public Pattern(Device device, float x1, float y1, float x2, float y2, Color colo */ public Pattern(Device device, float x1, float y1, float x2, float y2, Color color1, int alpha1, Color color2, int alpha2) { super(device); - x1 = DPIUtil.autoScaleUp(x1); - y1 = DPIUtil.autoScaleUp(y1); - x2 = DPIUtil.autoScaleUp(x2); - y2 = DPIUtil.autoScaleUp(y2); + this.x1 = x1; + this.x2 = x2; + this.y1 = y1; + this.y2 = y2; + this.color1 = color1; + this.color2 = color2; + this.alpha1 = alpha1; + this.alpha2 = alpha2; + this.isImagePattern = false; + initialZoom = DPIUtil.getDeviceZoom(); + initializeSize(initialZoom); +} + +long getHandle(int zoomLevel) { + if(!this.handleMap.containsKey(zoomLevel)) { + if (this.isImagePattern) { + setImageHandle(image, zoomLevel); + } else { + initializeSize(zoomLevel); + } + } + return this.handleMap.get(zoomLevel); +} + +private void initializeSize(int zoomLevel) { + float x1, y1, x2, y2; + long handle; + x1 = DPIUtil.autoScaleUp(this.x1, zoomLevel); + y1 = DPIUtil.autoScaleUp(this.y1, zoomLevel); + x2 = DPIUtil.autoScaleUp(this.x2, zoomLevel); + y2 = DPIUtil.autoScaleUp(this.y2, zoomLevel); if (color1 == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); if (color1.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); if (color2 == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); @@ -221,27 +255,32 @@ public Pattern(Device device, float x1, float y1, float x2, float y2, Color colo Gdip.LinearGradientBrush_SetInterpolationColors(handle, new int [] {foreColor, midColor, backColor}, new float[]{0, 0.5f, 1}, 3); } } + this.handleMap.put(zoomLevel, handle); init(); } + + @Override void destroy() { - int type = Gdip.Brush_GetType(handle); - switch (type) { - case Gdip.BrushTypeSolidColor: - Gdip.SolidBrush_delete(handle); - break; - case Gdip.BrushTypeHatchFill: - Gdip.HatchBrush_delete(handle); - break; - case Gdip.BrushTypeLinearGradient: - Gdip.LinearGradientBrush_delete(handle); - break; - case Gdip.BrushTypeTextureFill: - Gdip.TextureBrush_delete(handle); - break; + for (long handle: handleMap.values()) { + int type = Gdip.Brush_GetType(handle); + switch (type) { + case Gdip.BrushTypeSolidColor: + Gdip.SolidBrush_delete(handle); + break; + case Gdip.BrushTypeHatchFill: + Gdip.HatchBrush_delete(handle); + break; + case Gdip.BrushTypeLinearGradient: + Gdip.LinearGradientBrush_delete(handle); + break; + case Gdip.BrushTypeTextureFill: + Gdip.TextureBrush_delete(handle); + break; + } } - handle = 0; + handleMap.clear(); if (bitmapDestructor != null) { bitmapDestructor.run(); bitmapDestructor = null; @@ -260,7 +299,7 @@ void destroy() { */ @Override public boolean isDisposed() { - return handle == 0; + return handleMap.isEmpty(); } /** @@ -272,7 +311,7 @@ public boolean isDisposed() { @Override public String toString() { if (isDisposed()) return "Pattern {*DISPOSED*}"; - return "Pattern {" + handle + "}"; + return "Pattern {" + handleMap + "}"; } -} +} \ No newline at end of file diff --git a/tests/org.eclipse.swt.tests.win32/ManualTests/org/eclipse/swt/widgets/PatternWin32ManualTest.java b/tests/org.eclipse.swt.tests.win32/ManualTests/org/eclipse/swt/widgets/PatternWin32ManualTest.java new file mode 100644 index 00000000000..9c2de14ae70 --- /dev/null +++ b/tests/org.eclipse.swt.tests.win32/ManualTests/org/eclipse/swt/widgets/PatternWin32ManualTest.java @@ -0,0 +1,51 @@ +package org.eclipse.swt.widgets; + +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Pattern; +import org.eclipse.swt.internal.DPIUtil; + +public class PatternWin32ManualTest { + private static Display display = Display.getDefault(); + + public static void main (String [] args) { + int zoom = DPIUtil.getDeviceZoom(); + int scaledZoom = zoom * 3; + int width = 400; + int height = 300; + final Pattern pat = new Pattern(display, 0, 0, width, height, new Color(null, 200, 200, 200), 0, new Color(null, 255, 0, 0), 255); + + Shell shell = new Shell(display); + shell.setText("Unscaled shell"); + shell.setSize(width, height); + shell.addPaintListener(e -> { + e.gc.setBackground(new Color(null, 100, 200, 0)); + e.gc.fillRectangle(0, 0, shell.getBounds().width, shell.getBounds().height); + e.gc.setBackground(new Color(null, 255, 0, 0)); + e.gc.setBackgroundPattern(pat); + e.gc.fillRectangle(0, 0, shell.getBounds().width, shell.getBounds().height); + }); + shell.open(); + + DPIUtil.setDeviceZoom(scaledZoom); + Shell shell2 = new Shell(display); + shell2.nativeZoom = scaledZoom; + shell2.setText("Scaled shell"); + shell2.setSize(width, height); + shell2.addPaintListener(e -> { + e.gc.setBackground(new Color(null, 100, 200, 0)); + e.gc.fillRectangle(0, 0, shell2.getBounds().width, shell2.getBounds().height); + e.gc.setBackground(new Color(null, 255, 0, 0)); + e.gc.setBackgroundPattern(pat); + e.gc.fillRectangle(0, 0, shell2.getBounds().width, shell2.getBounds().height); + }); + shell2.open(); + + while (!shell.isDisposed() || !shell2.isDisposed()) { + if (!display.readAndDispatch()) + display.sleep(); + } + pat.dispose(); + shell.dispose(); + shell2.dispose(); + } +}