Skip to main content

Crate oxideav_scribe

Crate oxideav_scribe 

Source
Expand description

Pure-Rust font shaper + layout for the oxideav framework.

Scribe is a vector-only shaper: parse TTF / OTF tables → emit positioned vector glyphs as oxideav_core::Nodes. All pixel work — outline flattening, scanline anti-aliasing, alpha compositing — happens downstream in oxideav-raster.

Scope:

  • Shapercmap + GSUB type 4 (ligatures) + GPOS type 2 (pair kerning) + mark-to-base / mark-to-mark, enough for Latin / Cyrillic / Greek / basic CJK / Vietnamese / polytonic Greek.
  • Arabic contextual joining (round 7)shaping::arabic computes the joining form per character using the Unicode joining classes + an adjacency state machine; FaceChain::shape then translates Arabic letters into their Arabic Presentation Forms-B equivalents (U+FE70..U+FEFF) before cmap, so a font that ships the PF-B block (DejaVuSans, Noto Sans Arabic, Amiri) renders visually-correct contextual shapes — including LAM-ALEF ligatures via the existing GSUB pass.
  • Indic + Brahmic complex-script shaping (rounds 8 + 10 + 11 + 12 + 13)shaping::indic classifies Devanagari (U+0900..U+097F), Bengali (U+0980..U+09FF), Tamil (U+0B80..U+0BFF), Gurmukhi (U+0A00..U+0A7F), Gujarati (U+0A80..U+0AFF), Telugu (U+0C00..U+0C7F), Kannada (U+0C80..U+0CFF), Malayalam (U+0D00..U+0D7F), Oriya (U+0B00..U+0B7F), Sinhala (U+0D80..U+0DFF), Khmer (U+1780..U+17FF), Thai (U+0E00..U+0E7F), Lao (U+0E80..U+0EFF), and Myanmar / Burmese (U+1000..U+109F) codepoints into syllabic categories, segments runs into orthographic clusters, and applies per-script cluster transformations: pre-base matra reorder (a uniform mechanism across all scripts that have one) plus reph identification (the Indic core scripts; Tamil + Malayalam + Sinhala + Khmer + Thai + Lao are reph-disabled; Burmese identifies a kinzi NGA+Asat+Virama+Cons instead via RephKind::BurmeseKinzi). Khmer’s halant role is played by U+17D2 COENG which stacks subjoined consonants underneath the base; Thai + Lao have no halant and their pre-base vowels are already in storage order before their consonant. The FaceChain::shape pipeline applies the reorder before cmap so cmap-only fonts render simple clusters with the matra in the correct visual position. When the active face publishes a rphf GSUB lookup for the script, identified reph clusters get the leading RA glyph substituted to its reph-form and the halant glyph dropped via Font::gsub_apply_lookup_type_1. Round 11 wires cluster-position GSUB features (half / pref / blwf / abvf / pstf / pres / psts / abvs / blws). Round 13 adds a multi-glyph context-aware GSUB pass dispatching locl / nukt / akhn / cjct / init / haln via Font::gsub_apply_lookup_type_5 (Contextual) + gsub_apply_lookup_type_6 (Chained Context).
  • Variable fonts (rounds 9 + 14)Face::set_variation_coords / variation_axes / named_instances / is_variable surface the font’s fvar declarations; outlines flow through oxideav-ttf’s gvar interpolator. Shaper::with_variation_coords is the per-call override. Round 14 closes the metric-variation gap: Face::mvar() / metric_delta(tag), Face::hvar() / h_advance_delta(gid), Face::vvar() / v_advance_delta(gid), Face::stat() / stat_axes() / stat_axis_values() (with name_id(nid) resolving the human-readable label). Face::cff2() parses the CFF2 INDEX walker for presence + axis count + glyph count; full Type 2 v3 charstring evaluation with the blend operator is deferred.
  • Face::glyph_path / glyph_node — TrueType + OTF (CFF) outlines as oxideav_core::Path; CBDT/sbix colour bitmaps as Node::Image carrying a VideoFrame.
  • Shaper::shape_to_paths — vector text API: positioned (face_idx, Node, Transform2D) triples ready to compose into a VectorFrame. Each glyph is wrapped in a cache-keyed Group so the downstream rasterizer’s bitmap cache reuses the same memoised glyph across renders.
  • Face chain — multi-face fallback (primary → fallback chain), per-codepoint resolution.
  • Layout — line measurement + word-wrap (no bidi).
  • BiDi (rounds 186 + 191)bidi::bidi_class(c) returns the UAX #9 §3.2 normative bidirectional class for every code point scribe needs today (the 12 explicit-format controls, ASCII / Latin-1, Hebrew, four core Arabic blocks plus Syriac, Thaana, N’Ko, the two Arabic Presentation Forms blocks, and combining- mark NSMs); bidi::paragraph_level(text) implements UAX #9 rules P1 / P2 / P3, returning the paragraph embedding level (0 = LTR, 1 = RTL). bidi::split_paragraphs(text) is P1’s split (every type-B character is kept with the previous paragraph). Round 191 lands bidi::resolve_weak_types(classes, sos, eos), the §3.3.4 weak-type resolution pass (rules W1..W7) operating on one isolating run sequence in place: NSM inheritance (W1), EN-after-AL → AN (W2), AL → R (W3), single-separator-between-two-numbers collapse (W4), ET-adjacent-to-EN collapse (W5), leftover-separator neutralisation (W6), and EN-after-L → L (W7). Round 198 lands bidi::resolve_neutral_types(classes, embedding_level, sos, eos), the §3.3.5 neutral / isolate-formatting resolution pass (rules N1 + N2): every maximal NI run (B / S / WS / ON / LRI / RLI / FSI / PDI) collapses to a strong direction — matching neighbours via N1 (with EN / AN counting as R) or the embedding direction via N2. Round 204 lands bidi::resolve_implicit_levels(classes, embedding_level), the §3.3.6 implicit-level pass (rules I1 + I2): every character’s resolved type drives a per-character level adjustment per UAX #9 Table 5 (L stays at even, R goes +1; AN / EN go +2; under odd, L / EN / AN all go +1). Round 210 lands the §3.4 line-level pair: bidi::reset_trailing_levels(orig_classes, levels, paragraph_level) is rule L1 (separator + trailing whitespace + isolate-formatting characters reset back to the paragraph embedding level using the original class slice per §3.4) and bidi::reorder_line(levels) -> Vec<usize> is rule L2 (the progressive top-down reversal that produces a logical-to-visual permutation a renderer walks to emit glyphs in display order). Round 217 lands bidi::resolve_explicit_levels(classes, paragraph_level), the §3.3.2 explicit-level / override / isolate stack pass (rules X1..X9): produces a per-character embedding level + an override-rewritten effective-class slice + the X9-removed- character flag set, ready for X10’s isolating-run-sequence partition to feed the W / N / I phases. Round 227 lands bidi::process_paragraph(text, base_level) and the class-driven mirror bidi::process_paragraph_classes(classes, base_level), the §3 whole-paragraph driver that composes P → X → W → N → I in one call and returns a ParagraphBidi carrier carrying the paragraph level + the original classes + the X9-removed flag set + the resolved per-character level vector. The carrier exposes reorder_paragraph() (whole-paragraph L1 + L2 convenience) and reorder_line_range(start..end) (per-line variant for callers that have a line-breaker). Round 247 lands bidi::reorder_combining_marks(orig_classes, levels, &mut visual), the §3.4 rule L3 in-place permutation adjuster: every L2-reversed [NSM, …, NSM, base] block in the visual stream (identified by its strictly-decreasing logical indices) is reversed back to [base, NSM, …, NSM] so callers running a non-scribe mark-attachment policy get the spec’s “expects them to follow” alternative shape; the function is idempotent and ignores even-level (LTR) runs. Round 257 lands the §3.3.5 N0 bracket-pair pass: bidi::paired_bracket(c) is the BD14 / BD15 lookup for the six ASCII brackets ((), [], {}); bidi::bracket_pairs(chars, classes) runs the BD16 stack walk (63-deep, overflow → empty list, sort by opener); bidi::resolve_bracket_pairs(classes, pairs, embedding, sos) applies the N0 a / b / c / d cases in place (EN/AN counted as R for the inside-strong + preceding-strong walks, sequential ordering so inner pairs see the rewrites of outer ones, trailing-NSM inheritance per the §3.3.5 note); and bidi::process_paragraph_with_brackets(text, base_level) / process_paragraph_classes_with_brackets(classes, chars, base_level) are the §3 paragraph driver with N0 wired in between W7 and N1. The full Unicode BidiBrackets.txt table (the ~60 paired-bracket entries across the Mathematical Operators / CJK Symbols / Ornamental Brackets blocks) is not yet vendored under docs/text/unicode-bidi/; non-ASCII bracket pairs are deferred until the table lands. Round 268 lands the §3.4 L4 mirroring rule: bidi::mirrored_glyph(c) is the Bidi_Mirroring_Glyph acceptable-mirror-pair lookup for the same six ASCII brackets (an involution, None outside the seed set including the §3.4-excluded ornate parentheses U+FD3E / U+FD3F), and bidi::apply_mirroring(chars, levels) rewrites every odd-resolved-level (directionality R) position that has a mirror pair in place over the line’s logical character sequence. The wider BidiMirroring.txt pair table (mathematical operators, angle brackets, CJK bracket blocks) is deferred until that data file is vendored.

