slint icon indicating copy to clipboard operation
slint copied to clipboard

Subpixel font rendering

Open Enyium opened this issue 1 year ago • 5 comments
trafficstars

No renderer I tried (at least software, FemtoVG and Skia) rendered text on Windows 10 with ClearType, that is, utilizing the R, G, B hardware subpixels of the monitor. I have it turned on in my system (confirmed by screenshots with orange and blue sides on letters) and @tronical called the way Skia renders text the one and true way of doing it in another issue. ChatGPT with GPT-4o claimed that Skia is able to render using ClearType, but the text rendered with it in my Slint window only uses shades of gray.

Enyium avatar Aug 02 '24 10:08 Enyium

same as me, i think anti-aliasing is broken with FemtoVG and winit-skia backend, for both win and linux. But winit-software and qt backend have normal smoothing, you can try

$env:SLINT_BACKEND='winit-software'; cargo run --release

tkkcc avatar Aug 03 '24 19:08 tkkcc

I think that's a valid bug report. If I understand correctly, we're not setting the lcd config on the skia surface, and we should probably also set SK_FONT_HOST_USE_SYSTEM_SETTINGS when compiling skia to read the correct gramma correction values from the system.

tronical avatar Aug 06 '24 13:08 tronical

You added issue labels specifying this as a Windows bug. But I have no idea whether it works on the other OSs. macOS has subpixel font antialiasing; and with Linux, there are apparently also ways to render text like this.

Enyium avatar Aug 06 '24 13:08 Enyium

It's true that while macOS does support sub pixel anti-aliasing, it's not enabled by default. That said, AFAICS Skia uses glyphs rendered by CoreText that are LCD optimised.

On Linux, I don't see Skia supporting LCD filtering, i.e. I don't see it forwarding any filter setting to FreeType.

Setting the LCD config on the skia surface is a cross-platform matter, but we need to find a way to get the correct setting there. Unless... there isn't a way and we should just set it to kRGB_H_SkPixelGeometry?

tronical avatar Aug 09 '24 07:08 tronical

If, after using Skia in a way that activates ClearType, ClearType in Slint windows can't be deactivated anymore by changing the system setting, Slint should read the system setting SPI_GETFONTSMOOTHINGTYPE (there's also the ClearType-related SPI_GETFONTSMOOTHINGORIENTATION and SPI_GETFONTSMOOTHINGCONTRAST), and possibly also SPI_GETFONTSMOOTHING. It would need to be tested how Slint behaves after the change.

Enyium avatar Aug 22 '24 13:08 Enyium

Bump. Fonts look ugly for me on macOS.

bu5hm4nn avatar Sep 24 '24 17:09 bu5hm4nn

I'm also running into this issue on linux, where qt and winit-software look good but winit does not:

Image Image

As a disclaimer though, I'm on NixOS and might not have everything set up correctly.

As a complete guess, it looks like what could be happening is that the font glyphs are being rendered to a cache okay, but then shifted a half-pixel over and being drawn wrong as a result.

expenses avatar Sep 01 '25 13:09 expenses

Okay, I've narrowed this down to a femtovg issue https://github.com/femtovg/femtovg/issues/233.

expenses avatar Sep 01 '25 15:09 expenses

Things improve significantly if I just pass a scale of DPI 1 to femtovg. So something in that library is going wrong:

diff --git a/internal/renderers/femtovg/lib.rs b/internal/renderers/femtovg/lib.rs
index fc57c05e0..e157cfa1d 100644
--- a/internal/renderers/femtovg/lib.rs
+++ b/internal/renderers/femtovg/lib.rs
@@ -154,7 +154,7 @@ fn internal_render_with_post_callback(
                     // We pass an integer that is greater than or equal to the scale factor as
                     // dpi / device pixel ratio as the anti-alias of femtovg needs that to draw text clearly.
                     // We need to care about that `ceil()` when calculating metrics.
-                    femtovg_canvas.set_size(surface_size.width, surface_size.height, scale);
+                    femtovg_canvas.set_size(surface_size.width, surface_size.height, 1.0);
 
                     // Clear with window background if it is a solid color otherwise it will drawn as gradient
                     if let Some(Brush::SolidColor(clear_color)) = window_background_brush {
Image

In terms of subpixel font rendering specifically, it's something that can be looked into. But keep in mind that a significant issue is that different monitors use different subpixel arrangements, and there's no way to query that easily. So a type of subpixel rendering that great on one monitor might look worse than no subpixel rendering on another. https://osor.io/text goes into this.

expenses avatar Sep 02 '25 09:09 expenses