Maintain view stack as part of DispatchTree

This commit is contained in:
Antonio Scandurra 2024-01-09 15:12:23 +01:00
parent f55870f378
commit 84b05d6c05
3 changed files with 139 additions and 65 deletions

View File

@ -4,7 +4,7 @@ use crate::{
};
use collections::FxHashMap;
use parking_lot::Mutex;
use smallvec::SmallVec;
use smallvec::{smallvec, SmallVec};
use std::{
any::{Any, TypeId},
mem,
@ -18,6 +18,7 @@ pub struct DispatchNodeId(usize);
pub(crate) struct DispatchTree {
node_stack: Vec<DispatchNodeId>,
pub(crate) context_stack: Vec<KeyContext>,
view_stack: Vec<EntityId>,
nodes: Vec<DispatchNode>,
focusable_node_ids: FxHashMap<FocusId, DispatchNodeId>,
view_node_ids: FxHashMap<EntityId, DispatchNodeId>,
@ -49,6 +50,7 @@ impl DispatchTree {
Self {
node_stack: Vec::new(),
context_stack: Vec::new(),
view_stack: Vec::new(),
nodes: Vec::new(),
focusable_node_ids: FxHashMap::default(),
view_node_ids: FxHashMap::default(),
@ -60,8 +62,9 @@ impl DispatchTree {
pub fn clear(&mut self) {
self.node_stack.clear();
self.nodes.clear();
self.context_stack.clear();
self.view_stack.clear();
self.nodes.clear();
self.focusable_node_ids.clear();
self.view_node_ids.clear();
self.keystroke_matchers.clear();
@ -82,10 +85,14 @@ impl DispatchTree {
}
pub fn pop_node(&mut self) {
let node_id = self.node_stack.pop().unwrap();
if self.nodes[node_id.0].context.is_some() {
let node = &self.nodes[self.active_node_id().0];
if node.context.is_some() {
self.context_stack.pop();
}
if node.view_id.is_some() {
self.view_stack.pop();
}
self.node_stack.pop();
}
fn move_node(&mut self, source_node: &mut DispatchNode) {
@ -102,7 +109,7 @@ impl DispatchTree {
target_node.action_listeners = mem::take(&mut source_node.action_listeners);
}
pub fn graft(&mut self, view_id: EntityId, source: &mut Self) {
pub fn graft(&mut self, view_id: EntityId, source: &mut Self) -> SmallVec<[EntityId; 8]> {
let view_source_node_id = source
.view_node_ids
.get(&view_id)
@ -110,6 +117,7 @@ impl DispatchTree {
let view_source_node = &mut source.nodes[view_source_node_id.0];
self.move_node(view_source_node);
let mut grafted_view_ids = smallvec![view_id];
let mut source_stack = vec![*view_source_node_id];
for (source_node_id, source_node) in source
.nodes
@ -130,12 +138,17 @@ impl DispatchTree {
} else {
source_stack.push(source_node_id);
self.move_node(source_node);
if let Some(view_id) = source_node.view_id {
grafted_view_ids.push(view_id);
}
}
}
while !source_stack.is_empty() {
self.pop_node();
}
grafted_view_ids
}
pub fn clear_pending_keystrokes(&mut self) {
@ -192,6 +205,7 @@ impl DispatchTree {
let node_id = self.active_node_id();
self.active_node().view_id = Some(view_id);
self.view_node_ids.insert(view_id, node_id);
self.view_stack.push(view_id);
}
pub fn focus_contains(&self, parent: FocusId, child: FocusId) -> bool {
@ -322,6 +336,24 @@ impl DispatchTree {
focus_path
}
pub fn view_path(&self, view_id: EntityId) -> SmallVec<[EntityId; 8]> {
let mut view_path: SmallVec<[EntityId; 8]> = SmallVec::new();
let mut current_node_id = self.view_node_ids.get(&view_id).copied();
while let Some(node_id) = current_node_id {
let node = self.node(node_id);
if let Some(view_id) = node.view_id {
view_path.push(view_id);
}
current_node_id = node.parent;
}
view_path.reverse(); // Reverse the path so it goes from the root to the view node.
view_path
}
pub fn active_view_id(&self) -> Option<EntityId> {
self.view_stack.last().copied()
}
pub fn node(&self, node_id: DispatchNodeId) -> &DispatchNode {
&self.nodes[node_id.0]
}

View File

@ -11,13 +11,12 @@ pub(crate) type PointF = Point<f32>;
pub(crate) type PathVertex_ScaledPixels = PathVertex<ScaledPixels>;
pub type LayerId = u32;
pub type DrawOrder = u32;
#[derive(Default)]
pub(crate) struct SceneBuilder {
last_order: Option<(StackingOrder, LayerId)>,
layers_by_order: BTreeMap<StackingOrder, LayerId>,
orders_by_layer: BTreeMap<LayerId, StackingOrder>,
shadows: Vec<Shadow>,
quads: Vec<Quad>,
paths: Vec<Path<ScaledPixels>>,
@ -34,40 +33,39 @@ impl SceneBuilder {
orders[*layer_id as usize] = ix as u32;
}
self.layers_by_order.clear();
self.last_order = None;
for shadow in &mut self.shadows {
shadow.order = orders[shadow.order as usize];
shadow.order = orders[shadow.layer_id as usize];
}
self.shadows.sort_by_key(|shadow| shadow.order);
for quad in &mut self.quads {
quad.order = orders[quad.order as usize];
quad.order = orders[quad.layer_id as usize];
}
self.quads.sort_by_key(|quad| quad.order);
for path in &mut self.paths {
path.order = orders[path.order as usize];
path.order = orders[path.layer_id as usize];
}
self.paths.sort_by_key(|path| path.order);
for underline in &mut self.underlines {
underline.order = orders[underline.order as usize];
underline.order = orders[underline.layer_id as usize];
}
self.underlines.sort_by_key(|underline| underline.order);
for monochrome_sprite in &mut self.monochrome_sprites {
monochrome_sprite.order = orders[monochrome_sprite.order as usize];
monochrome_sprite.order = orders[monochrome_sprite.layer_id as usize];
}
self.monochrome_sprites.sort_by_key(|sprite| sprite.order);
for polychrome_sprite in &mut self.polychrome_sprites {
polychrome_sprite.order = orders[polychrome_sprite.order as usize];
polychrome_sprite.order = orders[polychrome_sprite.layer_id as usize];
}
self.polychrome_sprites.sort_by_key(|sprite| sprite.order);
for surface in &mut self.surfaces {
surface.order = orders[surface.order as usize];
surface.order = orders[surface.layer_id as usize];
}
self.surfaces.sort_by_key(|surface| surface.order);
@ -96,53 +94,46 @@ impl SceneBuilder {
let layer_id = self.layer_id_for_order(order);
match primitive {
Primitive::Shadow(mut shadow) => {
shadow.order = layer_id;
shadow.layer_id = layer_id;
self.shadows.push(shadow);
}
Primitive::Quad(mut quad) => {
quad.order = layer_id;
quad.layer_id = layer_id;
self.quads.push(quad);
}
Primitive::Path(mut path) => {
path.order = layer_id;
path.layer_id = layer_id;
path.id = PathId(self.paths.len());
self.paths.push(path);
}
Primitive::Underline(mut underline) => {
underline.order = layer_id;
underline.layer_id = layer_id;
self.underlines.push(underline);
}
Primitive::MonochromeSprite(mut sprite) => {
sprite.order = layer_id;
sprite.layer_id = layer_id;
self.monochrome_sprites.push(sprite);
}
Primitive::PolychromeSprite(mut sprite) => {
sprite.order = layer_id;
sprite.layer_id = layer_id;
self.polychrome_sprites.push(sprite);
}
Primitive::Surface(mut surface) => {
surface.order = layer_id;
surface.layer_id = layer_id;
self.surfaces.push(surface);
}
}
}
fn layer_id_for_order(&mut self, order: &StackingOrder) -> u32 {
if let Some((last_order, last_layer_id)) = self.last_order.as_ref() {
if last_order == order {
return *last_layer_id;
}
};
let layer_id = if let Some(layer_id) = self.layers_by_order.get(order) {
fn layer_id_for_order(&mut self, order: &StackingOrder) -> LayerId {
if let Some(layer_id) = self.layers_by_order.get(order) {
*layer_id
} else {
let next_id = self.layers_by_order.len() as LayerId;
self.layers_by_order.insert(order.clone(), next_id);
self.orders_by_layer.insert(next_id, order.clone());
next_id
};
self.last_order = Some((order.clone(), layer_id));
layer_id
}
}
}
@ -439,7 +430,9 @@ pub(crate) enum PrimitiveBatch<'a> {
#[derive(Default, Debug, Clone, Eq, PartialEq)]
#[repr(C)]
pub struct Quad {
pub order: u32, // Initially a LayerId, then a DrawOrder.
pub view_id: u32,
pub layer_id: LayerId,
pub order: DrawOrder,
pub bounds: Bounds<ScaledPixels>,
pub content_mask: ContentMask<ScaledPixels>,
pub background: Hsla,
@ -469,7 +462,9 @@ impl From<Quad> for Primitive {
#[derive(Debug, Clone, Eq, PartialEq)]
#[repr(C)]
pub struct Underline {
pub order: u32,
pub view_id: u32,
pub layer_id: LayerId,
pub order: DrawOrder,
pub bounds: Bounds<ScaledPixels>,
pub content_mask: ContentMask<ScaledPixels>,
pub thickness: ScaledPixels,
@ -498,7 +493,9 @@ impl From<Underline> for Primitive {
#[derive(Debug, Clone, Eq, PartialEq)]
#[repr(C)]
pub struct Shadow {
pub order: u32,
pub view_id: u32,
pub layer_id: LayerId,
pub order: DrawOrder,
pub bounds: Bounds<ScaledPixels>,
pub corner_radii: Corners<ScaledPixels>,
pub content_mask: ContentMask<ScaledPixels>,
@ -527,7 +524,9 @@ impl From<Shadow> for Primitive {
#[derive(Clone, Debug, Eq, PartialEq)]
#[repr(C)]
pub struct MonochromeSprite {
pub order: u32,
pub view_id: u32,
pub layer_id: LayerId,
pub order: DrawOrder,
pub bounds: Bounds<ScaledPixels>,
pub content_mask: ContentMask<ScaledPixels>,
pub color: Hsla,
@ -558,7 +557,9 @@ impl From<MonochromeSprite> for Primitive {
#[derive(Clone, Debug, Eq, PartialEq)]
#[repr(C)]
pub struct PolychromeSprite {
pub order: u32,
pub view_id: u32,
pub layer_id: LayerId,
pub order: DrawOrder,
pub bounds: Bounds<ScaledPixels>,
pub content_mask: ContentMask<ScaledPixels>,
pub corner_radii: Corners<ScaledPixels>,
@ -589,7 +590,9 @@ impl From<PolychromeSprite> for Primitive {
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Surface {
pub order: u32,
pub view_id: u32,
pub layer_id: LayerId,
pub order: DrawOrder,
pub bounds: Bounds<ScaledPixels>,
pub content_mask: ContentMask<ScaledPixels>,
pub image_buffer: media::core_video::CVImageBuffer,
@ -619,7 +622,9 @@ pub(crate) struct PathId(pub(crate) usize);
#[derive(Debug)]
pub struct Path<P: Clone + Default + Debug> {
pub(crate) id: PathId,
order: u32,
pub(crate) view_id: u32,
layer_id: LayerId,
order: DrawOrder,
pub(crate) bounds: Bounds<P>,
pub(crate) content_mask: ContentMask<P>,
pub(crate) vertices: Vec<PathVertex<P>>,
@ -633,6 +638,8 @@ impl Path<Pixels> {
pub fn new(start: Point<Pixels>) -> Self {
Self {
id: PathId(0),
view_id: 0,
layer_id: 0,
order: 0,
vertices: Vec::new(),
start,
@ -650,6 +657,8 @@ impl Path<Pixels> {
pub fn scale(&self, factor: f32) -> Path<ScaledPixels> {
Path {
id: self.id,
view_id: self.view_id,
layer_id: self.layer_id,
order: self.order,
bounds: self.bounds.scale(factor),
content_mask: self.content_mask.scale(factor),

View File

@ -295,8 +295,6 @@ pub(crate) struct Frame {
pub(crate) next_stacking_order_id: u32,
content_mask_stack: Vec<ContentMask<Pixels>>,
element_offset_stack: Vec<Point<Pixels>>,
pub(crate) view_parents: FxHashMap<EntityId, EntityId>,
pub(crate) view_stack: Vec<EntityId>,
pub(crate) reused_views: FxHashSet<EntityId>,
}
@ -313,8 +311,6 @@ impl Frame {
depth_map: Default::default(),
content_mask_stack: Vec::new(),
element_offset_stack: Vec::new(),
view_parents: FxHashMap::default(),
view_stack: Vec::new(),
reused_views: FxHashSet::default(),
}
}
@ -325,8 +321,6 @@ impl Frame {
self.dispatch_tree.clear();
self.depth_map.clear();
self.next_stacking_order_id = 0;
self.view_parents.clear();
debug_assert!(self.view_stack.is_empty());
self.reused_views.clear();
}
@ -886,8 +880,8 @@ impl<'a> WindowContext<'a> {
&mut self,
mut handler: impl FnMut(&Event, DispatchPhase, &mut WindowContext) + 'static,
) {
let view_id = self.active_view_id();
let order = self.window.next_frame.z_index_stack.clone();
let view_id = *self.window.next_frame.view_stack.last().unwrap();
self.window
.next_frame
.mouse_listeners
@ -1029,6 +1023,7 @@ impl<'a> WindowContext<'a> {
) {
let scale_factor = self.scale_factor();
let content_mask = self.content_mask();
let view_id = self.active_view_id();
let window = &mut *self.window;
for shadow in shadows {
let mut shadow_bounds = bounds;
@ -1037,6 +1032,8 @@ impl<'a> WindowContext<'a> {
window.next_frame.scene_builder.insert(
&window.next_frame.z_index_stack,
Shadow {
view_id: view_id.as_u64() as u32,
layer_id: 0,
order: 0,
bounds: shadow_bounds.scale(scale_factor),
content_mask: content_mask.scale(scale_factor),
@ -1054,11 +1051,14 @@ impl<'a> WindowContext<'a> {
pub fn paint_quad(&mut self, quad: PaintQuad) {
let scale_factor = self.scale_factor();
let content_mask = self.content_mask();
let view_id = self.active_view_id();
let window = &mut *self.window;
window.next_frame.scene_builder.insert(
&window.next_frame.z_index_stack,
Quad {
view_id: view_id.as_u64() as u32,
layer_id: 0,
order: 0,
bounds: quad.bounds.scale(scale_factor),
content_mask: content_mask.scale(scale_factor),
@ -1074,8 +1074,11 @@ impl<'a> WindowContext<'a> {
pub fn paint_path(&mut self, mut path: Path<Pixels>, color: impl Into<Hsla>) {
let scale_factor = self.scale_factor();
let content_mask = self.content_mask();
let view_id = self.active_view_id();
path.content_mask = content_mask;
path.color = color.into();
path.view_id = view_id.as_u64() as u32;
let window = &mut *self.window;
window
.next_frame
@ -1101,10 +1104,14 @@ impl<'a> WindowContext<'a> {
size: size(width, height),
};
let content_mask = self.content_mask();
let view_id = self.active_view_id();
let window = &mut *self.window;
window.next_frame.scene_builder.insert(
&window.next_frame.z_index_stack,
Underline {
view_id: view_id.as_u64() as u32,
layer_id: 0,
order: 0,
bounds: bounds.scale(scale_factor),
content_mask: content_mask.scale(scale_factor),
@ -1154,10 +1161,13 @@ impl<'a> WindowContext<'a> {
size: tile.bounds.size.map(Into::into),
};
let content_mask = self.content_mask().scale(scale_factor);
let view_id = self.active_view_id();
let window = &mut *self.window;
window.next_frame.scene_builder.insert(
&window.next_frame.z_index_stack,
MonochromeSprite {
view_id: view_id.as_u64() as u32,
layer_id: 0,
order: 0,
bounds,
content_mask,
@ -1204,11 +1214,14 @@ impl<'a> WindowContext<'a> {
size: tile.bounds.size.map(Into::into),
};
let content_mask = self.content_mask().scale(scale_factor);
let view_id = self.active_view_id();
let window = &mut *self.window;
window.next_frame.scene_builder.insert(
&window.next_frame.z_index_stack,
PolychromeSprite {
view_id: view_id.as_u64() as u32,
layer_id: 0,
order: 0,
bounds,
corner_radii: Default::default(),
@ -1246,11 +1259,14 @@ impl<'a> WindowContext<'a> {
Ok((params.size, Cow::Owned(bytes)))
})?;
let content_mask = self.content_mask().scale(scale_factor);
let view_id = self.active_view_id();
let window = &mut *self.window;
window.next_frame.scene_builder.insert(
&window.next_frame.z_index_stack,
MonochromeSprite {
view_id: view_id.as_u64() as u32,
layer_id: 0,
order: 0,
bounds,
content_mask,
@ -1282,11 +1298,14 @@ impl<'a> WindowContext<'a> {
})?;
let content_mask = self.content_mask().scale(scale_factor);
let corner_radii = corner_radii.scale(scale_factor);
let view_id = self.active_view_id();
let window = &mut *self.window;
window.next_frame.scene_builder.insert(
&window.next_frame.z_index_stack,
PolychromeSprite {
view_id: view_id.as_u64() as u32,
layer_id: 0,
order: 0,
bounds,
content_mask,
@ -1303,10 +1322,13 @@ impl<'a> WindowContext<'a> {
let scale_factor = self.scale_factor();
let bounds = bounds.scale(scale_factor);
let content_mask = self.content_mask().scale(scale_factor);
let view_id = self.active_view_id();
let window = &mut *self.window;
window.next_frame.scene_builder.insert(
&window.next_frame.z_index_stack,
Surface {
view_id: view_id.as_u64() as u32,
layer_id: 0,
order: 0,
bounds,
content_mask,
@ -1316,13 +1338,23 @@ impl<'a> WindowContext<'a> {
}
pub(crate) fn reuse_geometry(&mut self) {
let view_id = self.active_view_id();
let window = &mut self.window;
let view_id = *window.next_frame.view_stack.last().unwrap();
assert!(window.next_frame.reused_views.insert(view_id));
window
let grafted_view_ids = window
.next_frame
.dispatch_tree
.graft(view_id, &mut window.rendered_frame.dispatch_tree)
.graft(view_id, &mut window.rendered_frame.dispatch_tree);
for view_id in grafted_view_ids {
assert!(window.next_frame.reused_views.insert(view_id));
}
}
fn active_view_id(&self) -> EntityId {
self.window
.next_frame
.dispatch_tree
.active_view_id()
.expect("a view should always be active")
}
/// Draw pixels to the display for this window based on the contents of its scene.
@ -1375,6 +1407,7 @@ impl<'a> WindowContext<'a> {
.draw(active_tooltip.cursor_offset, available_space, cx);
});
}
self.window.dirty_views.clear();
self.window
.next_frame
@ -1385,6 +1418,7 @@ impl<'a> WindowContext<'a> {
);
self.window.next_frame.focus = self.window.focus;
self.window.root_view = Some(root_view);
for (type_id, listeners) in &mut self.window.rendered_frame.mouse_listeners {
let next_listeners = self
.window
@ -1434,7 +1468,6 @@ impl<'a> WindowContext<'a> {
}
self.window.drawing = false;
self.window.dirty_views.clear();
ELEMENT_ARENA.with_borrow_mut(|element_arena| element_arena.clear());
scene
@ -2132,9 +2165,13 @@ pub trait BorrowWindow: BorrowMut<Window> + BorrowMut<AppContext> {
}
fn with_view_id<R>(&mut self, view_id: EntityId, f: impl FnOnce(&mut Self) -> R) -> R {
self.window_mut().next_frame.view_stack.push(view_id);
self.window_mut().next_frame.dispatch_tree.push_node(None);
self.window_mut()
.next_frame
.dispatch_tree
.associate_view(view_id);
let result = f(self);
self.window_mut().next_frame.view_stack.pop();
self.window_mut().next_frame.dispatch_tree.pop_node();
result
}
@ -2495,17 +2532,13 @@ impl<'a, V: 'static> ViewContext<'a, V> {
}
pub fn notify(&mut self) {
let mut dirty_view_id = Some(self.view.entity_id());
while let Some(view_id) = dirty_view_id {
if self.window_cx.window.dirty_views.insert(view_id) {
dirty_view_id = self
.window_cx
.window
.rendered_frame
.view_parents
.get(&view_id)
.copied();
} else {
for view_id in self
.window
.rendered_frame
.dispatch_tree
.view_path(self.view.entity_id())
{
if !self.window.dirty_views.insert(view_id) {
break;
}
}