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