Skip to content
Patrick Walton edited this page Oct 24, 2019 · 5 revisions

FAQ

Why bind to platform-specific font libraries instead of replicating the native font rendering in Rust?

It's impractical to replicate the hinting behavior of Windows DirectWrite and the FreeType autohinter. See the following questions and answers.

Why can't the hinting behavior of Windows DirectWrite be replicated in Rust?

The Windows font rasterizer heavily uses the TrueType hinting (more precisely, grid-fitting) feature. A TrueType hinting specification exists, and relatively-recent third-party implementations of it likewise exist, but the interaction between ClearType (Microsoft's implementation of subpixel antialiasing) and TrueType hinting is complex. Beat Stamm documents the basic problem: that a transform of 3x in the horizontal direction causes overflows in common TrueType fonts due to the pervasive use of 16-bit fixed point coordinates. Microsoft's solution is to patch the TrueType instructions in various ways at runtime in order to work around these issues. For GDI, the solution is a complex series of hacks; for DirectWrite, the solution is to ignore all horizontal hinting instructions (though see this issue), which still amounts to a series of hacks, albeit a less complex one. These hacks are not documented or specified, other than informally in Beat Stamm's book and in the FreeType source, but they are necessary to match the system rendering. In the author's judgment, attempting to reverse engineer and replicate these hacks is not worth the effort and risk.

Note that FreeType has gone to the effort of closely matching the Windows font rasterizer. Therefore, FreeType can be appropriate for a Windows-like rendering if desired.

Why can't the FreeType autohinter be replicated in Rust?

Like the Windows TrueType font hinters, the FreeType autohinter is also an undocumented and unstable series of heuristics and hacks. These are more involved than even those of DirectWrite; they infer metrics from the shapes of well-known glyphs (like the Latin letter 'o' and so forth). Replicating these would be difficult, and the code would easily become out of date.

Why does matching the system rendering on Linux require the FreeType autohinter?

For a long time, FreeType was not commonly packaged with TrueType hinting enabled on common distributions. Therefore, Linux fonts were designed with the autohinter in mind. Desktop Linux users (as well of users of BSD and so forth) have come to expect the results of FreeType autohinting.

What about macOS and iOS?

Unless the application explicitly requests bilevel (black and white) rendering, Apple's text rasterizer doesn't do grid-fitting and ignores the TrueType instructions. (An exception may be for some CJK fonts that use the hinting instructions to assemble the glyphs—what FreeType calls "tricky" fonts. I have not investigated this.) Instead, Apple's font rasterizer uses some simple vertical pixel snapping heuristics to align the stems of glyphs to the baseline and x-height. This behavior is much easier to replicate, and in fact Pathfinder and rusttype can rasterize fonts virtually identically to macOS and iOS when appropriately configured.

For the sake of simplicity and consistency with other platforms, font-kit includes bindings to the native font loading and rasterization services of Core Text and Core Graphics, even though these two libraries are not strictly necessary to achieve a macOS-like look.

OK, but I don't care about hinting. Can I have a pure-Rust implementation of font loading?

Yes, it would probably be desirable to have a rusttype loader for this use case. Contributions are welcome!

Does this mean that I need to use the platform rasterizer to make fonts look native on Windows and Linux?

No, unless you are using bilevel (black and white) rendering. You just need to use FreeType to apply the hinting instructions first before handing the resulting outlines off to a vector rasterizer like Pathfinder. (Bilevel rendering is more complex because of features like dropout control which require integration with the rasterizer. Fortunately, it's not used much anymore.)