accesskit_atspi_common/
adapter.rs

1// Copyright 2022 The AccessKit Authors. All rights reserved.
2// Licensed under the Apache License, Version 2.0 (found in
3// the LICENSE-APACHE file) or the MIT license (found in
4// the LICENSE-MIT file), at your option.
5
6// Derived from Chromium's accessibility abstraction.
7// Copyright 2017 The Chromium Authors. All rights reserved.
8// Use of this source code is governed by a BSD-style license that can be
9// found in the LICENSE.chromium file.
10
11use crate::{
12    context::{ActionHandlerNoMut, ActionHandlerWrapper, AppContext, Context},
13    filters::filter,
14    node::{NodeIdOrRoot, NodeWrapper, PlatformNode, PlatformRoot},
15    util::WindowBounds,
16    AdapterCallback, Event, ObjectEvent, WindowEvent,
17};
18use accesskit::{ActionHandler, NodeId, Role, TreeUpdate};
19use accesskit_consumer::{FilterResult, Node, Tree, TreeChangeHandler, TreeState};
20use atspi_common::{InterfaceSet, Politeness, State};
21use std::fmt::{Debug, Formatter};
22use std::{
23    collections::HashSet,
24    sync::{
25        atomic::{AtomicUsize, Ordering},
26        Arc, RwLock,
27    },
28};
29
30struct AdapterChangeHandler<'a> {
31    adapter: &'a Adapter,
32    added_nodes: HashSet<NodeId>,
33    removed_nodes: HashSet<NodeId>,
34    checked_text_change: HashSet<NodeId>,
35    selection_changed: HashSet<NodeId>,
36}
37
38impl<'a> AdapterChangeHandler<'a> {
39    fn new(adapter: &'a Adapter) -> Self {
40        Self {
41            adapter,
42            added_nodes: HashSet::new(),
43            removed_nodes: HashSet::new(),
44            checked_text_change: HashSet::new(),
45            selection_changed: HashSet::new(),
46        }
47    }
48
49    fn add_node(&mut self, node: &Node) {
50        let id = node.id();
51        if self.added_nodes.contains(&id) {
52            return;
53        }
54        self.added_nodes.insert(id);
55
56        let role = node.role();
57        let is_root = node.is_root();
58        let wrapper = NodeWrapper(node);
59        let interfaces = wrapper.interfaces();
60        self.adapter.register_interfaces(node.id(), interfaces);
61        if is_root && role == Role::Window {
62            let adapter_index = self
63                .adapter
64                .context
65                .read_app_context()
66                .adapter_index(self.adapter.id)
67                .unwrap();
68            self.adapter.window_created(adapter_index, node.id());
69        }
70
71        let live = wrapper.live();
72        if live != Politeness::None {
73            if let Some(name) = wrapper.name() {
74                self.adapter
75                    .emit_object_event(node.id(), ObjectEvent::Announcement(name, live));
76            }
77        }
78        if let Some(true) = node.is_selected() {
79            self.enqueue_selection_changed_if_needed(node);
80        }
81    }
82
83    fn add_subtree(&mut self, node: &Node) {
84        self.add_node(node);
85        for child in node.filtered_children(&filter) {
86            self.add_subtree(&child);
87        }
88    }
89
90    fn remove_node(&mut self, node: &Node) {
91        let id = node.id();
92        if self.removed_nodes.contains(&id) {
93            return;
94        }
95        self.removed_nodes.insert(id);
96
97        let role = node.role();
98        let is_root = node.is_root();
99        let wrapper = NodeWrapper(node);
100        if is_root && role == Role::Window {
101            self.adapter.window_destroyed(node.id());
102        }
103        self.adapter
104            .emit_object_event(node.id(), ObjectEvent::StateChanged(State::Defunct, true));
105        self.adapter
106            .unregister_interfaces(node.id(), wrapper.interfaces());
107        if let Some(true) = node.is_selected() {
108            self.enqueue_selection_changed_if_needed(node);
109        }
110    }
111
112    fn remove_subtree(&mut self, node: &Node) {
113        for child in node.filtered_children(&filter) {
114            self.remove_subtree(&child);
115        }
116        self.remove_node(node);
117    }
118
119    fn emit_text_change_if_needed_parent(&mut self, old_node: &Node, new_node: &Node) {
120        if !new_node.supports_text_ranges() || !old_node.supports_text_ranges() {
121            return;
122        }
123        let id = new_node.id();
124        if self.checked_text_change.contains(&id) {
125            return;
126        }
127        self.checked_text_change.insert(id);
128        let old_text = old_node.document_range().text();
129        let new_text = new_node.document_range().text();
130
131        let mut old_chars = old_text.chars();
132        let mut new_chars = new_text.chars();
133        let mut prefix_usv_count = 0;
134        let mut prefix_byte_count = 0;
135        loop {
136            match (old_chars.next(), new_chars.next()) {
137                (Some(old_char), Some(new_char)) if old_char == new_char => {
138                    prefix_usv_count += 1;
139                    prefix_byte_count += new_char.len_utf8();
140                }
141                (None, None) => return,
142                _ => break,
143            }
144        }
145
146        let suffix_byte_count = old_text[prefix_byte_count..]
147            .chars()
148            .rev()
149            .zip(new_text[prefix_byte_count..].chars().rev())
150            .take_while(|(old_char, new_char)| old_char == new_char)
151            .fold(0, |count, (c, _)| count + c.len_utf8());
152
153        let old_content = &old_text[prefix_byte_count..old_text.len() - suffix_byte_count];
154        if let Ok(length) = old_content.chars().count().try_into() {
155            if length > 0 {
156                self.adapter.emit_object_event(
157                    id,
158                    ObjectEvent::TextRemoved {
159                        start_index: prefix_usv_count,
160                        length,
161                        content: old_content.to_string(),
162                    },
163                );
164            }
165        }
166
167        let new_content = &new_text[prefix_byte_count..new_text.len() - suffix_byte_count];
168        if let Ok(length) = new_content.chars().count().try_into() {
169            if length > 0 {
170                self.adapter.emit_object_event(
171                    id,
172                    ObjectEvent::TextInserted {
173                        start_index: prefix_usv_count,
174                        length,
175                        content: new_content.to_string(),
176                    },
177                );
178            }
179        }
180    }
181
182    fn emit_text_change_if_needed(&mut self, old_node: &Node, new_node: &Node) {
183        if let Role::TextRun | Role::GenericContainer = new_node.role() {
184            if let (Some(old_parent), Some(new_parent)) = (
185                old_node.filtered_parent(&filter),
186                new_node.filtered_parent(&filter),
187            ) {
188                self.emit_text_change_if_needed_parent(&old_parent, &new_parent);
189            }
190        } else {
191            self.emit_text_change_if_needed_parent(old_node, new_node);
192        }
193    }
194
195    fn emit_text_selection_change(&self, old_node: Option<&Node>, new_node: &Node) {
196        if !new_node.supports_text_ranges() {
197            return;
198        }
199        let Some(old_node) = old_node else {
200            if let Some(selection) = new_node.text_selection() {
201                if !selection.is_degenerate() {
202                    self.adapter
203                        .emit_object_event(new_node.id(), ObjectEvent::TextSelectionChanged);
204                }
205            }
206            if let Some(selection_focus) = new_node.text_selection_focus() {
207                if let Ok(offset) = selection_focus.to_global_usv_index().try_into() {
208                    self.adapter
209                        .emit_object_event(new_node.id(), ObjectEvent::CaretMoved(offset));
210                }
211            }
212            return;
213        };
214        if !old_node.is_focused() || new_node.raw_text_selection() == old_node.raw_text_selection()
215        {
216            return;
217        }
218
219        if let Some(selection) = new_node.text_selection() {
220            if !selection.is_degenerate()
221                || old_node
222                    .text_selection()
223                    .map(|selection| !selection.is_degenerate())
224                    .unwrap_or(false)
225            {
226                self.adapter
227                    .emit_object_event(new_node.id(), ObjectEvent::TextSelectionChanged);
228            }
229        }
230
231        let old_caret_position = old_node
232            .raw_text_selection()
233            .map(|selection| selection.focus);
234        let new_caret_position = new_node
235            .raw_text_selection()
236            .map(|selection| selection.focus);
237        if old_caret_position != new_caret_position {
238            if let Some(selection_focus) = new_node.text_selection_focus() {
239                if let Ok(offset) = selection_focus.to_global_usv_index().try_into() {
240                    self.adapter
241                        .emit_object_event(new_node.id(), ObjectEvent::CaretMoved(offset));
242                }
243            }
244        }
245    }
246
247    fn enqueue_selection_changed_if_needed_parent(&mut self, node: Node) {
248        if !node.is_container_with_selectable_children() {
249            return;
250        }
251        let id = node.id();
252        if self.selection_changed.contains(&id) {
253            return;
254        }
255        self.selection_changed.insert(id);
256    }
257
258    fn enqueue_selection_changed_if_needed(&mut self, node: &Node) {
259        if !node.is_item_like() {
260            return;
261        }
262        if let Some(node) = node.selection_container(&filter) {
263            self.enqueue_selection_changed_if_needed_parent(node);
264        }
265    }
266
267    fn emit_selection_changed(&mut self) {
268        for id in self.selection_changed.iter() {
269            if self.removed_nodes.contains(id) {
270                continue;
271            }
272            self.adapter
273                .emit_object_event(*id, ObjectEvent::SelectionChanged);
274        }
275    }
276}
277
278impl TreeChangeHandler for AdapterChangeHandler<'_> {
279    fn node_added(&mut self, node: &Node) {
280        if filter(node) == FilterResult::Include {
281            self.add_node(node);
282        }
283    }
284
285    fn node_updated(&mut self, old_node: &Node, new_node: &Node) {
286        self.emit_text_change_if_needed(old_node, new_node);
287        let filter_old = filter(old_node);
288        let filter_new = filter(new_node);
289        if filter_new != filter_old {
290            if filter_new == FilterResult::Include {
291                if filter_old == FilterResult::ExcludeSubtree {
292                    self.add_subtree(new_node);
293                } else {
294                    self.add_node(new_node);
295                }
296            } else if filter_old == FilterResult::Include {
297                if filter_new == FilterResult::ExcludeSubtree {
298                    self.remove_subtree(old_node);
299                } else {
300                    self.remove_node(old_node);
301                }
302            }
303        } else if filter_new == FilterResult::Include {
304            let old_wrapper = NodeWrapper(old_node);
305            let new_wrapper = NodeWrapper(new_node);
306            let old_interfaces = old_wrapper.interfaces();
307            let new_interfaces = new_wrapper.interfaces();
308            let kept_interfaces = old_interfaces & new_interfaces;
309            self.adapter
310                .unregister_interfaces(new_wrapper.id(), old_interfaces ^ kept_interfaces);
311            self.adapter
312                .register_interfaces(new_node.id(), new_interfaces ^ kept_interfaces);
313            let bounds = *self.adapter.context.read_root_window_bounds();
314            new_wrapper.notify_changes(&bounds, self.adapter, &old_wrapper);
315            self.emit_text_selection_change(Some(old_node), new_node);
316            if new_node.is_selected() != old_node.is_selected() {
317                self.enqueue_selection_changed_if_needed(new_node);
318            }
319        }
320    }
321
322    fn focus_moved(&mut self, old_node: Option<&Node>, new_node: Option<&Node>) {
323        if let (None, Some(new_node)) = (old_node, new_node) {
324            if let Some(root_window) = root_window(new_node.tree_state) {
325                self.adapter.window_activated(&NodeWrapper(&root_window));
326            }
327        } else if let (Some(old_node), None) = (old_node, new_node) {
328            if let Some(root_window) = root_window(old_node.tree_state) {
329                self.adapter.window_deactivated(&NodeWrapper(&root_window));
330            }
331        }
332        if let Some(node) = new_node {
333            self.adapter
334                .emit_object_event(node.id(), ObjectEvent::StateChanged(State::Focused, true));
335            self.emit_text_selection_change(None, node);
336        }
337        if let Some(node) = old_node {
338            self.adapter
339                .emit_object_event(node.id(), ObjectEvent::StateChanged(State::Focused, false));
340        }
341    }
342
343    fn node_removed(&mut self, node: &Node) {
344        if filter(node) == FilterResult::Include {
345            self.remove_node(node);
346        }
347    }
348}
349
350static NEXT_ADAPTER_ID: AtomicUsize = AtomicUsize::new(0);
351
352/// If you use this function, you must ensure that only one adapter at a time
353/// has a given ID.
354pub fn next_adapter_id() -> usize {
355    NEXT_ADAPTER_ID.fetch_add(1, Ordering::Relaxed)
356}
357
358pub struct Adapter {
359    id: usize,
360    callback: Box<dyn AdapterCallback + Send + Sync>,
361    context: Arc<Context>,
362}
363
364impl Debug for Adapter {
365    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
366        f.debug_struct("Adapter")
367            .field("id", &self.id)
368            .field("callback", &"AdapterCallback")
369            .field("context", &self.context)
370            .finish()
371    }
372}
373
374impl Adapter {
375    pub fn new(
376        app_context: &Arc<RwLock<AppContext>>,
377        callback: impl 'static + AdapterCallback + Send + Sync,
378        initial_state: TreeUpdate,
379        is_window_focused: bool,
380        root_window_bounds: WindowBounds,
381        action_handler: impl 'static + ActionHandler + Send,
382    ) -> Self {
383        let id = next_adapter_id();
384        Self::with_id(
385            id,
386            app_context,
387            callback,
388            initial_state,
389            is_window_focused,
390            root_window_bounds,
391            action_handler,
392        )
393    }
394
395    pub fn with_id(
396        id: usize,
397        app_context: &Arc<RwLock<AppContext>>,
398        callback: impl 'static + AdapterCallback + Send + Sync,
399        initial_state: TreeUpdate,
400        is_window_focused: bool,
401        root_window_bounds: WindowBounds,
402        action_handler: impl 'static + ActionHandler + Send,
403    ) -> Self {
404        Self::with_wrapped_action_handler(
405            id,
406            app_context,
407            callback,
408            initial_state,
409            is_window_focused,
410            root_window_bounds,
411            Arc::new(ActionHandlerWrapper::new(action_handler)),
412        )
413    }
414
415    /// This is an implementation detail of `accesskit_unix`, required for
416    /// robust state transitions with minimal overhead.
417    pub fn with_wrapped_action_handler(
418        id: usize,
419        app_context: &Arc<RwLock<AppContext>>,
420        callback: impl 'static + AdapterCallback + Send + Sync,
421        initial_state: TreeUpdate,
422        is_window_focused: bool,
423        root_window_bounds: WindowBounds,
424        action_handler: Arc<dyn ActionHandlerNoMut + Send + Sync>,
425    ) -> Self {
426        let tree = Tree::new(initial_state, is_window_focused);
427        let focus_id = tree.state().focus_id();
428        let context = Context::new(app_context, tree, action_handler, root_window_bounds);
429        context.write_app_context().push_adapter(id, &context);
430        let adapter = Self {
431            id,
432            callback: Box::new(callback),
433            context,
434        };
435        adapter.register_tree();
436        if let Some(id) = focus_id {
437            adapter.emit_object_event(id, ObjectEvent::StateChanged(State::Focused, true));
438        }
439        adapter
440    }
441
442    fn register_tree(&self) {
443        fn add_children(node: Node<'_>, to_add: &mut Vec<(NodeId, InterfaceSet)>) {
444            for child in node.filtered_children(&filter) {
445                let child_id = child.id();
446                let wrapper = NodeWrapper(&child);
447                let interfaces = wrapper.interfaces();
448                to_add.push((child_id, interfaces));
449                add_children(child, to_add);
450            }
451        }
452
453        let mut objects_to_add = Vec::new();
454
455        let (adapter_index, root_id) = {
456            let tree = self.context.read_tree();
457            let tree_state = tree.state();
458            let mut app_context = self.context.write_app_context();
459            app_context.toolkit_name = tree_state.toolkit_name().map(|s| s.to_string());
460            app_context.toolkit_version = tree_state.toolkit_version().map(|s| s.to_string());
461            let adapter_index = app_context.adapter_index(self.id).unwrap();
462            let root = tree_state.root();
463            let root_id = root.id();
464            let wrapper = NodeWrapper(&root);
465            objects_to_add.push((root_id, wrapper.interfaces()));
466            add_children(root, &mut objects_to_add);
467            (adapter_index, root_id)
468        };
469
470        for (id, interfaces) in objects_to_add {
471            self.register_interfaces(id, interfaces);
472            if id == root_id {
473                self.window_created(adapter_index, id);
474            }
475        }
476    }
477
478    pub fn platform_node(&self, id: NodeId) -> PlatformNode {
479        PlatformNode::new(&self.context, self.id, id)
480    }
481
482    pub fn root_id(&self) -> NodeId {
483        self.context.read_tree().state().root_id()
484    }
485
486    pub fn platform_root(&self) -> PlatformRoot {
487        PlatformRoot::new(&self.context.app_context)
488    }
489
490    fn register_interfaces(&self, id: NodeId, new_interfaces: InterfaceSet) {
491        self.callback.register_interfaces(self, id, new_interfaces);
492    }
493
494    fn unregister_interfaces(&self, id: NodeId, old_interfaces: InterfaceSet) {
495        self.callback
496            .unregister_interfaces(self, id, old_interfaces);
497    }
498
499    pub(crate) fn emit_object_event(&self, target: NodeId, event: ObjectEvent) {
500        let target = NodeIdOrRoot::Node(target);
501        self.callback
502            .emit_event(self, Event::Object { target, event });
503    }
504
505    fn emit_root_object_event(&self, event: ObjectEvent) {
506        let target = NodeIdOrRoot::Root;
507        self.callback
508            .emit_event(self, Event::Object { target, event });
509    }
510
511    pub fn set_root_window_bounds(&mut self, new_bounds: WindowBounds) {
512        let mut bounds = self.context.root_window_bounds.write().unwrap();
513        *bounds = new_bounds;
514    }
515
516    pub fn update(&mut self, update: TreeUpdate) {
517        let mut handler = AdapterChangeHandler::new(self);
518        let mut tree = self.context.tree.write().unwrap();
519        tree.update_and_process_changes(update, &mut handler);
520        drop(tree);
521        handler.emit_selection_changed();
522    }
523
524    pub fn update_window_focus_state(&mut self, is_focused: bool) {
525        let mut handler = AdapterChangeHandler::new(self);
526        let mut tree = self.context.tree.write().unwrap();
527        tree.update_host_focus_state_and_process_changes(is_focused, &mut handler);
528    }
529
530    fn window_created(&self, adapter_index: usize, window: NodeId) {
531        self.emit_root_object_event(ObjectEvent::ChildAdded(adapter_index, window));
532    }
533
534    fn window_activated(&self, window: &NodeWrapper<'_>) {
535        self.callback.emit_event(
536            self,
537            Event::Window {
538                target: window.id(),
539                name: window.name().unwrap_or_default(),
540                event: WindowEvent::Activated,
541            },
542        );
543        self.emit_object_event(window.id(), ObjectEvent::StateChanged(State::Active, true));
544        self.emit_root_object_event(ObjectEvent::ActiveDescendantChanged(window.id()));
545    }
546
547    fn window_deactivated(&self, window: &NodeWrapper<'_>) {
548        self.callback.emit_event(
549            self,
550            Event::Window {
551                target: window.id(),
552                name: window.name().unwrap_or_default(),
553                event: WindowEvent::Deactivated,
554            },
555        );
556        self.emit_object_event(window.id(), ObjectEvent::StateChanged(State::Active, false));
557    }
558
559    fn window_destroyed(&self, window: NodeId) {
560        self.emit_root_object_event(ObjectEvent::ChildRemoved(window));
561    }
562
563    pub fn id(&self) -> usize {
564        self.id
565    }
566
567    pub fn is_window_focused(&self) -> bool {
568        self.context.read_tree().state().is_host_focused()
569    }
570
571    pub fn root_window_bounds(&self) -> WindowBounds {
572        *self.context.read_root_window_bounds()
573    }
574
575    /// This is an implementation detail of `accesskit_unix`, required for
576    /// robust state transitions with minimal overhead.
577    pub fn wrapped_action_handler(&self) -> Arc<dyn ActionHandlerNoMut + Send + Sync> {
578        Arc::clone(&self.context.action_handler)
579    }
580}
581
582fn root_window(current_state: &TreeState) -> Option<Node<'_>> {
583    const WINDOW_ROLES: &[Role] = &[Role::AlertDialog, Role::Dialog, Role::Window];
584    let root = current_state.root();
585    if WINDOW_ROLES.contains(&root.role()) {
586        Some(root)
587    } else {
588        None
589    }
590}
591
592impl Drop for Adapter {
593    fn drop(&mut self) {
594        let root_id = self.context.read_tree().state().root_id();
595        self.window_destroyed(root_id);
596        // Note: We deliberately do the following here, not in a Drop
597        // implementation on context, because AppContext owns a second
598        // strong reference to Context, and we need that to be released.
599        self.context.write_app_context().remove_adapter(self.id);
600    }
601}