iris: Widget::draw reports the size it used, replacing desired_width/height

Implements LAYOUT.md end to end: one fn draw(&mut self, &mut Painter) ->
Size replaces draw + desired_width/desired_height on every widget in
iris/src/widget/, SizeCtx and Cache are deleted, and a moved widget
(Scroll, Offset) costs one move_offsets write resolved by a shared
resolve_move WGSL function in both shader stages -- O(1) regardless of
how many primitives are in its subtree, measured at 500 in the new
iris/src/layout_tests.rs (a plain unit test: UiRenderState touches no
GPU or window).

Five real bugs surfaced only by diffing iris/run-headless.sh screenshots
against the pre-change tree and are written up in LAYOUT.md's
"Deviations found during implementation": Aligned's provisional draw
composing painter.region() a second time through widget_within; Sized/
MaxSize reporting a capped size while still painting their child
unconstrained (fine under the old two-pass model, wrong once a parent
like Aligned draws before knowing the final size); a widget's
move_offsets parent link being unreadable from self.active while its
own ActiveData is still mid-construction; Painter::reposition needing
the child's *painted* footprint (its reported size, top-left anchored)
rather than its offered region; and a widget's move slot needing to be
reused in place across redraws, with its delta reset, rather than
reallocated.

All four iris/examples render pixel-identical to the pre-change tree.
cargo fmt/clippy/test clean across the workspace (18 tests: 14
pre-existing plus 4 new).

Co-Authored-By: Claude Sonnet <noreply@anthropic.com>
This commit is contained in:
irisandClaude Sonnet committed 2026-09-04 23:40:56 -04:00
1 parent e0a473e090
commit 1a6599e1b2
36 files changed
+1200 -593

No files matched your search

+18
View File
@@ -39,6 +39,24 @@ session spending an afternoon on them again.
- **Done**: E0 (toolchain), E1 (Masonry on android-view, which found the
keyboard gap — now explained, see below), I0a, I0b (iris builds on a
pinned nightly and runs), I1 (parley + glyph atlas).
- **Done, 2026-09-04: the `Widget::draw`/layout redesign (LAYOUT.md).**
`desired_width`/`desired_height`/`SizeCtx`/`Cache` are gone; every widget
in `iris/src/widget/` implements one `fn draw(&mut self, &mut Painter) ->
Size`. A moved widget (`Scroll`, `Offset`) now costs one
`move_offsets` write resolved by a shared `resolve_move` WGSL function in
both shader stages, independent of how many primitives are in its
subtree — measured at 500 in `iris/src/layout_tests.rs`, which also
covers the unchanged-frame, hit-test-after-move and mask-follows-move
pass conditions as plain unit tests (no GPU or window needed, since
`UiRenderState` touches neither). All four examples render
pixel-identically to before the change. See LAYOUT.md's "Deviations
found during implementation" for five real bugs the design's first draft
did not anticipate — worth reading before touching `Aligned`, `Sized`,
`MaxSize`, `Scroll`, or the move-slot lifecycle again. Not done: a
pixel-level screenshot check of a `Masked`-wrapped `Scroll` (no example
builds one yet — the numeric check in `layout_tests.rs` stands in), and
exercising `GpuTextures::grow_array` (a second atlas layer opening) under
load — see TEXTURES.md.
- **E1's keyboard gap is Masonry's `as_input_connection` returning `None`
(a TODO), not android-view or `EditorInfo`.** android-view's own demo
implements the `InputConnection` trait over a parley editor and gets