diff --git a/Cargo.toml b/Cargo.toml index 5105095e1..b017ee36a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,14 +13,14 @@ use_camera = ["freya/use_camera"] hot-reload = ["freya/hot-reload"] [patch.crates-io] -dioxus = { git = "https://github.com/DioxusLabs/dioxus", rev = "f266213618b9715e9df8c28fb51ca81e38b28055" } -dioxus-rsx = { git = "https://github.com/DioxusLabs/dioxus", rev = "f266213618b9715e9df8c28fb51ca81e38b28055" } -dioxus-core-macro = { git = "https://github.com/DioxusLabs/dioxus", rev = "f266213618b9715e9df8c28fb51ca81e38b28055" } -dioxus-hooks = { git = "https://github.com/DioxusLabs/dioxus", rev = "f266213618b9715e9df8c28fb51ca81e38b28055" } -dioxus-signals = { git = "https://github.com/DioxusLabs/dioxus", rev = "f266213618b9715e9df8c28fb51ca81e38b28055" } -dioxus-core = { git = "https://github.com/DioxusLabs/dioxus", rev = "f266213618b9715e9df8c28fb51ca81e38b28055" } -dioxus-hot-reload = { git = "https://github.com/DioxusLabs/dioxus", rev = "f266213618b9715e9df8c28fb51ca81e38b28055" } -dioxus-router = { git = "https://github.com/DioxusLabs/dioxus", rev = "f266213618b9715e9df8c28fb51ca81e38b28055" } +dioxus = { git = "https://github.com/DioxusLabs/dioxus", rev = "46b0eeb12cf2b388d29a9061b74e9470a8487679" } +dioxus-rsx = { git = "https://github.com/DioxusLabs/dioxus", rev = "46b0eeb12cf2b388d29a9061b74e9470a8487679" } +dioxus-core-macro = { git = "https://github.com/DioxusLabs/dioxus", rev = "46b0eeb12cf2b388d29a9061b74e9470a8487679" } +dioxus-hooks = { git = "https://github.com/DioxusLabs/dioxus", rev = "46b0eeb12cf2b388d29a9061b74e9470a8487679" } +dioxus-signals = { git = "https://github.com/DioxusLabs/dioxus", rev = "46b0eeb12cf2b388d29a9061b74e9470a8487679" } +dioxus-core = { git = "https://github.com/DioxusLabs/dioxus", rev = "46b0eeb12cf2b388d29a9061b74e9470a8487679" } +dioxus-hot-reload = { git = "https://github.com/DioxusLabs/dioxus", rev = "46b0eeb12cf2b388d29a9061b74e9470a8487679" } +dioxus-router = { git = "https://github.com/DioxusLabs/dioxus", rev = "46b0eeb12cf2b388d29a9061b74e9470a8487679" } [workspace.dependencies] freya = { path = "crates/freya", version = "0.1" } diff --git a/crates/common/src/paragraphs.rs b/crates/common/src/paragraphs.rs index e7ccbe57e..a435234d7 100644 --- a/crates/common/src/paragraphs.rs +++ b/crates/common/src/paragraphs.rs @@ -22,12 +22,14 @@ impl ParagraphElements { pub fn remove_paragraph(&self, node_id: NodeId, text_id: &Uuid) { let mut paragraphs = self.paragraphs.lock().unwrap(); - let text_group = paragraphs.get_mut(text_id).unwrap(); + let text_group = paragraphs.get_mut(text_id); - text_group.retain(|id| *id != node_id); + if let Some(text_group) = text_group { + text_group.retain(|id| *id != node_id); - if text_group.is_empty() { - paragraphs.remove(text_id); + if text_group.is_empty() { + paragraphs.remove(text_id); + } } } diff --git a/crates/components/src/switch.rs b/crates/components/src/switch.rs index 89d45a311..5eb5cd656 100644 --- a/crates/components/src/switch.rs +++ b/crates/components/src/switch.rs @@ -94,13 +94,10 @@ pub fn Switch(props: SwitchProps) -> Element { platform.set_cursor(CursorIcon::Pointer); }; - let onclick = { - let ontoggled = props.ontoggled.clone(); - move |e: MouseEvent| { - e.stop_propagation(); - focus.focus(); - ontoggled.call(()); - } + let onclick = move |e: MouseEvent| { + e.stop_propagation(); + focus.focus(); + props.ontoggled.call(()); }; let onkeydown = move |e: KeyboardEvent| { diff --git a/crates/core/src/dom/mutations_writer.rs b/crates/core/src/dom/mutations_writer.rs index a86ca373b..1d1b82109 100644 --- a/crates/core/src/dom/mutations_writer.rs +++ b/crates/core/src/dom/mutations_writer.rs @@ -132,9 +132,6 @@ impl<'a> WriteMutations for MutationsWriter<'a> { } fn remove_node(&mut self, id: dioxus_core::ElementId) { - let node_id = self.native_writer.state.element_to_node_id(id); - let mut dom_adapter = DioxusDOMAdapter::new_with_cache(self.native_writer.rdom); - self.layout.remove(node_id, &mut dom_adapter, true); self.remove(id); self.native_writer.remove_node(id); } diff --git a/crates/core/src/events/events_measurer.rs b/crates/core/src/events/events_measurer.rs index 1f14f33ec..776d15c2c 100644 --- a/crates/core/src/events/events_measurer.rs +++ b/crates/core/src/events/events_measurer.rs @@ -192,8 +192,6 @@ fn measure_dom_events( 'event: for collateral_event in collateral_events { let mut child_node: Option = None; - let listeners = rdom.get_listening_sorted(&collateral_event); - // Iterate over the event nodes for PotentialEvent { node_id, @@ -205,28 +203,25 @@ fn measure_dom_events( continue; }; - // Iterate over the event listeners - for listener in &listeners { - if listener.id() == *node_id { - let valid_node = if let Some(child_node) = child_node { - is_node_parent_of(rdom, child_node, *node_id) - } else { - true - }; + if rdom.is_node_listening(node_id, &collateral_event) { + let valid_node = if let Some(child_node) = child_node { + is_node_parent_of(rdom, child_node, *node_id) + } else { + true + }; - if valid_node { - let mut valid_event = event.clone(); - valid_event.set_name(collateral_event); - valid_events.push(PotentialEvent { - node_id: *node_id, - event: valid_event, - layer: *layer, - }); - - // Stack events that do not bubble up - if event.get_name().does_bubble() { - continue 'event; - } + if valid_node { + let mut valid_event = event.clone(); + valid_event.set_name(collateral_event); + valid_events.push(PotentialEvent { + node_id: *node_id, + event: valid_event, + layer: *layer, + }); + + // Stack events that do not bubble up + if event.get_name().does_bubble() { + continue 'event; } } } @@ -274,7 +269,7 @@ fn emit_global_events_listeners( ) { for global_event in global_events { let event_name = global_event.get_name(); - let listeners = fdom.rdom().get_listening_sorted(&event_name); + let listeners = fdom.rdom().get_listeners(&event_name); for listener in listeners { let element_id = listener.mounted_id().unwrap(); diff --git a/crates/core/src/plugins.rs b/crates/core/src/plugins.rs index acb6b13fb..5a54ffa58 100644 --- a/crates/core/src/plugins.rs +++ b/crates/core/src/plugins.rs @@ -47,6 +47,10 @@ pub enum PluginEvent<'a> { /// After measuring the layout. FinishedLayout(&'a Torin), + + StartedUpdatingDOM, + + FinishedUpdatingDOM, } /// Skeleton for Freya plugins. diff --git a/crates/freya/src/plugins/performance_overlay.rs b/crates/freya/src/plugins/performance_overlay.rs index 19aeb38a3..d09f50a7a 100644 --- a/crates/freya/src/plugins/performance_overlay.rs +++ b/crates/freya/src/plugins/performance_overlay.rs @@ -2,7 +2,8 @@ use std::time::{Duration, Instant}; use freya_core::plugins::{FreyaPlugin, PluginEvent}; use freya_engine::prelude::{ - Color, FontStyle, ParagraphBuilder, ParagraphStyle, Slant, TextShadow, TextStyle, Weight, Width, + Color, FontStyle, Paint, PaintStyle, ParagraphBuilder, ParagraphStyle, Rect, Slant, TextShadow, + TextStyle, Weight, Width, }; #[derive(Default)] @@ -11,6 +12,10 @@ pub struct PerformanceOverlayPlugin { started_render: Option, started_layout: Option, finished_layout: Option, + started_dom_updates: Option, + finished_dom_updates: Option, + fps_historic: Vec, + max_fps: usize, } impl FreyaPlugin for PerformanceOverlayPlugin { @@ -20,6 +25,10 @@ impl FreyaPlugin for PerformanceOverlayPlugin { PluginEvent::FinishedLayout(_) => { self.finished_layout = Some(self.started_layout.unwrap().elapsed()) } + PluginEvent::StartedUpdatingDOM => self.started_dom_updates = Some(Instant::now()), + PluginEvent::FinishedUpdatingDOM => { + self.finished_dom_updates = Some(self.started_dom_updates.unwrap().elapsed()) + } PluginEvent::BeforeRender { .. } => self.started_render = Some(Instant::now()), PluginEvent::AfterRender { canvas, @@ -28,6 +37,7 @@ impl FreyaPlugin for PerformanceOverlayPlugin { } => { let started_render = self.started_render.take().unwrap(); let finished_layout = self.finished_layout.unwrap(); + let finished_dom_updates = self.finished_dom_updates.unwrap(); let rdom = freya_dom.rdom(); let layout = freya_dom.layout(); @@ -57,6 +67,11 @@ impl FreyaPlugin for PerformanceOverlayPlugin { 30.0, ); + self.fps_historic.push(self.frames.len()); + if self.fps_historic.len() > 70 { + self.fps_historic.remove(0); + } + // Rendering time add_text( &mut paragraph_builder, @@ -71,6 +86,13 @@ impl FreyaPlugin for PerformanceOverlayPlugin { 18.0, ); + // DOM updates time + add_text( + &mut paragraph_builder, + format!("DOM Updates: {}ms \n", finished_dom_updates.as_millis()), + 18.0, + ); + // DOM size add_text( &mut paragraph_builder, @@ -88,6 +110,31 @@ impl FreyaPlugin for PerformanceOverlayPlugin { let mut paragraph = paragraph_builder.build(); paragraph.layout(f32::MAX); paragraph.paint(canvas, (5.0, 0.0)); + + let mut paint = Paint::default(); + paint.set_anti_alias(true); + paint.set_style(PaintStyle::Fill); + paint.set_color(Color::from_argb(120, 255, 255, 255)); + + self.max_fps = self + .max_fps + .max(self.fps_historic.iter().max().copied().unwrap_or_default()); + let start_x = 5.0; + let start_y = 150.0 + self.max_fps.max(60) as f32; + + canvas.draw_rect(Rect::new(5., 150., 200., start_y), &paint); + + for (i, fps) in self.fps_historic.iter().enumerate() { + let mut paint = Paint::default(); + paint.set_anti_alias(true); + paint.set_style(PaintStyle::Fill); + paint.set_color(Color::from_rgb(63, 255, 0)); + paint.set_stroke_width(3.0); + + let x = start_x + (i * 2) as f32; + let y = start_y - *fps as f32 + 2.0; + canvas.draw_circle((x, y), 2.0, &paint); + } } _ => {} } diff --git a/crates/native-core/src/real_dom.rs b/crates/native-core/src/real_dom.rs index b68f08d34..bf0f5bf87 100644 --- a/crates/native-core/src/real_dom.rs +++ b/crates/native-core/src/real_dom.rs @@ -238,18 +238,18 @@ impl RealDom { NodeMut::new(id, self) } - /// Find all nodes that are listening for an event, sorted by there height in the dom progressing starting at the bottom and progressing up. - /// This can be useful to avoid creating duplicate events. - pub fn get_listening_sorted(&self, event: &EventName) -> Vec> { + pub fn is_node_listening(&self, node_id: &NodeId, event: &EventName) -> bool { + self.nodes_listening + .get(event) + .map(|listeners| listeners.contains(node_id)) + .unwrap_or_default() + } + + pub fn get_listeners(&self, event: &EventName) -> Vec> { if let Some(nodes) = self.nodes_listening.get(event) { - let mut listening: Vec<_> = nodes + nodes .iter() - .map(|id| (*id, self.tree_ref().height(*id).unwrap())) - .collect(); - listening.sort_by(|(_, h1), (_, h2)| h1.cmp(h2).reverse()); - listening - .into_iter() - .map(|(id, _)| NodeRef { id, dom: self }) + .map(|id| NodeRef { id: *id, dom: self }) .collect() } else { Vec::new() @@ -624,8 +624,7 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> { .mark_child_changed(parent_id); } let children_ids = self.child_ids(); - let children_ids_vec = children_ids.to_vec(); - for child in children_ids_vec { + for child in children_ids { self.dom.get_mut(child).unwrap().remove(); } self.dom.tree_mut().remove(id); diff --git a/crates/renderer/src/app.rs b/crates/renderer/src/app.rs index ef0f785ce..205358bcd 100644 --- a/crates/renderer/src/app.rs +++ b/crates/renderer/src/app.rs @@ -133,20 +133,25 @@ impl App { /// Make the first build of the VirtualDOM and sync it with the RealDOM. pub fn init_doms(&mut self) { + self.plugins.send(PluginEvent::StartedUpdatingDOM); let scale_factor = self.window_env.window.scale_factor() as f32; self.provide_vdom_contexts(); self.sdom.get_mut().init_dom(&mut self.vdom, scale_factor); + self.plugins.send(PluginEvent::FinishedUpdatingDOM); } /// Update the DOM with the mutations from the VirtualDOM. pub fn apply_vdom_changes(&mut self) -> (bool, bool) { + self.plugins.send(PluginEvent::StartedUpdatingDOM); let scale_factor = self.window_env.window.scale_factor() as f32; let (repaint, relayout) = self .sdom .get_mut() .render_mutations(&mut self.vdom, scale_factor); + self.plugins.send(PluginEvent::FinishedUpdatingDOM); + if repaint { if let Some(mutations_notifier) = &self.mutations_notifier { mutations_notifier.notify_one(); diff --git a/crates/state/src/layout.rs b/crates/state/src/layout.rs index 7dc305d84..95ea43171 100644 --- a/crates/state/src/layout.rs +++ b/crates/state/src/layout.rs @@ -31,7 +31,7 @@ pub struct LayoutState { pub position: Position, pub content: Content, pub node_ref: Option, - pub node_id: NodeId + pub node_id: NodeId, } #[partial_derive_state]