Judge a kept contract against the box it was asked in

A local redraw keeps the narrower guarantee its parent holds when the new
drawing covers it, so widening and narrowing back do not churn the parent.
It checked that guarantee against `placement`, where the answer put the
drawing, rather than `region`, the box the drawing was made in and the box
both contracts are about. The two differ on every axis a widget reported
less than it was offered, so any such widget escalated to its parent every
time its contract widened -- which is the churn the retention exists to
avoid. `resize` and `try_reuse` both already ask about `region`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
iris-aiandClaude Opus 5 committed 2026-09-20 00:18:18 -04:00
1 parent aea0387567
commit 713e3e747b
2 files changed
+60 -1

No files matched your search

+4 -1
View File
@@ -1102,8 +1102,11 @@ impl UiRenderState {
{
active.answer = was_answer;
}
// Against the box it was asked in, which is what both contracts are
// about. Where the answer put the drawing is shorter than that
// wherever the widget reported less than it was offered.
if active.holds.covers(was_holds)
&& was_holds.contains(self.output_size, active.rel_base, active.placement)
&& was_holds.contains(self.output_size, active.rel_base, active.region)
{
active.holds = was_holds;
}
+56
View File
@@ -1477,3 +1477,59 @@ fn a_redrawn_subtree_is_not_undrawn_by_the_parent_it_left() {
assert_eq!(h.region(&leaf), before);
}
}
/// A leaf that reports less than the box it is given and states which lengths
/// of that box its drawing holds for, so a test can widen the contract
/// without changing the answer.
struct Contracted {
holds: std::ops::RangeInclusive<Px>,
size: Size,
}
impl Widget for Contracted {
fn draw(&mut self, painter: &mut Painter) -> Size {
painter.holds(Axis::X, self.holds.clone());
self.size
}
}
struct CountedParent {
inner: StrongWidget,
draws: Rc<Cell<usize>>,
}
impl Widget for CountedParent {
fn draw(&mut self, painter: &mut Painter) -> Size {
self.draws.set(self.draws.get() + 1);
painter.widget(&self.inner).size()
}
}
#[test]
fn widening_what_a_drawing_holds_for_does_not_relay_out_the_parent() {
let mut h = Harness::new((400, 200));
let child = Contracted {
holds: Px::from_int(300)..=Px::from_int(500),
size: Size::from((100, 200)),
}
.add(&mut h.rsc);
let draws = Rc::new(Cell::new(0));
let root = CountedParent {
inner: child.upgrade(&mut h.rsc),
draws: draws.clone(),
}
.add(&mut h.rsc);
h.set_root(root);
let settled = draws.get();
// The same answer, good for more boxes than before, so the guarantee the
// parent kept still holds.
h.rsc[child].holds = Px::from_int(200)..=Px::from_int(600);
h.frame();
assert_eq!(
draws.get(),
settled,
"a wider contract for the same answer is not a change to lay out"
);
}