COOLJAPAN
← All posts

OxiText 0.2.3 Released — Font-Fallback Rendering Was Silently Drawing the Wrong Glyphs

OxiText 0.2.3 fixes a font-fallback bug where a single `.notdef` hit could re-point every already-shaped glyph in a run to the wrong font's glyph table — invisible whenever two fonts share glyph-id numbering. Adds a script-tag introspection API. 851 tests passing. The sovereign Pure Rust text layer for COOLJAPAN.

release oxitext pure-rust cooljapan noffi text typography shaping fallback correctness

A font-fallback bug that only misdraws text when your primary and fallback fonts number their glyphs differently is the kind of bug that passes every test you happen to run with Noto Sans.

Today we released OxiText 0.2.3 — a shaping-correctness release that fixes a silent glyph-misattribution bug in the .notdef font-fallback path, and adds a small API for checking whether the shaper accepts a given OpenType script tag before you shape anything.

No C. No Fortran. No system font-shaping library anywhere in the graph. OxiText compiles to a single static binary (or WASM) with no build-time C toolchain — Pure Rust from font bytes to rendered pixel.

Why OxiText 0.2.3 is a game changer

Font-fallback bugs are the worst kind to catch in testing, because they depend on which two fonts you happen to pair:

OxiText 0.2.3 ends all of that.

Technical Deep Dive: where the bug lived and how the fix closes it

  1. The data-model gap. ShapedRun was designed around the assumption that one run means one font. Font fallback broke that assumption without changing the type, so the run’s single font_data field became a race between “whichever font supplied the last glyph.”
  2. The fix, structurally. shape_run_with_notdef_fallback now watches for font boundaries as it walks a cluster’s shaped glyphs and emits a new ShapedRun each time the source font changes, preserving logical (not visual) order within the original run.
  3. Why no caller had to change. The bidi-reordering path already produces multiple ShapedRuns per logical line (one per bidi run), so every downstream consumer — layout, rasterization — already iterates &[ShapedRun] rather than assuming exactly one. Font-fallback splitting into multiple runs is the same shape of change, just from a different trigger.
  4. The script-tag API. Script/Tag/tag_from_bytes live in oxitext-shape and are re-exported through the oxitext facade’s pure feature, so a caller building on the high-level Pipeline API doesn’t need a direct dependency on the shaper crate just to validate a script tag ahead of a ShapeRequest.

Getting Started

[dependencies]
oxitext = "0.2.3"  # latest stable
use oxitext::{Pipeline, prelude::*};

let font_data = std::fs::read("my-font.ttf")?;
let mut pipeline = Pipeline::from_bytes(&font_data)?;

// Measure a string
let metrics = pipeline.measure("Hello, world!", &TextStyle::default())?;
println!("width={:.1} height={:.1}", metrics.total_width, metrics.total_height);

// Shape, lay out, and rasterize to RGBA pixels
let bg = Rgba8 { r: 255, g: 255, b: 255, a: 255 };
let fg = Rgba8 { r: 0, g: 0, b: 0, a: 255 };
let image = pipeline.render_to_image("Hello, OxiText!", &TextStyle::default(), bg, fg)?;
println!("{}x{} RGBA pixels", image.width, image.height);

See crates/oxitext/examples/quick_start.rs for the compile-checked, runnable version of this snippet (cargo run -p oxitext --example quick_start), including the lower-level Pipeline::render call that returns per-line and per-glyph layout data.

What’s New in 0.2.3

Tips

This is the foundation

OxiText is part of NoFFI — the COOLJAPAN initiative replacing every C/C++/Fortran/-sys dependency in the Rust ecosystem with a clean, memory-safe, Pure-Rust implementation. It pairs with OxiFont for font parsing and discovery, and sits underneath OxiUI (every widget that draws text, via the oxitext-sdf GPU glyph atlas), oximedia (subtitles and captions), and every other COOLJAPAN surface that shapes or rasterizes text — including a caption pipeline that depends on it directly for font-fallback-heavy subtitle rendering, exactly the code path this release fixes.

Repository: https://github.com/cool-japan/oxitext

Star the repo if you want a text stack where a silent, font-pairing-dependent rendering bug gets found and fixed before it reaches your users, not after.

The era of trusting font-fallback rendering because your test fonts happen to share glyph-id numbering is over. Pure Rust typography — sovereign, correct, and now provably right about which font drew which glyph — is here.

KitaSan at COOLJAPAN OÜ August 12, 2026

↑ Back to all posts