pub fn build_layout_engine(
arena: &Arena,
root_id: u32,
width: u16,
) -> Option<(TaffyEngine, Rect)>Expand description
Build a fresh layout engine for the arena tree rooted at root_id, compute
layout at the given width, and return the built engine plus the root rect.
This is the M3-A engine-lifetime seam (ADR-3,
docs/adr3-engine-lifetime.md) — the public entry InkRoot
(inkferro-napi, M3-D) calls each render_frame. render_to_string calls
it as step 1 of its own body, so the two paths cannot drift. It is the single
place the taffy tree is constructed, so callers cannot accidentally re-run
node creation against a populated engine (which would duplicate child lists —
insert_child appends).
It is pub (not pub(crate)) because the consumer lives in a different
crate (inkferro-napi). Returning the concrete TaffyEngine — rather than
impl LayoutEngine — lets InkRoot store it as a named field and read
computed(id) later (still via the LayoutEngine trait). This deliberately
names the concrete backend across the napi boundary; the ADR-1
LayoutEngine-trait seam still governs behavior, and a backend swap would
change only this return type in one place.
Returns the built-and-computed engine so a single per-frame build serves
both the render walk (M3-E reads engine.computed(id) as the rect accessor)
and measure(id) (M3-F reads engine.computed(id) from the same stored
build) — no second rebuild.
§Per-frame rebuild (ADR-3 Option A)
Always allocates a fresh TaffyEngine. Persistence is the Arena’s job; the
engine is a pure function of the arena at render time. A fresh engine
re-set_measures every text node, satisfying the measure-invalidation
discipline (layout/engine.rs:78-82) for free.
Returns None if calculate fails (e.g. an inconsistent tree); the caller
renders an empty frame, matching the prior render_to_string error path.