Eskil Abrahamsen Blomfeldt

Hint, hint, nudge, nudge, say no more!

Published Monday March 14th, 2011
16 Comments on Hint, hint, nudge, nudge, say no more!
Posted in C++, KOffice, macOS, Painting, Qt, Windows

At the time of writing, the task with the most votes in Qt’s bug tracker is the somewhat vaguely named umbrella task “Allow better font rendering for projects like Koffice”.

The background for the task is a lacking cross-platform support in Qt for text layouts done in the design metrics of the font. Depending on the font back-end in the operating system, text in Qt might be hinted, meaning that the glyphs are altered slightly before they are painted on screen, optimized to be painted in a specific size and resolution. For high-density devices, such as printers, hinting the glyphs is unnecessary, but for lower-density displays such as desktop monitors, it will make the text crisper and easier to read by aligning its outlines to the pixel grid.

Typical examples are Windows’ GDI, which hints glyphs in vertical and horizontal directions (full hinting), and Mac OS X’s Core Text, which does absolutely no hinting at all. With FreeType, the text rasterization technology used on Linux, this is customizable between full hinting, just vertical hinting and no hinting. Look at the following screenshot to see the difference between Windows and Mac text rasterization.

GDI/Core Text text rasterization comparison

GDI/Core Text text rasterization comparison

Looking at e.g. the ‘e’ in “Lorem” in this screenshot, you’ll see that the GDI version is sharper and more defined. This is due to the hinting altering the shapes slightly to align them to the pixel grid, to avoid having parts of the outline that are centered between two pixels, giving a slightly more smudgy appearance.

A second thing you will notice, if you zoom in on the two examples, is that every instance of a given character in the GDI version is rasterized exactly the same, while in Core Text its appearance will differ depending on the character’s position in the string. This is due to subpixel positioning of the glyphs in the Core Text version, causing the glyphs to cover different fractions of pixels (and subpixels) based on its position (see my blog about subpixel positioning in the raster paint engine.) When a glyph is aligned to the pixel grid, so are its metrics, so in GDI, each glyph is positioned at whole pixels, giving the exact same rasterization for each instance.

The third thing to notice, is the one that originally triggered QTBUG-10615: The widths of the lines of text in the GDI version are different from in the Core Text version. In the example above, the difference is small, but very visible. In other examples, it might even affect properties of the layout, such as line breaks in the text. For text in user interfaces, this will be largely irrelevant. The UI can adapt to minor differences in the metrics of the text, and the main concern is that the application looks at home on the platform where it’s running, so this is what Qt has focused on in the past. In more typographically sensitive use cases, however, it could be a disaster, as it prevents the typographer from predicting the size and layout of the text when moving to a device with a different density, such as a printer. This is such a problem that some typographical applications, such as Microsoft Word, will first do its layout in design metrics, then calculate the error in metrics between the rendered glyphs and the glyphs in the layout, and then distribute this error evenly out between words and between letters for more accuracy (but giving some odd effects in lines of text that do not contain any spaces). In Qt, we’ve ignored the problem so far.

Together with Jiang, I’ve spent the last few weeks looking at this issue, and in order to rectify the situation we’ll add a new property to QFont in Qt 4.8: QFont::hintingPreference() (the naming refers to the fact that behavior is not guaranteed, but that we’ll try to do our best given the capabilities of the font back-end. Please let me know if there are any views on what the API should be, as it is not set in stone yet.)

The platform support has some limitations: On Core Text, the text is already typographically correct, and text in native user interfaces is also rendered unhinted, so there is no support for any hinting style other than “None” on this platform. On GDI, there’s no way of turning off hinting, so older Windows platforms will not benefit from this API either.

The two major platforms on which we’ve focused are:

  • FreeType, which can be used to rasterize text on Linux platforms and Symbian. We can support all three levels of hinting on top of this back-end: “None”, “Vertical only (light)” and “Full”.
  • DirectWrite, which is supported on Windows Vista after the Platform Update has been installed, and on Windows 7. We can support full hinting and vertical hinting on this back-end.

(note: In order to get support for the DirectWrite back-end, you need to build Qt with the configuration flag “-directwrite” which will make your applications depend on DirectWrite support from your target platforms.)

Lets look at the same screenshot as before, but with DirectWrite rasterization added for comparison:

GDI/Core Text/DirectWrite text rasterization comparison

GDI/Core Text/DirectWrite text rasterization comparison

Looking at this screenshot, you’ll see that DirectWrite renders the text with the same metrics as Core Text (the design metrics in the font), thus giving equal line widths as in the Core Text version. If you zoom in, you will also see that the DirectWrite engine positions glyphs at subpixels, giving a range of slightly different rasterizations for each character based on its position in the string. Finally, you’ll see that the DirectWrite rasterization is still crisper than the Core Text equivalent. This is because DirectWrite still hints the glyphs in the vertical direction (look at e.g. the horizontal bar in the ‘e’, which lies between two pixels in the Core Text rasterization). It doesn’t affect a horizontal text layout, but gives a slightly crisper rasterization which some people consider more readable than the completely unhinted text.