See README.md for a tour and the deferral list.

Re-exports§

pub use bidi::apply_mirroring;
pub use bidi::bidi_class;
pub use bidi::bracket_pairs;
pub use bidi::isolating_run_sequences;
pub use bidi::level_runs;
pub use bidi::mirrored_glyph;
pub use bidi::paired_bracket;
pub use bidi::paragraph_level;
pub use bidi::process_paragraph;
pub use bidi::process_paragraph_classes;
pub use bidi::process_paragraph_classes_with_brackets;
pub use bidi::process_paragraph_with_brackets;
pub use bidi::process_text;
pub use bidi::reorder_combining_marks;
pub use bidi::reorder_line;
pub use bidi::reset_trailing_levels;
pub use bidi::resolve_bracket_pairs;
pub use bidi::resolve_explicit_levels;
pub use bidi::resolve_implicit_levels;
pub use bidi::resolve_neutral_types;
pub use bidi::resolve_weak_types;
pub use bidi::split_paragraphs;
pub use bidi::BidiClass;
pub use bidi::BracketKind;
pub use bidi::ExplicitLevels;
pub use bidi::IsolatingRunSequence;
pub use bidi::LevelRun;
pub use bidi::ParagraphBidi;
pub use bidi::ParagraphSlice;
pub use bidi::TextBidi;
pub use bidi::MAX_DEPTH;
pub use color::Rgba;
pub use color::TRANSPARENT;
pub use color::WHITE;
pub use color_glyph::ColorGlyphBitmap;
pub use face::Face;
pub use face::FaceKind;
pub use face_chain::FaceChain;
pub use layout::reorder_line_visual;
pub use layout::run_width;
pub use layout::wrap_lines;
pub use layout::VisualLine;
pub use shaper::PositionedGlyph;
pub use shaper::Shaper;
pub use shaper::ShaperBuilder;
pub use shaping::bengali_category;
pub use shaping::bengali_feature_tags;
pub use shaping::burmese_category;
pub use shaping::burmese_feature_tags;
pub use shaping::cluster_boundaries;
pub use shaping::cluster_boundaries_with;
pub use shaping::compute_forms;
pub use shaping::devanagari_category;
pub use shaping::devanagari_feature_tags;
pub use shaping::feature_tags_for_run;
pub use shaping::gujarati_category;
pub use shaping::gujarati_feature_tags;
pub use shaping::gurmukhi_category;
pub use shaping::gurmukhi_feature_tags;
pub use shaping::joining_class;
pub use shaping::kannada_category;
pub use shaping::kannada_feature_tags;
pub use shaping::khmer_category;
pub use shaping::khmer_feature_tags;
pub use shaping::lao_category;
pub use shaping::lao_feature_tags;
pub use shaping::malayalam_category;
pub use shaping::malayalam_feature_tags;
pub use shaping::oriya_category;
pub use shaping::oriya_feature_tags;
pub use shaping::presentation_form;
pub use shaping::reorder_cluster;
pub use shaping::reorder_cluster_with;
pub use shaping::script_indic_tags;
pub use shaping::shape_text_with_font;
pub use shaping::shape_text_with_script_with_font;
pub use shaping::sinhala_category;
pub use shaping::sinhala_feature_tags;
pub use shaping::tamil_category;
pub use shaping::tamil_feature_tags;
pub use shaping::telugu_category;
pub use shaping::telugu_feature_tags;
pub use shaping::thai_category;
pub use shaping::thai_feature_tags;
pub use shaping::ClusterFlags;
pub use shaping::IndicCategory;
pub use shaping::JoiningClass;
pub use shaping::JoiningForm;
pub use shaping::ReorderRules;
pub use shaping::RephKind;
pub use shaping::Script;
pub use shaping::BENGALI_RULES;
pub use shaping::BURMESE_RULES;
pub use shaping::DEVANAGARI_RULES;
pub use shaping::GUJARATI_RULES;
pub use shaping::GURMUKHI_RULES;
pub use shaping::KANNADA_RULES;
pub use shaping::KHMER_RULES;
pub use shaping::LAO_RULES;
pub use shaping::MALAYALAM_RULES;
pub use shaping::ORIYA_RULES;
pub use shaping::SINHALA_RULES;
pub use shaping::TAMIL_RULES;
pub use shaping::TELUGU_RULES;
pub use shaping::THAI_RULES;
pub use style::synthetic_italic_shear;
pub use style::Style;
pub use style::DEFAULT_SYNTHETIC_ITALIC_DEG;
pub use style::ITALIC_ANGLE_EPSILON_DEG;

