diff --git a/core/src/ui/render_state.rs b/core/src/ui/render_state.rs index e156dc0..c235836 100644 --- a/core/src/ui/render_state.rs +++ b/core/src/ui/render_state.rs @@ -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; } diff --git a/tests/cases/retained.rs b/tests/cases/retained.rs index 059aa0d..8b473a7 100644 --- a/tests/cases/retained.rs +++ b/tests/cases/retained.rs @@ -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, + 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>, +} + +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" + ); +}