Library / SDK
servo/font-kit avatar
servo/font-kit

font-kit: one Rust interface over four system font stacks

A cross-platform font loading library written in Rust

843 stars139 forksRustApache-2.0

At a glance

What is it?
font-kit is a Rust library from the Servo project that hides the differences between Core Text, DirectWrite, Fontconfig and FreeType behind a single API for finding fonts, matching them and rasterizing glyphs. It is MIT or Apache-2.0 licensed and shaped for embedded and cross platform applications, but it deliberately stops before text shaping.
Who is it for?
Adopt font-kit if you are writing a Rust application, especially a Servo derived one, that needs to find fonts on more than one platform and rasterize glyphs without linking three different font libraries yourself. Do not adopt it as a text shaping engine, since the documentation says proper shaping is beyond its scope, and skip it if you only need to load a font bundled with your app, where the source feature can be omitted entirely.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 55 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One API over Core Text, DirectWrite and Fontconfig

font-kit provides a common interface to the various system font libraries, and the services it offers are finding fonts on the system, performing nearest-font matching and rasterizing glyphs. It comes from the Servo project, which is why it exists: a browser engine that runs on macOS, Windows, Linux and Android needs to find and draw text on all of them, and each platform has a different native font stack.

The design is a split into two kinds of backends. A source is a platform font database, and it allows lookup of installed fonts by name or attributes. A loader is a font loading library, and it allows font files, TTF, OTF and so on, to be loaded from a file on disk or from bytes in memory.

The important consequence is that sources and loaders can be freely intermixed at runtime. The documentation gives the example of looking up a font via DirectWrite and rendering it via FreeType. That sounds like a small detail and it is not, because it means the font database and the rasterizer are separate decisions. An application can use the platform's own font database on each OS while rasterizing through one consistent engine, or take fonts from a directory it ships while still asking the system about metrics.

The available loaders are Core Text on macOS, which is the system font loader there and does not do hinting except when bilevel rendering is in use; DirectWrite on Windows, the newer system framework for text rendering, which does vertical hinting but not full hinting; and FreeType, described as a full-featured font rendering framework and available cross-platform.

The available sources are wider still. Core Text and DirectWrite for the macOS and Windows system databases, Fontconfig which is described as a technically platform-neutral but in practice Unix-specific API to query and match fonts, a Filesystem source that reads fonts from a path on disk and is the default on Android, a Memory source that reads from a fixed set of fonts in memory, and a Multi source that allows multiple sources to be queried at once.

Looking up a font and rasterizing a glyph

The synopsis in the README is the shortest complete example of the API. You create a SystemSource, select a font by PostScript name, load it, find the glyph for a character, make a canvas and rasterize:

rust
let font = SystemSource::new()
    .select_by_postscript_name("ArialMT")
    .unwrap()
    .load()
    .unwrap();

let glyph_id = font.glyph_for_char('A').unwrap();
let mut canvas = Canvas::new(&Size2D::new(32, 32), Format::A8);

font.rasterize_glyph(
    &mut canvas,
    glyph_id,
    32.0,
    &Point2D::new(0.0, 32.0),
    HintingOptions::None,
    RasterizationOptions::GrayscaleAa,
)
.unwrap();

Three things in that snippet are worth understanding. The lookup is by PostScript name, which is the identifier that is actually stable across platforms, not the human readable family name that varies. The canvas is a 32 by 32 buffer in the A8 format, a single channel alpha mask, which is the format a renderer wants when it will composite the glyph itself. And the rasterization call takes a size, a baseline origin, a hinting option and a rasterization option, with GrayscaleAa selected here.

The hinting argument is where the platform differences show up in practice. Passing HintingOptions::None gives you unhinted outlines, which is the right choice for a display at a size where hinting artifacts would be visible. On macOS the Core Text loader does not do hinting except in bilevel rendering, and DirectWrite on Windows does vertical hinting but not full hinting, so asking for full hinting on those platforms gives you less than the name suggests. FreeType is the loader that can do the full job.

The feature list also covers the operations around the glyph rather than the glyph itself. Loading fonts from files or memory, determining whether files on disk or in memory represent fonts at all, interoperating with native font APIs, querying metadata, doing simple glyph to character mapping, reading unhinted or hinted vector outlines, calculating glyph and font metrics, looking up glyph advances and origins, looking up all fonts on the system, searching by family or PostScript name, and performing font matching according to the CSS Fonts Module Level 3 specification.

