docs: the transcript's edges were three faults, and what the rig found
IRIS_TODO's 2026-09-07 top-edge entry closed with the root cause of each, the six layer-1 test names, and what was suspected and turned out not to be it -- no culling test compared a row's top against the viewport's, and 03c6be8's header duplicate is untouched and still open. The later report's "you shouldn't be able to scroll below the bottom (or above top)" is ticked with why the clamp is a correction measured from the layout walk rather than a clamp inside the scroll setter: nothing at the moment of a scroll knows where the content ends. RUST.md gains the same account in "Where things stand", plus the three things this said about the new test rig -- layer 1 found all of it in seconds and the emulator was not used; layer 2 is where the missing clip is visible, with the command; and an assertion that reads the wrong thing hides the bug it is for, which is how a list resting 1398px past its own first row passed a test about stopping at that row. Also the last of the six tests, the bottom end of the clamp (`scrolling_past_the_last_row_settles_on_it`) -- the same rule at the edge the top-edge work had no reason to touch.
This commit is contained in:
1 parent
e922b73d7a
commit
690161e5e9
3 files changed
+134
-5
No files matched your search
+55
-3
@@ -934,7 +934,7 @@ do not duplicate it there.
|
||||
|
||||
## From the phone, 2026-09-07 (build from ed04d4c)
|
||||
|
||||
- [ ] **"Some transcript blocks will be hidden until I uncover enough of
|
||||
- [x] **"Some transcript blocks will be hidden until I uncover enough of
|
||||
them."** Two screenshots of the bench app's transcript at the top
|
||||
edge, both wrong in opposite directions: in one, rows scrolled above
|
||||
the viewport are still drawn and bleed *through* the header bar
|
||||
@@ -956,10 +956,62 @@ do not duplicate it there.
|
||||
drawn if any part of it intersects the viewport, and the viewport is
|
||||
the list's own region.
|
||||
|
||||
**Done, e922b73 + d507ae4.** Three causes, and the rule above is what
|
||||
they are all fixed with (`List::intersects_viewport`).
|
||||
`iris/transcript-fixture/tests/top_edge.rs` is the layer-1
|
||||
reproduction -- the real screen under a bench-app-shaped header --
|
||||
and each test was confirmed to fail on its own subject and no other.
|
||||
|
||||
1. *Drawn over the header*: **nothing was clipping the list at all**,
|
||||
and a row straddling an edge is drawn in full, so the part above
|
||||
the list was on screen. It could not be `.masked()` before, either:
|
||||
`Painter::set_mask` aborted when an ancestor already had a mask,
|
||||
and the list's own rows use `.masked()` (a code fence, a tool
|
||||
card's title). So masks nest now -- `Mask::parent`, walked in the
|
||||
fragment stage, chained rather than intersected on the CPU because
|
||||
each mask moves with its own widget. `the_list_is_clipped_to_its_
|
||||
own_box`.
|
||||
2. *Rows already scrolled past still drawn*: the layout walk runs from
|
||||
the anchor, `scroll` moves the anchor's offset and nothing else, so
|
||||
panning leaves the anchor's row further and further outside the
|
||||
viewport and **every row between it and the viewport was drawn,
|
||||
every frame** -- measured at 64 rows for a 2012px viewport after 8
|
||||
scrolls of 3000px. `place` skips a row whose known box does not
|
||||
overlap, and `rehome_anchor` puts the anchor back on a visible row
|
||||
each frame without moving anything drawn.
|
||||
`rows_that_have_left_the_viewport_are_not_drawn`.
|
||||
3. *The blank band*: not a culling rule at all -- the list could rest
|
||||
**past its own first row** (`fling_toward_the_start_stops_at_the_
|
||||
first_row` was leaving it 1398px below a 600px viewport, a blank
|
||||
screen, and that test's own assertion could not see it).
|
||||
`clamp_to_content` gives the gap back. Both ends:
|
||||
`scrolling_past_the_first_row_settles_on_it`,
|
||||
`scrolling_past_the_last_row_settles_on_it`. This is also the first
|
||||
item of the later report below.
|
||||
|
||||
What was suspected and is *not* what happened: the visible-range test
|
||||
never compared a row's top against the viewport's top (there was no
|
||||
culling test at all), and `03c6be8`'s header duplicate is untouched by
|
||||
any of this -- it stays open. A row straddling the top edge is drawn
|
||||
both before and after; the test that would catch that mistake
|
||||
(`the_row_across_the_top_edge_is_drawn`) is in place, and fails if the
|
||||
rule is written against the row's top instead of its bottom.
|
||||
|
||||
## From the phone, 2026-09-07, later (build from 4274b8b, ai-app-bench b47eb73)
|
||||
|
||||
- [ ] **"You shouldn't be able to scroll below the bottom (or above
|
||||
top)."** The list's offset is not clamped to its content range while
|
||||
- [x] **"You shouldn't be able to scroll below the bottom (or above
|
||||
top)."** Done in e922b73, as `List::clamp_to_content` rather than as a
|
||||
clamp inside the scroll setter: nothing at the moment of a `scroll`
|
||||
call knows where the content ends (that is what walking the rows finds
|
||||
out), so the correction is measured from the ends the layout walk
|
||||
already placed and written to the anchor. In the app that lands in the
|
||||
same frame -- a scrolled list is dirty, and `redraw_updates` drains
|
||||
the mark the correction sets before the frame is submitted -- so
|
||||
nothing displaced is displayed; only a full-tree redraw (a resize)
|
||||
could show one frame of it. A fling that reaches an end already ends
|
||||
there (`tick_fling`'s `hit_bound`), and now stops *on* the end rather
|
||||
than wherever the spline's last step had put it. Layer-1 tests at both
|
||||
ends, listed in the item above. The list's offset is not clamped to its content range while
|
||||
dragging and/or flinging. Compose's `LazyColumn` never moves content
|
||||
past its ends -- the overscroll *effect* on Android 12+ is a stretch
|
||||
drawn over clamped content, not a displacement. Clamp the offset in
|
||||
|
||||
Reference in new issue
Block a user