eclipse.platform.swt icon indicating copy to clipboard operation
eclipse.platform.swt copied to clipboard

Incorrect font height

Open PatrickTasse opened this issue 1 year ago • 5 comments

Describe the bug

The font is not the expected height in pixels, and FontMetrics.getHeight() is wrong according to Javadoc.

To Reproduce

for (int h = 1; h <= 100; h++) { Font font = new Font(getDisplay(), new FontData("Arial", h, SWT.NORMAL)); gc.setFont(font); FontData fd = font.getFontData()[0]; System.out.println("fontData.getHeight()="+fd.getHeight()+"pts gc.getFontMetrics().getHeight()="+gc.getFontMetrics().getHeight()+"pts gc.textExtent("").y="+gc.textExtent("").y+"px gc.getDevice().getDPI().y="+gc.getDevice().getDPI().y+"dpi"); font.dispose(); }

Expected behavior

I would expect that for a font height 'h' in points, the font height in pixels should be: h pts x DPI px/in / PPI pts/in where DPI is 96 according to Device.getDPI() and PPI is 72 pts/in so a ratio of 4/3, but the snippet above outputs: fontData.getHeight()=24pts gc.getFontMetrics().getHeight()=36pts gc.textExtent("").y=36px gc.getDevice().getDPI().y=96dpi fontData.getHeight()=100pts gc.getFontMetrics().getHeight()=150pts gc.textExtent("").y=150px gc.getDevice().getDPI().y=96dpi it appears that the ratio of px/pt is 3/2?

Also, FontMetrics.getHeight()'s Javadoc states: "Returns the height of the font described by the receiver, measured in points." but the returned value is obviously in pixels. I'm not sure if the value or the Javadoc is wrong?

If there is some other external scaling factor that is missing, is there a way to determine it programmatically? I would expect that it would be considered in Device.getDPI().

The use case I have is to set the font height (in points) to get an exact desired height in pixels.

Environment:

  1. Select the platform(s) on which the behavior is seen:
    • [ ] All OS
    • [ ] Windows
    • [x] Linux
    • [ ] macOS
  1. Additional OS info (e.g. OS version, Linux Desktop, etc)

Linux Ubuntu

  1. JRE/JDK version

Version since

Tested on Eclipse 4.31 SWT 3.125

PatrickTasse avatar Apr 24 '24 14:04 PatrickTasse

Could you provide a simple test case that shows the problem, ideally as an SWT test? Could you please also specify your screen resolution, OS, Desktop, X11 or Wayland, SWT and GTK3 versions?

iloveeclipse avatar Apr 24 '24 17:04 iloveeclipse

1920x1200, Linux Ubuntu, Gnome Shell, X11, SWT 3.125.0.v20240227-1638, GTK 3.24.33

image

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

public class SnippetFont {

	public static void main(String[] args) {
		Display display = new Display();
		String gtkVersion = System.getProperty("org.eclipse.swt.internal.gtk.version");
		Shell shell = new Shell(display);
		shell.setText("gtk version:" + gtkVersion + " display bounds:" + display.getBounds() + " DPI:" + display.getDPI().y);

		shell.setLayout(new FillLayout());

		shell.addPaintListener(e -> {
			GC gc = e.gc;
			gc.setForeground(display.getSystemColor(SWT.COLOR_BLACK));
			gc.setBackground(display.getSystemColor(SWT.COLOR_CYAN));
			int x = 3;
			int y = 3;
			final int PPI = 72;
			final int DPI = display.getDPI().y;
			for (int pixels = 2; pixels <= 100; pixels++) {
				int points = pixels * PPI / DPI;
				Font font = new Font(display, new FontData("Arial", points, SWT.NORMAL ) );
				gc.setFont(font);
				FontData fd = gc.getFont().getFontData()[0];
				FontMetrics fm = gc.getFontMetrics();
				String text = String.format("desired pixels:%d calculated points:%d*%d/%d=%d fontData.height:%d fontMetrics.height:%d",
						pixels, pixels, PPI, DPI, points, fd.getHeight(), fm.getHeight());
				Point textExtent = gc.textExtent(text);
				gc.drawText(text, x, y, false);
				gc.drawText("textExtent.y:" + textExtent.y, x + textExtent.x + 10, y, true);
				font.dispose();
				y += textExtent.y + 3;
			}
		});

		shell.setBounds(display.getBounds());
		shell.open();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}
		display.dispose();
	}
}

PatrickTasse avatar Apr 24 '24 18:04 PatrickTasse

If I make the points = 2/3 * pixels, I get the desired result but I can't explain the math :(

image

PatrickTasse avatar Apr 24 '24 19:04 PatrickTasse

Try changing screen's DPI to 200% in your Linux settings and see what the new "magic" constant would be.

SyntevoAlex avatar Apr 25 '24 17:04 SyntevoAlex

Try changing screen's DPI to 200% in your Linux settings and see what the new "magic" constant would be.

I'm not sure if this is what you mean, but I set Scale to 200% and programmatically the numbers are the same except that the actual display is zoomed 2x.

image

PatrickTasse avatar May 02 '24 15:05 PatrickTasse