Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of Pattern to enable multi zoom level support for win32 #1265

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.*;
Expand All @@ -39,22 +41,18 @@
*/
public class Pattern extends Resource {

/**
* the OS resource for the Pattern
* (Warning: This field is platform dependent)
* <p>
* <b>IMPORTANT:</b> This field is <em>not</em> 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.
* </p>
*
* @noreference This field is not intended to be referenced by clients.
*/
public long handle;
private int initialZoom;

private Runnable bitmapDestructor;

// These are the possible fields with which a pattern can be initialized from the appropriate constructors.
private final Image image;
private float baseX1, baseY1, baseX2, baseY2;
private Color color1, color2;
private int alpha1, alpha2;

private final Map<Integer, Long> zoomLevelToHandle = 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.
Expand Down Expand Up @@ -88,22 +86,9 @@ public Pattern(Device device, Image image) {
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();
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);
bitmapDestructor = () -> {
Gdip.Bitmap_delete(img);
if (gdipImage[1] != 0) {
long hHeap = OS.GetProcessHeap ();
OS.HeapFree(hHeap, 0, gdipImage[1]);
}
};
if (handle == 0) {
bitmapDestructor.run();
SWT.error(SWT.ERROR_NO_HANDLES);
}
this.image = image;
initialZoom = DPIUtil.getDeviceZoom();
setImageHandle(image, initialZoom);
init();
}

Expand Down Expand Up @@ -187,10 +172,36 @@ 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.baseX1 = x1;
this.baseX2 = x2;
this.baseY1 = y1;
this.baseY2 = y2;
this.color1 = color1;
this.color2 = color2;
this.alpha1 = alpha1;
this.alpha2 = alpha2;
this.image = null;
initialZoom = DPIUtil.getDeviceZoom();
initializeSize(initialZoom);
}

long getHandle(int zoom) {
if (!this.zoomLevelToHandle.containsKey(zoom)) {
if (isImagePattern()) {
setImageHandle(image, zoom);
} else {
initializeSize(zoom);
}
}
return this.zoomLevelToHandle.get(zoom);
}

private void initializeSize(int zoom) {
long handle;
float x1 = DPIUtil.autoScaleUp(this.baseX1, zoom);
float y1 = DPIUtil.autoScaleUp(this.baseY1, zoom);
float x2 = DPIUtil.autoScaleUp(this.baseX2, zoom);
float y2 = DPIUtil.autoScaleUp(this.baseY2, zoom);
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);
Expand Down Expand Up @@ -221,27 +232,51 @@ 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.zoomLevelToHandle.put(zoom, handle);
init();
}

void setImageHandle(Image image, int zoom) {
long[] gdipImage = image.createGdipImage(zoom);
long img = gdipImage[0];
int width = Gdip.Image_GetWidth(img);
int height = Gdip.Image_GetHeight(img);
long handle = Gdip.TextureBrush_new(img, Gdip.WrapModeTile, 0, 0, width, height);
bitmapDestructor = () -> {
Gdip.Bitmap_delete(img);
if (gdipImage[1] != 0) {
long hHeap = OS.GetProcessHeap ();
OS.HeapFree(hHeap, 0, gdipImage[1]);
}
};
if (handle == 0) {
bitmapDestructor.run();
SWT.error(SWT.ERROR_NO_HANDLES);
} else {
zoomLevelToHandle.put(zoom, handle);
}
}

@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: zoomLevelToHandle.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;
zoomLevelToHandle.clear();
if (bitmapDestructor != null) {
bitmapDestructor.run();
bitmapDestructor = null;
Expand All @@ -260,7 +295,7 @@ void destroy() {
*/
@Override
public boolean isDisposed() {
return handle == 0;
return zoomLevelToHandle.isEmpty();
}

/**
Expand All @@ -272,7 +307,11 @@ public boolean isDisposed() {
@Override
public String toString() {
if (isDisposed()) return "Pattern {*DISPOSED*}";
return "Pattern {" + handle + "}";
return "Pattern {" + zoomLevelToHandle + "}";
}

private boolean isImagePattern() {
return image != null;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*******************************************************************************
* 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.widgets;
fedejeanne marked this conversation as resolved.
Show resolved Hide resolved

import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Pattern;
import org.eclipse.swt.internal.DPIUtil;

/*
* This Snippet tests a pattern at multiple zoom levels.
*
* It is difficult to test the pattern at multiple zoom level automatically since we also need
* to test the visual behavior. It is important to make sure that the pattern looks the same
* regardless of its size as per the zoom level. On the execution, 2 shells are
* opened at 2 different zoom levels. The pattern is a gradient of 2 colors. On both the
* shells, the pattern should be uniformly drawn and the size difference of both the patterns
* should be clearly visible without any visual difference except for the size. The size
* difference should be equal to the scalingFactor in the snippet.
*
*/
public class PatternWin32ManualTest {
fedejeanne marked this conversation as resolved.
Show resolved Hide resolved
private static Display display = Display.getDefault();

public static void main (String [] args) {
fedejeanne marked this conversation as resolved.
Show resolved Hide resolved
int zoom = DPIUtil.getDeviceZoom();
int scalingFactor = 3;
int scaledZoom = zoom * scalingFactor;
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 shell1 = createShellWithPattern(width, height, pat, zoom);
Shell shell2 = createShellWithPattern(width, height, pat, scaledZoom);

while (!shell1.isDisposed() || !shell2.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
pat.dispose();
shell1.dispose();
shell2.dispose();
}

private static Shell createShellWithPattern(int width, int height, final Pattern pat, int nativeZoom) {
Shell shell = new Shell(display);
shell.nativeZoom = nativeZoom;
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();
return shell;
}
}
Loading