The crisp fonts saga

Philip Race philip.race at oracle.com
Fri Dec 15 21:40:22 UTC 2023


I already gave a brief explanation of why FX text rendering is what it is.
I will expand on it a bit but a number of the salient points have 
already been made by others.
It is unlikely we will make anything other than carefully considered 
tweaks, so this is by way of explanation.

I'm not going to try to reply directly every single point made in this 
already very long thread,
I'm just going to tell it as I see it.

My experience is that above anything else in UIs, text rendering is a 
topic that generates a lot
of heat / discussion / etc and some times opinion are colored by experience.

There's the old quote
"You can please some of the people some of the time, all of the people 
some of the time,
some of the people all of the time, but you can never please all of the 
people all of the time."

As applied to font rendering it is more like
"You can please some of the people some of the time" and the quote stops 
right there ! At best !

Some people absolutely insist that being true to the design is what is 
most important
A high contrast is the most important to someone else.
No jaggies is important to another person.
Hinting is essential to some people in some cases. To other people it is 
anathema.
etc, etc.

Every one of these decisions and the consequences is sure to fall foul 
of someone's views,
If you want to reply to a specific point / decision / choice disagreeing 
with it, I'll not be surprised because
opinions differ. Even if you can actually get several people to agree in 
principle on what
they want, someone else will disagree, BUT you'll also run into the 
feasibility of it and consequences.

Overall, FX hasn't tried to look like the platform and to some extent 
that carries over into the text.
Meaning whereas Swing would provide a platform L&F and go to great 
lengths to use the SAME
font in the SAME way, FX has no contract to do that.
And on top of that it isn't just arbitrary application of the tastes of 
one FX UX architect back in the day.
There are technical issues behind it.

Having said that FX is not trying to emulate the platform, it is 
actually using platform APIs to do all the rendering.
But what is "the" platform API ? On Windows, many people prefer GDI 
rendering, whereas FX
uses the more modern DirectWrite API. And some people are very unhappy 
with DW in general
"https://superuser.com/questions/1484267/permanently-delete-directwrite-from-microsoft-windows"
You can find plenty more examples like this.

And of course Windows itself at the end user configuration level, as 
well as for applications
directly using APIs like DW and freetype often provide some set of knobs 
that affect some aspect of the rendering.
So there is no single true "the platform rendering".

A bit more history.
The first version of FX didn't have its own graphics pipeline, it was a 
wrapper around Java 2D & AWT.
T2K was used by Sun / Oracle JDK since JDK 1.2.
It was written by one of the original TrueType developers at Apple
The hinting support in it came directly from Apple.
So it was in fact quite good at what it did. But it was a snapshot, so 
over time it became old
and we had to maintain it and update it ourselves, fixing bugs, adding 
new features.
So JavaFX used T2K implicitly.

Actually one of the 'knocks' on T2K for FX was that there was some truly 
appalling
rendering of a family of fonts called "Amble" which Sun had commercially 
licensed to
be included with FX applications and provide FX apps with a consistent 
look across platforms.
It turned out that the problem was because those fonts were evaluated on 
the Apple platform
looking at how macOS rendered them. macOS even then ignored hints. And 
it turned out that
these fonts were hinted, and specified in the 'gasp' table to apply 
those hints but the hints were terrible.
The solution was to turn off hinting when using those fonts and then it 
was fine, but by then
there was already a perception of T2K as "poor", when really it was the 
fonts and the mistake
was to have licensed them.

Other commercial font rasteriser products were considered to be included 
instead in FX's own native Prism pipeline.
But using T2K was also considered for FX because licensing an additional 
font technology is extremely expensive.
But the direction of going open source ultimately forced the decision to 
use platform APIs, but
that doesn't make it a bad decision, although it meant you now could 
never have a consistent cross-platform
look that you controlled and had to manage at least 3 implementations.
Open-sourcing also meant the Amble fonts were dropped because they could 
not be open-sourced.
[BTW a similar thing happened when JDK was open sourced : T2K was 
dropped and so were the Lucida fonts]

But what comes out of all of this history is that un-hinted, macOS-like 
rendering is what was
wanted for FX for aesthetic  (yes, such a thing is subjective, I'm just 
telling the story) reasons
Even when hi-dpi displays were rare.

