Rendering and observations#
Two pipelines end in one scene. A native application's is semantic application state →
native page → layout → scene → optional RGBA. A web page's is HTML → DOM → cascade →
layout → paint → scene → optional RGBA, run by cw-web (see
architecture). Everything below the scene — hit testing, the semantic
observation, the rasterizer, the font stack — is shared, and structured-only observations
stop before rasterization in both. No Chromium process is involved in either.
cw-scene::Scene stores dimensions, background, revision, nodes and an optional
typeface. A node has a stable ID, integer bounds, primitive, optional semantic
role/label/value, interaction identifier, clipping, optional rounded_clip
({rect, radius}, honoured by hit testing), transform, z-order and opacity.
A client that round-trips scene JSON must carry typeface and rounded_clip
through, or it will silently lose font selection and window-corner clipping. A
UiText/UiTextBold node may carry its own typeface (omitted when absent), which
overrides the scene's for that node: browser pages whose theme names a font set every
text node in the family the list resolves to (cw_scene::fonts::resolve_family).
The twelve primitives are Box, RoundedBox, UiText, UiTextBold, Text,
AssetImage, Shadow, Image, Path, Symbol, Backdrop and Region
(invisible interaction area). Symbol is a tintable vector glyph; Backdrop is a
frosted-glass material. Affine coefficients use 1/1024 units; clipping is expressed
in scene coordinates.
The scene supplies deterministic flow layout. Text measurement is per-primitive:
UiText/UiTextBold are measured proportionally from the generated advance tables
in cw-scene::metrics, with word wrapping and ellipsizing; the Text primitive
(terminals, editors) keeps fixed-cell measurement and its golden pixels for plain
rows. UiText/UiTextBold take two optional fields, omitted from scene JSON when
unset so existing scenes serialize unchanged: italic (bool) and lang ("zh-Hans",
"zh-Hant", "ja", "ko"), which picks regional Han forms. cw_scene::Style
(bold, italic, lang) is what the metrics functions take; a plain bool still means
bold.
Pair kerning: the web faces (Typeface::WEB — Arimo, Tinos, Carlito, Caladea, Lato,
Source Sans 3, Source Serif 4, Montserrat and Playfair Display; Cousine, JetBrains
Mono, Gelasio and Poppins have no kern pairs) kern as Chromium does.
metrics::kern(typeface, style, left, right, size) is the adjustment between two
adjacent characters in the same 1/64 px as advance (kern_units gives it in font
units), and text_width, wrap, ellipsize and text::layout all add it, so the
renderer, which places a run's glyphs from text::layout, draws a kerned run exactly
as wide as it measures. The platform faces and DejaVu (Inter, OpenSans, Ubuntu,
Roboto, DejaVu, Mono) are not kerned: the desktop shells and apps were laid out,
and their golden frames pinned, on plain advances, and the bundled subsets carry no
GPOS for the renderer to have applied. The web engine turns kerning off for a run
with a non-zero letter-spacing, as CSS requires.
Hit testing uses transformed coordinates, clipping, disabled state and z-order;
later nodes win equal-z ties. It operates without generating pixels.
ScenePatch applies upserts, removals and background changes against an expected
revision and produces damaged rectangles. Invalid revision/duplicate-ID updates
are rejected atomically. The rasterizer can use damage to update the existing
frame; compare full and incremental output in tests when adding primitives.
Thirty-five font files are embedded, not one: DejaVu Sans, Sans Bold, Sans Oblique,
Sans Bold Oblique and Sans Mono; regular, bold, italic and bold italic Inter, Open
Sans, Roboto and Ubuntu for the per-platform shells; and regular and bold Noto Sans
Hebrew, Arabic, Thai, Devanagari, Bengali, Georgian and Armenian. The CJK faces (Noto
Sans SC and KR in two weights, and Traditional Chinese, Japanese and Korean locale
forms), Noto Emoji, Noto Color Emoji and eight further scripts form a font pack that
native builds embed and the Wasm build fetches on demand. They ship under three
licenses (DejaVu, SIL OFL 1.1 and the Ubuntu Font Licence 1.0); all notices are in
crates/graphics/render/assets, which is the authoritative list and
documents the fallback chain, italics, colour emoji, locale forms and the pack.
UiText is laid out by cw_scene::text: a deterministic fallback chain, Unicode
bidirectional reordering (right-to-left paragraphs and mixed runs), OpenType shaping
with rustybuzz (Arabic joining and lam-alef, Indic reordering and conjuncts, Thai
and Hebrew mark attachment, emoji ZWJ/flag/keycap/skin-tone ligatures) and line
breaking between CJK characters with kinsoku. Scene metrics and the renderer share
that one layout, so measured widths, wraps and ellipses are exactly what is drawn.
Emoji draw in colour from Noto Color Emoji's COLRv1 tables, painted by the renderer's own deterministic COLR rasterizer (gradients, clip boxes, transforms and composite modes), identically natively and in Wasm; the monochrome glyphs remain the fallback while the colour file is absent.
Scene layout is a deliberately smaller system than the web engine above it: it is flow
layout for native pages, and it does not claim CSS, vertical or justified text or
browser compositor compatibility. Native applications should be designed for that
contract. Web pages are not: they go through cw-web, which is where CSS, the DOM and
script live, and which is what every crates/services/* site is written against. The limits
that remain — no vertical writing modes, no synthetic italics where a face lacks a
slant — are listed with the supported property table in
crates/web/engine/src/style/properties/mod.rs and enforced for authored sites by
html::validate_strict.
Benchmarks must distinguish layout, scene patching, rasterization, readback and image encoding. See performance for reproducible commands and comparison limits; lower scene-update time alone does not establish faster full pixel production.
Raster details: source-over compositing uses straight RGBA. Image uses nearest
neighbour sampling; AssetImage larger than 256x256 (wallpapers) uses a centred,
aspect-preserving crop with bilinear filtering. Polygon paths support fills and
strokes, antialiased. fontdue is pinned and uses the bundled fonts.
Glyph/text-mask caches are bounded. The checked raster API rejects frames above
16,777,216 pixels. Text wraps and ellipsizes on measured advances for UiText, on
fixed cells for Text, with fallback for unavailable glyphs. Text lays out as a
terminal does (cw_scene::text::terminal): grapheme clusters in cells, combining
marks in their base's cell, East Asian wide characters and emoji across two cells,
right-to-left runs reordered within each row (VTE's implicit bidi mode) and script
runs shaped, so Arabic joins cell by cell.
OS desktop scenes#
The optional native OS presentation composes application scenes
with deterministic desktop/mobile chrome in Rust. UiText is proportional and picks
its face from Scene::typeface — Inter, Open Sans, Ubuntu or Roboto per platform,
DejaVu Sans as the fallback — or from its own typeface, which may also be one of the
thirteen web families (Arimo, Tinos, Cousine, Gelasio, Carlito, Caladea, Lato, Source
Sans 3, Source Serif 4, Poppins, Montserrat, Playfair Display, JetBrains Mono; see
crates/graphics/render/assets/README.md, "Web faces"). RoundedBox supplies antialiased rounded surfaces with
matching hit tests. Existing Text and its golden pixels remain unchanged. Application nodes
can now have translated scene coordinates inside window content clips. The mouse pointer
is part of a desktop frame: a Path glyph at the last pointer position, shaped for what is
under it (see Pointer); phones draw none.