To complete the comparison, lets add two examples rendered with the FreeType engine as well:

GDI/Core Text/DirectWrite/FreeType text rasterization comparison

GDI/Core Text/DirectWrite/FreeType text rasterization comparison

As is visible here, the “no hinting” case corresponds to the Core Text rasterization, the “vertical hinting” (what is known as “light” in FreeType) corresponds to the DirectWrite rasterization, and the “full hinting” case corresponds to the GDI rasterization.

Please allow some time for these changes to reach mainline. The FreeType changes are still being polished, and the DirectWrite back-end needs to go through a few stages of testing and integration before it reaches the outside. Soon should be able to support typographically correct text rendering in your application for these three main back-ends.

update: Added “full hinting” example to final image as requested.

Do you like this? Share it
Share on LinkedInGoogle+Share on FacebookTweet about this on Twitter

Posted in C++, KOffice, macOS, Painting, Qt, Windows


SpinyNorman says:

Nice to see core Qt getting some attention!

It’d be useful if you could add FreeType full hinting to that last example to round out the comparisons.

Joshua Grauman says:

This is great! Thanks so much for continuing to work on this! How would adding Harfbuzz support to MacOS effect this? Would it allow vertical hinting on MacOSX?

Eskil Abrahamsen Blomfeldt Eskil Abrahamsen Blomfeldt says:

Joshua, Harfbuzz only does the shaping, not the actual text rendering, so it wouldn’t affect hinting unfortunately.

christoph says:

A fourth value for the hinting mode: “Default”, which means it uses what the user configured in .fonts.conf (and what Qt 4.7 uses).

Eskil Abrahamsen Blomfeldt Eskil Abrahamsen Blomfeldt says:

SpinyNorman: Updated the final image with the full hinting-example.

Cristoph: Currently the possible hinting preferences are: PreferDefaultHinting, PreferNoHinting, PreferVerticalHinting and PreferFullHinting. On Windows the first option will give you full hinting, while on FreeType it will give you the system configuration.

Jiang Jiang says:

@christoph: yes we have this mode, and it works almost exactly as you described (well, it also take the value in gconf in consideration).

Marcus says:

What I would like to see: QApplication::setFontSystem( “freetype” ) on all platforms (similiar to ::setGraphicsSystem(“raster”) )!
Would that be even possible ? Seems to be the only way to get rid of “Ok, done, lets see how it looks on Mac … *bäm* 🙂

Joshua Grauman says:

@Marcus: See the following task If you are interested in Harfbuzz shaping on Mac, also consider voting for it if it is important to you:

James Larcombe says:

Very interesting. In your previous blogs you’ve discussed switching to using the raster paint engine on Mac OS X. What will this do to the comparison you posted? Presumably then Windows and Mac will be pixel-identical… but not if you switch to a DirectWrite-based backend on Windows?

amol says:

Nice. Have you seen any performance gain with DirectWrite font engine on windows?

Eskil Abrahamsen Blomfeldt Eskil Abrahamsen Blomfeldt says:

James: The system font engine will still be in charge of rasterizing the glyphs, and the raster engine has been updated to support subpixel positioning in Qt 4.8, so the comparisons should look identical. In fact, the raster engine was used to produce the Windows rasterizations in this blog post.

amol: I haven’t done any formal testing of performance yet, but I don’t expect much difference for most common use cases, as the glyphs are cached after the first time they have been rasterized. Using the DirectWrite engine will consume more memory for the glyph cache in the raster or GL engines though, as they will have to cache up to twelve different instances of each glyph to support subpixel positions.

SpinyNorman says:

@Eskil Thanks for adding the full hinting comparison.

Neko says:

And it all looks like crap because of the damned sub-pixel smoothing! That last FreeType/Full example positively *glows* green for me.

aportale says:

@Neko: Most likely your screen has a different rgb component layout than what Eskils screenshots are optimized for. I assume that if the text rendering happens on your system (and supbixel rendering is adjusted to your screen), it looks correct.
However I am, too personally a fan of full hinting and pure gray shades (no subpixel). These look great on Mobile devices with 230-300 dpi.

dxwang1981 says:

I have try to disable hinting , so I delete the 10-autohint.conf in/etc/fonts/conf.d directory under ubuntu and solaris x86, sparc. but the width is still different. shoud I need to set setGraphicsSystem to use raster under ubuntu and solaris. or use X11 ?

Commenting closed.

Get started today with Qt Download now