Compare commits
4
Commits
781199a7c9
...
750217631d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
750217631d | ||
|
|
9b4cc329ce | ||
|
|
02048eab77 | ||
|
|
d8d51221ee |
No files matched your search
@@ -72,6 +72,7 @@ labelled! {
|
|||||||
TextBreaks = "text line breaks",
|
TextBreaks = "text line breaks",
|
||||||
GlyphPlacements = "glyph placements",
|
GlyphPlacements = "glyph placements",
|
||||||
OutsidePinnedLen = "reuse outside: the length it was pinned to",
|
OutsidePinnedLen = "reuse outside: the length it was pinned to",
|
||||||
|
OutsideWindow = "reuse outside: this window",
|
||||||
OutsideRelBase = "reuse outside: a rel base",
|
OutsideRelBase = "reuse outside: a rel base",
|
||||||
OutsideRegion = "reuse outside: a region length",
|
OutsideRegion = "reuse outside: a region length",
|
||||||
}
|
}
|
||||||
@@ -352,7 +353,7 @@ pub(crate) fn reuse(id: WidgetId, outcome: ReuseOutcome) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A drawing that cannot be reused because the box on offer is outside what
|
/// A drawing that cannot be reused because the box on offer is outside what
|
||||||
/// it holds for, and which of the three contracts said so. They overlap: a
|
/// it holds for, and which of the four contracts said so. They overlap: a
|
||||||
/// drawing can be outside two of them at once, and counting each is what
|
/// drawing can be outside two of them at once, and counting each is what
|
||||||
/// says where a rel base redrawing more than it should is coming from.
|
/// says where a rel base redrawing more than it should is coming from.
|
||||||
pub(crate) fn outside(
|
pub(crate) fn outside(
|
||||||
@@ -369,10 +370,12 @@ pub(crate) fn outside(
|
|||||||
if holds.region_len.is_some_and(|pinned| pinned != len) {
|
if holds.region_len.is_some_and(|pinned| pinned != len) {
|
||||||
bump(Counter::OutsidePinnedLen);
|
bump(Counter::OutsidePinnedLen);
|
||||||
}
|
}
|
||||||
if !holds.window.contains(window)
|
if !holds.window.contains(window) {
|
||||||
|| holds
|
bump(Counter::OutsideWindow);
|
||||||
.rel_base
|
}
|
||||||
.is_some_and(|pinned| pinned != rel_base[axis])
|
if holds
|
||||||
|
.rel_base
|
||||||
|
.is_some_and(|pinned| pinned != rel_base[axis])
|
||||||
{
|
{
|
||||||
bump(Counter::OutsideRelBase);
|
bump(Counter::OutsideRelBase);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,14 +84,6 @@ pub struct RegionAlign {
|
|||||||
pub y: AxisAlign,
|
pub y: AxisAlign,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RegionAlign {
|
|
||||||
/// Both axes at the near edge: the start of a box in its own orientation.
|
|
||||||
pub const NEAR: Self = Self {
|
|
||||||
x: AxisAlign::NEG,
|
|
||||||
y: AxisAlign::NEG,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RegionAlign {
|
impl RegionAlign {
|
||||||
pub const TOP_LEFT: Self = Self::new(AxisAlign::NEG, AxisAlign::NEG);
|
pub const TOP_LEFT: Self = Self::new(AxisAlign::NEG, AxisAlign::NEG);
|
||||||
pub const TOP_CENTER: Self = Self::new(AxisAlign::CENTER, AxisAlign::NEG);
|
pub const TOP_CENTER: Self = Self::new(AxisAlign::CENTER, AxisAlign::NEG);
|
||||||
|
|||||||
@@ -11,15 +11,6 @@ pub enum Axis {
|
|||||||
impl Axis {
|
impl Axis {
|
||||||
/// Both of them, for the layout code that asks the same question of each.
|
/// Both of them, for the layout code that asks the same question of each.
|
||||||
pub const BOTH: [Self; 2] = [Self::X, Self::Y];
|
pub const BOTH: [Self; 2] = [Self::X, Self::Y];
|
||||||
|
|
||||||
/// A per-axis pair with `aligned` on this axis and `ortho` on the other,
|
|
||||||
/// which is what `from_axis` does for a vector.
|
|
||||||
pub fn pair<T>(self, aligned: T, ortho: T) -> [T; 2] {
|
|
||||||
match self {
|
|
||||||
Self::X => [aligned, ortho],
|
|
||||||
Self::Y => [ortho, aligned],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::ops::Not for Axis {
|
impl std::ops::Not for Axis {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ impl Holds {
|
|||||||
Self { lo: len, hi: len }
|
Self { lo: len, hi: len }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn contains(&self, len: Px) -> bool {
|
pub const fn contains(self, len: Px) -> bool {
|
||||||
len.raw() >= self.lo.raw() && len.raw() <= self.hi.raw()
|
len.raw() >= self.lo.raw() && len.raw() <= self.hi.raw()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-10
@@ -1108,20 +1108,23 @@ impl UiRenderState {
|
|||||||
let old = self.remove(id, false, rsc);
|
let old = self.remove(id, false, rsc);
|
||||||
let drawn = self.draw_inner(id, info, old, rsc);
|
let drawn = self.draw_inner(id, info, old, rsc);
|
||||||
let active = self.active.get_mut(&id).unwrap();
|
let active = self.active.get_mut(&id).unwrap();
|
||||||
// A wider contract does not invalidate the guarantee the parent kept.
|
|
||||||
// Retain that guarantee so widening and narrowing back do not churn it.
|
|
||||||
if let Some(was) = was_answer
|
|
||||||
&& drawn.answer.size == was.size
|
|
||||||
&& drawn.answer.holds.covers(was.holds)
|
|
||||||
{
|
|
||||||
active.answer = was_answer;
|
|
||||||
}
|
|
||||||
// Against the box it was asked in, which is what both contracts are
|
// Against the box it was asked in, which is what both contracts are
|
||||||
// about. Where the answer put the drawing is shorter than that
|
// about. Where the answer put the drawing is shorter than that
|
||||||
// wherever the widget reported less than it was offered.
|
// wherever the widget reported less than it was offered.
|
||||||
if active.holds.covers(was_holds)
|
let (window, rel_base, region) = (self.output_size, active.rel_base, active.region);
|
||||||
&& was_holds.contains(self.output_size, active.rel_base, active.region)
|
// A wider contract does not invalidate the guarantee the parent kept.
|
||||||
|
// Retain that guarantee so widening and narrowing back do not churn
|
||||||
|
// it -- but only where the narrower range still holds here: one this
|
||||||
|
// window is outside is refused by the parent's next ask, and refusing
|
||||||
|
// it throws away the drawing this one just made.
|
||||||
|
if let Some(was) = was_answer
|
||||||
|
&& drawn.answer.size == was.size
|
||||||
|
&& drawn.answer.holds.covers(was.holds)
|
||||||
|
&& was.holds.contains(window, rel_base, region)
|
||||||
{
|
{
|
||||||
|
active.answer = was_answer;
|
||||||
|
}
|
||||||
|
if active.holds.covers(was_holds) && was_holds.contains(window, rel_base, region) {
|
||||||
active.holds = was_holds;
|
active.holds = was_holds;
|
||||||
}
|
}
|
||||||
if active.answer != was_answer || active.holds != was_holds {
|
if active.answer != was_answer || active.holds != was_holds {
|
||||||
|
|||||||
@@ -22,12 +22,12 @@ impl UiRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(&mut self) {
|
pub fn draw(&mut self) {
|
||||||
let output = match self.surface.get_current_texture() {
|
let (output, suboptimal) = match self.surface.get_current_texture() {
|
||||||
CurrentSurfaceTexture::Success(texture) => texture,
|
CurrentSurfaceTexture::Success(texture) => (texture, false),
|
||||||
CurrentSurfaceTexture::Suboptimal(texture) => {
|
// Used for this frame, and the swapchain rebuilt after it has
|
||||||
self.surface.configure(&self.device, &self.config);
|
// been presented: configuring the surface while a texture it
|
||||||
texture
|
// handed out is still alive panics.
|
||||||
}
|
CurrentSurfaceTexture::Suboptimal(texture) => (texture, true),
|
||||||
CurrentSurfaceTexture::Outdated | CurrentSurfaceTexture::Lost => {
|
CurrentSurfaceTexture::Outdated | CurrentSurfaceTexture::Lost => {
|
||||||
self.surface.configure(&self.device, &self.config);
|
self.surface.configure(&self.device, &self.config);
|
||||||
return;
|
return;
|
||||||
@@ -60,6 +60,9 @@ impl UiRenderer {
|
|||||||
self.queue.submit(std::iter::once(encoder.finish()));
|
self.queue.submit(std::iter::once(encoder.finish()));
|
||||||
self.window.pre_present_notify();
|
self.window.pre_present_notify();
|
||||||
self.queue.present(output);
|
self.queue.present(output);
|
||||||
|
if suboptimal {
|
||||||
|
self.surface.configure(&self.device, &self.config);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resize(&mut self, size: &PhysicalSize<u32>) {
|
pub fn resize(&mut self, size: &PhysicalSize<u32>) {
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ impl Widget for Span {
|
|||||||
if shrinks {
|
if shrinks {
|
||||||
// Choosing between a fixed and a relative length from the
|
// Choosing between a fixed and a relative length from the
|
||||||
// span's own eventual width admits multiple fixed points.
|
// span's own eventual width admits multiple fixed points.
|
||||||
// A scalable child therefore makes Children scalable too;
|
// A scalable child therefore makes the span scalable too;
|
||||||
// only fixed children are compared with one another.
|
// only fixed children are compared with one another.
|
||||||
if !used.is_px() {
|
if !used.is_px() {
|
||||||
ortho = LayoutLen::LEFTOVER;
|
ortho = LayoutLen::LEFTOVER;
|
||||||
|
|||||||
+41
-1
@@ -1480,14 +1480,17 @@ fn a_redrawn_subtree_is_not_undrawn_by_the_parent_it_left() {
|
|||||||
|
|
||||||
/// A leaf that reports less than the box it is given and states which lengths
|
/// 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
|
/// of that box its drawing holds for, so a test can widen the contract
|
||||||
/// without changing the answer.
|
/// without changing the answer. It counts its draws, since what a kept
|
||||||
|
/// contract costs is whether the parent has to make it draw again.
|
||||||
struct Contracted {
|
struct Contracted {
|
||||||
holds: std::ops::RangeInclusive<Px>,
|
holds: std::ops::RangeInclusive<Px>,
|
||||||
size: Size,
|
size: Size,
|
||||||
|
draws: Rc<Cell<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Widget for Contracted {
|
impl Widget for Contracted {
|
||||||
fn draw(&mut self, painter: &mut Painter) -> Size {
|
fn draw(&mut self, painter: &mut Painter) -> Size {
|
||||||
|
self.draws.set(self.draws.get() + 1);
|
||||||
painter.holds(Axis::X, self.holds.clone());
|
painter.holds(Axis::X, self.holds.clone());
|
||||||
self.size
|
self.size
|
||||||
}
|
}
|
||||||
@@ -1511,6 +1514,7 @@ fn widening_what_a_drawing_holds_for_does_not_relay_out_the_parent() {
|
|||||||
let child = Contracted {
|
let child = Contracted {
|
||||||
holds: Px::from_int(300)..=Px::from_int(500),
|
holds: Px::from_int(300)..=Px::from_int(500),
|
||||||
size: Size::from((100, 200)),
|
size: Size::from((100, 200)),
|
||||||
|
draws: Rc::new(Cell::new(0)),
|
||||||
}
|
}
|
||||||
.add(&mut h.rsc);
|
.add(&mut h.rsc);
|
||||||
let draws = Rc::new(Cell::new(0));
|
let draws = Rc::new(Cell::new(0));
|
||||||
@@ -1533,3 +1537,39 @@ fn widening_what_a_drawing_holds_for_does_not_relay_out_the_parent() {
|
|||||||
"a wider contract for the same answer is not a change to lay out"
|
"a wider contract for the same answer is not a change to lay out"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The other half of the rule above: a kept contract is the narrower one, so
|
||||||
|
/// it is only worth keeping where it still holds. A window the old range is
|
||||||
|
/// outside is not one its parent can be handed back, and keeping it there
|
||||||
|
/// throws away the drawing the widget just made.
|
||||||
|
#[test]
|
||||||
|
fn a_contract_this_window_is_outside_is_not_kept() {
|
||||||
|
let mut h = Harness::new((400, 200));
|
||||||
|
let leaf_draws = Rc::new(Cell::new(0));
|
||||||
|
let child = Contracted {
|
||||||
|
holds: Px::from_int(300)..=Px::from_int(500),
|
||||||
|
size: Size::from((100, 200)),
|
||||||
|
draws: leaf_draws.clone(),
|
||||||
|
}
|
||||||
|
.add(&mut h.rsc);
|
||||||
|
let root = CountedParent {
|
||||||
|
inner: child.upgrade(&mut h.rsc),
|
||||||
|
draws: Rc::new(Cell::new(0)),
|
||||||
|
}
|
||||||
|
.add(&mut h.rsc);
|
||||||
|
h.set_root(root);
|
||||||
|
|
||||||
|
// Wide enough that the old contract leaves the new box out, and the leaf
|
||||||
|
// is marked in the same frame -- so it settles itself first and its
|
||||||
|
// parent draws afterwards, asking about what it settled.
|
||||||
|
h.resize((600, 200));
|
||||||
|
h.rsc[child].holds = Px::from_int(200)..=Px::from_int(700);
|
||||||
|
let settled = leaf_draws.get();
|
||||||
|
h.frame();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
leaf_draws.get(),
|
||||||
|
settled + 1,
|
||||||
|
"the leaf settled once and its parent kept what it settled"
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in new issue
Block a user