# Allsorts: a Rust font parser, shaping engine and subsetter

> Allsorts is an Apache 2.0 licensed Rust crate that parses OpenType, WOFF and WOFF2 fonts, shapes text across a long list of scripts, subsets fonts for PDF embedding and instances variable fonts. The judgement is that it is a working production component that came out of Prince, with correctness pinned to HarfBuzz and the Adobe test suite, and with two gaps a user has to cover elsewhere, Unicode normalisation and font lookup.

**yeslogic/allsorts** — Font parser, shaping engine, and subsetter implemented in Rust

- Repository: https://github.com/yeslogic/allsorts
- Website: https://yeslogic.com/blog/allsorts-rust-font-shaping-engine/
- Stars: 802 · Forks: 27
- Language: Rust
- License: Apache-2.0
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/yeslogic-allsorts

## A shaping engine pulled out of a PDF typesetter

Allsorts began inside Prince, the tool that typesets HTML and CSS documents into PDF, and it was extracted from there into a standalone crate. The README is explicit about the division of labour that resulted: in Prince, Allsorts is responsible for all font loading and for font shaping, while the layout engine around it does the rest.

That origin explains the shape of the crate. This is not a general text rendering library. It parses font files, decides which glyphs a string of Unicode codepoints maps to, and can produce a smaller font for embedding. Rendering the glyphs is somebody else's job, and the README points at Pathfinder or FreeType for that step.

The crate is published as allsorts on crates.io with the documentation on docs.rs, it is written by YesLogic, and the licence field in the manifest says Apache-2.0. The manifest sets edition 2021 and a rust-version floor of 1.83, which is also the stated minimum supported Rust version. The current crate version is 0.17.0, published on 2026-05-13, and the last push to the repository carries the same date.

## Parsing covers glyf, CFF, CFF2 and the two web font wrappers

The parsing side handles the font containers a browser or a document engine is likely to meet. TrueType and OpenType outlines are supported in their glyf flavour and in the CFF and CFF2 flavours, and the two web font wrappers, WOFF and WOFF2, are parsed as well.

The dependencies explain the mechanics. brotli-decompressor handles the Brotli payload that WOFF2 uses, flate2 handles the zlib compressed streams that WOFF and other formats rely on, and bitreader and byteorder take the binary apart. There are also crates for the boring parts: crc32fast for checksums, encoding_rs for the character encodings a font can declare, glyph-names for the post table naming convention, and num-traits and itertools for the numeric work.

The parser is handwritten, and the README says so and explains why that is on the list of things to change. The plan is to replace it with machine generated code produced by the Fathom project, a declarative data definition language from the same author. In other words, the parsing layer is the part of Allsorts most likely to be rewritten, while the shaping layer is the part with the specifications behind it.

## Shaping is where the long script list earns its keep

Font shaping is the step that turns text into positioned glyphs, honouring the kerning, ligature and substitution rules the font itself declares. For English it is unremarkable. For the scripts on the Allsorts list it is where the real work sits, and the list is long: Arabic, Cyrillic, Greek, Hebrew, Khmer, Lao, Latin, Myanmar, Syriac and Thai, plus the Indic scripts, where Bengali, Devanagari, Gujarati, Gurmukhi, Kannada, Malayalam, Oriya, Sinhala, Tamil and Telugu each need their own reordering and positioning behaviour.

The engine was built alongside a written specification for OpenType shaping, and that specification is what the implementation follows. The README credits it as the specification the shaping engine was developed in conjunction with, which is an unusual arrangement: rather than reverse engineering a behaviour, the author wrote down the behaviour first.

The dependency list supports the same picture. ucd-trie provides the compact trie structures for the Unicode character database, and three separate Unicode data crates supply canonical combining classes, general categories and joining types. Joining types in particular are the Arabic and Syriac shaping data, the property that tells the engine which letters join and which do not. Together they say that the shaping engine is driven by the Unicode data rather than by a table of hardcoded language rules.

## Subsetting for PDF embedding and instancing variable fonts

Two output capabilities sit alongside parsing and shaping, and both are aimed at the document pipeline Allsorts came from.

The subsetter takes TrueType, OpenType, WOFF and WOFF2 fonts and produces smaller fonts that are suitable for PDF embedding. That is a practical requirement rather than a nicety, because a PDF that carries a full font pays for every glyph in it, and the set of glyphs actually used in a document is usually a small fraction of the font.

The instancing side goes the other way. Allsorts can take a variable font and produce a non-variable font from it, which is how a document engine pins a variable font to a particular instance for output, so that the result does not depend on a renderer understanding the variation axes.

Together with the shaping engine, these three capabilities form a complete preparation pipeline: read a font, decide the glyphs and their positions for a given string, then write out a font containing only what was used. The tools that exercise the pipeline live in a separate repository, allsorts-tools, which is where you would look for runnable pieces that parse, shape and subset a font end to end.

## What Allsorts deliberately leaves out: normalisation and font lookup

