Track retained layout validity explicitly
This commit is contained in:
1 parent
691e3eb23c
commit
29c7881c8a
25 files changed
+836
-795
No files matched your search
+83
-53
@@ -6,22 +6,22 @@ use iris::harness::{Harness, assert_corners};
|
||||
use iris::prelude::*;
|
||||
|
||||
/// A leaf that counts its draws and reports whatever size it is given, so a
|
||||
/// test can see what the retained path skipped.
|
||||
/// test can see what the retained path skipped. One that reads its box in
|
||||
/// pixels has a drawing that holds for that box alone.
|
||||
struct Counted {
|
||||
draws: Rc<Cell<usize>>,
|
||||
size: Size,
|
||||
dependence: OnResize,
|
||||
reads_box: bool,
|
||||
}
|
||||
|
||||
impl Widget for Counted {
|
||||
fn draw(&mut self, _: &mut Painter) -> Size {
|
||||
fn draw(&mut self, painter: &mut Painter) -> Size {
|
||||
self.draws.set(self.draws.get() + 1);
|
||||
if self.reads_box {
|
||||
painter.px_size();
|
||||
}
|
||||
self.size
|
||||
}
|
||||
|
||||
fn on_resize(&self, _: Axis) -> OnResize {
|
||||
self.dependence
|
||||
}
|
||||
}
|
||||
|
||||
struct Counts(Rc<Cell<usize>>);
|
||||
@@ -32,22 +32,63 @@ impl Counts {
|
||||
}
|
||||
}
|
||||
|
||||
fn counted(h: &mut Harness, size: Size, dependence: OnResize) -> (WeakWidget<Counted>, Counts) {
|
||||
fn counted(h: &mut Harness, size: Size, reads_box: bool) -> (WeakWidget<Counted>, Counts) {
|
||||
let draws = Rc::new(Cell::new(0));
|
||||
let id = Counted {
|
||||
draws: draws.clone(),
|
||||
size,
|
||||
dependence,
|
||||
reads_box,
|
||||
}
|
||||
.add(&mut h.rsc);
|
||||
(id, Counts(draws))
|
||||
}
|
||||
|
||||
struct Layered {
|
||||
children: [StrongWidget<Rect>; 2],
|
||||
_revision: usize,
|
||||
}
|
||||
|
||||
impl Widget for Layered {
|
||||
fn draw(&mut self, painter: &mut Painter) -> Size {
|
||||
painter.child_layer();
|
||||
painter.widget(&self.children[0]);
|
||||
painter.next_layer();
|
||||
painter.widget(&self.children[1]);
|
||||
Size::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_redrawn_layered_widget_keeps_the_layer_it_was_entered_on() {
|
||||
let mut h = Harness::new((400, 200));
|
||||
let children = [
|
||||
rect(Color::RED).add_strong(&mut h.rsc),
|
||||
rect(Color::BLUE).add_strong(&mut h.rsc),
|
||||
];
|
||||
let root = Layered {
|
||||
children,
|
||||
_revision: 0,
|
||||
}
|
||||
.add(&mut h.rsc);
|
||||
h.set_root(root);
|
||||
|
||||
h.rsc[root]._revision += 1;
|
||||
h.frame();
|
||||
|
||||
let label = h.rsc.widgets().label(root.id());
|
||||
let active = h
|
||||
.render
|
||||
.debug(h.rsc.widgets(), label)
|
||||
.find(|active| active.id == root.id())
|
||||
.unwrap();
|
||||
assert_eq!(active.layer, 0);
|
||||
}
|
||||
|
||||
/// A fixed-width leaf beside one that takes what is left over, so changing
|
||||
/// the first hands the second a different box without the output changing.
|
||||
fn pair(h: &mut Harness, leftover: OnResize) -> (WeakWidget<Counted>, Counts, WidgetId) {
|
||||
let (first, _) = counted(h, Size::from((100, 200)), OnResize::Translate);
|
||||
let (second, draws) = counted(h, Size::LEFTOVER, leftover);
|
||||
fn pair(h: &mut Harness, reads_box: bool) -> (WeakWidget<Counted>, Counts, WidgetId) {
|
||||
let (first, _) = counted(h, Size::from((100, 200)), false);
|
||||
let (second, draws) = counted(h, Size::LEFTOVER, reads_box);
|
||||
h.set_root((first, second).span(Dir::RIGHT));
|
||||
(first, draws, second.id())
|
||||
}
|
||||
@@ -55,7 +96,7 @@ fn pair(h: &mut Harness, leftover: OnResize) -> (WeakWidget<Counted>, Counts, Wi
|
||||
#[test]
|
||||
fn a_leaf_that_ignores_its_box_is_not_drawn_again_when_the_box_changes() {
|
||||
let mut h = Harness::new((400, 200));
|
||||
let (first, draws, second) = pair(&mut h, OnResize::Scale);
|
||||
let (first, draws, second) = pair(&mut h, false);
|
||||
let settled = draws.get();
|
||||
assert_corners!(h, second, (100, 0), (400, 200));
|
||||
|
||||
@@ -73,7 +114,7 @@ fn a_leaf_that_ignores_its_box_is_not_drawn_again_when_the_box_changes() {
|
||||
#[test]
|
||||
fn a_leaf_that_depends_on_its_box_is_drawn_again_when_the_box_changes() {
|
||||
let mut h = Harness::new((400, 200));
|
||||
let (first, draws, second) = pair(&mut h, OnResize::Redraw);
|
||||
let (first, draws, second) = pair(&mut h, true);
|
||||
let settled = draws.get();
|
||||
|
||||
h.rsc[first].size = Size::from((150, 200));
|
||||
@@ -88,8 +129,8 @@ fn a_leaf_that_depends_on_its_box_is_drawn_again_when_the_box_changes() {
|
||||
#[test]
|
||||
fn a_span_child_that_declares_its_length_is_drawn_once() {
|
||||
let mut h = Harness::new((400, 200));
|
||||
let (told, told_draws) = counted(&mut h, Size::from((100, 200)), OnResize::Translate);
|
||||
let (asked, asked_draws) = counted(&mut h, Size::from((100, 200)), OnResize::Translate);
|
||||
let (told, told_draws) = counted(&mut h, Size::from((100, 200)), false);
|
||||
let (asked, asked_draws) = counted(&mut h, Size::from((100, 200)), true);
|
||||
// The span takes one child's length from its hint and has to draw the
|
||||
// other to find out, so only the second is drawn before it is placed.
|
||||
let hinted = told.width(100).add(&mut h.rsc);
|
||||
@@ -106,7 +147,7 @@ fn a_span_child_that_declares_its_length_is_drawn_once() {
|
||||
#[test]
|
||||
fn a_span_relays_out_when_a_child_it_measured_changes() {
|
||||
let mut h = Harness::new((400, 200));
|
||||
let (first, _, second) = pair(&mut h, OnResize::Translate);
|
||||
let (first, _, second) = pair(&mut h, false);
|
||||
|
||||
h.rsc[first].size = Size::from((250, 200));
|
||||
h.frame();
|
||||
@@ -118,8 +159,8 @@ fn a_span_relays_out_when_a_child_it_measured_changes() {
|
||||
#[test]
|
||||
fn a_repaint_that_keeps_its_size_does_not_relay_out() {
|
||||
let mut h = Harness::new((400, 200));
|
||||
let (first, draws) = counted(&mut h, Size::from((100, 200)), OnResize::Translate);
|
||||
let (second, _) = counted(&mut h, Size::LEFTOVER, OnResize::Translate);
|
||||
let (first, draws) = counted(&mut h, Size::from((100, 200)), false);
|
||||
let (second, _) = counted(&mut h, Size::LEFTOVER, false);
|
||||
h.set_root((first, second).span(Dir::RIGHT));
|
||||
let settled = draws.get();
|
||||
|
||||
@@ -179,20 +220,20 @@ fn a_parent_that_only_read_a_hint_relays_out_when_the_hint_changes() {
|
||||
assert_corners!(h, inner, (0, 0), (400, 120));
|
||||
}
|
||||
|
||||
/// Reads the output's size, which nothing but its own draw can put right.
|
||||
struct ReadsOutput {
|
||||
/// Reads its box's size, which nothing but its own draw can put right.
|
||||
struct ReadsBox {
|
||||
draws: Rc<Cell<usize>>,
|
||||
}
|
||||
|
||||
impl Widget for ReadsOutput {
|
||||
impl Widget for ReadsBox {
|
||||
fn draw(&mut self, painter: &mut Painter) -> Size {
|
||||
self.draws.set(self.draws.get() + 1);
|
||||
Size::px(painter.output_size() / 4.0)
|
||||
Size::px(painter.px_size() / 4.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads the output across one axis only, and says so: its drawing follows
|
||||
/// a taller box on its own, so only a wider one is worth a draw.
|
||||
/// Reads its box across one axis only, so its drawing holds for a taller
|
||||
/// box on its own and only a wider one is worth a draw.
|
||||
struct ReadsWidth {
|
||||
draws: Rc<Cell<usize>>,
|
||||
}
|
||||
@@ -200,21 +241,14 @@ struct ReadsWidth {
|
||||
impl Widget for ReadsWidth {
|
||||
fn draw(&mut self, painter: &mut Painter) -> Size {
|
||||
self.draws.set(self.draws.get() + 1);
|
||||
Size::px((painter.output_len(Axis::X) / 4.0, 20.0).into())
|
||||
}
|
||||
|
||||
fn on_resize(&self, axis: Axis) -> OnResize {
|
||||
match axis {
|
||||
Axis::X => OnResize::Redraw,
|
||||
Axis::Y => OnResize::Scale,
|
||||
}
|
||||
Size::px((painter.px_len(Axis::X) / 4.0, 20.0).into())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_resize_does_not_redraw_what_the_shader_can_move() {
|
||||
let mut h = Harness::new((400, 200));
|
||||
let (leaf, draws) = counted(&mut h, Size::LEFTOVER, OnResize::Scale);
|
||||
let (leaf, draws) = counted(&mut h, Size::LEFTOVER, false);
|
||||
h.set_root(leaf);
|
||||
let settled = draws.get();
|
||||
|
||||
@@ -231,12 +265,12 @@ fn a_resize_does_not_redraw_what_the_shader_can_move() {
|
||||
}
|
||||
|
||||
/// The output is the root of the box chain, so a resize is a box that changed
|
||||
/// length and `OnResize` answers for it -- there is not a second rule for the
|
||||
/// window. A drawing that does not scale is redrawn whichever box moved.
|
||||
/// length like any other -- there is not a second rule for the window. A
|
||||
/// drawing that holds for one length is drawn again whichever box moved.
|
||||
#[test]
|
||||
fn a_resize_redraws_what_does_not_scale() {
|
||||
let mut h = Harness::new((400, 200));
|
||||
let (leaf, draws) = counted(&mut h, Size::LEFTOVER, OnResize::Redraw);
|
||||
let (leaf, draws) = counted(&mut h, Size::LEFTOVER, true);
|
||||
h.set_root(leaf);
|
||||
let settled = draws.get();
|
||||
|
||||
@@ -248,10 +282,10 @@ fn a_resize_redraws_what_does_not_scale() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_resize_redraws_what_read_the_output() {
|
||||
fn a_resize_redraws_what_read_its_box() {
|
||||
let mut h = Harness::new((400, 200));
|
||||
let draws = Rc::new(Cell::new(0));
|
||||
let leaf = ReadsOutput {
|
||||
let leaf = ReadsBox {
|
||||
draws: draws.clone(),
|
||||
}
|
||||
.add(&mut h.rsc);
|
||||
@@ -265,7 +299,7 @@ fn a_resize_redraws_what_read_the_output() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_resize_only_redraws_read_output_axes() {
|
||||
fn a_resize_only_redraws_read_axes() {
|
||||
let mut h = Harness::new((400, 200));
|
||||
let draws = Rc::new(Cell::new(0));
|
||||
let leaf = ReadsWidth {
|
||||
@@ -309,7 +343,7 @@ fn subpixel_resize_changes_accumulate_from_the_last_layout() {
|
||||
#[test]
|
||||
fn subpixel_box_changes_accumulate_from_the_last_draw() {
|
||||
let mut h = Harness::new((400, 200));
|
||||
let (first, draws, _) = pair(&mut h, OnResize::Redraw);
|
||||
let (first, draws, _) = pair(&mut h, true);
|
||||
let settled = draws.get();
|
||||
|
||||
for width in [100.02, 100.04, 100.05] {
|
||||
@@ -327,7 +361,7 @@ fn subpixel_box_changes_accumulate_from_the_last_draw() {
|
||||
fn reporting_the_same_output_size_does_not_start_a_resize() {
|
||||
let mut h = Harness::new((400, 200));
|
||||
let draws = Rc::new(Cell::new(0));
|
||||
let leaf = ReadsOutput {
|
||||
let leaf = ReadsBox {
|
||||
draws: draws.clone(),
|
||||
}
|
||||
.add(&mut h.rsc);
|
||||
@@ -368,7 +402,7 @@ fn a_change_two_levels_under_its_reader_still_reaches_it() {
|
||||
// Every wrapper up to the outer pad read the size below it, so the outer
|
||||
// pad is what draws again -- and the span it hands the box to is the same
|
||||
// size as before, which is what lets a draw reuse its way past the leaf.
|
||||
let (leaf, _) = counted(&mut h, Size::px((100, 100).into()), OnResize::Redraw);
|
||||
let (leaf, _) = counted(&mut h, Size::px((100, 100).into()), true);
|
||||
let padded = leaf.pad(10).add(&mut h.rsc);
|
||||
let below = rect(Color::RED).add(&mut h.rsc);
|
||||
h.set_root((padded, below).span(Dir::DOWN).pad(12));
|
||||
@@ -380,8 +414,8 @@ fn a_change_two_levels_under_its_reader_still_reaches_it() {
|
||||
assert_corners!(h, below, (12, 232), (388, 388));
|
||||
}
|
||||
|
||||
/// Claims its drawing survives its box changing length, and has a child so
|
||||
/// that the walk looking for what does not has one to reach.
|
||||
/// Reads nothing of its box, so its drawing holds for any length, and has a
|
||||
/// child so that whatever asks about the subtree has one to reach.
|
||||
struct Stretchy {
|
||||
inner: StrongWidget,
|
||||
draws: Rc<Cell<usize>>,
|
||||
@@ -392,10 +426,6 @@ impl Widget for Stretchy {
|
||||
self.draws.set(self.draws.get() + 1);
|
||||
painter.widget(&self.inner).size()
|
||||
}
|
||||
|
||||
fn on_resize(&self, _: Axis) -> OnResize {
|
||||
OnResize::Scale
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -430,8 +460,8 @@ fn a_widened_row_redraws_what_reads_its_length_and_nothing_else() {
|
||||
let mut h = Harness::new((400, 200));
|
||||
// What a transcript row is: something whose shaping depends on the width
|
||||
// it is given, beside something that only has to be the right shape.
|
||||
let (wraps, wrap_draws) = counted(&mut h, Size::LEFTOVER, OnResize::Redraw);
|
||||
let (backing, back_draws) = counted(&mut h, Size::LEFTOVER, OnResize::Scale);
|
||||
let (wraps, wrap_draws) = counted(&mut h, Size::LEFTOVER, true);
|
||||
let (backing, back_draws) = counted(&mut h, Size::LEFTOVER, false);
|
||||
let row = (backing, wraps).span(Dir::RIGHT).add(&mut h.rsc);
|
||||
let bar = rect(Color::RED).width(100).add(&mut h.rsc);
|
||||
h.set_root((bar, row).span(Dir::RIGHT));
|
||||
@@ -455,9 +485,9 @@ fn a_declared_length_child_is_not_redrawn_when_the_box_around_it_grows() {
|
||||
// again would be for a width it does not have. The declared width is what
|
||||
// lets the span say that without drawing it: a width the span learnt by
|
||||
// drawing the child in its own box is only an answer for that box.
|
||||
let (counter, draws) = counted(&mut h, Size::from((80, 200)), OnResize::Redraw);
|
||||
let (counter, draws) = counted(&mut h, Size::from((80, 200)), true);
|
||||
let fixed = counter.width(80).add(&mut h.rsc);
|
||||
let (leftover, _) = counted(&mut h, Size::LEFTOVER, OnResize::Scale);
|
||||
let (leftover, _) = counted(&mut h, Size::LEFTOVER, false);
|
||||
let row = (fixed, leftover).span(Dir::RIGHT).add(&mut h.rsc);
|
||||
let bar = rect(Color::RED).width(100).add(&mut h.rsc);
|
||||
h.set_root((bar, row).span(Dir::RIGHT));
|
||||
|
||||
Reference in new issue
Block a user