/** * The Unicode Bidirectional Algorithm (UAX #9), shared by the measurer and * every renderer the way `writingMode.ts` shares vertical orientation. * * Arabic and Hebrew run right to left, digits and Latin words inside them * left to right, and the order in which a line's pieces are painted follows * from the characters themselves: their `Bidi_Class`, the paragraph's base * direction and any explicit isolates (`:rtl[…]`, `:ltr[…]`, or the Unicode * controls U+2066–U+2069). {@link resolveParagraph} resolves a paragraph's * embedding levels (rules P2–P3, X1–X10, W1–W7, N0–N2, I1–I2); the line * functions apply L1 (trailing white space back to the paragraph level) and * L2 (reversal) to one line of it once the line breaker has cut it, so the * breaker works on the logical text and never needs to know about * direction. L3 (combining marks) is the shaper's business and L4 * (mirroring) is {@link mirroredChar}. * * Text is UTF-16: levels are kept per code unit, a surrogate pair's two * units always share one level, and the order functions return the index * of each code point's first unit. Characters rule X9 removes (embedding * and override controls, `BN`) get the level of the character before them, * so they never split a run; they paint nothing. * * Conformance: the full `BidiCharacterTest.txt` and `BidiTest.txt` of * Unicode 18 pass (see `__tests__/bidi.test.ts`). The data tables are in * `bidiData.ts`, generated by `scripts/gen-bidi-data.mjs`. */ import type { InlineDirection } from './parse/types.js'; /** A Unicode `Bidi_Class` (UAX #9 table 4). */ export type BidiClass = 'L' | 'R' | 'AL' | 'EN' | 'ES' | 'ET' | 'AN' | 'CS' | 'NSM' | 'BN' | 'B' | 'S' | 'WS' | 'ON' | 'LRE' | 'LRO' | 'RLE' | 'RLO' | 'PDF' | 'LRI' | 'RLI' | 'FSI' | 'PDI'; /** Every `Bidi_Class`, by its code in the data tables. */ export declare const BIDI_CLASS_NAMES: readonly BidiClass[]; /** A paragraph's base direction as configured: `auto` takes it from the * first strong letter (rules P2–P3), left to right when there is none. */ export type BaseDirection = 'ltr' | 'rtl' | 'auto'; /** A code point's Unicode `Bidi_Class`. */ export declare function bidiClassOf(cp: number): BidiClass; /** Whether a code point is a right-to-left letter (`Bidi_Class` `R` or * `AL`): Hebrew, Arabic, Syriac, Thaana, N'Ko, Adlam and the other * scripts written from right to left. Digits, punctuation and marks are * not, whatever text they sit in. */ export declare function isRtlScriptChar(cp: number): boolean; /** * Whether a paragraph needs the bidi algorithm at all: it holds a * right-to-left letter or a control that opens a right-to-left embedding, * override or isolate. Text without one, in a left-to-right paragraph, * resolves to even levels throughout and paints in logical order, so the * layout can skip the algorithm (and stays exactly as it was). Arabic-Indic * digits alone do not count: they run left to right. */ export declare function needsBidi(text: string): boolean; /** * The mirrored form of a character (`Bidi_Mirroring_Glyph`, rule L4): `)` * for `(`, `»` for `«`, `≥` for `≤`. A renderer paints it in place of the * character when the character's resolved level is odd and the font does * not mirror it itself (OpenType `rtlm`). A character without a mirror is * returned unchanged, as is anything longer than one code point. * * The ornate parentheses of Quranic text, U+FD3E ﴾ and U+FD3F ﴿, have no * mirror and are not paired brackets: Unicode 14 gave them their present * general categories (FD3F opens, FD3E closes, as they are written in * Arabic) and keeps them out of `BidiMirroring.txt` and `BidiBrackets.txt` * on purpose, so they always paint as they are encoded. */ export declare function mirroredChar(ch: string): string; /** The mirrored form of a code point (see {@link mirroredChar}), or the * code point itself when it has none. */ export declare function mirroredCodePoint(cp: number): number; /** A Unicode `Joining_Type` (ArabicShaping.txt): `D` dual-joining (most * Arabic letters), `R` right-joining (alef, dal, ra, waw…: joined only to * the letter before them), `L` left-joining, `C` join-causing (tatweel, * ZWJ), `T` transparent (harakat and other marks, skipped when deciding * what joins), `U` non-joining. */ export type JoiningType = 'U' | 'C' | 'D' | 'R' | 'L' | 'T'; /** A code point's Unicode `Joining_Type`. */ export declare function joiningTypeOf(cp: number): JoiningType; /** Whether a text holds a letter of a joining script: a character that is * dual-, right- or left-joining (Arabic, Syriac, N'Ko, Mongolian, Adlam…). * Join-causing characters alone do not count: a ZWJ also sits inside emoji * sequences. */ export declare function hasJoiningScript(text: string): boolean; /** * Whether the character starting at `index` is joined to the next * non-transparent character of `text` (cursive Arabic: the two letters * connect, so a cut, a style change or a kashida between them must keep * the connection). It joins when it joins forward (`D`, `L`, `C`) and the * next one joins backward (`D`, `R`, `C`); transparent marks between them * (harakat) are skipped. `false` at the end of the text, and when `index` * itself is a transparent mark. */ export declare function joinsWithNext(text: string, index: number): boolean; /** Whether any two characters of a text join (see {@link joinsWithNext}): * a word that must be measured, cut and painted as one shaped run. */ export declare function joinsLetters(text: string): boolean; /** The embedding levels of one paragraph, before any line is cut. */ export interface BidiParagraph { /** The paragraph's text, in logical order. */ readonly text: string; /** The paragraph embedding level: 0 left to right, 1 right to left. */ readonly paragraphLevel: number; /** Resolved embedding level of each UTF-16 unit (rules X1–I2; L1 is per * line, see {@link lineLevels}). Odd levels run right to left. */ readonly levels: Uint8Array; /** Each unit's original `Bidi_Class` code: what L1 reads. */ readonly classes: Uint8Array; } /** A stretch of a paragraph set as an isolate of its own direction (an * inline `:rtl[…]` / `:ltr[…]`), as if it were wrapped in RLI/LRI … PDI: * `[start, end)` in UTF-16 units. Isolates nest or are disjoint. */ export interface BidiIsolate { start: number; end: number; direction: 'ltr' | 'rtl'; } /** What the engine reads on top of UAX #9 when it resolves a paragraph. */ export interface BidiOptions { /** * The paragraph belongs to a document written in the Arabic script * (#665). Rule W2 reads European digits as an Arabic number when an * Arabic letter comes before them, so `شكل 3-1` orders its two numbers * from right to left, as `شكل ٣-١` does; the same number with no letter * before it (`3-1 الأبواب`, a heading's number, or `3-1` alone in a * contents column) would stay a left-to-right `3-1`, the 3 on the left, * and one book would print one number two ways. With this option a * European number that opens a right-to-left run (a paragraph, an * isolate) is read as the numbers after the document's letters are, as * an Arabic number: the start of the run counts as an Arabic letter for * rule W2. The digits of a number never change order; only how a * hyphen, a plus or a percent sign beside it joins it to the next * number. Left-to-right runs are not touched. */ arabicNumbers?: boolean; } /** * Resolve the embedding levels of one paragraph (UAX #9 up to I2). `base` * is the paragraph direction: `ltr`, `rtl`, or `auto` for the direction of * its first strong letter (left to right when it has none). `isolates` * sets stretches of the text as directional isolates, as if their bounds * held RLI/LRI and PDI controls (the inline `:rtl[…]` and `:ltr[…]`); the * text itself may also hold the Unicode controls. A paragraph separator * (`B`) ends the embeddings opened before it, as at the end of a paragraph; * callers split the text at paragraph breaks first (rule P1). `options` * are the engine's own readings on top of the algorithm * ({@link BidiOptions}); without them the result is UAX #9's. */ export declare function resolveParagraph(text: string, base?: BaseDirection, isolates?: readonly BidiIsolate[], options?: BidiOptions): BidiParagraph; /** A span of a parsed paragraph as {@link resolveSpans} reads it. */ interface DirectedSpan { text: string; direction?: InlineDirection; } /** * The isolates of a paragraph's spans (`InlineSpan.direction`, set by * `:rtl[…]` and `:ltr[…]`) as ranges of their joined text. Spans of one * isolate share its `id`; an isolate nested in another names it as `outer`. */ export declare function spanIsolates(spans: readonly DirectedSpan[]): BidiIsolate[]; /** {@link resolveParagraph} for a paragraph given as its spans: the text is * their texts joined, and their `direction` isolates apply. */ export declare function resolveSpans(spans: readonly DirectedSpan[], base?: BaseDirection): BidiParagraph; /** * The algorithm proper, on class codes. `text` (with `map` from class * positions to text positions, `-1` for a virtual control) gives the code * units the paired-bracket rule reads; without it no bracket pairs. * @internal Exported for the conformance tests (`BidiTest.txt` lists * classes, not characters). */ export declare function resolveClasses(cls: Uint8Array, baseLevel: number, text: string | null, map: Int32Array | null, /** {@link BidiOptions.arabicNumbers}. */ arabicLead?: boolean): { levels: Uint8Array; paragraphLevel: number; }; /** * The levels of one line of a paragraph, `[start, end)` in UTF-16 units, * after rule L1: segment and paragraph separators, and the white space and * isolate controls before them or at the end of the line, go back to the * paragraph level (a space that ends an Arabic line inside an English * paragraph sits at the line's right end, not inside the Arabic run). * Index 0 of the result is the line's first unit. */ export declare function lineLevels(par: BidiParagraph, start?: number, end?: number): Uint8Array; /** * Rule L2 on any sequence of items with levels (characters, or a line's * segments with the level of each): the indices of `levels[start..end)` * from left to right. Every run at or above each odd level is reversed, * from the highest level down. */ export declare function visualOrder(levels: ArrayLike, start?: number, end?: number): number[]; /** * The characters of one line of a paragraph in visual order, left to right * (rules L1 and L2): the index, in the paragraph's text, of each code * point's first unit. */ export declare function lineVisualOrder(par: BidiParagraph, start?: number, end?: number): number[]; /** A run of one level within a line: `[start, end)` in the paragraph's * text, painted right to left when `level` is odd. */ export interface BidiRun { start: number; end: number; level: number; } /** * One line of a paragraph as runs of one level each, in visual order (left * to right): what a renderer paints, each run shaped in its own direction * (an odd level is right to left). Rules L1 and L2. */ export declare function lineRuns(par: BidiParagraph, start?: number, end?: number): BidiRun[]; /** One run of a marker read at a right-to-left level ({@link markerRuns}). */ export interface MarkerRun { text: string; /** Where the run starts in the marker's text (its reading order). */ start: number; /** At an odd level: painted right to left, its brackets mirrored. */ rtl?: true; } /** * A marker that reads right to left (`VDTBlock.bulletDirection`) as the * runs a renderer paints, in visual order (from the sheet's left to its * right): `1-` gives the hyphen, then the number. Each run is one bidi * level (UAX #9, rules L1 and L2, at a right-to-left paragraph level); in * an Arabic-script document (`'rtl-arabic'`) European digits read as * Arabic numbers (#665). */ export declare function markerRuns(text: string, direction: 'rtl' | 'rtl-arabic'): MarkerRun[]; /** Whether a marker's order differs when its leading European digits read * as Arabic numbers (`BidiOptions.arabicNumbers`, #665). */ export declare function arabicMarkNeeded(text: string): boolean; /** * A marker that reads right to left as the one text a browser sets right * to left in that order ({@link markerRuns}): its own, with an Arabic * letter mark before it where an Arabic-script document reads its leading * European digits as an Arabic number (`3-1`, the 3 on the right). What * the canvas paints, the HTML writes and, in a document shaped in its own * language, the layout measures (#770). */ export declare function markerSetText(text: string, direction: 'rtl' | 'rtl-arabic'): string; export {}; //# sourceMappingURL=bidi.d.ts.map