Measure a dirty widget where its parent asked, not in a box its answer decided
A local redraw drew a dirty widget in the box it was placed in. When a reader decided that box from the widget's own answer -- an aligned span sized to its children, a text at the tail of a row, a scroll's content -- the old answer is a fixed point of measuring there whatever the content now says, so the layout had two stable answers and which one it reached depended on the tree's history. `tests/unsettled.rs` has the two shrunk cases: the four-widget aligned span, and a scroll placing a pass-through `SetSize` in a box the content decided, where the span under it was placed once and nothing at its own edge said so. `ActiveData::offered_px` keeps the pixel size of the box the parent first asked about the child in, whether through `known_len` or a first `place`, beside `px`, the box it drew against. A dirty widget whose size reads an axis on which some reader up its chain gave what it read a box other than the one it asked in is not drawn locally: the chain is marked and the parent of the highest such placement draws, since above it every box is a constraint rather than an answer. The walk goes up the whole reader chain because a pass-through hands a derived box down unchanged. `Scroll` read its box's length for the clamp through `px_len`, which records the reported size as depending on it, and it does not: its size is its content's. That made every scroll tick a size question asked in a derived box, at 34x the instructions. `Painter::px_len_for_draw` is the read that records nothing. Instructions per frame on the depth-8 rig against the previous head: `many` at 32 dirty 0.66M to 0.74M, at 130 dirty 27.7M to 26.5M, `resize` 15.8M to 15.0M, `scroll`, `repaint` and `size` unchanged. The shrinking fuzzer passes 200 trees at depth 7 in all four cases, the hundred-seed sweep passes, and the five reference renders and the resize render are byte-identical. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
65f68bbb8a
commit
02ff8c7454
6 files changed
+200
-51
No files matched your search
+5
-19
@@ -442,25 +442,11 @@ fn adding_and_removing_span_children_lands_where_growing_it_that_way_would() {
|
||||
}
|
||||
}
|
||||
|
||||
/// Reproduces a divergence that predates the position chain: laying a tree out
|
||||
/// again does not always land where growing it cold does.
|
||||
///
|
||||
/// Every one seen so far is a wrapping text on a span's *own* axis, where the
|
||||
/// two draws do not agree. The span measures the child in the whole box, the
|
||||
/// child shapes to that width and reports the width it used, the span then
|
||||
/// places it in exactly that width -- which is a length change, so the child
|
||||
/// shapes again, and its longest line is shorter than the box it was just
|
||||
/// given. Each pass narrows it, so where the tree ends up depends on how many
|
||||
/// passes it has had, and a warm tree has had a different number from a cold
|
||||
/// one. Layout is supposed to be a function of the state alone.
|
||||
///
|
||||
/// A span whose axis is not the wrap axis is stable, which is every real
|
||||
/// column of text, and why nothing else has run into this.
|
||||
///
|
||||
/// 7 of these 90 diverge on `db1751f`, before the chain; 30 do with it, since
|
||||
/// a placed child reaches the second shaping more often. Both numbers are the
|
||||
/// same defect, and it wants fixing where the two draws meet -- LAYOUT.md §4 --
|
||||
/// rather than anywhere in the chain.
|
||||
/// The same property over a hundred seeds and every scenario. What it has
|
||||
/// found so far was never where the trees disagreed: a text measured in a box
|
||||
/// it was not going to get, and a widget re-measured in a box its own answer
|
||||
/// had decided. `tests/shrink.rs` is how a seed from here becomes a tree
|
||||
/// small enough to read.
|
||||
#[test]
|
||||
#[ignore = "a hundred seeds, rather than the seven the others check"]
|
||||
fn a_long_run_of_seeds_agrees() {
|
||||
|
||||
Reference in new issue
Block a user