A memory-safe font engine for Rust: decode, instance, subset, shape, rasterize, and read color/math data out of TTF, OTF, and TTC fonts – entirely in pure Rust, with #![forbid(unsafe_code)] enforced at the crate root.
taetype started as taepdf's internal font engine and grew into a standalone crate once it became clear the same primitives – real glyph IDs, real advances, real subset bytes – are useful well outside PDF generation: web font optimization, variable-to-static conversion, server-side image generation, native typesetting, font inspection in CI.
cargo add taetype- Decode – TTF, OTF, and TTC (font collections). Reads the full table directory, not a fixed allowlist, so nothing in the source font gets silently dropped.
- Instance – the full OpenType Font Variations model (
fvar,avarformats 1 and 2,gvar,HVAR,VVAR,MVAR,cvar) for TrueType-outline variable fonts, plus CFF2 (vstore, charstringblend/vsindexresolution, full subroutine inlining) for CFF-outline ones. Either outline format turns into a static instance at any axis position. - Subset – TrueType (
glyf, with composite-glyph and GSUB-closure dependency chasing) and CFF, including CID-keyed CFF (FDArray/FDSelect) andseaccomposite accented glyphs. CFF2 fonts are instanced to a static CFF table first, then subset through the same path. GSUB/GPOS/GDEF are rewritten glyph-by-glyph, not dropped – ligatures, kerning, and mark attachment all keep working on the subset font. COLR (v0 and v1) and CPAL carry through too, with the same dependency chasing applied to color references. - Shape – GSUB ligatures, GPOS kerning, complex scripts, and vertical writing via
rustybuzz(a Rust port of HarfBuzz), plus a feature-toggling heuristic for OpenTypeJSTFjustification priorities. - Rasterize – taetype's own from-scratch CPU rasterizer (
taerizer::cpu), turning any outline (TrueType or CFF/CFF2, at any instanced axis position) into a grayscale anti-aliased coverage bitmap. Nounsafe, no third-party rasterizer dependency. - Color fonts – COLR v0 and v1 (gradients, transforms, composition, variable paints) with CPAL palettes, CBDT/CBLC and
sbixbitmap strikes, and SVG-in-OpenType documents. - Math typesetting – the full
MATHtable: all 56 constants, per-glyph italics correction and top-accent attachment, sub/superscript kerning, and growable-glyph construction for stretchy delimiters. - Vertical writing metrics –
VORGfor CFF/CFF2 fonts, with the spec-correct TrueType derivation (vmtx+glyfbounding box) forglyf-outline fonts. - Font metadata –
STAT(style-linking axis/value taxonomy),BASE(script baseline positions), named instances, OS/2 andposttypographic metrics (subscript/superscript, strikeout, underline, x-height).
Every method above is real, exercised by real fixture fonts, and covered by tests – see Verification for exactly how that's checked, not just claimed.
Every number and pixel below came directly out of taetype's own API calls – nothing here is a mockup, a hand-tuned SVG, or a number typed in by hand.
shape finds the 27 glyphs one real paragraph of body text actually uses out of Inter's (SIL OFL 1.1) 2,937 total, then subset throws away everything else – GSUB/GPOS included, rewritten rather than dropped.
Every glyph above is drawn individually at shape's own real advances – not a browser reshaping a real font on its own, which would only prove the font has ligatures, not that taetype computed them.
Each image is glyph_bitmap's actual return value on Noto Color Emoji (SIL OFL 1.1, CBDT/CBLC format) – a real PNG strike pulled straight out of the font, drawn with zero compositing.
The same glyph, instanced at three axis positions – the composited color layers render through instance()'s real, unmodified output, but the "dx" value under each column is colr_v1_paint's own resolved PaintVarTranslate offset, not read off the picture.
There's no browser math-layout engine to "secretly" do this instead – every position in this fraction comes from math_constants's real values on STIX Two Math (SIL OFL 1.1).
Everything below is a method on taetype::Font. A Font owns its own decoded table data and caches instancing/shaping/advance work internally – there's no global registry, so keep the value around however suits your program (a HashMap keyed by font name, a struct field, a Vec). All position/size values are in 1000 units-per-em, regardless of what units-per-em the source font actually uses, so numbers are comparable across fonts without extra scaling math on your end.
use taetype::Font;
let font_bytes = std::fs::read("MyFont.ttf")?;
let font = Font::from_bytes(&font_bytes)?;
// Shape real text – this is where ligatures and kerning actually get computed.
let shaped = font.shape("Hello, world", &[("wght", 400.0)], false)
.expect("font must be shapeable");
// Keep only the glyphs that string actually used.
let subset = font.subset(&shaped.glyphs, &[("wght", 400.0)])
.expect("subsetting must succeed");
// subset.ttf is a font file containing only those glyphs.Font::from_bytes(bytes: &[u8]) -> Result<Font, FontError>
Font::from_ttc(bytes: &[u8], index: usize) -> Result<Font, FontError>
Font::ttc_font_count(bytes: &[u8]) -> usizefrom_bytes loads a plain TTF/OTF file. from_ttc loads one member font out of a TrueType Collection (.ttc) by index – call ttc_font_count first to find out how many member fonts a collection holds.
family_name(&self) -> Option<String>
style(&self) -> &'static str // "normal" | "italic"
is_variable(&self) -> bool
upm(&self) -> u16
num_glyphs(&self) -> u16
name_string(&self, name_id: u16) -> Option<String>family_name/style read name/OS/2/head for the two most commonly needed identifiers. name_string is the general-purpose escape hatch for any other name table entry by ID (version, license, trademark, designer, manufacturer, typographic subfamily, and so on – see the OpenType name ID registry). upm is the font's real units-per-em – you generally don't need this, since every other method already normalizes to 1000 units-per-em for you.
ascender(&self) -> i32
descender(&self) -> i32
cap_height(&self) -> i32
bbox(&self) -> Vec<i32> // [xMin, yMin, xMax, yMax]
flags(&self) -> u32
italic_angle(&self) -> f64Whole-font metrics, scaled to 1000 units-per-em. flags is a PDF-style descriptor bitmask (fixed-pitch, serif, script, italic) computed from post/OS/2/head, useful if you're embedding the font somewhere that expects that convention.
typographic_metrics(&self) -> Option<TypographicMetrics>
// struct TypographicMetrics {
// x_height: i32, underline_position: i32, underline_thickness: i32,
// strikeout_size: i32, strikeout_position: i32,
// subscript: SubSuperMetrics, superscript: SubSuperMetrics,
// }
// struct SubSuperMetrics { x_size: i32, y_size: i32, x_offset: i32, y_offset: i32 }The OS/2 and post fields no other method surfaces: where underlines and strikeouts sit, and the recommended size/offset for synthesized sub/superscripts. x_height reads sxHeight, which only exists in OS/2 version 2 and later – it's 0 on older tables rather than a guess. None only when the font has no OS/2 table at all.
glyph_ids(&self, text: &str) -> Vec<u16>
glyph_id(&self, codepoint: u32) -> u16
has_glyph(&self, codepoint: u32) -> bool
variation_glyph_id(&self, base: u32, selector: u32) -> Option<u16>
advance_widths(&self, gids: &[u16], axes: &[(&str, f64)]) -> Vec<f64>
vertical_advance(&self, gid: u16, axes: &[(&str, f64)]) -> u32
measure_width(&self, text: &str, axes: &[(&str, f64)], font_size: f64) -> f64glyph_ids resolves each character of text through cmap in order (no shaping – see Shaping when ligatures/kerning matter); glyph_id is the single-codepoint version. has_glyph is a coverage check. variation_glyph_id resolves a Unicode Variation Sequence (a base codepoint plus a selector like U+FE0E/U+FE0F for text/emoji presentation) through cmap format 14; None means there's no override, so the plain glyph_id result already applies.
advance_widths/vertical_advance take an axes slice of (tag, value) pairs – &[("wght", 700.0)], &[("wght", 700.0), ("opsz", 32.0)], &[("wdth", 125.0), ("slnt", -10.0)], or any other axis a variable font defines, all work the same way. An axis left out of axes stays at the font's own default; this same convention applies to every axes parameter across the whole API. measure_width shapes internally when possible, so ligatures and kerning are reflected in the returned width, not just a naive per-character sum – it silently falls back to that sum only for the rare font rustybuzz can't open.
vertical_origin(&self, gid: u16) -> Option<i32>
default_vertical_origin(&self) -> i32VORG, the per-glyph vertical origin Y used for top-to-bottom (CJK) writing. Per spec, this only really applies to CFF/CFF2-outline fonts: for TrueType (glyf) outlines the value is derived instead from vmtx's top-side bearing plus the glyph's own bounding-box top, and an explicit VORG table on a glyf font is ignored, exactly as the spec requires. None covers "no vertical metrics at all," plus one genuine, permanent gap: a CFF/CFF2 font with no VORG table has no way to derive this value without interpreting its charstrings to compute a bounding box, which taetype's CFF path deliberately doesn't do (the CFF outline reader only ever draws charstrings, it never accumulates a geometry-derived box for this purpose) – a documented scope cut, not a bug. VORG now survives subset for CFF/CFF2 fonts too, same as TrueType.
axes(&self) -> Vec<FvarAxis>
// struct FvarAxis { tag: String, min: f64, default: f64, max: f64 }fvar's own axis definitions – the continuous range a caller needs to build something like an axis slider. Distinct from named_instances below, which only surfaces the font's preset design points, not the full range.
named_instances(&self) -> Vec<NamedInstance>
// struct NamedInstance { name: Option<String>, postscript_name: Option<String>, coords: Vec<(String, f64)> }The design presets a variable font ships as a menu (e.g. "Thin," "Bold," "Condensed Light"), read from fvar's named instances. name/postscript_name are None when the name table has no matching entry. Empty when the font has no fvar, or fvar has no named instances.
stat_info(&self) -> Option<StatInfo>
// struct StatInfo { axes: Vec<StatAxis>, values: Vec<StatAxisValue>, elided_fallback_name: Option<String> }
// struct StatAxis { tag: String, name: Option<String>, ordering: u16 }
// enum StatAxisValue {
// Single { axis_index: u16, name: Option<String>, value: f64, elidable: bool },
// Range { axis_index: u16, name: Option<String>, nominal: f64, min: f64, max: f64, elidable: bool },
// Linked { axis_index: u16, name: Option<String>, value: f64, linked_value: f64, elidable: bool },
// Combo { name: Option<String>, values: Vec<(u16, f64)>, elidable: bool },
// }STAT data: the axis/value taxonomy behind style-linking – which named values combine into a compound style name like "Condensed SemiBold Italic." StatAxisValue's four variants map directly to the OpenType spec's formats 1 through 4. None when the font has no STAT table.
base_info(&self, script_tag: &str, vertical: bool) -> Option<BaseScriptInfo>
// struct BaseScriptInfo { default_baseline_tag: Option<String>, baseline_coords: HashMap<String, i16> }BASE data: where a script's baselines (roman, hanging, ideographic, math, and so on) sit relative to each other, for the given writing direction. None when the font has no BASE table, no axis for that direction, or no entry for script_tag.
justification_glyphs(&self, script_tag: &str) -> Option<Vec<u16>>
justification_priorities(&self, script_tag: &str, lang_sys_tag: Option<&str>) -> Option<Vec<JstfModLists>>
// struct JstfModLists {
// shrinkage_enable_gsub: Option<Vec<u16>>, shrinkage_disable_gsub: Option<Vec<u16>>,
// shrinkage_enable_gpos: Option<Vec<u16>>, shrinkage_disable_gpos: Option<Vec<u16>>,
// extension_enable_gsub: Option<Vec<u16>>, extension_disable_gsub: Option<Vec<u16>>,
// extension_enable_gpos: Option<Vec<u16>>, extension_disable_gpos: Option<Vec<u16>>,
// // (shrinkage_jstf_max/extension_jstf_max: Option<usize> byte offsets exist too, unparsed – no consumer needs JstfMax's own embedded Lookup table yet)
// }JSTF data for your own line-justification logic. justification_glyphs returns the extender glyphs for a script (e.g. the Arabic kashida) that your own logic can insert or repeat to stretch a line. justification_priorities returns one JstfModLists per priority level, in the order they should be tried – see Shaping below for how to actually apply one via shape_justified. lang_sys_tag: None resolves the script's default language system; Some(tag) resolves a specific one.
shape(&self, text: &str, axes: &[(&str, f64)], vertical: bool) -> Option<ShapedRun>
// struct ShapedRun { glyphs: Vec<u16>, advances: Vec<f64>, clusters: Vec<u32> }Full GSUB/GPOS shaping via rustybuzz: ligatures, kerning, complex scripts, all resolved. clusters maps each output glyph back to the character index (not byte offset) it came from – use it for cursor placement or highlighting. Returns None only for fonts rustybuzz can't open; fall back to glyph_ids + advance_widths in that rare case.
shape_justified(&self, text: &str, axes: &[(&str, f64)], vertical: bool, mods: &JstfModLists, shrink: bool) -> Option<ShapedRun>Shapes with one JstfModLists priority level's GSUB/GPOS enable/disable lists applied, via a feature-tag toggling heuristic (shrink selects the shrinkage_* fields when true, extension_* when false). This bypasses the internal shape cache shape benefits from – if you're iteratively re-shaping to fit a line, cache the result on your own side.
instance(&self, axes: &[(&str, f64)]) -> Vec<u8>Turns a variable font into a full static instance at the given axis position – the whole sfnt, no subsetting. Works for both TrueType-outline and CFF2-outline variable fonts.
subset(&self, gids: &[u16], axes: &[(&str, f64)]) -> Result<SubsetResult, FontError>
subset_text(&self, text: &str, axes: &[(&str, f64)]) -> Result<SubsetResult, FontError>
// struct SubsetResult { ttf: Vec<u8>, gid_map: Vec<u16> }subset is the low-level tier: give it the glyph IDs a document actually uses (typically shape(...).glyphs) and it returns a font file containing only those glyphs plus everything GSUB/GPOS/GDEF need to keep working on them – GID-addressed, no cmap/name, suited to callers (like PDF embedding) that address glyphs directly by ID. gid_map is the old-to-new glyph ID remap for TrueType subsets; empty for CFF subsets, which blank out unused glyphs in place instead of renumbering. COLR (v0 and v1) and CPAL carry through automatically when present – every glyph a surviving color definition depends on (a v0 layer, a v1 PaintGlyph/PaintColrGlyph reference) is chased and kept too, not just the glyphs requested directly. CFF-flavored output is always a real sfnt-wrapped OTF now (never bare CFF program bytes), the same shape as TrueType output.
subset_text is the higher-level counterpart: give it real text instead of glyph IDs, and it resolves glyphs via the font's own cmap, then adds a minimal cmap + name back to the output – directly usable via @font-face or any other character-addressed consumer, not GID-only. Carries COLR/CPAL through the same way subset does.
outline_glyph(&self, gid: u16, pen: &mut dyn OutlinePen) -> Option<()>
pub trait OutlinePen {
fn move_to(&mut self, x: f32, y: f32);
fn line_to(&mut self, x: f32, y: f32);
fn quad_to(&mut self, cx: f32, cy: f32, x: f32, y: f32);
fn curve_to(&mut self, c1x: f32, c1y: f32, c2x: f32, c2y: f32, x: f32, y: f32);
fn close(&mut self);
}Draws one glyph's outline as a flat move/line/quad/curve stream, via your own pen implementation. Composite glyf transforms and CFF/CFF2 charstring interpretation are already fully resolved before your pen ever sees a call – you never need to handle nested components or subroutine calls yourself. None when the glyph has neither a CFF /CFF2 table nor glyf outline data.
This draws the font's own stored default-instance geometry directly, with no re-instancing – for a variable font, call instance(axes) first and load the result as its own Font to outline a specific axis position.
rasterize_glyph(&self, gid: u16, px: f32, axes: &[(&str, f64)]) -> Option<RasterizedGlyph>
// struct RasterizedGlyph { metrics: Metrics, bitmap: Vec<u8> }
// struct Metrics {
// xmin: i32, ymin: i32, width: usize, height: usize,
// advance_width: f32, advance_height: f32, bounds: OutlineBounds,
// }Rasterizes gid at px pixels-per-em into a grayscale, anti-aliased coverage bitmap – one byte per pixel, bitmap.len() == width * height, row-major, no padding. This runs through taetype's own outline reader and its own from-scratch CPU rasterizer (taerizer::cpu), so it works identically for TrueType and CFF/CFF2 glyphs, at any instanced axis position, with no third-party rasterizer dependency anywhere in the call chain. None when px <= 0.0 or the glyph has no outline data.
let rasterized = font.rasterize_glyph(gid, 32.0, &[("wght", 700.0)])
.expect("glyph must have outline data");
// rasterized.bitmap[row * rasterized.metrics.width + col] is that pixel's coverage, 0-255.glyph_bitmap(&self, gid: u16, target_ppem: u16) -> Option<GlyphBitmap>
// struct GlyphBitmap { png: Vec<u8>, ppem: u16, origin_x: i16, origin_y: i16 }Pulls the nearest-size real PNG strike from sbix (Apple) or CBDT/CBLC (Google) – whichever the font actually has. target_ppem picks the closest available strike, favoring the smallest one at or above your target for the sharpest result; if your target exceeds every available strike, you get the largest one instead. None when the font has neither table, or has no bitmap for this particular glyph.
colr_layers(&self, gid: u16) -> Option<Vec<ColrLayer>>
colr_layers_for_palette(&self, gid: u16, palette_index: u16) -> Option<Vec<ColrLayer>>
// type ColrLayer = (u16, u8, u8, u8, u8, bool); // (glyph_id, r, g, b, a, is_foreground)
palette_count(&self) -> u16
palette_info(&self) -> Vec<PaletteInfo>
// struct PaletteInfo { index: u16, light_safe: bool, dark_safe: bool, name_id: Option<u16> }colr_layers returns each COLR v0 layer for a glyph, colored from CPAL palette 0; colr_layers_for_palette is the same for any palette index a multi-palette CPAL table offers. is_foreground marks a layer meant to use the surrounding text color rather than a palette entry. None when the glyph has no COLR v0 layers. light_safe/dark_safe are always false and name_id always None for CPAL version 0, which carries no such metadata – that's the font not shipping the data, not a taetype limitation.
svg_glyph_document(&self, gid: u16) -> Option<String>Raw SVG XML for a glyph from an SVG table, returned as-is – no parsing, no scaling, no color-scheme handling on taetype's side, that's on you. None covers: no SVG table, no entry for this glyph, or a gzip-compressed document (a spec-legal option a small number of fonts use, deliberately not supported – it would pull in a DEFLATE implementation for a narrow case).
colr_v1_paint(&self, gid: u16, axes: &[(&str, f64)], palette_index: u16) -> Option<Paint>
enum Paint {
Solid { is_foreground: bool, r: u8, g: u8, b: u8, alpha: u8 },
LinearGradient { extend: u8, stops: Vec<ColorStop>, x0: f64, y0: f64, x1: f64, y1: f64, x2: f64, y2: f64 },
RadialGradient { extend: u8, stops: Vec<ColorStop>, x0: f64, y0: f64, r0: f64, x1: f64, y1: f64, r1: f64 },
SweepGradient { extend: u8, stops: Vec<ColorStop>, cx: f64, cy: f64, start_angle: f64, end_angle: f64 },
Glyph { glyph_id: u16, child: Box<Paint> }, // source outline used as a clip shape
ColrGlyph { glyph_id: u16, child: Box<Paint> }, // another base glyph's whole paint graph, already resolved inline
Layers(Vec<Paint>),
Transform { matrix: [f64; 6], child: Box<Paint> },
Translate { dx: f64, dy: f64, child: Box<Paint> },
Scale { sx: f64, sy: f64, center: Option<(f64, f64)>, child: Box<Paint> },
ScaleUniform { s: f64, center: Option<(f64, f64)>, child: Box<Paint> },
Rotate { angle: f64, center: Option<(f64, f64)>, child: Box<Paint> }, // degrees
Skew { x_angle: f64, y_angle: f64, center: Option<(f64, f64)>, child: Box<Paint> }, // degrees
Composite { source: Box<Paint>, mode: u8, backdrop: Box<Paint> },
}
// struct ColorStop { offset: f64, is_foreground: bool, r: u8, g: u8, b: u8, alpha: u8 }COLR version 1's full paint graph for a glyph, fully resolved against axes (variable paints) and palette_index – a recursive tree, not a flat layer list, since v1 supports gradients, transforms, and nested composition v0's flat layers can't express. Try this first; fall back to colr_layers/colr_layers_for_palette when it returns None (no COLR table, a v0-only table, or a v1 table where this particular glyph has no v1 paint – all three fall back the same way). extend: 0 = pad, 1 = repeat, 2 = reflect. Composite's mode is a Porter-Duff CompositeMode value. A pathological or malicious paint cycle (through ColrGlyph or ordinary nesting) resolves to None rather than hanging or crashing – recursion is depth-bounded internally.
math_constants(&self) -> Option<MathConstants> // all 56 fields, see below
math_italics_correction(&self, gid: u16) -> Option<f64>
math_top_accent_attachment(&self, gid: u16) -> f64
math_is_extended_shape(&self, gid: u16) -> bool
math_kern(&self, gid: u16, corner: MathKernCorner, height: f64) -> f64
math_glyph_variants(&self, gid: u16, vertical: bool) -> Option<MathGlyphConstruction>
math_min_connector_overlap(&self) -> Option<f64>Surfaces the OpenType MATH table's structured data. taetype doesn't lay out formulas itself – same "engine surfaces data" split as everywhere else in this API – a math-layout engine on your side consumes this.
math_constants returns all 56 fields as one struct, scaled to 1000 units-per-em – except the three percentage fields (script_percent_scale_down, script_script_percent_scale_down, radical_degree_bottom_raise_percent), which are percentages, not design-unit metrics, and cross unscaled. None when the font has no MATH table.
math_top_accent_attachment returns the spec's own real fallback for a glyph with no explicit attachment point – the glyph's geometrical center with respect to advance width – not a bare 0.
enum MathKernCorner { TopRight, TopLeft, BottomRight, BottomLeft }Both height and the returned kern value are in 1000-unit-per-em units. 0 when the glyph isn't covered or that corner has no kern data, matching the spec's own "a kerning amount of zero is assumed."
struct MathGlyphConstruction { assembly: Option<GlyphAssembly>, variants: Vec<MathGlyphVariant> }
struct GlyphAssembly { italics_correction: f64, parts: Vec<GlyphPart> }
struct GlyphPart { glyph_id: u16, start_connector_length: f64, end_connector_length: f64, full_advance: f64, is_extender: bool }
struct MathGlyphVariant { glyph_id: u16, advance: f64 }math_glyph_variants returns growable glyphs in the requested direction – vertical: true for tall parentheses/radicals, false for wide braces/arrows. is_extender marks parts that can be skipped or repeated to reach an arbitrary target size. None when the glyph has no construction data in that direction.
Per-MathValueRecord device-table pixel-rounding hints are dropped throughout, matching the spec's own guidance that an engine may ignore them – real fonts overwhelmingly don't rely on them.
struct FontError(/* private */);
impl std::error::Error for FontError {}
impl std::fmt::Display for FontError { /* human-readable message */ }Every fallible method returns Result<_, FontError>, and FontError implements the standard Error/Display traits, so ? and .to_string() both work the way you'd expect from any other Rust crate. Methods that can't meaningfully fail (a missing table just means "no data," not an error) return Option instead – None is the normal, expected outcome for "this font doesn't have that," not a signal something went wrong.
#![forbid(unsafe_code)] is enforced at the crate root – not a lint you can override locally, a hard compiler error on any unsafe block anywhere in this crate. Beyond that:
- 1,400+ unit and integration tests, covering every module from the CFF DICT number decoder up through the full GSUB/GPOS subsetting engine – real assertions against known-correct values, not just "doesn't panic" smoke tests.
- Differential testing against real fontTools (the Python reference implementation many other font tools are themselves validated against): decoding, instancing, and subsetting are checked byte-for-byte or value-for-value against fontTools' own output on real fixture fonts – variable fonts, CID-keyed CFF, COLR v0/v1, CBDT/sbix bitmaps,
MATHtables. These run behind a Python virtualenv dependency, so they're marked#[ignore]for a plaincargo testand run explicitly in CI/local verification. - Fuzzing – six
cargo-fuzz(libFuzzer) targets covering table extraction, TTC handling, subsetting, instancing,cmaplookup, and COLR v1 paint resolution, run against real font corpora with coverage tracking. Real bugs this surfaced (integer overflow from a negative CFF2 DICT operand, among others) are fixed with an explicit guard at the call site, not just patched over. - Property-based testing via
proptestfor invariants that hold across a whole input space, not just fixed test cases – e.g. "subsetting never panics, and the returned glyph ID map covers every requested glyph," checked against thousands of generated inputs, not one example. - Real sanitizer validation – demo and differential-test output fonts are checked with
opentype-sanitizer(OTS), the same sanitizer engine Chromium uses to reject malformed fonts, so "taetype's own tests pass" is never the only bar a generated font has to clear. - Mutation testing – targeted
cargo-mutantspasses on parsing/bounds-checking logic, confirmed at the call site with a code comment wherever a specific operator or branch was proven equivalent under mutation (not just "looks right").
MIT – see LICENSE.





