1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
//! 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>)` where
//! `MeasureFn` is 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.
//! - `TaffyEngine` owns a `HashMap<u32, Box<dyn MeasureFn>>` keyed by dom
//! node id. `calculate` passes a single closure to
//! `compute_layout_with_measure` that dispatches into that map.
//! - M1-4 wires real measurement by calling `set_measure` and 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`:
//!
//! ```text
//! const x = offsetX + yogaNode.getComputedLeft(); // line 129
//! const y = offsetY + yogaNode.getComputedTop(); // line 130
//! ```
//!
//! Ink 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):
//!
//! 1. Disable taffy's rounding (`TaffyTree::disable_rounding()` in
//! `TaffyEngine::new`); `tree.layout()` then returns unrounded floats.
//! 2. After `compute_layout_with_measure`, run a faithful port of
//! `roundLayoutResultsToPixelGrid` / `roundValueToPixelGrid`
//! (`taffy_engine.rs` `round_node` / `round_value_to_pixel_grid`),
//! specialized to `pointScaleFactor == 1.0`, in f64 with yoga's
//! `inexactEquals` epsilon (`0.0001`). The recursion carries *unrounded*
//! absolute offsets; positions round from the parent-relative value;
//! dimensions round as `round(absRight) - round(absLeft)`. Nodes with a
//! registered measure fn are treated as yoga `NodeType::Text` (floored, not
//! rounded down, so glyphs are never truncated).
//! 3. 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`/`y` are `i32`
//! (parent-relative, can be negative with margins); `width`/`height` are
//! `u16` (terminal cells fit).
pub use ;
pub use TaffyEngine;