Defer a twice-asked widget's local redraw to its parent

A span asks a share child twice in one draw: in the room, whose answer
its slots rest on, and in the decided slot, whose cross-axis answer it
reads. The record keeps only the second question, so a local redraw that
found that answer unchanged never told the row that the first had --
seed 946 at depth 6, where emptying a fixed-height column turns it from
a share into a fixed width as wide as the row. A widget its parent asked
more than once in one draw now defers to that parent, like one whose
declared length changed. Pinned as
unsettled::emptying_a_column_the_row_asked_twice_asks_the_row_again.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
iris-aiandClaude Fable 5.1 committed 2026-09-18 18:29:58 -04:00
1 parent 3091fb86df
commit 0ef87ebfcf
4 files changed
+105 -3

No files matched your search

+81
View File
@@ -846,3 +846,84 @@ fn adding_text_to_a_reverse_row_keeps_its_shared_height() {
let (_, other, _) = build(&mut cold, true);
assert_eq!(warm.region(&shared), cold.region(&other));
}
/// Nine widgets, shrunk from seed 946 at depth 6. The column is a share of
/// the row while its rect has room to draw and a fixed width once it has
/// not, so the row asks it twice: in the room, where it answers a share,
/// and in its slot, where it answers its text's width. Emptying the column
/// changes only the first answer. A local redraw that asked only the second
/// question kept the row as it was; the column has to defer to the row.
fn plant_column_that_is_a_share_only_while_its_rect_fits(
h: &mut Harness,
emptied: bool,
) -> (Vec<WidgetId>, WeakWidget<Span>, Vec<StrongWidget>) {
let first = wtext(PARAGRAPH).size(16).wrap(true).add(&mut h.rsc);
let filler = rect(Color::CYAN.alpha(126)).add(&mut h.rsc);
let second = wtext(PARAGRAPH).size(16).wrap(true).add(&mut h.rsc);
let mut spare: Vec<StrongWidget> =
vec![filler.add_strong(&mut h.rsc), second.add_strong(&mut h.rsc)];
let mut children: Vec<StrongWidget> = vec![first.add_strong(&mut h.rsc)];
if !emptied {
children.append(&mut spare);
}
let column = Span {
children,
dir: Dir::DOWN,
gap: Px::ZERO,
}
.height(159)
.add(&mut h.rsc);
let left = rect(Color::MAGENTA.alpha(189)).add(&mut h.rsc);
let right = rect(Color::BLUE.alpha(0)).add(&mut h.rsc);
let row = Span {
children: vec![
left.add_strong(&mut h.rsc),
column.add_strong(&mut h.rsc),
right.add_strong(&mut h.rsc),
],
dir: Dir::RIGHT,
gap: Px::ZERO,
}
.add(&mut h.rsc);
let end = rect(Color::MAGENTA.alpha(189)).add(&mut h.rsc);
let root = Span {
children: vec![end.add_strong(&mut h.rsc), row.add_strong(&mut h.rsc)],
dir: Dir::LEFT,
gap: Px::ZERO,
}
.add(&mut h.rsc);
h.set_root(root);
(
vec![
first.id(),
filler.id(),
second.id(),
column.id(),
left.id(),
right.id(),
row.id(),
end.id(),
root.id(),
],
column,
spare,
)
}
#[test]
fn emptying_a_column_the_row_asked_twice_asks_the_row_again() {
let mut warm = Harness::new((900, 1200));
let (ids, column, _spare) =
plant_column_that_is_a_share_only_while_its_rect_fits(&mut warm, false);
warm.frame();
// Kept alive: dropping the last share of a widget frees its id.
let _removed: Vec<StrongWidget> = warm.rsc[column].children.drain(1..).collect();
warm.frame();
let mut cold = Harness::new((900, 1200));
let (cold_ids, _, _spare) =
plant_column_that_is_a_share_only_while_its_rect_fits(&mut cold, true);
cold.frame();
assert_same_regions(&warm, &ids, &cold, &cold_ids);
}