1
0
Fork 0
forked from wry/wry

Coalesce layout animation candidates

This commit is contained in:
atagen 2026-05-27 22:24:01 +10:00
parent 502a93a00a
commit 02222d5189

View file

@ -171,6 +171,28 @@ pub(crate) struct LayoutAnimationCandidate {
hierarchy: MultiphaseWindowHierarchy,
}
fn coalesce_layout_animation_candidates(
candidates: Vec<LayoutAnimationCandidate>,
) -> Vec<LayoutAnimationCandidate> {
let mut merged: Vec<LayoutAnimationCandidate> = vec![];
for candidate in candidates {
if let Some(existing) = merged
.iter_mut()
.find(|existing| existing.node_id == candidate.node_id)
{
existing.new = candidate.new;
existing.curve = candidate.curve;
existing.hierarchy = MultiphaseWindowHierarchy::new(
existing.hierarchy.source,
candidate.hierarchy.target,
);
} else {
merged.push(candidate);
}
}
merged
}
pub struct State {
pub pid: c::pid_t,
pub kb_ctx: KbvmContext,
@ -1619,6 +1641,10 @@ impl State {
let Some(candidates) = self.layout_animation_batch.borrow_mut().take() else {
return;
};
let candidates = coalesce_layout_animation_candidates(candidates);
if candidates.is_empty() {
return;
}
let now = self.now_nsec();
let windows: Vec<_> = candidates
.iter()
@ -2431,6 +2457,132 @@ impl State {
}
}
#[cfg(test)]
mod tests {
use {
super::*,
crate::animation::multiphase::MultiphaseHierarchyPosition,
};
fn rect(x1: i32, y1: i32, x2: i32, y2: i32) -> Rect {
Rect::new_saturating(x1, y1, x2, y2)
}
fn hierarchy(
source: MultiphaseHierarchyPosition,
target: MultiphaseHierarchyPosition,
) -> MultiphaseWindowHierarchy {
MultiphaseWindowHierarchy::new(source, target)
}
#[test]
fn layout_animation_candidates_coalesce_duplicate_nodes() {
let source = MultiphaseHierarchyPosition {
parent: Some(NodeId(10)),
depth: 2,
sibling_index: Some(1),
..Default::default()
};
let intermediate = MultiphaseHierarchyPosition {
parent: Some(NodeId(11)),
depth: 1,
sibling_index: Some(0),
..Default::default()
};
let target = MultiphaseHierarchyPosition {
parent: Some(NodeId(12)),
depth: 0,
sibling_index: Some(2),
..Default::default()
};
let second_source = MultiphaseHierarchyPosition {
parent: Some(NodeId(20)),
depth: 1,
sibling_index: Some(0),
..Default::default()
};
let second_target = MultiphaseHierarchyPosition {
parent: Some(NodeId(20)),
depth: 1,
sibling_index: Some(1),
..Default::default()
};
let candidates = vec![
LayoutAnimationCandidate {
node_id: NodeId(1),
old: rect(0, 0, 100, 100),
new: rect(0, 0, 80, 100),
curve: AnimationCurve::Linear,
hierarchy: hierarchy(source, intermediate),
},
LayoutAnimationCandidate {
node_id: NodeId(2),
old: rect(100, 0, 200, 100),
new: rect(120, 0, 220, 100),
curve: AnimationCurve::Linear,
hierarchy: hierarchy(second_source, second_target),
},
LayoutAnimationCandidate {
node_id: NodeId(1),
old: rect(0, 0, 80, 100),
new: rect(0, 0, 60, 100),
curve: AnimationCurve::from_config(4),
hierarchy: hierarchy(intermediate, target),
},
];
let merged = coalesce_layout_animation_candidates(candidates);
assert_eq!(merged.len(), 2);
assert_eq!(merged[0].node_id, NodeId(1));
assert_eq!(merged[0].old, rect(0, 0, 100, 100));
assert_eq!(merged[0].new, rect(0, 0, 60, 100));
assert_eq!(merged[0].curve, AnimationCurve::from_config(4));
assert_eq!(merged[0].hierarchy, hierarchy(source, target));
assert_eq!(merged[1].node_id, NodeId(2));
assert_eq!(merged[1].old, rect(100, 0, 200, 100));
assert_eq!(merged[1].new, rect(120, 0, 220, 100));
assert_eq!(merged[1].hierarchy, hierarchy(second_source, second_target));
}
#[test]
fn layout_animation_candidates_keep_coalesced_layout_noops() {
let hierarchy = MultiphaseWindowHierarchy::default();
let candidates = vec![
LayoutAnimationCandidate {
node_id: NodeId(1),
old: rect(0, 0, 100, 100),
new: rect(0, 0, 80, 100),
curve: AnimationCurve::Linear,
hierarchy,
},
LayoutAnimationCandidate {
node_id: NodeId(1),
old: rect(0, 0, 80, 100),
new: rect(0, 0, 100, 100),
curve: AnimationCurve::Linear,
hierarchy,
},
LayoutAnimationCandidate {
node_id: NodeId(2),
old: rect(100, 0, 200, 100),
new: rect(120, 0, 220, 100),
curve: AnimationCurve::Linear,
hierarchy,
},
];
let merged = coalesce_layout_animation_candidates(candidates);
assert_eq!(merged.len(), 2);
assert_eq!(merged[0].node_id, NodeId(1));
assert_eq!(merged[0].old, rect(0, 0, 100, 100));
assert_eq!(merged[0].new, rect(0, 0, 100, 100));
assert_eq!(merged[1].node_id, NodeId(2));
}
}
#[derive(Debug, Error)]
pub enum ShmScreencopyError {
#[error("There is no render context")]