From 5b4e544911f3613186b03daa095a16f0573af8ea Mon Sep 17 00:00:00 2001 From: Matt Hunzinger Date: Fri, 21 Jun 2024 14:23:08 -0400 Subject: [PATCH] Send basic tree updates on dom change --- packages/dioxus-blitz/src/window.rs | 65 ++++++++++++++++++++++++++++- packages/dom/src/document.rs | 11 ++++- 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/packages/dioxus-blitz/src/window.rs b/packages/dioxus-blitz/src/window.rs index e90573c6..b78fc578 100644 --- a/packages/dioxus-blitz/src/window.rs +++ b/packages/dioxus-blitz/src/window.rs @@ -1,12 +1,13 @@ use crate::waker::UserEvent; use blitz::{RenderState, Renderer, Viewport}; -use blitz_dom::DocumentLike; +use blitz_dom::{Document, DocumentLike, Node}; use winit::keyboard::PhysicalKey; #[allow(unused)] use wgpu::rwh::HasWindowHandle; use muda::{AboutMetadata, Menu, MenuId, MenuItem, PredefinedMenuItem, Submenu}; +use std::mem; use std::sync::Arc; use std::task::Waker; use vello::Scene; @@ -23,10 +24,40 @@ struct State { #[cfg(feature = "accesskit")] node_ids: std::collections::HashMap, + #[cfg(feature = "accesskit")] + next_id: u64, + /// Main menu bar of this view's window. _menu: Menu, } +impl State { + fn build_node(&mut self, node_id: usize, node: &Node) -> (accesskit::NodeId, accesskit::Node) { + let mut node_builder = accesskit::NodeBuilder::default(); + if let Some(element_data) = node.element_data() { + let name = element_data.name.local.to_string(); + let role = match &*name { + "button" => accesskit::Role::Button, + "div" | "section" => accesskit::Role::Group, + "p" => accesskit::Role::Paragraph, + _ => accesskit::Role::Unknown, + }; + + node_builder.set_role(role); + node_builder.set_name(name); + } else if node.is_text_node() { + node_builder.set_role(accesskit::Role::StaticText); + node_builder.set_name(node.text_content()); + } + + let id = accesskit::NodeId(self.next_id); + self.next_id += 1; + + self.node_ids.insert(id, node_id); + (id, node_builder.build()) + } +} + pub(crate) struct View<'s, Doc: DocumentLike> { pub(crate) renderer: Renderer<'s, Window, Doc>, pub(crate) scene: Scene, @@ -57,7 +88,35 @@ impl<'a, Doc: DocumentLike> View<'a, Doc> { None => false, Some(waker) => { let cx = std::task::Context::from_waker(waker); - self.renderer.poll(cx) + if self.renderer.poll(cx) { + let Some(ref mut state) = self.state else { + return true; + }; + + let changed = mem::take(&mut self.renderer.dom.as_mut().changed); + if !changed.is_empty() { + let doc = self.renderer.dom.as_ref(); + + let nodes = changed + .iter() + .map(|id| { + let node = doc.get_node(*id).unwrap(); + state.build_node(*id, node) + }) + .collect(); + + let tree_update = accesskit::TreeUpdate { + nodes, + tree: None, + focus: accesskit::NodeId(1), + }; + state.adapter.update_if_active(|| tree_update); + } + + true + } else { + false + } } } } @@ -366,6 +425,8 @@ impl<'a, Doc: DocumentLike> View<'a, Doc> { adapter: accesskit_winit::Adapter::with_event_loop_proxy(&window, proxy.clone()), #[cfg(feature = "accesskit")] node_ids: Default::default(), + #[cfg(feature = "accesskit")] + next_id: 1, _menu: menu, }); diff --git a/packages/dom/src/document.rs b/packages/dom/src/document.rs index 7fe878a4..5182c8ea 100644 --- a/packages/dom/src/document.rs +++ b/packages/dom/src/document.rs @@ -5,7 +5,7 @@ use crate::{Node, NodeData, TextNodeData}; use selectors::{matching::QuirksMode, Element}; use slab::Slab; use std::any::Any; -use std::collections::{HashMap, VecDeque}; +use std::collections::{HashMap, HashSet, VecDeque}; use style::invalidation::element::restyle_hints::RestyleHint; use style::selector_parser::ServoElementSnapshot; use style::servo::media_queries::FontMetricsProvider; @@ -92,6 +92,8 @@ pub struct Document { pub(crate) layout_ctx: parley::LayoutContext, pub(crate) hover_node_id: Option, + + pub changed: HashSet, } impl Document { @@ -122,6 +124,7 @@ impl Document { layout_ctx: parley::LayoutContext::new(), hover_node_id: None, + changed: HashSet::new(), }; // Initialise document with root Document node @@ -184,6 +187,9 @@ impl Document { // id as usize, // ); + // Mark the new node as changed. + self.changed.insert(id); + id } @@ -227,6 +233,9 @@ impl Document { let parent_id = node.parent.unwrap_or_default(); let parent = &mut self.nodes[parent_id]; + // Mark the node's parent as changed. + self.changed.insert(parent_id); + let mut children = std::mem::take(&mut parent.children); children.splice( node_child_idx..node_child_idx,