iris: the composer scrolls on a finger -- a dp cap worth zero, a stale mask slot, a hit box moved twice

Wrapping the composer's field in .scrollable().masked() needed three
layout defects fixed first, each with a headless regression test that was
confirmed to fail without its fix:

- MaxSize/Sized reported a caller's declared dp length unresolved, and
  Span places a child from the abs/rel of what it reported, so dp(168)
  was worth zero: the bar got a slot of nothing the moment its content
  passed six lines and the Scroll inside measured its container at -63px
  (container=-63 content=415.8 amt=478.8 on the emulator). Len::fold_dp,
  used on the way out, plus a debug_assert in draw_inner that a reported
  Size carries no dp -- the rule is about every widget, not those two.
- Masked allocated a fresh mask slot per draw, and draw_inner's
  unchanged-region fast path does not revisit descendants, so they kept
  clipping against a box the bar had moved away from: four live mask
  entries, none of them current, and the field drew nothing.
  ActiveData::own_mask, allocated once and rewritten in place.
- mov updates active.region and accumulates the same delta on the move
  slot, and resolved_region added both, so a panned widget's own hit box
  sat at twice the pan -- the composer's field was untappable after a
  drag. ActiveData::move_applied.

Scroll itself measured the right number by a misleading route; it is
written against painter.px_size() now and still reports its content's
size, since reporting the container makes the answer a function of
itself.

Verified on this checkout's emulator: swipe 540 1200 -> 540 1460 moved
the field's Message box 31,1041..1048,1509 -> 31,1131..1048,1651 with its
height unchanged at 468px.

run-bench.sh polled logcat for a prefix copy_report also logs at startup,
so it printed a report that had never been run.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
irisandClaude Fable 5.1 committed 2026-09-06 17:17:42 -04:00
1 parent d73db97629
commit 167862ca1b
14 files changed
+567 -39

No files matched your search

+25
View File
@@ -5,6 +5,31 @@ they can be judged and reversed later. Detail lives in RUST.md (and IRIS.md
for iris API changes); this file is only the summary. Newest first. Items
marked **DEFERRED** are ones the agent chose not to decide alone.
## 2026-09-06 (composer scroll and the streaming block model)
- **A streamed message becomes a column of per-block widgets.** Decided by
the design agent; recorded here because it is the shape of every message
on screen. A transcript row is one `TextEdit` today, so a streamed delta
re-shapes the entire message through parley on every event -- the stream
phase is the one place iris is behind Compose on your phone (p50 18.2ms
vs 13.4ms). A row becomes a column of one widget per markdown block
(paragraph, heading, fence, list, table) and a delta replaces only the
last block, keeping every earlier block's layout. **Rejected:** splitting
parley's layout at block boundaries inside one text widget (couples
iris's text widget to markdown structure, and parley has no incremental
API), and caching shaped runs per paragraph inside `TextEdit` (a second
cache with its own invalidation beside the glyph cache). Chosen because
P1's markdown block model is needed anyway, so the split happens once, in
`client-core`, and iris stays a text renderer. **Status: designed, not
built** -- this pass spent its budget on the composer's three layout
defects; docs/RUST.md has the design and the pass conditions.
- **The composer's overflowing text now scrolls on a finger**, capped at
six lines and clipped to the bar. Reverses the "still does not scroll"
item below.
- **A widget may not report a `dp` length** (see IRIS.md). A rule for
widget authors, enforced by a `debug_assert!`; nothing changes for app
code.
## 2026-09-06 (stale-primitives and touch-scroll pass)
- **A vertical drag inside a focused composer now scrolls rather than