Bring your own text engine.
The engine draws text through a single trait. bite-gp-parley is a second implementation of it — install the crate, hand it to the application at startup, and every existing div() keeps rendering. Nothing else in the tree changes.
One trait to implement.
TextSystem lives in gpui_engine and covers shaping, layout and rasterization. The facade exposes exactly one way to replace it: Application::with_text_system. A text engine written outside the repository plugs in through that method, which is what makes this an install rather than a patch.
# Cargo.toml
[dependencies]
bite-gpui = "1.21"
bite-gp-parley = "1.21"
use gpui::*;
use gpui_parley::ParleyTextSystem;
fn main() {
application()
// new() already returns an Arc, which is what this wants
.with_text_system(ParleyTextSystem::new())
.run(|cx: &mut App| {
cx.open_window(WindowOptions::default(), |_, cx| {
cx.new(|_| MyView)
})
.unwrap();
});
}
Cargo exposes a dependency under its library name, and the
published package keeps its upstream lib target — so
bite-gp-parley is use gpui_parley::…, with no
package = key in your manifest.
What it changes.
Both columns below are the same operations on the same font and the same 16 px text, called through &dyn TextSystem so the implementation is the only variable. The vanilla column is what a Linux user gets without asking for anything — DefaultTextSystem over CosmicTextSystem. The parley column is bite-gp-parley 1.21.1.
| operation | vanilla | parley | result |
|---|---|---|---|
| new — cold, registers one face | 5.75 µs | 44.24 ms | 7,700× slower |
| resolve_font | 67.9 ns | 99.5 ns | 1.5× slower |
| bounding_box | 18.1 ns | 4.8 ns | 3.8× faster |
| line_metrics — ascent + descent + baseline | 68.0 ns | 5.9 ns | 11.5× faster |
| layout_line — a 3-line paragraph | 131.30 µs | 83.31 µs | 1.58× faster |
| wrap_line — the same paragraph, 420 px | 79.07 µs | 33.27 µs | 2.4× faster |
| raster_bounds, cached | 22.3 ns | 62.5 ns | 2.8× slower |
| raster_bounds, uncached | 3.36 µs | 7.79 µs | 2.3× slower |
| rasterize_glyph | 3.06 µs | 15.48 µs | 5.1× slower |
Mean estimates from criterion, 100 measurements per benchmark. Host: Intel i7-8750H, linux x86_64 — a laptop, not a controlled benchmarking host.
It is a trade, not a win.
Parley is faster where the engine drives text in bulk: wrapping the same paragraph is 2.4× faster, a three-line layout 1.58×, and the per-font metrics — the numbers a rearchitected engine reads constantly — 3.8× and 11.5×. It is slower at putting one glyph on screen: 15.48 µs to rasterize a 16 px glyph against vanilla's 3.06 µs.
A project that swaps the text system is buying shaping — complex scripts, font fallback, family stacks — and paying for it in rasterization. The point of publishing both columns is that this is visible before you install it rather than after.
ParleyTextSystem::new is 7,700× vanilla's, and that is the host's fonts, not a regression in the same work: it builds a fontique collection with system_fonts: true, enumerating every font on the machine. The previous release, which did not, constructed in 33.88 µs. It is paid once per process, and it is what buys the host-font fallback the crate exists for — worth knowing before installing it in something that starts often.
The cache both systems share.
Memoizing glyph raster bounds is the mechanism behind the dramatic ratio on the marketing page, so the honest measurement is cached against uncached within one implementation:
| implementation | uncached | cached | the cache buys |
|---|---|---|---|
| vanilla | 3.36 µs | 22.3 ns | 151× |
| parley 1.21.1 | 7.79 µs | 62.5 ns | 125× |
| parley 1.21.0 (previous) | 36.30 µs | 61.2 ns | 593× |
The two parley rows differ only in the uncached path: 36.30 µs down to 7.79 µs, with the cached path unchanged at roughly 62 ns.
What the release changed.
The rasterization cost above was not always 15.48 µs. The hinting instance is now cached per face and size instead of rebuilt once per rasterized glyph, which is the whole of the improvement below — measured on the same host within an hour of each other.
| operation | 1.21.0 | 1.21.1 | result |
|---|---|---|---|
| rasterize_glyph | 78.30 µs | 15.48 µs | 5.1× faster |
| raster_bounds, uncached | 36.30 µs | 7.79 µs | 4.7× faster |
| layout_line | 95.93 µs | 83.31 µs | 1.15× faster |
| wrap_line | 15.56 µs | 33.27 µs | 2.1× slower |
| new | 33.88 µs | 44.24 ms | host fonts |
The wrap_line loss and the metric costs in the first table are the same host-font-database change as the 44 ms: each lookup now consults the shaper's own database rather than a table held by the crate.
Run it yourself.
The harness is one file, and its two columns are two implementations behind the same trait — one implementation measured alone would say what Parley costs, not what choosing Parley costs.
That harness is part of the project's own usage suite, which is not published yet — so the table above is backed by a recorded run, with its command, toolchain, host and every sample, rather than by a repository you can clone today. What you can run right now is the crate's own cost examples.