Expand description
Layout engine trait and Taffy backend.
§Design decisions
§Trait surface (plan adaptation)
The plan listed set_measure(id, …) as part of the trait. Taffy 0.10’s
measure story is a closure passed to compute_layout_with_measure rather
than a per-node callback registered up-front (see taffy_tree.rs:905-922
and the measure.rs example). Putting set_measure on the trait would
force every backend to own a registry, but the signature of the stored
function is backend-specific. Therefore:
- The trait has
set_measure(id, Box<dyn MeasureFn>)whereMeasureFnis a type alias for the concrete closure shape that taffy needs. Any yoga-ffi backend that has the same terminal-cell measure contract can implement the same trait. If a future backend needs a different shape, the trait gets a second method; that is the narrowest breaking change possible. TaffyEngineowns aHashMap<u32, Box<dyn MeasureFn>>keyed by dom node id.calculatepasses a single closure tocompute_layout_with_measurethat dispatches into that map.- M1-4 wires real measurement by calling
set_measureand does NOT need to touch the trait definition.
§Rounding (yoga-compatible pixel-grid post-pass)
render-node-to-output.ts:129-130 uses the yoga-computed values directly
as array column/row indices, with no Math.round/floor/ceil:
const x = offsetX + yogaNode.getComputedLeft(); // line 129
const y = offsetY + yogaNode.getComputedTop(); // line 130Ink trusts yoga’s own pixel rounding, which yoga applies after the flex
solve in roundLayoutResultsToPixelGrid (yoga 3.2.1
yoga/algorithm/PixelGrid.cpp). Taffy 0.10 also rounds when
use_rounding = true, but with a different rule (cumulative
round-half-away in compute::round_layout, taffy compute/mod.rs:219).
That difference produces ±1 divergences against the ink oracle on tie-breaks
(e.g. a 3.5-cell leading space: yoga floors a text node’s position to 3,
taffy rounds to 4) and on text-node sizing.
We therefore (M1-7):
- Disable taffy’s rounding (
TaffyTree::disable_rounding()inTaffyEngine::new);tree.layout()then returns unrounded floats. - After
compute_layout_with_measure, run a faithful port ofroundLayoutResultsToPixelGrid/roundValueToPixelGrid(taffy_engine.rsround_node/round_value_to_pixel_grid), specialized topointScaleFactor == 1.0, in f64 with yoga’sinexactEqualsepsilon (0.0001). The recursion carries unrounded absolute offsets; positions round from the parent-relative value; dimensions round asround(absRight) - round(absLeft). Nodes with a registered measure fn are treated as yogaNodeType::Text(floored, not rounded down, so glyphs are never truncated). - Store the rounded, parent-relative integer rects keyed by dom id;
computed()returns from that map (falling back to the live taffy layout only for a node that was never laid out).x/yarei32(parent-relative, can be negative with margins);width/heightareu16(terminal cells fit).
Structs§
- Rect
- The computed position and size of a node in terminal cells.
- Taffy
Engine - Taffy 0.10 backend.
Traits§
- Layout
Engine - Stable interface over a layout backend.
Type Aliases§
- Measure
Fn - A measure function for a leaf node.