eclipse.platform.swt
eclipse.platform.swt copied to clipboard
Incorrect font height
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:
- Select the platform(s) on which the behavior is seen:
-
- [ ] All OS
-
- [ ] Windows
-
- [x] Linux
-
- [ ] macOS
- Additional OS info (e.g. OS version, Linux Desktop, etc)
Linux Ubuntu
- JRE/JDK version
Version since
Tested on Eclipse 4.31 SWT 3.125
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?
1920x1200, Linux Ubuntu, Gnome Shell, X11, SWT 3.125.0.v20240227-1638, GTK 3.24.33
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();
}
}
If I make the points = 2/3 * pixels, I get the desired result but I can't explain the math :(
Try changing screen's DPI to 200% in your Linux settings and see what the new "magic" constant would be.
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.