Skip to content

Text

Checked against 2994ef5 on 2026-11-10 by Capy (review pass: Subagent 124 and fable). The files it covers are unchanged since.

niso lays text out itself, with Parley, on every platform: line breaking, shaping, bidi, font fallback. Hosts get shaped glyph runs with each glyph’s position and draw them with the platform’s own rasterizer. Text in a niso app doesn’t come from UILabel or TextView, so it’s measured and wrapped exactly as the core says, which is what keeps layout the same everywhere and comparable to Chrome.

Each inline formatting context (a paragraph, a button’s label) is one native text view. The TEXT op carries its runs: font id, size, color, decorations, glyph ids and positions, and the text each run was shaped from (Render stream format).

  • Apple: draws the glyphs at the core’s positions.
  • Android: draws a run as text with drawTextRun where that shapes the same as the core did, so the platform applies the user’s settings (outline text under high-contrast text), and as glyphs otherwise.
  • iced: rasterizes the glyphs with swash into one bitmap per text node.

Fonts are the platform’s own system fonts plus the page’s @font-face fonts, so the same text can measure and wrap differently from one platform to the next unless the page brings its own fonts. system-ui resolves to the platform’s UI font, and the hosts publish the platform’s text styles as CSS (Platform style).

Text follows the user’s text size and bold text settings without the page doing anything: the host gives the core its scale (niso_dom_set_text_scale) and weights (niso_dom_set_font_weight_adjustment, niso_dom_set_system_font_weights), and every computed font size and weight changes while CSS lengths stay put (System settings).

Text drawn by niso can’t be selected or copied: no host offers selection, a context menu or the clipboard on page text. Native text fields (<input>, <textarea>) are the platform’s own, so selection, copy and paste, autocorrect and IME composition work in them as in any app, and their selectionStart, setSelectionRange and the rest are on main. IME input reaches nothing else: there are no composition events and contenteditable isn’t editable. Range and the Selection API (getSelection) are on the selection-range branch, not on main.

Widgets, Live Activities and notifications can’t take glyphs, so templates carry text as strings and the target lays it out itself (Surfaces).

Laying a block out with the platform’s own text engine (TextKit 2, StaticLayout) as an opt-in is designed but not built: Text layout driver is the spike and its measurements.