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