1use accesskit::{Node as NodeData, NodeId, Tree as TreeData, TreeUpdate};
7use immutable_chunkmap::map::MapM as ChunkMap;
8use std::{
9 collections::{HashMap, HashSet},
10 sync::Arc,
11};
12
13use crate::node::{Node, NodeState, ParentAndIndex};
14
15#[derive(Clone)]
16pub struct State {
17 pub(crate) nodes: ChunkMap<NodeId, NodeState>,
18 pub(crate) data: TreeData,
19 focus: NodeId,
20 is_host_focused: bool,
21}
22
23#[derive(Default)]
24struct InternalChanges {
25 added_node_ids: HashSet<NodeId>,
26 updated_node_ids: HashSet<NodeId>,
27 removed_node_ids: HashSet<NodeId>,
28}
29
30impl State {
31 fn validate_global(&self) {
32 if self.nodes.get_key(&self.data.root).is_none() {
33 panic!("Root id #{} is not in the node list", self.data.root.0);
34 }
35 if self.nodes.get_key(&self.focus).is_none() {
36 panic!("Focused id #{} is not in the node list", self.focus.0);
37 }
38 }
39
40 fn update(
41 &mut self,
42 update: TreeUpdate,
43 is_host_focused: bool,
44 mut changes: Option<&mut InternalChanges>,
45 ) {
46 let mut orphans = HashSet::new();
47
48 if let Some(tree) = update.tree {
49 if tree.root != self.data.root {
50 orphans.insert(self.data.root);
51 }
52 self.data = tree;
53 }
54
55 let root = self.data.root;
56 let mut pending_nodes: HashMap<NodeId, _> = HashMap::new();
57 let mut pending_children = HashMap::new();
58
59 fn add_node(
60 nodes: &mut ChunkMap<NodeId, NodeState>,
61 changes: &mut Option<&mut InternalChanges>,
62 parent_and_index: Option<ParentAndIndex>,
63 id: NodeId,
64 data: NodeData,
65 ) {
66 let state = NodeState {
67 parent_and_index,
68 data: Arc::new(data),
69 };
70 nodes.insert_cow(id, state);
71 if let Some(changes) = changes {
72 changes.added_node_ids.insert(id);
73 }
74 }
75
76 for (node_id, node_data) in update.nodes {
77 orphans.remove(&node_id);
78
79 let mut seen_child_ids = HashSet::new();
80 for (child_index, child_id) in node_data.children().iter().enumerate() {
81 if seen_child_ids.contains(child_id) {
82 panic!(
83 "Node #{} of TreeUpdate includes duplicate child #{};",
84 node_id.0, child_id.0
85 );
86 }
87 orphans.remove(child_id);
88 let parent_and_index = ParentAndIndex(node_id, child_index);
89 if let Some(child_state) = self.nodes.get_mut_cow(child_id) {
90 if child_state.parent_and_index != Some(parent_and_index) {
91 child_state.parent_and_index = Some(parent_and_index);
92 }
93 } else if let Some(child_data) = pending_nodes.remove(child_id) {
94 add_node(
95 &mut self.nodes,
96 &mut changes,
97 Some(parent_and_index),
98 *child_id,
99 child_data,
100 );
101 } else {
102 pending_children.insert(*child_id, parent_and_index);
103 }
104 seen_child_ids.insert(child_id);
105 }
106
107 if let Some(node_state) = self.nodes.get_mut_cow(&node_id) {
108 if node_id == root {
109 node_state.parent_and_index = None;
110 }
111 for child_id in node_state.data.children().iter() {
112 if !seen_child_ids.contains(child_id) {
113 orphans.insert(*child_id);
114 }
115 }
116 if *node_state.data != node_data {
117 node_state.data = Arc::new(node_data);
118 if let Some(changes) = &mut changes {
119 changes.updated_node_ids.insert(node_id);
120 }
121 }
122 } else if let Some(parent_and_index) = pending_children.remove(&node_id) {
123 add_node(
124 &mut self.nodes,
125 &mut changes,
126 Some(parent_and_index),
127 node_id,
128 node_data,
129 );
130 } else if node_id == root {
131 add_node(&mut self.nodes, &mut changes, None, node_id, node_data);
132 } else {
133 pending_nodes.insert(node_id, node_data);
134 }
135 }
136
137 if !pending_nodes.is_empty() {
138 panic!("TreeUpdate includes {} nodes which are neither in the current tree nor a child of another node from the update: {}", pending_nodes.len(), short_node_list(pending_nodes.keys()));
139 }
140 if !pending_children.is_empty() {
141 panic!("TreeUpdate's nodes include {} children ids which are neither in the current tree nor the id of another node from the update: {}", pending_children.len(), short_node_list(pending_children.keys()));
142 }
143
144 self.focus = update.focus;
145 self.is_host_focused = is_host_focused;
146
147 if !orphans.is_empty() {
148 let mut to_remove = HashSet::new();
149
150 fn traverse_orphan(
151 nodes: &ChunkMap<NodeId, NodeState>,
152 to_remove: &mut HashSet<NodeId>,
153 id: NodeId,
154 ) {
155 to_remove.insert(id);
156 let node = nodes.get(&id).unwrap();
157 for child_id in node.data.children().iter() {
158 traverse_orphan(nodes, to_remove, *child_id);
159 }
160 }
161
162 for id in orphans {
163 traverse_orphan(&self.nodes, &mut to_remove, id);
164 }
165
166 for id in to_remove {
167 if self.nodes.remove_cow(&id).is_some() {
168 if let Some(changes) = &mut changes {
169 changes.removed_node_ids.insert(id);
170 }
171 }
172 }
173 }
174
175 self.validate_global();
176 }
177
178 fn update_host_focus_state(
179 &mut self,
180 is_host_focused: bool,
181 changes: Option<&mut InternalChanges>,
182 ) {
183 let update = TreeUpdate {
184 nodes: vec![],
185 tree: None,
186 focus: self.focus,
187 };
188 self.update(update, is_host_focused, changes);
189 }
190
191 pub fn serialize(&self) -> TreeUpdate {
192 let mut nodes = Vec::new();
193
194 fn traverse(state: &State, nodes: &mut Vec<(NodeId, NodeData)>, id: NodeId) {
195 let node = state.nodes.get(&id).unwrap();
196 nodes.push((id, (*node.data).clone()));
197
198 for child_id in node.data.children().iter() {
199 traverse(state, nodes, *child_id);
200 }
201 }
202
203 traverse(self, &mut nodes, self.data.root);
204 assert_eq!(nodes.len(), self.nodes.len());
205
206 TreeUpdate {
207 nodes,
208 tree: Some(self.data.clone()),
209 focus: self.focus,
210 }
211 }
212
213 pub fn has_node(&self, id: NodeId) -> bool {
214 self.nodes.get(&id).is_some()
215 }
216
217 pub fn node_by_id(&self, id: NodeId) -> Option<Node<'_>> {
218 self.nodes.get(&id).map(|node_state| Node {
219 tree_state: self,
220 id,
221 state: node_state,
222 })
223 }
224
225 pub fn root_id(&self) -> NodeId {
226 self.data.root
227 }
228
229 pub fn root(&self) -> Node<'_> {
230 self.node_by_id(self.root_id()).unwrap()
231 }
232
233 pub fn is_host_focused(&self) -> bool {
234 self.is_host_focused
235 }
236
237 pub fn focus_id(&self) -> Option<NodeId> {
238 self.is_host_focused.then_some(self.focus)
239 }
240
241 pub fn focus(&self) -> Option<Node<'_>> {
242 self.focus_id().map(|id| self.node_by_id(id).unwrap())
243 }
244
245 pub fn app_name(&self) -> Option<String> {
246 self.data.app_name.clone()
247 }
248
249 pub fn toolkit_name(&self) -> Option<String> {
250 self.data.toolkit_name.clone()
251 }
252
253 pub fn toolkit_version(&self) -> Option<String> {
254 self.data.toolkit_version.clone()
255 }
256}
257
258pub trait ChangeHandler {
259 fn node_added(&mut self, node: &Node);
260 fn node_updated(&mut self, old_node: &Node, new_node: &Node);
261 fn focus_moved(&mut self, old_node: Option<&Node>, new_node: Option<&Node>);
262 fn node_removed(&mut self, node: &Node);
263}
264
265pub struct Tree {
266 state: State,
267}
268
269impl Tree {
270 pub fn new(mut initial_state: TreeUpdate, is_host_focused: bool) -> Self {
271 let Some(tree) = initial_state.tree.take() else {
272 panic!("Tried to initialize the accessibility tree without a root tree. TreeUpdate::tree must be Some.");
273 };
274 let mut state = State {
275 nodes: ChunkMap::new(),
276 data: tree,
277 focus: initial_state.focus,
278 is_host_focused,
279 };
280 state.update(initial_state, is_host_focused, None);
281 Self { state }
282 }
283
284 pub fn update(&mut self, update: TreeUpdate) {
285 self.state.update(update, self.state.is_host_focused, None);
286 }
287
288 pub fn update_and_process_changes(
289 &mut self,
290 update: TreeUpdate,
291 handler: &mut impl ChangeHandler,
292 ) {
293 let mut changes = InternalChanges::default();
294 let old_state = self.state.clone();
295 self.state
296 .update(update, self.state.is_host_focused, Some(&mut changes));
297 self.process_changes(old_state, changes, handler);
298 }
299
300 pub fn update_host_focus_state(&mut self, is_host_focused: bool) {
301 self.state.update_host_focus_state(is_host_focused, None);
302 }
303
304 pub fn update_host_focus_state_and_process_changes(
305 &mut self,
306 is_host_focused: bool,
307 handler: &mut impl ChangeHandler,
308 ) {
309 let mut changes = InternalChanges::default();
310 let old_state = self.state.clone();
311 self.state
312 .update_host_focus_state(is_host_focused, Some(&mut changes));
313 self.process_changes(old_state, changes, handler);
314 }
315
316 fn process_changes(
317 &self,
318 old_state: State,
319 changes: InternalChanges,
320 handler: &mut impl ChangeHandler,
321 ) {
322 for id in &changes.added_node_ids {
323 let node = self.state.node_by_id(*id).unwrap();
324 handler.node_added(&node);
325 }
326 for id in &changes.updated_node_ids {
327 let old_node = old_state.node_by_id(*id).unwrap();
328 let new_node = self.state.node_by_id(*id).unwrap();
329 handler.node_updated(&old_node, &new_node);
330 }
331 if old_state.focus_id() != self.state.focus_id() {
332 let old_node = old_state.focus();
333 if let Some(old_node) = &old_node {
334 let id = old_node.id();
335 if !changes.updated_node_ids.contains(&id)
336 && !changes.removed_node_ids.contains(&id)
337 {
338 if let Some(old_node_new_version) = self.state.node_by_id(id) {
339 handler.node_updated(old_node, &old_node_new_version);
340 }
341 }
342 }
343 let new_node = self.state.focus();
344 if let Some(new_node) = &new_node {
345 let id = new_node.id();
346 if !changes.added_node_ids.contains(&id) && !changes.updated_node_ids.contains(&id)
347 {
348 if let Some(new_node_old_version) = old_state.node_by_id(id) {
349 handler.node_updated(&new_node_old_version, new_node);
350 }
351 }
352 }
353 handler.focus_moved(old_node.as_ref(), new_node.as_ref());
354 }
355 for id in &changes.removed_node_ids {
356 let node = old_state.node_by_id(*id).unwrap();
357 handler.node_removed(&node);
358 }
359 }
360
361 pub fn state(&self) -> &State {
362 &self.state
363 }
364}
365
366fn short_node_list<'a>(nodes: impl ExactSizeIterator<Item = &'a NodeId>) -> String {
367 if nodes.len() > 10 {
368 format!(
369 "[{} ...]",
370 nodes
371 .take(10)
372 .map(|id| format!("#{}", id.0))
373 .collect::<Vec<_>>()
374 .join(", "),
375 )
376 } else {
377 format!(
378 "[{}]",
379 nodes
380 .map(|id| format!("#{}", id.0))
381 .collect::<Vec<_>>()
382 .join(", "),
383 )
384 }
385}
386
387#[cfg(test)]
388mod tests {
389 use accesskit::{NodeBuilder, NodeId, Role, Tree, TreeUpdate};
390
391 #[test]
392 fn init_tree_with_root_node() {
393 let update = TreeUpdate {
394 nodes: vec![(NodeId(0), NodeBuilder::new(Role::Window).build())],
395 tree: Some(Tree::new(NodeId(0))),
396 focus: NodeId(0),
397 };
398 let tree = super::Tree::new(update, false);
399 assert_eq!(NodeId(0), tree.state().root().id());
400 assert_eq!(Role::Window, tree.state().root().role());
401 assert!(tree.state().root().parent().is_none());
402 }
403
404 #[test]
405 fn root_node_has_children() {
406 let update = TreeUpdate {
407 nodes: vec![
408 (NodeId(0), {
409 let mut builder = NodeBuilder::new(Role::Window);
410 builder.set_children(vec![NodeId(1), NodeId(2)]);
411 builder.build()
412 }),
413 (NodeId(1), NodeBuilder::new(Role::Button).build()),
414 (NodeId(2), NodeBuilder::new(Role::Button).build()),
415 ],
416 tree: Some(Tree::new(NodeId(0))),
417 focus: NodeId(0),
418 };
419 let tree = super::Tree::new(update, false);
420 let state = tree.state();
421 assert_eq!(
422 NodeId(0),
423 state.node_by_id(NodeId(1)).unwrap().parent().unwrap().id()
424 );
425 assert_eq!(
426 NodeId(0),
427 state.node_by_id(NodeId(2)).unwrap().parent().unwrap().id()
428 );
429 assert_eq!(2, state.root().children().count());
430 }
431
432 #[test]
433 fn add_child_to_root_node() {
434 let root_builder = NodeBuilder::new(Role::Window);
435 let first_update = TreeUpdate {
436 nodes: vec![(NodeId(0), root_builder.clone().build())],
437 tree: Some(Tree::new(NodeId(0))),
438 focus: NodeId(0),
439 };
440 let mut tree = super::Tree::new(first_update, false);
441 assert_eq!(0, tree.state().root().children().count());
442 let second_update = TreeUpdate {
443 nodes: vec![
444 (NodeId(0), {
445 let mut builder = root_builder;
446 builder.push_child(NodeId(1));
447 builder.build()
448 }),
449 (NodeId(1), NodeBuilder::new(Role::RootWebArea).build()),
450 ],
451 tree: None,
452 focus: NodeId(0),
453 };
454 struct Handler {
455 got_new_child_node: bool,
456 got_updated_root_node: bool,
457 }
458 fn unexpected_change() {
459 panic!("expected only new child node and updated root node");
460 }
461 impl super::ChangeHandler for Handler {
462 fn node_added(&mut self, node: &crate::Node) {
463 if node.id() == NodeId(1) {
464 self.got_new_child_node = true;
465 return;
466 }
467 unexpected_change();
468 }
469 fn node_updated(&mut self, old_node: &crate::Node, new_node: &crate::Node) {
470 if new_node.id() == NodeId(0)
471 && old_node.data().children().is_empty()
472 && new_node.data().children() == [NodeId(1)]
473 {
474 self.got_updated_root_node = true;
475 return;
476 }
477 unexpected_change();
478 }
479 fn focus_moved(
480 &mut self,
481 _old_node: Option<&crate::Node>,
482 _new_node: Option<&crate::Node>,
483 ) {
484 unexpected_change();
485 }
486 fn node_removed(&mut self, _node: &crate::Node) {
487 unexpected_change();
488 }
489 }
490 let mut handler = Handler {
491 got_new_child_node: false,
492 got_updated_root_node: false,
493 };
494 tree.update_and_process_changes(second_update, &mut handler);
495 assert!(handler.got_new_child_node);
496 assert!(handler.got_updated_root_node);
497 let state = tree.state();
498 assert_eq!(1, state.root().children().count());
499 assert_eq!(NodeId(1), state.root().children().next().unwrap().id());
500 assert_eq!(
501 NodeId(0),
502 state.node_by_id(NodeId(1)).unwrap().parent().unwrap().id()
503 );
504 }
505
506 #[test]
507 fn remove_child_from_root_node() {
508 let root_builder = NodeBuilder::new(Role::Window);
509 let first_update = TreeUpdate {
510 nodes: vec![
511 (NodeId(0), {
512 let mut builder = root_builder.clone();
513 builder.push_child(NodeId(1));
514 builder.build()
515 }),
516 (NodeId(1), NodeBuilder::new(Role::RootWebArea).build()),
517 ],
518 tree: Some(Tree::new(NodeId(0))),
519 focus: NodeId(0),
520 };
521 let mut tree = super::Tree::new(first_update, false);
522 assert_eq!(1, tree.state().root().children().count());
523 let second_update = TreeUpdate {
524 nodes: vec![(NodeId(0), root_builder.build())],
525 tree: None,
526 focus: NodeId(0),
527 };
528 struct Handler {
529 got_updated_root_node: bool,
530 got_removed_child_node: bool,
531 }
532 fn unexpected_change() {
533 panic!("expected only removed child node and updated root node");
534 }
535 impl super::ChangeHandler for Handler {
536 fn node_added(&mut self, _node: &crate::Node) {
537 unexpected_change();
538 }
539 fn node_updated(&mut self, old_node: &crate::Node, new_node: &crate::Node) {
540 if new_node.id() == NodeId(0)
541 && old_node.data().children() == [NodeId(1)]
542 && new_node.data().children().is_empty()
543 {
544 self.got_updated_root_node = true;
545 return;
546 }
547 unexpected_change();
548 }
549 fn focus_moved(
550 &mut self,
551 _old_node: Option<&crate::Node>,
552 _new_node: Option<&crate::Node>,
553 ) {
554 unexpected_change();
555 }
556 fn node_removed(&mut self, node: &crate::Node) {
557 if node.id() == NodeId(1) {
558 self.got_removed_child_node = true;
559 return;
560 }
561 unexpected_change();
562 }
563 }
564 let mut handler = Handler {
565 got_updated_root_node: false,
566 got_removed_child_node: false,
567 };
568 tree.update_and_process_changes(second_update, &mut handler);
569 assert!(handler.got_updated_root_node);
570 assert!(handler.got_removed_child_node);
571 assert_eq!(0, tree.state().root().children().count());
572 assert!(tree.state().node_by_id(NodeId(1)).is_none());
573 }
574
575 #[test]
576 fn move_focus_between_siblings() {
577 let first_update = TreeUpdate {
578 nodes: vec![
579 (NodeId(0), {
580 let mut builder = NodeBuilder::new(Role::Window);
581 builder.set_children(vec![NodeId(1), NodeId(2)]);
582 builder.build()
583 }),
584 (NodeId(1), NodeBuilder::new(Role::Button).build()),
585 (NodeId(2), NodeBuilder::new(Role::Button).build()),
586 ],
587 tree: Some(Tree::new(NodeId(0))),
588 focus: NodeId(1),
589 };
590 let mut tree = super::Tree::new(first_update, true);
591 assert!(tree.state().node_by_id(NodeId(1)).unwrap().is_focused());
592 let second_update = TreeUpdate {
593 nodes: vec![],
594 tree: None,
595 focus: NodeId(2),
596 };
597 struct Handler {
598 got_old_focus_node_update: bool,
599 got_new_focus_node_update: bool,
600 got_focus_change: bool,
601 }
602 fn unexpected_change() {
603 panic!("expected only focus change");
604 }
605 impl super::ChangeHandler for Handler {
606 fn node_added(&mut self, _node: &crate::Node) {
607 unexpected_change();
608 }
609 fn node_updated(&mut self, old_node: &crate::Node, new_node: &crate::Node) {
610 if old_node.id() == NodeId(1)
611 && new_node.id() == NodeId(1)
612 && old_node.is_focused()
613 && !new_node.is_focused()
614 {
615 self.got_old_focus_node_update = true;
616 return;
617 }
618 if old_node.id() == NodeId(2)
619 && new_node.id() == NodeId(2)
620 && !old_node.is_focused()
621 && new_node.is_focused()
622 {
623 self.got_new_focus_node_update = true;
624 return;
625 }
626 unexpected_change();
627 }
628 fn focus_moved(
629 &mut self,
630 old_node: Option<&crate::Node>,
631 new_node: Option<&crate::Node>,
632 ) {
633 if let (Some(old_node), Some(new_node)) = (old_node, new_node) {
634 if old_node.id() == NodeId(1) && new_node.id() == NodeId(2) {
635 self.got_focus_change = true;
636 return;
637 }
638 }
639 unexpected_change();
640 }
641 fn node_removed(&mut self, _node: &crate::Node) {
642 unexpected_change();
643 }
644 }
645 let mut handler = Handler {
646 got_old_focus_node_update: false,
647 got_new_focus_node_update: false,
648 got_focus_change: false,
649 };
650 tree.update_and_process_changes(second_update, &mut handler);
651 assert!(handler.got_old_focus_node_update);
652 assert!(handler.got_new_focus_node_update);
653 assert!(handler.got_focus_change);
654 assert!(tree.state().node_by_id(NodeId(2)).unwrap().is_focused());
655 assert!(!tree.state().node_by_id(NodeId(1)).unwrap().is_focused());
656 }
657
658 #[test]
659 fn update_node() {
660 let child_builder = NodeBuilder::new(Role::Button);
661 let first_update = TreeUpdate {
662 nodes: vec![
663 (NodeId(0), {
664 let mut builder = NodeBuilder::new(Role::Window);
665 builder.set_children(vec![NodeId(1)]);
666 builder.build()
667 }),
668 (NodeId(1), {
669 let mut builder = child_builder.clone();
670 builder.set_name("foo");
671 builder.build()
672 }),
673 ],
674 tree: Some(Tree::new(NodeId(0))),
675 focus: NodeId(0),
676 };
677 let mut tree = super::Tree::new(first_update, false);
678 assert_eq!(
679 Some("foo".into()),
680 tree.state().node_by_id(NodeId(1)).unwrap().name()
681 );
682 let second_update = TreeUpdate {
683 nodes: vec![(NodeId(1), {
684 let mut builder = child_builder;
685 builder.set_name("bar");
686 builder.build()
687 })],
688 tree: None,
689 focus: NodeId(0),
690 };
691 struct Handler {
692 got_updated_child_node: bool,
693 }
694 fn unexpected_change() {
695 panic!("expected only updated child node");
696 }
697 impl super::ChangeHandler for Handler {
698 fn node_added(&mut self, _node: &crate::Node) {
699 unexpected_change();
700 }
701 fn node_updated(&mut self, old_node: &crate::Node, new_node: &crate::Node) {
702 if new_node.id() == NodeId(1)
703 && old_node.name() == Some("foo".into())
704 && new_node.name() == Some("bar".into())
705 {
706 self.got_updated_child_node = true;
707 return;
708 }
709 unexpected_change();
710 }
711 fn focus_moved(
712 &mut self,
713 _old_node: Option<&crate::Node>,
714 _new_node: Option<&crate::Node>,
715 ) {
716 unexpected_change();
717 }
718 fn node_removed(&mut self, _node: &crate::Node) {
719 unexpected_change();
720 }
721 }
722 let mut handler = Handler {
723 got_updated_child_node: false,
724 };
725 tree.update_and_process_changes(second_update, &mut handler);
726 assert!(handler.got_updated_child_node);
727 assert_eq!(
728 Some("bar".into()),
729 tree.state().node_by_id(NodeId(1)).unwrap().name()
730 );
731 }
732
733 #[test]
738 fn no_change_update() {
739 let update = TreeUpdate {
740 nodes: vec![
741 (NodeId(0), {
742 let mut builder = NodeBuilder::new(Role::Window);
743 builder.set_children(vec![NodeId(1)]);
744 builder.build()
745 }),
746 (NodeId(1), {
747 let mut builder = NodeBuilder::new(Role::Button);
748 builder.set_name("foo");
749 builder.build()
750 }),
751 ],
752 tree: Some(Tree::new(NodeId(0))),
753 focus: NodeId(0),
754 };
755 let mut tree = super::Tree::new(update.clone(), false);
756 struct Handler;
757 fn unexpected_change() {
758 panic!("expected no changes");
759 }
760 impl super::ChangeHandler for Handler {
761 fn node_added(&mut self, _node: &crate::Node) {
762 unexpected_change();
763 }
764 fn node_updated(&mut self, _old_node: &crate::Node, _new_node: &crate::Node) {
765 unexpected_change();
766 }
767 fn focus_moved(
768 &mut self,
769 _old_node: Option<&crate::Node>,
770 _new_node: Option<&crate::Node>,
771 ) {
772 unexpected_change();
773 }
774 fn node_removed(&mut self, _node: &crate::Node) {
775 unexpected_change();
776 }
777 }
778 let mut handler = Handler {};
779 tree.update_and_process_changes(update, &mut handler);
780 }
781}