Fonts started to look better on Ubuntu 23.04

https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/6190

May be related to this change.

Em ter., 12 de dez. de 2023 11:10, Mark Raynsford <org.open...@io7m.com>
escreveu:

> Hello!
>
> I've never been particularly satisfied with the font rendering in
> JavaFX. In particular, on Linux, the text always appears very soft and
> blurry compared to non-JavaFX applications on the same system. Even
> applications that render antialiased text with Java2D seem to look
> better.
>
> I decided to take a look into it to see if anything could be done about
> this, and I have some questions. I'm only looking at the Freetype
> implementation in Prism currently, as that's all I can realistically
> test on at the moment.
>
> For reference, here's how text rendered at 16px using Terminus TTF
> looks today:
>
> https://ataxia.io7m.com/2023/12/12/hinting_nobitmaps_normal.png
>
> I'm not sure if I'm alone on this, but I find this almost migraine-
> inducing. No other application on my system, including those that use
> Freetype, using that font at that size will render as blurry as that.
>
> Looking at
> modules/javafx.graphics/src/main/java/com/sun/javafx/font/freetype/FTFo
> ntFile.java, I see this in initGlyph():
>
> ```
> int flags = OSFreetype.FT_LOAD_RENDER | OSFreetype.FT_LOAD_NO_HINTING |
> OSFreetype.FT_LOAD_NO_BITMAP;
> ```
>
> Additionally, the code might also add the FT_LOAD_TARGET_NORMAL
> or FT_LOAD_TARGET_LCD flags later, but I'll assume
> FT_LOAD_TARGET_NORMAL for the sake of avoiding combinatorial explosions
> in testing at this point.
>
> Essentially, we discard hinting information, and we discard bitmap
> information. I'm not sure why we do either of these things. I decided
> to try different combinations of flags to see what would happen.
>
> Here's FT_LOAD_RENDER | FT_LOAD_NO_BITMAP (no bitmaps, but using
> hinting data):
>
> https://ataxia.io7m.com/2023/12/12/hinting_nobitmaps_normal.png
>
> That's no real improvement. Here's FT_LOAD_RENDER | FT_LOAD_NO_HINTING
> (ignore hinting data, but use bitmaps if they are included):
>
> https://ataxia.io7m.com/2023/12/12/nohinting_bitmaps_normal.png
>
> That, to my poor suffering eyes, is already a _vast_ improvement.
>
> Let's try including both hinting and bitmaps (FT_LOAD_RENDER):
>
> https://ataxia.io7m.com/2023/12/12/hinting_bitmaps_normal.png
>
> Inspecting that in an image editor shows the pixels of the text to be
> identical.
>
> So, clearly, Terminus TTF includes bitmaps for smaller text sizes.
> Let's try another font such as Droid Sans that renders crisply at ~10pt
> sizes on my system, and that I'm reasonably confident doesn't include
> any bitmaps.
>
> Here's the JavaFX default (FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP):
>
> https://ataxia.io7m.com/2023/12/12/droid_12_nohinting_nobitmaps.png
>
> That's pretty nasty. Let's enable hinting (FT_LOAD_NO_BITMAP):
>
> https://ataxia.io7m.com/2023/12/12/droid_12_hinting_nobitmaps.png
>
> That's already a lot better. If you overlay the two images in an image
> editor, it's clear that the glyph shapes are not quite the same (with
> hinting, some glyphs are ever-so-slightly taller).
>
> For completeness, let's allow bitmaps:
>
> https://ataxia.io7m.com/2023/12/12/droid_12_hinting_bitmaps.png
>
> The rendered glyphs are pixel-identical.
>
> Now, most modern desktops have options to disable antialiasing for text
> under a given size. Antialiasing on 10pt text is rarely an improvement
> over just not having it as there are so few pixels to work with. I
> decided to experiment a bit with turning off antialiasing. This
> requires setting the load target to FT_LOAD_TARGET_MONO so that
> Freetype returns a monochrome image instead of what amounts to an alpha
> coverage map. Unfortunately, this does also change the format of the
> image returned to a 1bpp image instead of an 8bpp greyscale image, and
> JavaFX isn't equipped to handle that. However, we can do the conversion
> manually if we see that bitmap.pixel_mode == 1, and then the rest of
> JavaFX doesn't need to care about it:
>
> ```
> if (bitmap.pixel_mode == 1) {
>   byte[] newBuffer = new byte[width * height];
>   for (int y = 0; y < height; y++) {
>     final var rowOffset = y * width;
>     for (int x = 0; x < width; x++) {
>       final var byteOffset = rowOffset + x;
>       newBuffer[byteOffset] = bitAt(buffer, x, y, pitch);
>     }
>   }
>   buffer = newBuffer;
> }
>
> private static byte bitAt(byte[] buffer, int x, int y, int pitch)
> {
>   final var byteOffset = (y * pitch) + (x / 8);
>   final var bitOffset = 7 - (x % 8);
>   final var bit = (buffer[byteOffset] >>> bitOffset) & 1;
>   return (byte) (bit == 1 ? 0xff : 0x00);
> }
> ```
>
> Here's the JavaFX default of (FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)
> combined with FT_LOAD_TARGET_MONO:
>
> https://ataxia.io7m.com/2023/12/12/droid_12_nohinting_nobitmaps_mono.png
>
> That's not a typeface even a mother could love. :)
>
> However, what happens if we enable hinting?
>
> Here's (FT_LOAD_NO_BITMAP | FT_LOAD_TARGET_MONO):
>
> https://ataxia.io7m.com/2023/12/12/droid_12_hinting_nobitmaps_mono.png
>
> I mean, it's not exactly wonderful for Droid Sans 12 (the O is a little
> mangled), but that's more an issue with the font itself. It's certainly
> better than the result _without_ hinting.
>
> Amusingly, here's DejaVu Sans at 7pt, (FT_LOAD_NO_BITMAP |
> FT_LOAD_TARGET_MONO):
>
> https://ataxia.io7m.com/2023/12/12/dejavu_12_hinting_nobitmaps_mono.png
>
> That, to my eyes, looks pretty good. The JavaFX defaults for the same
> font are not good:
>
> https://ataxia.io7m.com/2023/12/12/dejavu_12_nohinting_nobitmaps_normal.png
>
> I've tried on multiple systems (all Linux, however), and I've yet to be
> able to contrive a situation where the JavaFX defaults give better
> rendering results with any combinations of font sizes, with or without
> AA. A brief inspection of the JDK's Java2D sources show that it does
> conditionally use FT_LOAD_NO_HINTING depending on various settings
> (there are comments about FT_LOAD_NO_HINTING yielding constant-sized
> glyphs, which supposedly can make things easier in some cases). The
> Java2D results on the systems I tested are consistently better.
>
> So I guess my questions are:
>
>   * Why do we discard hinting information?
>   * Why do we discard bitmaps?
>   * Would JavaFX accept patches to allow hinting, bitmaps, and
> FT_LOAD_TARGET_MONO? Ideally this should be developer-controlled, so I
> would need to come up with a pleasant API for it.
>
> My experience has been that most JavaFX applications tend to bundle
> fonts rather than relying on anything the system has. I suspect that,
> given that developers are including their own fonts, they are the best
> equipped to answer questions about hinting and AA, rather than just
> setting values and hoping that the font they get will work well, so an
> explicit API might be fine.
>
> --
> Mark Raynsford | https://www.io7m.com
>
>

Reply via email to