1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
//! Pure-Rust font shaper + layout for the
//! [oxideav](https://github.com/OxideAV) framework.
//!
//! Scribe is a **vector-only shaper**: parse TTF / OTF tables → emit
//! positioned vector glyphs as [`oxideav_core::Node`]s. All pixel
//! work — outline flattening, scanline anti-aliasing, alpha
//! compositing — happens downstream in
//! [`oxideav-raster`](https://github.com/OxideAV/oxideav-raster).
//!
//! Scope:
//! - **Shaper** — `cmap` + 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.
pub use ;
pub use ;
pub use ColorGlyphBitmap;
pub use ;
pub use FaceChain;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
/// Errors emitted by the scribe pipeline.