Modules§

bidi
Unicode Bidirectional Algorithm — UAX #9 character classes, paragraph-level resolution (rules P1 / P2 / P3), explicit-level / override / isolate stack (rules X1..X9), weak-type resolution (rules W1..W7), bracket-pair resolution (rule N0 — full normative BidiBrackets.txt table, Unicode 16.0), neutral-type resolution (rules N1 and N2), implicit-level resolution (rules I1 / I2), line-level reordering (rules L1 / L2 / L3), and bidi mirroring (rule L4 — full BidiMirroring.txt table, Unicode 16.0).
color
Small colour primitives used by the rasterizer + composer.
color_glyph
Color-glyph rasterizer — bridges oxideav_ttf::ColorBitmap (raw CBDT PNG bytes + per-glyph metrics) to a straight-alpha RGBA8 buffer.
face
Face — owning wrapper around oxideav_ttf::Font / oxideav_otf::Font plus per-face identity for the glyph-bitmap cache.
face_chain
FaceChain — ordered list of faces consulted in priority order when shaping. Round-2 fallback support: when the primary face doesn’t have a glyph for a codepoint, the chain walks down the list until one does, falling back to the primary’s .notdef only if no face provides a glyph.
layout
Single-line measurement + word-wrap helpers for round-1.
shaper
Text shaper: cmap → ligature substitution → pair kerning → mark-to-base attachment → mark-to-mark stacking → cursive attachment.
shaping
Script-aware shaping helpers layered on top of the cmap → GSUB → GPOS pipeline in crate::shaper.
style
Font request style — italic knob the shaper honours when emitting glyph paths.
variations
Variable-font metrics + style-attribute tables that scribe parses locally — MVAR, HVAR, VVAR, STAT, plus name table id resolution and the CFF2 INDEX walker.

Structs§

NamedInstance
One named instance (a pre-defined coordinate vector).
VariationAxis
One variation axis as published in the font’s fvar table. All values are in user-space units (Fixed 16.16 scaled to f32 here).

Enums§

Error
Errors emitted by the scribe pipeline.