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

[Win32] Drawing produces unsymmetric results without swt.autoScale=false for 4k monitor with zooming #1596

Open
tmssngr opened this issue Nov 15, 2024 · 11 comments

Comments

@tmssngr
Copy link
Contributor

tmssngr commented Nov 15, 2024

Describe the bug
Code that draws a circle and and a line symmetric with 100% zoom causes asymmetric results with 175% zoom factor.

To Reproduce
Run following snippet

import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;

public class HiDpiDrawing {
	public static void main(String[] args) {
//		System.getProperties().putIfAbsent("swt.autoScale", "false");
		final Display display = new Display();

		final Shell shell = new Shell(display);
		shell.addListener(SWT.Paint, event -> {
			final GC gc = event.gc;
			gc.setAntialias(SWT.ON);
			gc.setLineWidth(3);
			final Path path = new Path(display);
			int radius = 3;
			path.moveTo(15, 0);
			path.lineTo(15, 15 - radius);
			path.moveTo(15, 15 + radius);
			path.lineTo(15, 100);
			gc.drawPath(path);
			path.dispose();
			gc.setBackground(gc.getForeground());
			drawOval(gc, radius + 2);
			gc.setBackground(new Color(255, 255, 255));
			drawOval(gc, radius);
		});

		shell.setSize(400, 300);
		shell.open();

		while (!shell.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}

		shell.dispose();
	}

	private static void drawOval(GC gc, int radius) {
		gc.fillOval(15 - radius, 15 - radius, 2 * radius + 1, 2 * radius + 1);
	}
}

on Windows with 100% zoom level and with 175% zoom level.

Expected behavior
The dot is always drawn symmetric to the line, no matter what zoom level (otherwise it would look ugly).

Screenshots
With 100% zoom level:
100
close-up:
100%-zoomed
With 175% zoom level:
175
close-up:
175%-zoomed

When removing the // from the comment line, the result looks fine for 175% zoom, too.

Environment:

  1. Select the platform(s) on which the behavior is seen:
    • All OS
    • Windows
    • Linux
    • macOS
  1. Additional OS info (e.g. OS version, Linux Desktop, etc)
    Tried on Windows 11 with 4k monitor.
@tmssngr
Copy link
Contributor Author

tmssngr commented Nov 15, 2024

With swt.autoScale=quarter or exact it looks even worse:
175%-swt autoScale=quarter
close-up:
175%-swt autoScale=quarter-zoomed
Hence it looks like there is no way to draw symmetric elements without setting swt.autoScale=false.

@HeikoKlare
Copy link
Contributor

The oval at 100% is also asymmetric (can be seen in different colors from anti-aliasing), it only becomes more visible at 175% because the calculation is more off. With swt.autoScale=false you just hide that as rendering just still happens at 100%, where the asymmetry is only harder to see.

@tmssngr
Copy link
Contributor Author

tmssngr commented Nov 15, 2024

Asking users, I reckon 99% would answer the 100% version looks symmetric.

How do we need to draw these elements that they look fine between 100% and 200% zoom level for 99% of the users?

@HeikoKlare
Copy link
Contributor

Asking users, I reckon 99% would answer the 100% version looks symmetric.

Might be, but what does that change? Using the 175% version and placing users at 175% the distance of the monitor than when using the 100% version, they will probably also consider it symmetric...
It's asymmetric, so there seems to be a bug in rendering, which is more visible when using higher scale values. There is nothing better in using swt.autoScale=false than using any other scale value with respect to symmetry. Things are simply just too small to see it when using no scaling for HiDPI monitors.

How do we need to draw these elements that they look fine between 100% and 200% zoom level for 99% of the users?

My first impression is that this is a bug in SWT. So there may be no other way than looking into SWT code, finding the cause of the bug, and fixing it.

@tmssngr
Copy link
Contributor Author

tmssngr commented Nov 15, 2024

With swt.autoScale=false I have the possibility to optimize it for larger zoom levels, because I have control over all pixels, not just control over double-pixels:
175%-swt autoScale=false
Close-up:
175%-swt autoScale=false-zoomed

IMHO one problem is that pixel coordinates simply are scaled. But there are draw operations like fillXxx that expect the right/lower coordinate outside the drawn area. The other problem is that for most draw operations only int coordinates are allowed, so it scales only to multiples of 2.

I wonder how other drawing APIs handle such fractional scaling.

@laeubi
Copy link
Contributor

laeubi commented Nov 16, 2024

If I look at your snippet I'm not sure you are taking the line width into account correctly, you set a line width of three but I can't find you possibly account for this.

Beside that, yes only having int coordinates (except for example Path) is a big limitation compared to e.g. AWTs Graphics2D, e.g AWT uses the concept of Shapes what is really convenient and powerful.

@tmssngr
Copy link
Contributor Author

tmssngr commented Nov 18, 2024

@laeubi In SmartGit we are using the zoom factor (1 or 2) to draw the lines with the correct width. The result looks correct with all zoom levels.

@tmssngr
Copy link
Contributor Author

tmssngr commented Nov 19, 2024

Assuming following code:

gc.setLineWidth(1);
gc.drawLine(0, 1, 10, 1);

what exactly we can expect to happen for 100% zoom level and especially for 200% zoom level? How wide the line should be with 200% zoom (I'd expect 2 pixels), where exactly it should be drawn, should the line be fully visible if drawn at the coordinate 0?

Assuming the following code:

gc.fillRect(1, 1, 10, 5);

how wide the rect (in pixels) should be with 200% zoom? Which pixels should be covered?

Should we expect to get the same rendering result on all 3 platforms?

tmssngr pushed a commit to syntevo/eclipse.platform.swt that referenced this issue Nov 21, 2024
When drawing a vertical line at x == 1 with 200% zoom level (HiDPI),
MacOS draws it on the physical pixel coordinates 2 and 3 while on
Windows (with the existing code) it was drawn at 1 and 2.

In other words: the existing code drew lines 1 pixel too far left/top.
This commit should resolve this.
tmssngr pushed a commit to syntevo/eclipse.platform.swt that referenced this issue Nov 21, 2024
…ithout swt.autoScale=false for 4k monitor with zooming

When drawing a vertical line at x == 1 with 200% zoom level (HiDPI),
MacOS draws it on the physical pixel coordinates 2 and 3 while on
Windows (with the existing code) it was drawn at 1 and 2.

In other words: the existing code drew lines 1 pixel too far left/top.
This commit should resolve this.
@tmssngr
Copy link
Contributor Author

tmssngr commented Nov 21, 2024

Please give the pull request a try.

@BeckerWdf
Copy link
Contributor

Please give the pull request a try.

You mean this one: #1607 ?

@tmssngr
Copy link
Contributor Author

tmssngr commented Nov 22, 2024

Yes, this the PR #1607. I know that it can't be merged right now because of feature-freeze, but I want you to give it a try.

tmssngr pushed a commit to syntevo/eclipse.platform.swt that referenced this issue Nov 26, 2024
…ithout swt.autoScale=false for 4k monitor with zooming

When drawing a vertical line at x == 1 with 200% zoom level (HiDPI),
MacOS draws it on the physical pixel coordinates 2 and 3 while on
Windows (with the existing code) it was drawn at 1 and 2.

In other words: the existing code drew lines 1 pixel too far left/top.
This commit should resolve this.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants