rust-fontconfig
Pure-Rust rewrite of the Linux fontconfig library (no system dependencies) - using allsorts as a font parser to support .woff, .woff2, .ttc, .otf and .ttf
NOTE: Also works on Windows, macOS and WASM - without external dependencies!
Motivation
There are a number of reasons why I want to have a pure-Rust version of fontconfig:
- fontconfig with all dependencies (expat and freetype) is ~190.000 lines of C (extremely bloated for what it does)
- fontconfig, freetype, expat and basically any kind of parsing in C is a common attack vector (via maliciously crafted fonts). The Rust version (allsorts) checks the boundaries before accessing memory, so attacks via font files should be less common.
- it gets rid of the cmake / cc dependencies necessary to build azul on Linux
- fontconfig isn't really a "hard" library to rewrite, it just parses fonts and selects fonts by name
- Rust has existing xml parsers and font parsers, just use those
- It allows fontconfig libraries to be purely statically linked
- Font parsing / loading can be easily multithreaded (parsing font files in parallel)
- It reduces the number of necessary non-Rust dependencies on Linux for azul to 0
- fontconfig (or at least the Rust bindings) do not allow you to store an in-memory cache, only an on-disk cache, requiring disk access on every query (= slow)
no_stdsupport ("bring your own font files") for WASM
Now for the more practical reasons:
- libfontconfig 0.12.x sometimes hangs and crashes (see issue)
- libfontconfig introduces build issues with cmake / cc (see issue)
- To support font fallback in CSS selectors and text runs based on Unicode ranges, you have to do several calls into C, since fontconfig doesn't handle that
- The rust rewrite uses multithreading and memory mapping, since that is faster than reading each file individually
- The rust rewrite only parses the font tables necessary to select the name, not the entire font
- The rust rewrite uses very few allocations (some are necessary because of UTF-16 / UTF-8 conversions and multithreading lifetime issues)
Usage
Basic Font Query
use ;
Find All Monospace Fonts
use ;
Font Matching for Multilingual Text
use ;
Using from C
Linking with the C API
The rust-fontconfig library provides C-compatible bindings that can be used from C/C++ applications.
Binary Downloads
You can download pre-built binary files from the latest GitHub release:
- Windows:
rust_fontconfig.dllandrust_fontconfig.lib - macOS:
librust_fontconfig.dylibandlibrust_fontconfig.a - Linux:
librust_fontconfig.soandlibrust_fontconfig.a
Building from Source
Alternatively, you can build the library from source:
# Clone the repository
# Build with FFI support
# The generated libraries will be in target/release
Including in Your C Project
- Copy the header file from
ffi/rust_fontconfig.hto your include directory - Link against the static or dynamic library
- Include the header file in your C code:
Minimal C Example
int
For a more comprehensive example, see the example.c file included in the repository.
Compiling the C Example
On Linux:
On macOS:
On Windows:
Performance
- cache building: ~90ms for ~530 fonts
- cache query: ~4µs
Features
- Font matching by name, family, style properties, or Unicode ranges
- Support for font weights (thin, light, normal, bold, etc.)
- Support for font stretches (condensed, normal, expanded, etc.)
- Multilingual text support with automatic font fallback
- In-memory font loading and caching
- Optional
no_stdsupport - C API for integration with non-Rust languages
License
MIT