Font matching follows the CSS specification

The matching feature deserves separate attention because it is the part that saves the most work.

Performing font matching according to the CSS Fonts Module Level 3 specification means the library implements a standardised algorithm rather than a private heuristic. When you ask for a family name and it is not present, the algorithm walks the rules the specification defines, through the available families, styles and weights, and picks the closest match by a defined ordering. That behaviour is what a browser does, and it means an application using font-kit will substitute fonts the way a web page does.

The alternative approach, rolling your own matching, produces the classic set of bugs. A request for a bold variant of a family returns the regular one, or a synthetic bold is applied where a real bold face was available, or the fallback chain differs between platforms so the same design renders differently on macOS and Linux. Delegating to a documented specification removes that class of problem.

The caveat is that matching is only as good as the source it queries. On Linux that is Fontconfig, which brings its own configuration into the picture, and on Windows it is DirectWrite, which has its own idea of what is installed. The specification defines how to pick from a set of faces, not how the set is assembled, so two machines with different font installs will still match differently. The Multi source, which allows multiple sources to be queried at once, is the mechanism for querying more than one database when you need a specific answer.

It is also worth being clear that matching is not shaping. The library does simple glyph to character mapping, and the documentation says that for more complex use cases a shaper is required and that proper shaping is beyond the scope of font-kit.

Cargo features decide what actually gets compiled

The Cargo manifest shows a library that is careful about what it links. The default feature set is source, and the feature list is small and explicit: loader-freetype pulling in freetype-sys, loader-freetype-default making that the default loader, source-fontconfig pulling in yeslogic-fontconfig-sys, source-fontconfig-dlopen for dynamic loading, source-fontconfig-default to make it the default source, and source itself, which the manifest shows as an empty feature.

The empty source feature is the mechanism for the size reduction the README describes. If you do not need to locate fonts on the system at all, for example if all your fonts are stored with your app, you can omit the default source feature and none of that code will be included. For a browser that ships its own fallback fonts, that is a meaningful reduction in both binary size and the number of native libraries you have to ship.

There is a platform warning worth reading twice. On Windows and macOS, the FreeType loader and the Fontconfig source are not built by default. To build them you use the loader-freetype and source-fontconfig Cargo features, and to make them the default you use loader-freetype-default and source-fontconfig-default. The README adds a warning that source-fontconfig-default is rarely what you want on those two platforms, which is a fair warning given that Fontconfig is described as in practice Unix-specific.

The manifest also shows the version floor. The package version is 0.14.3, the edition is 2018 and rust-version is 1.77, so any toolchain older than that will not build it.

The dependencies are a mix of pure Rust and platform bindings. bitflags, byteorder, float-ord, libc and log are ordinary Rust crates. pathfinder_geometry and pathfinder_simd do the vector geometry work. freetype-sys and yeslogic-fontconfig-sys are the C bindings, both optional and both selected by features. The platform specific sections pull in dwrote and winapi on Windows, core-foundation, core-graphics and core-text on macOS and iOS, and fall back to freetype-sys and yeslogic-fontconfig-sys on everything else.

Building it and the Linux system dependencies

The README gives one dependency line, and it is for Ubuntu:

`sudo apt install pkg-config libfreetype6-dev libfontconfig1-dev`

That covers the two C libraries the crate links against on Linux, FreeType and Fontconfig. There is no separate build script to run beyond what Cargo does, though the repository does contain a build.rs file for the cases that need it, and a c directory for the C sources.

The examples directory is the best guide to the API. It holds fallback.rs, list-fonts.rs, match-font.rs and render-glyph.rs, which between them cover the four things an application typically needs: enumerating what is installed, matching a request against what is installed, rendering a single glyph and falling back when a font is missing. The dev dependencies in the manifest back that up, with clap for argument parsing, colored for terminal output, pbr for progress bars and prettytable-rs for tabular output, which is what a set of command line examples needs.

Documentation is published on docs.rs, and the README badge points there, so the API reference is generated from the source rather than maintained by hand.

One note on the code layout. The repository has a src directory, a resources directory and a tests directory, plus examples, and the manifest excludes resources from the published package. The resources directory appears to hold test fonts, since the crate needs font files to exercise its loaders, and excluding them keeps the published crate small.