But there were technical reasons too.
Java 2D/Swing uses hinting. As well as using GDI rendering not DW. But 
there's a price to pay.
Swing UIs do not scale linearly. Text measurement needs to be given the 
true final scale used during
rendering to the device to be able to layout a UI. This is painful to do 
and get right.
Also even if you do that it means that if you have something like a text 
area and you go to print
the formatted content, you do NOT get WYSIWYG. It needs to be re-flowed 
for printer resolution.

And hi-dpi displays, or even moderately scales like windows 1.25 scale 
affect the layout of apps.
And app developers all too often get this wrong.
And if you drag a window from one screen to another with different 
scales, Swing needs to do
re-layout due to this. This is a part of the reason retro-fitting Swing 
to support hidpi on windows
is still suffering from a bug tail.

This is all down to using hinting.

And "bitmaps" in a font are extremely rare. I think one Windows font 
that isn't a CJK font (Garamond)
has them, and ultimately they are just a pre-composed hinted image, 
available only at select sizes.
So being able to point to one font and the results of using bitmaps 
there isn't anything approaching a useful solution.

And animations using text - not common in Swing, but central to FX - are 
very jerky if you use hinting.
Tricks like taking an image for the whole string and transforming that 
work OK if the animation is
going at a speed no one can see. But if you stop it at some point, or 
slow it, it is obvious, and if
you at the stopped point re-draw as hinted text, there can be an obvious 
brief discontinuity.

And then on top of that hinting is not even designed to be used in such 
rotated cases.
It is adjusting the outline on the assumption that it causes a pixel to 
be touched on the unrotated grid.
If it is rotated - or sheared, the hints are not easily applied.
And to make matters worse, hinting is about aligning to the pixel grid 
and there are even
pre-composed integer advances to be used for the hinted glyphs. These 
can map very poorly
to a non-integral position when rotating, so independently of animation 
the advances between
glyphs can look extremely uneven and also cause a non-straight baseline.

And as the Amble case points out, you are dependent on the quality of 
the hinting which is
very expensive. Poor hinting is worse than none. Microsoft ship well 
hinted fonts but they
have deep pockets. On Linux, at least historically, hinting was patchy 
at best in the various free fonts.

LCD text also doesn't work well with rotations because the 3X resolution 
you get is only in one orientation.
And you absolutely CANNOT use the image scaling trick in this case, else 
the people already
complaining about color fringing will go bananas.

So far as I can tell Apple got rid of LCD in part because it made no 
sense on iOS where people rotate
devices and they have hidpi screens, but I agree with anyone who thinks 
it was a bit premature to remove
it from the macOS desktop where they don't always control the display 
device, but that's Apple.
Perhaps their solution is "please buy one of our expensive retina displays".

So the "Text" node defaults to greyscale, whereas UI controls, which are 
much less likely to be transformed
in such a way, default to LCD (or at least should, I wasn't sure if some 
of those Linux images Thiago posted
were grey or LCD). LCD whilst not popular in some circles, is what 
Windows UIs use and offers better
contrast than the greyscale. Not everyone notices or is bothered by 
fringing. This is one of those compromises.

So ultimately getting rid of all such workarounds, meaning mainly 
hinting and LCD sub-pixel text which
address limitations of the raster grid brings with it benefits such as 
consistent layout, simpler
APIs, more true rendering of the font. The major downside is 
lower-contrast text that doesn't
look so good on lower-dpi devices because fewer pixels are solid black 
(or whatever the text color is).

Possibly (only possibly) FT_LOAD_TARGET_LIGHT is something that could be 
used at least in conjunction
with LCD text on Linux if it really has no impact on string length. Or 
anything else that matters.
Quite possibly it wasn't even doing the same thing back when the current 
freetype settings were coded up.
And we produce a single binary that has to run on Linux versions from 
ancient to cutting edge.

I have no idea if current versions of DW offer something similar.

Oh, one other problem is that IIRC, Modena either uses "not quite black" 
as the text color or it
is on top of a "not quite white" background, or something like that. So 
that doesn't help in getting
better contrast or reducing fringing.

-phil.






More information about the openjfx-dev mailing list