From 38b3a81053599369809c34ceac1ba0e715fb5915 Mon Sep 17 00:00:00 2001 From: iris-ai <4+iris-ai@noreply.localhost> Date: Sat, 19 Sep 2026 02:51:08 -0400 Subject: [PATCH] Pin a frame by the fraction the child declared `size_hint` resolves a child's hint against the asking widget's frame and pins that frame, so a later draw cannot reuse a resolution made against a different one. It asked the *resolved* hint whether it still had a fraction, which is false whenever the frame is itself pixels -- a slot of a row, or the box a stack's sizing child decided -- and the pin was dropped there. Ask the declared hint, which is what made this draw depend on the frame, and what `ruled` in `render_state` already asks for a rule. No generated tree distinguishes the two: the fuzzer grows no `rel` rules, and a frame that changes almost always changes a box the other pins catch. Kept for the reason the `frame_len` pin beside it is kept -- "these two invalidations always coincide" is an assumption nothing states. --- core/src/ui/painter.rs | 50 +++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/core/src/ui/painter.rs b/core/src/ui/painter.rs index c625923..0531147 100644 --- a/core/src/ui/painter.rs +++ b/core/src/ui/painter.rs @@ -267,36 +267,32 @@ impl<'a> Painter<'a> { let widgets = self.rsc.widgets(); // A rule is the answer where there is one: it wins over whatever the // widget would draw, so it has to win over what the widget says too. - let hint = widgets - .size_rules(id.id()) - .axis(axis) - .exact() - .or_else(|| { - widgets - .get_dyn(id.id()) - .and_then(|widget| widget.size_hint(axis)) - }) - .map(|hint| hint.within_len(self.frame.axis(axis))); + let hint = widgets.size_rules(id.id()).axis(axis).exact().or_else(|| { + widgets + .get_dyn(id.id()) + .and_then(|widget| widget.size_hint(axis)) + }); + let frame = self.frame.axis(axis); + let resolved = hint.map(|hint| hint.within_len(frame)); #[cfg(feature = "layout-diagnostics")] - diag::hint_read(id.id(), self.id, axis, hint); - match hint { - Some(hint) => { - #[cfg(feature = "layout-diagnostics")] - diag::bump(Counter::HintHits); - self.depend_on(id); - // A fraction was just resolved against this frame, so what - // this draw does with it is a function of the frame's length. - if hint.rel != Rel::ZERO { - self.frame_own_len[axis as usize] = Some(self.frame.axis(axis)); - } - Some(hint) - } - None => { - #[cfg(feature = "layout-diagnostics")] - diag::bump(Counter::HintMisses); - None + { + diag::hint_read(id.id(), self.id, axis, resolved); + diag::bump(match resolved { + Some(_) => Counter::HintHits, + None => Counter::HintMisses, + }); + } + if let Some(hint) = hint { + self.depend_on(id); + // Resolving a fraction against this frame makes this draw a + // function of the frame's length. The fraction to ask about is + // the child's own: resolved against a frame of pixels, none is + // left to see it by. + if hint.rel != Rel::ZERO { + self.frame_own_len[axis as usize] = Some(frame); } } + resolved } fn depend_on(&mut self, child: &StrongWidget) {