Where the library stops, and what to weigh

The scope boundary is stated plainly in the feature list. font-kit does simple glyph to character mapping, and for more complex use cases a shaper is required, with proper shaping beyond its scope. That is a real limit for any text that needs more than one to one character mapping: Arabic joining, Indic reordering, ligature formation and the cluster logic that goes with them are all shaper territory. If your application renders user supplied text in those scripts, font-kit alone will not give you correct output.

The second limit is hinting fidelity. The platform loaders are honest about what they do, Core Text without hinting except in bilevel rendering and DirectWrite with vertical hinting but not full hinting, so a project that needs full hinting quality has to use the FreeType loader, which on Windows and macOS means opting in with a Cargo feature rather than getting it by default.

The third is the dependency shape. A library that links to DirectWrite on Windows, Core Text on macOS and FreeType plus Fontconfig on Linux is a library with a wide native surface, which for a library that ends up in a shipped application means testing on each platform and handling the case where a system library version differs from what the bindings expect. The dlopen variant of source-fontconfig exists precisely to defer that problem to runtime.

The comparison with the alternatives is instructive. Using the platform API directly, Core Text on macOS and DirectWrite on Windows, gives you the best native integration and no abstraction, at the cost of two code paths and no portability. Using a font parsing library directly gives you outlines and metrics but no system font database and no matching, so you end up writing the lookup layer yourself. font-kit is the middle option: it does not give you the platform's sharpest corners, but it gives you one API and the CSS matching behaviour, which is the part most applications would otherwise get wrong.

For maintenance, the repository is not archived and the last push was on 2026-08-29, with the listed releases v0.14.3 and v0.14.2 both dated 2025-07-12 and v0.14.1 from 2024-07-18. The licence is stated as the same terms as Rust itself, which in the manifest is MIT OR Apache-2.0, with the LICENSE-APACHE and LICENSE-MIT files at the repository root. The dual licence is the usual choice for a library that is meant to be usable inside both permissive and copyleft projects.

Editorial conclusion

Adopt font-kit if you are writing a Rust application, especially a Servo derived one, that needs to find fonts on more than one platform and rasterize glyphs without linking three different font libraries yourself. Do not adopt it as a text shaping engine, since the documentation says proper shaping is beyond its scope, and skip it if you only need to load a font bundled with your app, where the source feature can be omitted entirely. Verify first which loader and source combinations your target platforms build by default, since FreeType and Fontconfig are not built on Windows and macOS unless you ask for them, and check the rust-version floor of 1.77 against your toolchain.

Frequently asked questions

What is font-kit and which platforms does it support?

font-kit is a cross-platform font loading library written in Rust, from the Servo project, providing a common interface to the various system font libraries. It works with Core Text on macOS, DirectWrite on Windows and Fontconfig on Unix-like systems, and the source list also covers filesystem, memory and multi sources.

How do I look up a font and rasterize a glyph with font-kit?

Create a SystemSource, select the font with select_by_postscript_name, call load, then find the glyph with glyph_for_char, make a Canvas with the size and Format you want, and call rasterize_glyph with a size, baseline origin, HintingOptions and RasterizationOptions.

Why are FreeType and Fontconfig not built by default on Windows and macOS?

On those two platforms the native loaders, DirectWrite and Core Text, are used instead. You can opt in with the loader-freetype and source-fontconfig Cargo features, and the README warns that source-fontconfig-default is rarely what you want there, since Fontconfig is in practice Unix-specific.

Does font-kit do text shaping for Arabic or Indic scripts?

No. It does simple glyph to character mapping, and the documentation states that for more complex use cases a shaper is required, with proper shaping beyond the scope of font-kit.

What system packages do I need to build font-kit on Ubuntu?

The README gives `sudo apt install pkg-config libfreetype6-dev libfontconfig1-dev`. The manifest also sets a rust-version of 1.77, so your toolchain has to be at least that version.

What license is font-kit released under?

MIT OR Apache-2.0, described in the README as the same terms as Rust itself, with the LICENSE-APACHE and LICENSE-MIT files at the repository root.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. README
  4. Releases
  5. servo/font-kit on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/servo-font-kit.svg)](https://hysenlabs.com/projects/servo-font-kit)

Was this useful?