Separate measured-answer dependencies from retained drawing validity

This commit is contained in:
iris-ai committed 2026-09-17 17:10:55 -04:00
1 parent c44bd198ee
commit f860f716e6
7 files changed
+188 -356

No files matched your search

+71 -195
View File
@@ -1022,210 +1022,86 @@ fn glyph_origins_compose_identically_when_drawn_and_when_retained() {
}
#[test]
fn padding_and_stack_frames_follow_the_extent_without_drawing_again() {
struct Observed<W> {
widget: W,
draws: Rc<Cell<usize>>,
}
impl<W: Widget> Widget for Observed<W> {
fn draw(&mut self, painter: &mut Painter) -> Size {
self.draws.set(self.draws.get() + 1);
self.widget.draw(painter)
}
}
struct Frame {
child: StrongWidget,
extent: UiRegion,
}
impl Widget for Frame {
fn draw(&mut self, painter: &mut Painter) -> Size {
painter.widget_at(
&self.child,
UiRegion::FULL,
[Some(self.extent.x), Some(self.extent.y)],
);
Size::LEFTOVER
}
}
for node in [false, true] {
let plant = |h: &mut Harness, extent| {
let draws = Rc::new(Cell::new(0));
let leaf = rect(Color::BLUE).masked().add(&mut h.rsc);
h.rsc.widgets_mut().set_region_node(leaf, node);
let fixed = rect(Color::RED).width(31).height(19).add(&mut h.rsc);
let stack = Observed {
widget: Stack {
children: vec![leaf.add_strong(&mut h.rsc), fixed.add_strong(&mut h.rsc)],
size: StackSize::Default,
},
draws: draws.clone(),
}
.add_strong(&mut h.rsc);
let pad = Observed {
widget: Pad {
inner: stack,
padding: Padding::uniform(7).with_left(13),
},
draws: draws.clone(),
}
.add_strong(&mut h.rsc);
let root = Frame { child: pad, extent }.add(&mut h.rsc);
h.set_root(root);
(root, leaf, fixed, draws)
};
let mut warm = Harness::new((403, 211));
let (root, leaf, fixed, draws) = plant(&mut warm, UiRegion::FULL);
for (start, end) in [(0.13, 0.83), (-0.17, 1.23), (0.31, 0.67)] {
let extent = UiRegion::new(
UiSpan::new(Len::rel(start) + Len::px(3.125), Len::rel(end)),
UiSpan::new(Len::px(11.25), Len::rel(end)),
);
let before = draws.get();
warm.rsc[root].extent = extent;
warm.frame();
assert_eq!(draws.get(), before);
let mut cold = Harness::new((403, 211));
let (_, other, other_fixed, _) = plant(&mut cold, extent);
for (a, b) in [(leaf.id(), other.id()), (fixed.id(), other_fixed.id())] {
assert_eq!(warm.region(&a), cold.region(&b));
assert_eq!(primitive_bounds(&warm, a), primitive_bounds(&cold, b));
}
let mask = |h: &Harness, id: WidgetId| {
let active = &h.render.active[&id];
let mask = &h.rsc.ui().masks[active.mask.idx()];
h.render
.moves
.resolve(mask.move_idx, mask.region)
.to_px(h.render.output_size())
};
assert_eq!(mask(&warm, leaf.id()), mask(&cold, other.id()));
}
fn resizing_does_not_remeasure_a_fixed_stack_for_its_unmeasured_overlay() {
let mut h = Harness::new((400, 200));
let (sizing, _) = counted(&mut h, Size::from((100, 80)), false);
let (overlay, draws) = counted(&mut h, Size::LEFTOVER, true);
h.set_root((sizing, overlay).stack().size(StackSize::Child(0)));
let settled = draws.get();
h.resize((800, 300));
h.frame();
assert_eq!(draws.get(), settled);
assert_corners!(h, overlay, (350, 110), (450, 190));
}
struct Unmeasured {
child: StrongWidget,
draws: Rc<Cell<usize>>,
}
impl Widget for Unmeasured {
fn draw(&mut self, painter: &mut Painter) -> Size {
self.draws.set(self.draws.get() + 1);
painter.widget(&self.child);
Size::LEFTOVER
}
}
#[test]
fn moving_an_extent_child_preserves_the_slot_chosen_from_its_measurement() {
struct Measured;
impl Widget for Measured {
fn draw(&mut self, painter: &mut Painter) -> Size {
let width = painter.px_len(Axis::X);
painter.primitive(RectPrimitive::color(Color::BLUE));
Size::from((80, if width > Px::from_int(100) { 40 } else { 60 }))
}
}
struct Frame {
child: StrongWidget,
start: f32,
}
impl Widget for Frame {
fn draw(&mut self, painter: &mut Painter) -> Size {
painter.widget_at(
&self.child,
UiRegion::FULL,
[
Some(UiSpan::new(
Len::px(self.start),
Len::px(self.start + 200.0),
)),
Some(UiSpan::FULL),
],
);
Size::LEFTOVER
}
}
fn a_declared_size_change_stops_at_an_independent_parent() {
let mut h = Harness::new((400, 200));
let leaf = Measured.add(&mut h.rsc);
let stack = (leaf,).stack().add_strong(&mut h.rsc);
let root = Frame {
child: stack,
start: 0.0,
let leaf = rect(Color::RED).width(100).add(&mut h.rsc);
let parent = Unmeasured {
child: leaf.add_strong(&mut h.rsc),
draws: Rc::new(Cell::new(0)),
}
.add_strong(&mut h.rsc);
let draws = Rc::new(Cell::new(0));
h.set_root(Unmeasured {
child: parent,
draws: draws.clone(),
});
let settled = draws.get();
h.set_len(leaf, Axis::X, 150);
h.frame();
assert_corners!(h, leaf, (125, 0), (275, 200));
assert_eq!(draws.get(), settled);
}
#[test]
fn an_unmeasured_child_still_invalidates_its_parents_drawing_on_resize() {
let mut h = Harness::new((400, 200));
let draws = Rc::new(Cell::new(0));
let leaf = ReadsWidth {
draws: draws.clone(),
}
.add(&mut h.rsc);
h.set_root(root);
assert_corners!(h, leaf, (60, 80), (140, 120));
h.rsc[root].start = 30.0;
h.set_root((leaf,).stack());
let settled = draws.get();
h.resize((800, 200));
h.frame();
assert_corners!(h, leaf, (90, 80), (170, 120));
assert_eq!(
primitive_bounds(&h, leaf.id()),
vec![h.region(&leaf).unwrap()]
);
assert!(draws.get() > settled);
assert_corners!(h, leaf, (300, 90), (500, 110));
}
#[test]
fn extent_frames_keep_fractional_reports_and_numeric_dependencies_valid() {
struct Container {
child: StrongWidget,
region: UiRegion,
}
impl Widget for Container {
fn draw(&mut self, painter: &mut Painter) -> Size {
painter
.widget_within(&self.child, DrawRegion::Extent(self.region))
.size()
}
}
struct Frame {
child: StrongWidget,
extent: UiRegion,
answer: Rc<Cell<Size>>,
}
impl Widget for Frame {
fn draw(&mut self, painter: &mut Painter) -> Size {
self.answer.set(
painter
.widget_at(
&self.child,
UiRegion::FULL,
[Some(self.extent.x), Some(self.extent.y)],
)
.size(),
);
Size::LEFTOVER
}
}
for fractional in [false, true] {
for region in [
UiRegion::FULL,
UiRegion::new(UiSpan::new(Len::rel(0.13), Len::rel(0.79)), UiSpan::FULL),
] {
let plant = |h: &mut Harness, extent| {
let size = if fractional {
Size {
x: rel(0.5),
y: LayoutLen::px(27),
}
} else {
Size::from((80, 27))
};
let (leaf, _) = counted(h, size, !fractional);
let child = Container {
child: leaf.add_strong(&mut h.rsc),
region,
}
.add_strong(&mut h.rsc);
let answer = Rc::new(Cell::new(Size::ZERO));
let root = Frame {
child,
extent,
answer: answer.clone(),
}
.add(&mut h.rsc);
h.set_root(root);
(root, leaf, answer)
};
let mut warm = Harness::new((403, 211));
let (root, leaf, answer) = plant(&mut warm, UiRegion::FULL);
for width in [191.125, 297.25, 83.75] {
let extent =
UiRegion::new(UiSpan::new(Len::px(13.125), Len::px(width)), UiSpan::FULL);
warm.rsc[root].extent = extent;
warm.frame();
let mut cold = Harness::new((403, 211));
let (_, other, other_answer) = plant(&mut cold, extent);
assert_eq!(answer.get(), other_answer.get());
assert_eq!(warm.region(&leaf), cold.region(&other));
}
}
}
fn changed_drawing_dependencies_reach_ancestors_without_a_size_change() {
let mut h = Harness::new((400, 200));
let (leaf, draws) = counted(&mut h, Size::LEFTOVER, false);
h.set_root(((leaf,).stack(),).stack());
h.rsc[leaf].reads_box = true;
h.frame();
let settled = draws.get();
h.resize((800, 200));
h.frame();
assert_eq!(draws.get(), settled + 1);
assert_corners!(h, leaf, (0, 0), (800, 200));
}