Moved Frame struct into element context, to be close to it's associated methods

This commit is contained in:
Mikayla 2024-01-21 20:52:24 -08:00
parent c05edee2b5
commit b65cae5874
No known key found for this signature in database
7 changed files with 218 additions and 233 deletions

View file

@ -7,21 +7,144 @@ use std::{
};
use anyhow::Result;
use collections::{FxHashMap, FxHashSet};
use derive_more::{Deref, DerefMut};
use media::core_video::CVImageBuffer;
use smallvec::SmallVec;
use util::post_inc;
use crate::{
prelude::*, size, AppContext, AvailableSpace, Bounds, BoxShadow, ContentMask, Corners,
DevicePixels, DispatchPhase, ElementId, ElementStateBox, EntityId, FocusHandle, FontId,
GlyphId, Hsla, ImageData, InputHandler, IsZero, KeyContext, KeyEvent, LayoutId,
MonochromeSprite, MouseEvent, PaintQuad, Path, Pixels, PlatformInputHandler, Point,
PolychromeSprite, Quad, RenderGlyphParams, RenderImageParams, RenderSvgParams, Shadow,
SharedString, Size, Style, Surface, Underline, UnderlineStyle, Window, WindowContext,
prelude::*, size, AnyTooltip, AppContext, AvailableSpace, Bounds, BoxShadow, ContentMask,
Corners, CursorStyle, DevicePixels, DispatchPhase, DispatchTree, ElementId, ElementStateBox,
EntityId, FocusHandle, FocusId, FontId, GlobalElementId, GlyphId, Hsla, ImageData,
InputHandler, IsZero, KeyContext, KeyEvent, LayoutId, MonochromeSprite, MouseEvent, PaintQuad,
Path, Pixels, PlatformInputHandler, Point, PolychromeSprite, Quad, RenderGlyphParams,
RenderImageParams, RenderSvgParams, Scene, Shadow, SharedString, Size, StackingOrder, Style,
Surface, TextStyleRefinement, Underline, UnderlineStyle, Window, WindowContext,
SUBPIXEL_VARIANTS,
};
use super::RequestedInputHandler;
type AnyMouseListener = Box<dyn FnMut(&dyn Any, DispatchPhase, &mut ElementContext) + 'static>;
pub(crate) struct RequestedInputHandler {
pub(crate) view_id: EntityId,
pub(crate) handler: Option<PlatformInputHandler>,
}
pub(crate) struct TooltipRequest {
pub(crate) view_id: EntityId,
pub(crate) tooltip: AnyTooltip,
}
pub(crate) struct Frame {
pub(crate) focus: Option<FocusId>,
pub(crate) window_active: bool,
pub(crate) element_states: FxHashMap<GlobalElementId, ElementStateBox>,
pub(crate) mouse_listeners: FxHashMap<TypeId, Vec<(StackingOrder, EntityId, AnyMouseListener)>>,
pub(crate) dispatch_tree: DispatchTree,
pub(crate) scene: Scene,
pub(crate) depth_map: Vec<(StackingOrder, EntityId, Bounds<Pixels>)>,
pub(crate) z_index_stack: StackingOrder,
pub(crate) next_stacking_order_id: u32,
pub(crate) next_root_z_index: u8,
pub(crate) content_mask_stack: Vec<ContentMask<Pixels>>,
pub(crate) element_offset_stack: Vec<Point<Pixels>>,
pub(crate) requested_input_handler: Option<RequestedInputHandler>,
pub(crate) tooltip_request: Option<TooltipRequest>,
pub(crate) cursor_styles: FxHashMap<EntityId, CursorStyle>,
pub(crate) requested_cursor_style: Option<CursorStyle>,
pub(crate) view_stack: Vec<EntityId>,
pub(crate) reused_views: FxHashSet<EntityId>,
#[cfg(any(test, feature = "test-support"))]
pub(crate) debug_bounds: collections::FxHashMap<String, Bounds<Pixels>>,
}
impl Frame {
pub(crate) fn new(dispatch_tree: DispatchTree) -> Self {
Frame {
focus: None,
window_active: false,
element_states: FxHashMap::default(),
mouse_listeners: FxHashMap::default(),
dispatch_tree,
scene: Scene::default(),
depth_map: Vec::new(),
z_index_stack: StackingOrder::default(),
next_stacking_order_id: 0,
next_root_z_index: 0,
content_mask_stack: Vec::new(),
element_offset_stack: Vec::new(),
requested_input_handler: None,
tooltip_request: None,
cursor_styles: FxHashMap::default(),
requested_cursor_style: None,
view_stack: Vec::new(),
reused_views: FxHashSet::default(),
#[cfg(any(test, feature = "test-support"))]
debug_bounds: FxHashMap::default(),
}
}
pub(crate) fn clear(&mut self) {
self.element_states.clear();
self.mouse_listeners.values_mut().for_each(Vec::clear);
self.dispatch_tree.clear();
self.depth_map.clear();
self.next_stacking_order_id = 0;
self.next_root_z_index = 0;
self.reused_views.clear();
self.scene.clear();
self.requested_input_handler.take();
self.tooltip_request.take();
self.cursor_styles.clear();
self.requested_cursor_style.take();
debug_assert_eq!(self.view_stack.len(), 0);
}
pub(crate) fn focus_path(&self) -> SmallVec<[FocusId; 8]> {
self.focus
.map(|focus_id| self.dispatch_tree.focus_path(focus_id))
.unwrap_or_default()
}
pub(crate) fn finish(&mut self, prev_frame: &mut Self) {
// Reuse mouse listeners that didn't change since the last frame.
for (type_id, listeners) in &mut prev_frame.mouse_listeners {
let next_listeners = self.mouse_listeners.entry(*type_id).or_default();
for (order, view_id, listener) in listeners.drain(..) {
if self.reused_views.contains(&view_id) {
next_listeners.push((order, view_id, listener));
}
}
}
// Reuse entries in the depth map that didn't change since the last frame.
for (order, view_id, bounds) in prev_frame.depth_map.drain(..) {
if self.reused_views.contains(&view_id) {
match self
.depth_map
.binary_search_by(|(level, _, _)| order.cmp(level))
{
Ok(i) | Err(i) => self.depth_map.insert(i, (order, view_id, bounds)),
}
}
}
// Retain element states for views that didn't change since the last frame.
for (element_id, state) in prev_frame.element_states.drain() {
if self.reused_views.contains(&state.parent_view_id) {
self.element_states.entry(element_id).or_insert(state);
}
}
// Reuse geometry that didn't change since the last frame.
self.scene
.reuse_views(&self.reused_views, &mut prev_frame.scene);
self.scene.finish();
}
}
/// This context is used for assisting in the implementation of the element trait
#[derive(Deref, DerefMut)]
@ -169,6 +292,76 @@ impl<'a> VisualContext for ElementContext<'a> {
}
impl<'a> ElementContext<'a> {
pub(crate) fn reuse_view(&mut self) {
let view_id = self.parent_view_id();
let grafted_view_ids = self
.cx
.window
.next_frame
.dispatch_tree
.reuse_view(view_id, &mut self.cx.window.rendered_frame.dispatch_tree);
for view_id in grafted_view_ids {
assert!(self.window.next_frame.reused_views.insert(view_id));
// Reuse the previous input handler requested during painting of the reused view.
if self
.window
.rendered_frame
.requested_input_handler
.as_ref()
.map_or(false, |requested| requested.view_id == view_id)
{
self.window.next_frame.requested_input_handler =
self.window.rendered_frame.requested_input_handler.take();
}
// Reuse the tooltip previously requested during painting of the reused view.
if self
.window
.rendered_frame
.tooltip_request
.as_ref()
.map_or(false, |requested| requested.view_id == view_id)
{
self.window.next_frame.tooltip_request =
self.window.rendered_frame.tooltip_request.take();
}
// Reuse the cursor styles previously requested during painting of the reused view.
if let Some(style) = self.window.rendered_frame.cursor_styles.remove(&view_id) {
self.window.next_frame.cursor_styles.insert(view_id, style);
self.window.next_frame.requested_cursor_style = Some(style);
}
}
}
pub fn with_text_style<F, R>(&mut self, style: Option<TextStyleRefinement>, f: F) -> R
where
F: FnOnce(&mut Self) -> R,
{
if let Some(style) = style {
self.push_text_style(style);
let result = f(self);
self.pop_text_style();
result
} else {
f(self)
}
}
/// Updates the cursor style at the platform level.
pub fn set_cursor_style(&mut self, style: CursorStyle) {
let view_id = self.parent_view_id();
self.window.next_frame.cursor_styles.insert(view_id, style);
self.window.next_frame.requested_cursor_style = Some(style);
}
/// Sets a tooltip to be rendered for the upcoming frame
pub fn set_tooltip(&mut self, tooltip: AnyTooltip) {
let view_id = self.parent_view_id();
self.window.next_frame.tooltip_request = Some(TooltipRequest { view_id, tooltip });
}
/// Pushes the given element id onto the global stack and invokes the given closure
/// with a `GlobalElementId`, which disambiguates the given id in the context of its ancestor
/// ids. Because elements are discarded and recreated on each frame, the `GlobalElementId` is