The README keeps a short list of things the crate does not do, and for a library that does so much, the list deserves a close read before anything else.

First, Unicode normalisation is not supported. If your pipeline needs canonical equivalence to be resolved before shaping, Allsorts will not do it for you, and that step has to happen somewhere else in the pipeline.

Second, Allsorts does no font lookup or matching. Given a family name and a set of style requirements, choosing which file on disk to open is out of scope, and the recommendation is to use a library such as font-kit for that part.

Third, rendering is not included. After shaping, the README points at another library, Pathfinder or FreeType, to draw the glyphs, and mentions an overview of text rendering on Linux as background reading. The concepts are the same on other platforms.

These are not defects but boundaries, and they shape what a user has to assemble. A system that needs font selection, normalisation and rasterisation is looking at Allsorts plus at least two other pieces, while a system that already has those and only needs correct shaping and a subset for embedding is looking at exactly one.

## Cargo features choose the compression backend

The manifest exposes a small feature matrix, and the interesting part is the choice between three compression backends for flate2. The default is flate2_zlib, which uses the system zlib library and needs the zlib package. flate2_rust selects the pure Rust backend, miniz_oxide, and flate2_zlib-rs selects the zlib-rs implementation. Two more features exist for narrower purposes: prince enables the Prince specific tests and code, and specimen enables a module for generating HTML font specimens, which pulls in the upon and unicode-blocks crates.

The README is candid about the trade-off. In the authors' own testing the zlib backend was faster, but the Rust backend may be preferable for a pure Rust solution, in particular when compiling to WebAssembly or something similar, where linking a system zlib is awkward.

Building and testing the crate itself is unremarkable:

```bash
cargo build
cargo test
```

The repository also carries a criterion directory, but the benchmark definitions in the manifest are commented out, which is consistent with a crate whose performance claims live in the downstream document pipeline rather than in published numbers.

## Correctness is pinned to HarfBuzz and the Adobe test suite

The acknowledgements section is the most telling part of the README for anyone deciding whether to trust the shaping output. HarfBuzz, the widely used open source font shaping engine, was used as the reference for test output. The Adobe Annotated OpenType Specification test suite is part of the Allsorts test suite, so the crate is checked against a third party conformance corpus rather than only against itself. The ttf-parser crate supplied the CFF CharString parsing code, and the OpenType shaping documents provide the specification the engine implements.

The continuous integration runs the tests on Linux, macOS and Windows, and through Prince the code is also built for FreeBSD. The crate is also usable from Prince, where it has handled all font loading and all font shaping since the release of Prince 13 in 2019, which is the closest thing the project has to a production track record.

The remaining oddity is the handwritten parser described earlier, and the Fathom plan to generate it. That is a maintenance consideration rather than a risk to users today: the shaping half is specification driven and conformance tested, while the parsing half is expected to be regenerated at some point.

## Conclusion

Allsorts fits a Rust project that needs to lay out or embed text itself, because it covers the parsing, shaping and subsetting work in one dependency and its output is checked against HarfBuzz and the Adobe Annotated OpenType Specification suite. It is the wrong choice if you expect a complete text stack, since Unicode normalisation is not supported and font lookup and matching is left to a separate library such as font-kit, and it is the wrong choice if you need to render glyphs, because Allsorts stops at the shaped glyph run and leaves rasterisation to Pathfinder or FreeType. Before you adopt it, confirm that the scripts your users type in are on the shaping list, pick the flate2 backend that matches your build, and check that the last push, 2026-05-13, sits inside the maintenance window your team is willing to accept.

## FAQ

### What does the Allsorts crate do?

It parses TrueType and OpenType fonts in the glyf, CFF and CFF2 flavours as well as WOFF and WOFF2, shapes text into glyphs for scripts from Arabic to the Indic family, subsets fonts into smaller files suitable for PDF embedding, and instances variable fonts into non-variable ones.

### Does Allsorts do Unicode normalisation or pick fonts for me?

No on both counts, and the project says so plainly. Unicode normalisation is not supported, and Allsorts does no font lookup or matching, for which a library such as font-kit is recommended.

### Which Rust version does Allsorts need?

The stated minimum supported Rust version is 1.83.0, and the manifest sets the same rust-version floor. The crate builds with cargo build and the test suite runs with cargo test.

### How is Allsorts tested against other shaping engines?

HarfBuzz was used as the reference for test output, the Adobe Annotated OpenType Specification test suite is part of the test suite, and continuous integration runs on Linux, macOS and Windows.

## Sources

- [License: Apache-2.0](https://github.com/yeslogic/allsorts/blob/master/LICENSE)
- [Project website](https://yeslogic.com/blog/allsorts-rust-font-shaping-engine/)
- [README](https://github.com/yeslogic/allsorts/blob/master/README.md)
- [Releases](https://github.com/yeslogic/allsorts/releases)
- [yeslogic/allsorts on GitHub](https://github.com/yeslogic/allsorts)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/yeslogic-allsorts
