@@ -18,7 +18,6 @@ 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>,
@@ -50,7 +49,6 @@ 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(),
@@ -63,7 +61,6 @@ impl DispatchTree {
pub fn clear(&mut self) {
self.node_stack.clear();
self.context_stack.clear();
- self.view_stack.clear();
self.nodes.clear();
self.focusable_node_ids.clear();
self.view_node_ids.clear();
@@ -76,6 +73,15 @@ impl DispatchTree {
focus_id: Option<FocusId>,
view_id: Option<EntityId>,
) {
+ // Associate a view id to this only if it is the root node for the view.
+ let view_id = view_id.and_then(|view_id| {
+ if self.view_node_ids.contains_key(&view_id) {
+ None
+ } else {
+ Some(view_id)
+ }
+ });
+
let parent = self.node_stack.last().copied();
let node_id = DispatchNodeId(self.nodes.len());
self.nodes.push(DispatchNode {
@@ -96,7 +102,6 @@ impl DispatchTree {
}
if let Some(view_id) = view_id {
- self.view_stack.push(view_id);
self.view_node_ids.insert(view_id, node_id);
}
}
@@ -106,21 +111,14 @@ impl DispatchTree {
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) {
- self.push_node(
- source_node.context.take(),
- source_node.focus_id,
- source_node.view_id,
- );
- let target_node = self.active_node();
- target_node.key_listeners = mem::take(&mut source_node.key_listeners);
- target_node.action_listeners = mem::take(&mut source_node.action_listeners);
+ fn move_node(&mut self, source: &mut DispatchNode) {
+ self.push_node(source.context.take(), source.focus_id, source.view_id);
+ let target = self.active_node();
+ target.key_listeners = mem::take(&mut source.key_listeners);
+ target.action_listeners = mem::take(&mut source.action_listeners);
}
pub fn graft(&mut self, view_id: EntityId, source: &mut Self) -> SmallVec<[EntityId; 8]> {
@@ -354,10 +352,6 @@ impl DispatchTree {
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]
}
@@ -89,9 +89,11 @@ impl<V: Render> Element for View<V> {
_state: Option<Self::State>,
cx: &mut WindowContext,
) -> (LayoutId, Self::State) {
- let mut element = self.update(cx, |view, cx| view.render(cx).into_any_element());
- let layout_id = element.request_layout(cx);
- (layout_id, Some(element))
+ cx.with_view_id(self.entity_id(), |cx| {
+ let mut element = self.update(cx, |view, cx| view.render(cx).into_any_element());
+ let layout_id = element.request_layout(cx);
+ (layout_id, Some(element))
+ })
}
fn paint(&mut self, _: Bounds<Pixels>, element: &mut Self::State, cx: &mut WindowContext) {
@@ -228,10 +230,12 @@ impl AnyView {
available_space: Size<AvailableSpace>,
cx: &mut WindowContext,
) {
- cx.with_absolute_element_offset(origin, |cx| {
- let (layout_id, mut rendered_element) = (self.request_layout)(self, cx);
- cx.compute_layout(layout_id, available_space);
- cx.with_view_id(self.entity_id(), |cx| rendered_element.paint(cx));
+ cx.with_view_id(self.entity_id(), |cx| {
+ cx.with_absolute_element_offset(origin, |cx| {
+ let (layout_id, mut rendered_element) = (self.request_layout)(self, cx);
+ cx.compute_layout(layout_id, available_space);
+ rendered_element.paint(cx)
+ });
})
}
}
@@ -254,21 +258,23 @@ impl Element for AnyView {
state: Option<Self::State>,
cx: &mut WindowContext,
) -> (LayoutId, Self::State) {
- if self.cache {
- if let Some(state) = state {
- let layout_id = cx.request_layout(&state.root_style, None);
- return (layout_id, state);
+ cx.with_view_id(self.entity_id(), |cx| {
+ if self.cache {
+ if let Some(state) = state {
+ let layout_id = cx.request_layout(&state.root_style, None);
+ return (layout_id, state);
+ }
}
- }
- let (layout_id, element) = (self.request_layout)(self, cx);
- let root_style = cx.layout_style(layout_id).unwrap().clone();
- let state = AnyViewState {
- root_style,
- cache_key: None,
- element: Some(element),
- };
- (layout_id, state)
+ let (layout_id, element) = (self.request_layout)(self, cx);
+ let root_style = cx.layout_style(layout_id).unwrap().clone();
+ let state = AnyViewState {
+ root_style,
+ cache_key: None,
+ element: Some(element),
+ };
+ (layout_id, state)
+ })
}
fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
@@ -280,6 +280,7 @@ pub struct Window {
pub(crate) struct ElementStateBox {
inner: Box<dyn Any>,
+ parent_view_id: EntityId,
#[cfg(debug_assertions)]
type_name: &'static str,
}
@@ -290,11 +291,12 @@ pub(crate) struct Frame {
mouse_listeners: FxHashMap<TypeId, Vec<(StackingOrder, EntityId, AnyMouseListener)>>,
pub(crate) dispatch_tree: DispatchTree,
pub(crate) scene: Scene,
- pub(crate) depth_map: Vec<(StackingOrder, Bounds<Pixels>)>,
+ pub(crate) depth_map: Vec<(StackingOrder, EntityId, Bounds<Pixels>)>,
pub(crate) z_index_stack: StackingOrder,
pub(crate) next_stacking_order_id: u32,
content_mask_stack: Vec<ContentMask<Pixels>>,
element_offset_stack: Vec<Point<Pixels>>,
+ pub(crate) view_stack: Vec<EntityId>,
pub(crate) reused_views: FxHashSet<EntityId>,
}
@@ -311,6 +313,7 @@ impl Frame {
depth_map: Default::default(),
content_mask_stack: Vec::new(),
element_offset_stack: Vec::new(),
+ view_stack: Vec::new(),
reused_views: FxHashSet::default(),
}
}
@@ -323,6 +326,7 @@ impl Frame {
self.next_stacking_order_id = 0;
self.reused_views.clear();
self.scene.clear();
+ debug_assert_eq!(self.view_stack.len(), 0);
}
fn focus_path(&self) -> SmallVec<[FocusId; 8]> {
@@ -880,7 +884,7 @@ impl<'a> WindowContext<'a> {
&mut self,
mut handler: impl FnMut(&Event, DispatchPhase, &mut WindowContext) + 'static,
) {
- let view_id = self.active_view_id();
+ let view_id = self.parent_view_id().unwrap();
let order = self.window.next_frame.z_index_stack.clone();
self.window
.next_frame
@@ -967,17 +971,18 @@ impl<'a> WindowContext<'a> {
/// Called during painting to track which z-index is on top at each pixel position
pub fn add_opaque_layer(&mut self, bounds: Bounds<Pixels>) {
let stacking_order = self.window.next_frame.z_index_stack.clone();
- let depth_map = &mut self.window.next_frame.depth_map;
- match depth_map.binary_search_by(|(level, _)| stacking_order.cmp(level)) {
- Ok(i) | Err(i) => depth_map.insert(i, (stacking_order, bounds)),
- }
+ let view_id = self.parent_view_id().unwrap();
+ self.window
+ .next_frame
+ .depth_map
+ .push((stacking_order, view_id, bounds));
}
/// Returns true if there is no opaque layer containing the given point
/// on top of the given level. Layers whose level is an extension of the
/// level are not considered to be on top of the level.
pub fn was_top_layer(&self, point: &Point<Pixels>, level: &StackingOrder) -> bool {
- for (opaque_level, bounds) in self.window.rendered_frame.depth_map.iter() {
+ for (opaque_level, _, bounds) in self.window.rendered_frame.depth_map.iter() {
if level >= opaque_level {
break;
}
@@ -994,7 +999,7 @@ impl<'a> WindowContext<'a> {
point: &Point<Pixels>,
level: &StackingOrder,
) -> bool {
- for (opaque_level, bounds) in self.window.rendered_frame.depth_map.iter() {
+ for (opaque_level, _, bounds) in self.window.rendered_frame.depth_map.iter() {
if level >= opaque_level {
break;
}
@@ -1023,7 +1028,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 view_id = self.parent_view_id().unwrap();
let window = &mut *self.window;
for shadow in shadows {
let mut shadow_bounds = bounds;
@@ -1051,7 +1056,7 @@ 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 view_id = self.parent_view_id().unwrap();
let window = &mut *self.window;
window.next_frame.scene.insert(
@@ -1074,7 +1079,7 @@ 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();
+ let view_id = self.parent_view_id().unwrap();
path.content_mask = content_mask;
path.color = color.into();
@@ -1104,7 +1109,7 @@ impl<'a> WindowContext<'a> {
size: size(width, height),
};
let content_mask = self.content_mask();
- let view_id = self.active_view_id();
+ let view_id = self.parent_view_id().unwrap();
let window = &mut *self.window;
window.next_frame.scene.insert(
@@ -1161,7 +1166,7 @@ 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 view_id = self.parent_view_id().unwrap();
let window = &mut *self.window;
window.next_frame.scene.insert(
&window.next_frame.z_index_stack,
@@ -1214,7 +1219,7 @@ 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 view_id = self.parent_view_id().unwrap();
let window = &mut *self.window;
window.next_frame.scene.insert(
@@ -1259,7 +1264,7 @@ 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 view_id = self.parent_view_id().unwrap();
let window = &mut *self.window;
window.next_frame.scene.insert(
@@ -1298,7 +1303,7 @@ 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 view_id = self.parent_view_id().unwrap();
let window = &mut *self.window;
window.next_frame.scene.insert(
@@ -1322,7 +1327,7 @@ 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 view_id = self.parent_view_id().unwrap();
let window = &mut *self.window;
window.next_frame.scene.insert(
&window.next_frame.z_index_stack,
@@ -1338,8 +1343,7 @@ impl<'a> WindowContext<'a> {
}
pub(crate) fn reuse_geometry(&mut self) {
- println!("reusing geometry");
- let view_id = self.active_view_id();
+ let view_id = self.parent_view_id().unwrap();
let window = &mut self.window;
let grafted_view_ids = window
.next_frame
@@ -1350,17 +1354,8 @@ impl<'a> WindowContext<'a> {
}
}
- 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.
pub(crate) fn draw(&mut self) {
- println!("=====================");
self.window.dirty = false;
self.window.drawing = true;
@@ -1409,11 +1404,6 @@ impl<'a> WindowContext<'a> {
});
}
self.window.dirty_views.clear();
- self.window.next_frame.scene.insert_views_from_scene(
- &self.window.next_frame.reused_views,
- &mut self.window.rendered_frame.scene,
- );
- self.window.next_frame.scene.finish();
self.window
.next_frame
@@ -1425,6 +1415,7 @@ impl<'a> WindowContext<'a> {
self.window.next_frame.focus = self.window.focus;
self.window.root_view = Some(root_view);
+ // Reuse mouse listeners that didn't change since the last frame.
for (type_id, listeners) in &mut self.window.rendered_frame.mouse_listeners {
let next_listeners = self
.window
@@ -1439,6 +1430,43 @@ impl<'a> WindowContext<'a> {
}
}
+ // Reuse entries in the depth map that didn't change since the last frame.
+ for (order, view_id, bounds) in self.window.rendered_frame.depth_map.drain(..) {
+ if self.window.next_frame.reused_views.contains(&view_id) {
+ self.window
+ .next_frame
+ .depth_map
+ .push((order, view_id, bounds));
+ }
+ }
+ self.window
+ .next_frame
+ .depth_map
+ .sort_by(|a, b| a.0.cmp(&b.0));
+
+ // Retain element states for views that didn't change since the last frame.
+ for (element_id, state) in self.window.rendered_frame.element_states.drain() {
+ if self
+ .window
+ .next_frame
+ .reused_views
+ .contains(&state.parent_view_id)
+ {
+ self.window
+ .next_frame
+ .element_states
+ .entry(element_id)
+ .or_insert(state);
+ }
+ }
+
+ // Reuse geometry that didn't change since the last frame.
+ self.window.next_frame.scene.insert_views_from_scene(
+ &self.window.next_frame.reused_views,
+ &mut self.window.rendered_frame.scene,
+ );
+ self.window.next_frame.scene.finish();
+
let previous_focus_path = self.window.rendered_frame.focus_path();
mem::swap(&mut self.window.rendered_frame, &mut self.window.next_frame);
let current_focus_path = self.window.rendered_frame.focus_path();
@@ -1871,12 +1899,13 @@ impl<'a> WindowContext<'a> {
focus_handle: Option<FocusHandle>,
f: impl FnOnce(Option<FocusHandle>, &mut Self) -> R,
) -> R {
+ let parent_view_id = self.parent_view_id();
let window = &mut self.window;
let focus_id = focus_handle.as_ref().map(|handle| handle.id);
window
.next_frame
.dispatch_tree
- .push_node(context.clone(), focus_id, None);
+ .push_node(context.clone(), focus_id, parent_view_id);
let result = f(focus_handle, self);
@@ -1885,6 +1914,114 @@ impl<'a> WindowContext<'a> {
result
}
+ pub(crate) fn with_view_id<R>(
+ &mut self,
+ view_id: EntityId,
+ f: impl FnOnce(&mut Self) -> R,
+ ) -> R {
+ self.window.next_frame.view_stack.push(view_id);
+ let result = f(self);
+ self.window.next_frame.view_stack.pop();
+ result
+ }
+
+ /// Update or initialize state for an element with the given id that lives across multiple
+ /// frames. If an element with this id existed in the rendered frame, its state will be passed
+ /// to the given closure. The state returned by the closure will be stored so it can be referenced
+ /// when drawing the next frame.
+ pub(crate) fn with_element_state<S, R>(
+ &mut self,
+ id: ElementId,
+ f: impl FnOnce(Option<S>, &mut Self) -> (R, S),
+ ) -> R
+ where
+ S: 'static,
+ {
+ self.with_element_id(Some(id), |cx| {
+ let global_id = cx.window().element_id_stack.clone();
+
+ if let Some(any) = cx
+ .window_mut()
+ .next_frame
+ .element_states
+ .remove(&global_id)
+ .or_else(|| {
+ cx.window_mut()
+ .rendered_frame
+ .element_states
+ .remove(&global_id)
+ })
+ {
+ let ElementStateBox {
+ inner,
+ parent_view_id,
+ #[cfg(debug_assertions)]
+ type_name
+ } = any;
+ // Using the extra inner option to avoid needing to reallocate a new box.
+ let mut state_box = inner
+ .downcast::<Option<S>>()
+ .map_err(|_| {
+ #[cfg(debug_assertions)]
+ {
+ anyhow!(
+ "invalid element state type for id, requested_type {:?}, actual type: {:?}",
+ std::any::type_name::<S>(),
+ type_name
+ )
+ }
+
+ #[cfg(not(debug_assertions))]
+ {
+ anyhow!(
+ "invalid element state type for id, requested_type {:?}",
+ std::any::type_name::<S>(),
+ )
+ }
+ })
+ .unwrap();
+
+ // Actual: Option<AnyElement> <- View
+ // Requested: () <- AnyElemet
+ let state = state_box
+ .take()
+ .expect("element state is already on the stack");
+ let (result, state) = f(Some(state), cx);
+ state_box.replace(state);
+ cx.window_mut()
+ .next_frame
+ .element_states
+ .insert(global_id, ElementStateBox {
+ inner: state_box,
+ parent_view_id,
+ #[cfg(debug_assertions)]
+ type_name
+ });
+ result
+ } else {
+ let (result, state) = f(None, cx);
+ let parent_view_id = cx.parent_view_id().unwrap();
+ cx.window_mut()
+ .next_frame
+ .element_states
+ .insert(global_id,
+ ElementStateBox {
+ inner: Box::new(Some(state)),
+ parent_view_id,
+ #[cfg(debug_assertions)]
+ type_name: std::any::type_name::<S>()
+ }
+
+ );
+ result
+ }
+ })
+ }
+
+ fn parent_view_id(&self) -> Option<EntityId> {
+ self.window.next_frame.view_stack.last().copied()
+ }
+
/// Set an input handler, such as [`ElementInputHandler`][element_input_handler], which interfaces with the
/// platform to receive textual input with proper integration with concerns such
/// as IME interactions.
@@ -2169,16 +2306,6 @@ pub trait BorrowWindow: BorrowMut<Window> + BorrowMut<AppContext> {
result
}
- fn with_view_id<R>(&mut self, view_id: EntityId, f: impl FnOnce(&mut Self) -> R) -> R {
- self.window_mut()
- .next_frame
- .dispatch_tree
- .push_node(None, None, Some(view_id));
- let result = f(self);
- self.window_mut().next_frame.dispatch_tree.pop_node();
- result
- }
-
/// Update the global element offset relative to the current offset. This is used to implement
/// scrolling.
fn with_element_offset<R>(
@@ -2220,98 +2347,6 @@ pub trait BorrowWindow: BorrowMut<Window> + BorrowMut<AppContext> {
.unwrap_or_default()
}
- /// Update or initialize state for an element with the given id that lives across multiple
- /// frames. If an element with this id existed in the rendered frame, its state will be passed
- /// to the given closure. The state returned by the closure will be stored so it can be referenced
- /// when drawing the next frame.
- fn with_element_state<S, R>(
- &mut self,
- id: ElementId,
- f: impl FnOnce(Option<S>, &mut Self) -> (R, S),
- ) -> R
- where
- S: 'static,
- {
- self.with_element_id(Some(id), |cx| {
- let global_id = cx.window().element_id_stack.clone();
-
- if let Some(any) = cx
- .window_mut()
- .next_frame
- .element_states
- .remove(&global_id)
- .or_else(|| {
- cx.window_mut()
- .rendered_frame
- .element_states
- .remove(&global_id)
- })
- {
- let ElementStateBox {
- inner,
-
- #[cfg(debug_assertions)]
- type_name
- } = any;
- // Using the extra inner option to avoid needing to reallocate a new box.
- let mut state_box = inner
- .downcast::<Option<S>>()
- .map_err(|_| {
- #[cfg(debug_assertions)]
- {
- anyhow!(
- "invalid element state type for id, requested_type {:?}, actual type: {:?}",
- std::any::type_name::<S>(),
- type_name
- )
- }
-
- #[cfg(not(debug_assertions))]
- {
- anyhow!(
- "invalid element state type for id, requested_type {:?}",
- std::any::type_name::<S>(),
- )
- }
- })
- .unwrap();
-
- // Actual: Option<AnyElement> <- View
- // Requested: () <- AnyElemet
- let state = state_box
- .take()
- .expect("element state is already on the stack");
- let (result, state) = f(Some(state), cx);
- state_box.replace(state);
- cx.window_mut()
- .next_frame
- .element_states
- .insert(global_id, ElementStateBox {
- inner: state_box,
-
- #[cfg(debug_assertions)]
- type_name
- });
- result
- } else {
- let (result, state) = f(None, cx);
- cx.window_mut()
- .next_frame
- .element_states
- .insert(global_id,
- ElementStateBox {
- inner: Box::new(Some(state)),
-
- #[cfg(debug_assertions)]
- type_name: std::any::type_name::<S>()
- }
-
- );
- result
- }
- })
- }
-
/// Obtain the current content mask.
fn content_mask(&self) -> ContentMask<Pixels> {
self.window()