tpt-text

Rust

Pure-Rust, zero-FFI text shaping, bidi, line breaking, paragraph layout and hit-testing. no_std + alloc, with deterministic fixed-point output.

0 stars0 forks0 watchers6 open issuesApache License 2.0

Languages

Rust98.4%HTML0.6%JavaScript0.4%PowerShell0.3%Shell0.3%
README

tpt-text

Deterministic text shaping and layout in pure Rust. The same input produces the same glyph positions on every platform, including WebAssembly, so PDFs, CAD drawings and browser previews agree byte for byte.

Hello

use tpt_text::{layout_text, FontRegistry, Fx, TextStyle};

let registry = FontRegistry::new();
let font = std::fs::read("NotoSans-Regular.ttf")?;
let face = registry.load_font(font, 0)?;

let style = TextStyle::new(face.family(), Fx::from_int(16));
let layout = layout_text(&registry, "Hello, world", &style, Fx::from_int(200))?;

for line in &layout.lines {
    println!("line at y={} holds {} runs", line.top, line.runs.len());
}
println!("digest {:016x}", layout.digest());
# Ok::<(), Box<dyn std::error::Error>>(())

Features

AreaWhat you get
Shapingrustybuzz, OpenType features, letter spacing, variable-font axes
BidiUAX #9 resolution, visual reordering, per-line rule L1
Line breakingUAX #14 (Unicode 18), soft hyphens, caller-supplied hyphenation
Fallbackcaller-configured per-script chains, per-cluster font choice
Layoutalignment (start, end, left, right, centre, justify), tab stops, line height, truncation with ellipsis
Editingcaret from a point, point from a byte, selection rectangles
Outputpositions, glyph outlines, SVG, JSON with the serde feature, layout digests
Documentsseveral paragraphs with incremental relayout and a shape cache
Fontsin-memory registry, collections (.ttc), names read from the file, system fonts with fontdb
Targetsstd, no_std + alloc, wasm32-unknown-unknown

Cargo features:

FeatureDefaultAdds
stdyesstd::error::Error impls
fontdbnotpt_text::system::SystemFonts, OS font discovery
serdenoSerialize for layouts and styles; Deserialize for styles

Determinism

Layout arithmetic is fixed-point (Fx, 16.16) and integer-only. Floating point appears only where values enter or leave the crate, such as font variation values and conversions for display. CI runs a digest check that compares native output with output recorded from the WebAssembly build.

Crates in this repository

CratePurpose
tpt-textThe library
tpt-text-linebreakUAX #14 line breaking, no_std
tpt-text-wasmWebAssembly bindings and a browser demo
tpt-text-cliCommand-line layout: JSON, SVG, digest, break explanations
tpt-text-snapshotText snapshots of layouts for tests
tpt-text-goldenJSON golden files for tests

Examples: layout_svg, caret_selection, bidi_emoji. A renderer starter using tiny-skia is in templates/tiny-skia.

Guides: cookbook and migration.

Working on the repository

cargo xtask ci          # formatting, lints, tests, no_std and wasm builds, docs, digests
cargo xtask bench-check # benchmarks against crates/tpt-text/benches/baseline.txt

See CONTRIBUTING.md. Dual-licensed under MIT or Apache-2.0.