Every program that draws text starts by answering one quiet question: where is the font, and what is inside it? For decades the answer on Linux and beyond has been two C libraries — fontconfig to find the file, freetype to read it. Today, that whole layer becomes Pure Rust.
Today we’re releasing OxiFont 0.2.0 — the COOLJAPAN Pure Rust font discovery, parsing, subsetting, and web-font encoding layer for the oxi* ecosystem.
No fontconfig. No freetype. No FFI. No -sys crates. Under default features OxiFont is 100% Rust: a single static binary that enumerates installed fonts, parses font byte streams, matches families by CSS rules, and emits web fonts — with no system libraries and no build-time C toolchain in the way.
Why OxiFont
If you have ever shipped a Rust application that renders text, you have met the font-stack tax. fontconfig wants its XML config, its cache directories, and its platform-specific quirks. freetype is a sprawling C codebase linked through freetype-sys, dragging a native build dependency into every target you care about — including the WASM and cross-compilation targets where a C toolchain is exactly what you were trying to avoid.
None of that is essential complexity. Finding a font is a filesystem scan plus a parse of a few well-specified tables. Reading a font is parsing an SFNT container. Matching a family is a documented algorithm written down in the CSS Fonts specification. OxiFont does each of these directly, in memory-safe Rust, so the font layer stops being the reason your build needs a C compiler.
OxiFont draws a deliberate line. It covers discovery, parsing, metrics, matching, subsetting, and web-font encoding. Rasterization, hinting execution, shaping, and layout are out of scope by design — those belong to oxitext. OxiFont is the layer that tells you which font and what is in it; turning glyphs into pixels is someone else’s job.
What we built
OxiFont is a workspace of focused crates, each owning one slice of the problem. The oxifont facade crate re-exports the ecosystem and gives you the convenience entry points (load_font, load_font_bytes, detect_format, decode_and_parse, and a prelude), so most code only ever needs the one dependency.
-
oxifont-core— the vocabulary. The traits and types the whole stack speaks:FontFace,FontCatalog,FaceInfo,FontQuery,FontStyle,FontStretch,FontMetrics,GlyphOutline,KerningPair,ColorGlyphFormat,VariationAxis, andSfntTableMap. -
oxifont-parser— reading the bytes. TTF/OTF/TTC parsing viattf-parser, with a fullFontFaceimplementation: metrics, glyph outline extraction, kerning, color-glyph detection, and PostScript name. This is the part that replacesfreetype’s parsing role — without inheriting its hinting interpreter, which is deliberately excluded. -
oxifont-discovery— finding the files. A Pure Rust OS font-directory scanner for macOS, Linux, and Windows, built onwalkdir, with optionalfontconfigXML config parsing for compatibility. This isfontconfig’s enumeration job done as a plain filesystem walk. -
oxifont-adapter-pure— the catalog. Builds aFontDatabasefrom a filesystem scan, resolves CSS generic-family aliases, and offers an optional disk cache so repeated startups stay fast. -
oxifont-db— CSS Level 4 matching. An in-memory indexed database implementing CSS Fonts Level 4 §4.5 family/weight/style/stretch matching, with 60+ BCP-47 locale mappings, a fluentQuerybuilder, and an optional binary disk cache. This is where “give me sans-serif, weight 700” turns into a concrete face. -
oxifont-subset— shrinking fonts. A TrueType and CFF/CFF2 glyph subsetter: GSUB/GPOS/GDEF pruning, HVAR/VVAR rewriting, and COLR/CPAL, CBDT, SVG, sbix, and MATH subsetting, with variable-font support throughout. -
oxifont-webfont— shipping fonts to browsers. WOFF1 and WOFF2 decode and encode, including transformedglyf/loca/hmtxreconstruction, a streaming WOFF2 decoder, and font-format autodetection. -
oxifont-bundled— fonts in the binary. Compile-time embedded SIL-OFL-1.1 Noto fonts (Sans, Serif, Italic, Mono), with CJK JP/KR/SC/TC behind sub-features, so “no font installed” never has to be a failure mode.
Every default feature uses zero FFI. Native platform enumeration via CoreText (macOS) and DirectWrite (Windows) lives in a separate oxifont-adapter-native crate behind its native feature — opt-in, never on the default path. And fontconfig and freetype are permanently off-limits under any feature or adapter.
Getting Started
Add the facade crate:
[dependencies]
oxifont = "0.2"
Find a system font and read its metadata:
use oxifont::{FontDatabase, FontCatalog as _, FontQuery};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let db = FontDatabase::system()?;
if let Some(face) = db.find(&FontQuery::new().family("Arial")) {
println!("found: {} weight={}", face.family, face.weight);
}
Ok(())
}
Parse a font file directly and inspect what is inside:
use oxifont::{load_font, FontFace as _};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let face = load_font("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf")?;
println!("family: {}", face.family_name());
println!("units/em: {}", face.units_per_em());
println!("glyph count: {}", face.glyph_count());
Ok(())
}
Highlights
- Cross-platform font enumeration — installed fonts on Linux, macOS, and Windows via a Pure Rust filesystem scan.
- Broad format coverage — parse TTF, OTF, TTC, WOFF, and WOFF2 byte streams from one entry point.
- Real font internals — glyph metrics, CMap, OS/2 and
nametable data, kerning, and color-glyph detection. - CSS Level 4 matching — family/weight/style/stretch resolution with 60+ BCP-47 locale mappings.
- Subsetting to a codepoint set — TrueType and CFF/CFF2, including COLR/CPAL, CBDT, SVG, sbix, and MATH, with variable-font support.
- Web-font encode and decode — WOFF1 and WOFF2 in both directions, with a streaming WOFF2 decoder.
- Bundled Noto — embed OFL fonts (Latin/Greek/Cyrillic, plus CJK JP/KR/SC/TC) at compile time as a guaranteed fallback.
Tips
- Reach for the
dbfeature for real CSS matching. Enablefeatures = ["db"]to get theoxifont::dbmodule with the full Level 4Queryengine —Query::new(&db).family("sans-serif").weight(700).match_best()does exactly what a browser’s font selector does. - Subset before you ship. With
features = ["subset", "woff2"], passsubset_font(&bytes, &codepoints)aBTreeSet<char>of just the characters you use, thenencode_woff2(&subsetted)— your web font carries only the glyphs the page needs. - Never panic on a missing font: bundle one. Turn on
bundled-noto(andbundled-noto-cjk-jp/-kr/-sc/-tcfor CJK) to compile Noto straight into the binary as a fallback. - Cache the catalog. Both the pure adapter and
oxifont-dbsupport an optional binary disk cache — enable it so a cold start does not re-scan every font directory. - Native enumeration is opt-in and separate. If you want CoreText or DirectWrite results on macOS/Windows, depend on
oxifont-adapter-nativedirectly and enable itsnativefeature; it is no longer re-exported by the facade, which keeps the default path pure. - Don’t look for a rasterizer here. Hinting execution, shaping, and layout are intentionally out of scope — pair OxiFont’s metrics and outlines with
oxitextwhen you need to turn glyphs into pixels.
Part of the COOLJAPAN ecosystem
OxiFont belongs to NoFFI — the COOLJAPAN initiative to replace every C/C++/Fortran/-sys FFI dependency in the Rust ecosystem with a clean, memory-safe, 100% Pure Rust implementation. Here, that means retiring fontconfig (system enumeration and family matching) and freetype (parsing and outlines) from the dependency tree, while text shaping via harfbuzz-sys stays out of scope and lives in OxiText instead.
It is wired into the rest of the family. All DEFLATE/zlib work runs through oxiarc-deflate and all Brotli work through oxiarc-brotli — no flate2, brotli, miniz_oxide, or zip anywhere in the tree. And OxiFont is already the font foundation under OxiText (glyph metrics for layout), oxigaf (PDF CFF/Type-0 font embedding), oximedia (subtitle and OSD rendering), oxigdal-symbology (map labels), oxiphoton (image text overlay), and OxiUI (GUI text rendering).
Repository: https://github.com/cool-japan/oxifont
Star the repo if you want a font layer that finds, reads, and shrinks fonts without ever asking for a C compiler. ⭐
Pure Rust typography — sovereign, safe, and FFI-free.
— KitaSan at COOLJAPAN OÜ June 22, 2026