Skip to main content

tessera_ui/
component_tree.rs

1mod constraint;
2mod node;
3
4use std::{num::NonZero, sync::Arc};
5
6use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
7use tracing::{debug, warn};
8
9use crate::{
10    ComputeResourceManager, NodeId, Px, PxRect,
11    cursor::{CursorEventContent, PointerChange},
12    focus::{
13        FocusDirection, FocusHandleId, FocusOwner, PendingFocusCallbackInvocation, bind_focus_owner,
14    },
15    layout::{LayoutResult, RenderInput},
16    modifier::{
17        DrawModifierContent, DrawModifierContext, ImeInputModifierNode, KeyboardInputModifierNode,
18        OrderedModifierAction, PointerInputModifierNode,
19    },
20    px::{PxPosition, PxSize},
21    render_graph::{RenderGraph, RenderGraphBuilder},
22    runtime::{
23        LayoutDirtyNodes, RuntimePhase, StructureReconcileResult, TesseraRuntime,
24        push_current_component_instance_key, push_current_node_with_instance_logic_id, push_phase,
25    },
26    time::Instant,
27};
28
29pub use constraint::{AxisConstraint, Constraint, ParentConstraint};
30pub use node::{
31    ComputedData, ImeInput, ImeInputHandlerFn, ImeRequest, ImeSession, KeyboardInput,
32    KeyboardInputHandlerFn, MeasurementError, PointerEventPass, PointerInput,
33    PointerInputHandlerFn,
34};
35
36pub(crate) use node::{
37    ComponentNode, ComponentNodeMetaData, ComponentNodeMetaDatas, ComponentNodeTree, NodeRole,
38    WindowRequests, direct_layout_children, measure_node,
39};
40
41#[cfg(feature = "profiling")]
42use crate::profiler::{NodeMeta, Phase as ProfilerPhase, ScopeGuard as ProfilerScopeGuard};
43
44#[derive(Clone)]
45pub(crate) struct LayoutSnapshotEntry {
46    pub constraint_key: Constraint,
47    pub layout_result: LayoutResult,
48    pub child_constraints: Vec<Constraint>,
49    pub child_sizes: Vec<ComputedData>,
50}
51
52#[derive(Default)]
53pub(crate) struct LayoutSnapshotMap {
54    entries: HashMap<u64, LayoutSnapshotEntry>,
55}
56
57impl LayoutSnapshotMap {
58    pub(crate) fn clear(&mut self) {
59        self.entries.clear();
60    }
61
62    pub(crate) fn remove(&mut self, instance_key: &u64) -> Option<LayoutSnapshotEntry> {
63        self.entries.remove(instance_key)
64    }
65
66    pub(crate) fn insert(
67        &mut self,
68        instance_key: u64,
69        entry: LayoutSnapshotEntry,
70    ) -> Option<LayoutSnapshotEntry> {
71        self.entries.insert(instance_key, entry)
72    }
73
74    pub(crate) fn get_cloned(&self, instance_key: &u64) -> Option<LayoutSnapshotEntry> {
75        self.entries.get(instance_key).cloned()
76    }
77}
78
79pub(crate) fn nearest_replay_boundary_instance_key(
80    node_id: NodeId,
81    tree: &ComponentNodeTree,
82) -> u64 {
83    let mut current_id = node_id;
84    let mut fallback = 0;
85
86    loop {
87        let Some(node_ref) = tree.get(current_id) else {
88            return fallback;
89        };
90        let node = node_ref.get();
91        if fallback == 0 {
92            fallback = node.instance_key;
93        }
94        if node.replay.is_some() {
95            return node.instance_key;
96        }
97        let Some(parent_id) = node_ref.parent() else {
98            return fallback;
99        };
100        current_id = parent_id;
101    }
102}
103
104pub(crate) fn clear_layout_snapshots() {
105    TesseraRuntime::with_mut(|runtime| {
106        runtime.component_tree.clear_layout_snapshots();
107    });
108}
109
110#[derive(Clone, Copy)]
111pub(crate) struct LayoutContext<'a> {
112    snapshots: *mut LayoutSnapshotMap,
113    pub measure_self_nodes: &'a HashSet<u64>,
114    pub placement_self_nodes: &'a HashSet<u64>,
115    pub dirty_effective_nodes: &'a HashSet<u64>,
116    diagnostics: *mut LayoutDiagnosticsCollector,
117}
118
119#[cfg_attr(not(feature = "profiling"), allow(dead_code))]
120#[derive(Clone, Copy, Debug, Default)]
121pub struct LayoutFrameDiagnostics {
122    pub dirty_nodes_param: u64,
123    pub dirty_nodes_structural: u64,
124    pub dirty_nodes_with_ancestors: u64,
125    pub dirty_expand_ns: u64,
126    pub measure_node_calls: u64,
127    pub cache_hits_direct: u64,
128    pub cache_hits_boundary: u64,
129    pub cache_miss_no_entry: u64,
130    pub cache_miss_constraint: u64,
131    pub cache_miss_dirty_self: u64,
132    pub cache_miss_child_size: u64,
133    pub cache_store_count: u64,
134    pub cache_drop_non_cacheable_count: u64,
135}
136
137#[derive(Default)]
138pub(crate) struct LayoutDiagnosticsCollector {
139    measure_node_calls: u64,
140    cache_hits_direct: u64,
141    cache_hits_boundary: u64,
142    cache_miss_no_entry: u64,
143    cache_miss_constraint: u64,
144    cache_miss_dirty_self: u64,
145    cache_miss_child_size: u64,
146    cache_store_count: u64,
147    cache_drop_non_cacheable_count: u64,
148}
149
150impl LayoutDiagnosticsCollector {
151    fn snapshot(
152        &self,
153        dirty_nodes_param: u64,
154        dirty_nodes_structural: u64,
155        dirty_nodes_with_ancestors: u64,
156        dirty_expand_ns: u64,
157    ) -> LayoutFrameDiagnostics {
158        let cache_hits_direct = self.cache_hits_direct;
159        let cache_hits_boundary = self.cache_hits_boundary;
160        LayoutFrameDiagnostics {
161            dirty_nodes_param,
162            dirty_nodes_structural,
163            dirty_nodes_with_ancestors,
164            dirty_expand_ns,
165            measure_node_calls: self.measure_node_calls,
166            cache_hits_direct,
167            cache_hits_boundary,
168            cache_miss_no_entry: self.cache_miss_no_entry,
169            cache_miss_constraint: self.cache_miss_constraint,
170            cache_miss_dirty_self: self.cache_miss_dirty_self,
171            cache_miss_child_size: self.cache_miss_child_size,
172            cache_store_count: self.cache_store_count,
173            cache_drop_non_cacheable_count: self.cache_drop_non_cacheable_count,
174        }
175    }
176}
177
178impl LayoutContext<'_> {
179    pub(crate) fn new<'a>(
180        snapshots: &'a mut LayoutSnapshotMap,
181        measure_self_nodes: &'a HashSet<u64>,
182        placement_self_nodes: &'a HashSet<u64>,
183        dirty_effective_nodes: &'a HashSet<u64>,
184        diagnostics: &'a mut LayoutDiagnosticsCollector,
185    ) -> LayoutContext<'a> {
186        LayoutContext {
187            snapshots,
188            measure_self_nodes,
189            placement_self_nodes,
190            dirty_effective_nodes,
191            diagnostics,
192        }
193    }
194
195    #[inline]
196    pub(crate) fn snapshot(&self, instance_key: u64) -> Option<LayoutSnapshotEntry> {
197        // SAFETY: Layout snapshots are owned by the single-threaded compute
198        // pass. The pointer is created from a unique mutable borrow for the
199        // duration of the pass and only accessed on the same thread.
200        unsafe { (*self.snapshots).get_cloned(&instance_key) }
201    }
202
203    #[inline]
204    pub(crate) fn insert_snapshot(&self, instance_key: u64, entry: LayoutSnapshotEntry) {
205        // SAFETY: See `snapshot`.
206        unsafe {
207            (*self.snapshots).insert(instance_key, entry);
208        }
209    }
210
211    #[inline]
212    pub(crate) fn remove_snapshot(&self, instance_key: u64) {
213        // SAFETY: See `snapshot`.
214        unsafe {
215            (*self.snapshots).remove(&instance_key);
216        }
217    }
218
219    #[inline]
220    pub(crate) fn inc_measure_node_calls(&self) {
221        // SAFETY: Layout diagnostics are owned by the single-threaded compute pass.
222        // The pointer is created from a unique mutable borrow for the duration of
223        // that pass and is only accessed on the same thread during recursive
224        // layout measurement.
225        unsafe {
226            (*self.diagnostics).measure_node_calls += 1;
227        }
228    }
229
230    #[inline]
231    pub(crate) fn inc_cache_hit_direct(&self) {
232        unsafe {
233            (*self.diagnostics).cache_hits_direct += 1;
234        }
235    }
236
237    #[inline]
238    pub(crate) fn inc_cache_hit_boundary(&self) {
239        unsafe {
240            (*self.diagnostics).cache_hits_boundary += 1;
241        }
242    }
243
244    #[inline]
245    pub(crate) fn inc_cache_miss_no_entry(&self) {
246        unsafe {
247            (*self.diagnostics).cache_miss_no_entry += 1;
248        }
249    }
250
251    #[inline]
252    pub(crate) fn inc_cache_miss_constraint(&self) {
253        unsafe {
254            (*self.diagnostics).cache_miss_constraint += 1;
255        }
256    }
257
258    #[inline]
259    pub(crate) fn inc_cache_miss_dirty_self(&self) {
260        unsafe {
261            (*self.diagnostics).cache_miss_dirty_self += 1;
262        }
263    }
264
265    #[inline]
266    pub(crate) fn inc_cache_miss_child_size(&self) {
267        unsafe {
268            (*self.diagnostics).cache_miss_child_size += 1;
269        }
270    }
271
272    #[inline]
273    pub(crate) fn inc_cache_store_count(&self) {
274        unsafe {
275            (*self.diagnostics).cache_store_count += 1;
276        }
277    }
278
279    #[inline]
280    pub(crate) fn inc_cache_drop_non_cacheable_count(&self) {
281        unsafe {
282            (*self.diagnostics).cache_drop_non_cacheable_count += 1;
283        }
284    }
285}
286
287/// Parameters for the compute function
288pub(crate) struct ComputeParams<'a> {
289    pub screen_size: PxSize,
290    pub cursor_position: Option<PxPosition>,
291    pub pointer_changes: Vec<PointerChange>,
292    pub keyboard_events: Vec<winit::event::KeyEvent>,
293    pub ime_events: Vec<winit::event::Ime>,
294    pub retry_focus_move: Option<FocusDirection>,
295    pub retry_focus_reveal: bool,
296    pub modifiers: winit::keyboard::ModifiersState,
297    pub layout_dirty_nodes: &'a LayoutDirtyNodes,
298}
299
300#[derive(Debug)]
301pub(crate) enum ComputeMode<'a> {
302    Full {
303        compute_resource_manager: &'a mut ComputeResourceManager,
304        gpu: &'a wgpu::Device,
305    },
306    #[cfg(feature = "testing")]
307    LayoutOnly,
308}
309
310/// Respents a component tree
311pub struct ComponentTree {
312    /// We use indextree as the tree structure
313    tree: indextree::Arena<ComponentNode>,
314    /// Components' metadatas
315    metadatas: ComponentNodeMetaDatas,
316    layout_snapshots: LayoutSnapshotMap,
317    /// Used to remember the current node
318    node_queue: Vec<indextree::NodeId>,
319    /// Detached old-subtree nodes keyed by instance key during replay replace.
320    replay_reuse_candidates: HashMap<u64, indextree::NodeId>,
321    /// Active pointer hit paths keyed by pointer id.
322    /// Each path stores node instance keys from root to leaf.
323    active_pointer_paths: HashMap<u64, Vec<u64>>,
324    /// Per-tree focus owner used for keyboard and IME routing.
325    focus_owner: FocusOwner,
326}
327
328#[derive(Clone, PartialEq)]
329pub(crate) enum ReplayReplaceError {
330    NodeNotFound,
331    RootNodeNotReplaceable,
332    ReplayDidNotCreateRoot,
333}
334
335#[derive(Default)]
336pub(crate) struct ReplayReplaceResult {
337    pub removed_instance_keys: HashSet<u64>,
338    pub removed_instance_logic_ids: HashSet<u64>,
339    pub inserted_instance_keys: HashSet<u64>,
340    pub inserted_instance_logic_ids: HashSet<u64>,
341    pub reused_instance_logic_ids: HashSet<u64>,
342}
343
344pub(crate) struct ReplayReplaceContext {
345    parent_id: indextree::NodeId,
346    next_sibling: Option<indextree::NodeId>,
347    existing_children: HashSet<indextree::NodeId>,
348    previous_queue: Vec<indextree::NodeId>,
349    detached_root_id: indextree::NodeId,
350    detached_node_ids: HashSet<indextree::NodeId>,
351    removed_instance_keys: HashSet<u64>,
352    removed_instance_logic_ids: HashSet<u64>,
353}
354
355impl Default for ComponentTree {
356    fn default() -> Self {
357        Self::new()
358    }
359}
360
361impl ComponentTree {
362    /// Create a new ComponentTree
363    pub fn new() -> Self {
364        let tree = indextree::Arena::new();
365        let node_queue = Vec::new();
366        let metadatas = ComponentNodeMetaDatas::new();
367        Self {
368            tree,
369            node_queue,
370            metadatas,
371            layout_snapshots: LayoutSnapshotMap::default(),
372            replay_reuse_candidates: HashMap::default(),
373            active_pointer_paths: HashMap::default(),
374            focus_owner: FocusOwner::new(),
375        }
376    }
377
378    /// Clear the component tree
379    pub fn clear(&mut self) {
380        self.tree.clear();
381        self.metadatas.clear();
382        self.layout_snapshots.clear();
383        self.node_queue.clear();
384        self.replay_reuse_candidates.clear();
385        self.active_pointer_paths.clear();
386    }
387
388    /// Reset the entire component tree, including focus ownership state.
389    pub fn reset(&mut self) {
390        self.clear();
391        self.focus_owner.reset();
392    }
393
394    /// Get node by NodeId
395    pub(crate) fn get(&self, node_id: indextree::NodeId) -> Option<&ComponentNode> {
396        self.tree
397            .get(node_id)
398            .filter(|node| !node.is_removed())
399            .map(|node| node.get())
400    }
401
402    /// Get mutable node by NodeId
403    pub(crate) fn get_mut(&mut self, node_id: indextree::NodeId) -> Option<&mut ComponentNode> {
404        self.tree
405            .get_mut(node_id)
406            .filter(|node| !node.is_removed())
407            .map(|node| node.get_mut())
408    }
409
410    /// Find a node id by stable instance key.
411    pub(crate) fn find_node_id_by_instance_key(
412        &self,
413        instance_key: u64,
414    ) -> Option<indextree::NodeId> {
415        let root = self
416            .tree
417            .get_node_id_at(NonZero::new(1).expect("root node index must be non-zero"))?;
418        for edge in root.traverse(&self.tree) {
419            let indextree::NodeEdge::Start(node_id) = edge else {
420                continue;
421            };
422            let Some(node) = self.tree.get(node_id) else {
423                continue;
424            };
425            if node.get().instance_key == instance_key {
426                return Some(node_id);
427            }
428        }
429        None
430    }
431
432    pub(crate) fn live_instance_keys(&self) -> HashSet<u64> {
433        let Some(root) = self
434            .tree
435            .get_node_id_at(NonZero::new(1).expect("root node index must be non-zero"))
436        else {
437            return HashSet::default();
438        };
439
440        let mut instance_keys = HashSet::default();
441        for edge in root.traverse(&self.tree) {
442            let indextree::NodeEdge::Start(node_id) = edge else {
443                continue;
444            };
445            let Some(node) = self.tree.get(node_id) else {
446                continue;
447            };
448            instance_keys.insert(node.get().instance_key);
449        }
450        instance_keys
451    }
452
453    pub(crate) fn begin_replace_subtree_by_instance_key(
454        &mut self,
455        instance_key: u64,
456    ) -> Result<ReplayReplaceContext, ReplayReplaceError> {
457        self.replay_reuse_candidates.clear();
458        let Some(target_node_id) = self.find_node_id_by_instance_key(instance_key) else {
459            return Err(ReplayReplaceError::NodeNotFound);
460        };
461
462        let Some(parent_id) = self.tree.get(target_node_id).and_then(|n| n.parent()) else {
463            return Err(ReplayReplaceError::RootNodeNotReplaceable);
464        };
465
466        let mut next_sibling = None;
467        let mut seen_target = false;
468        for child in parent_id.children(&self.tree) {
469            if seen_target {
470                next_sibling = Some(child);
471                break;
472            }
473            if child == target_node_id {
474                seen_target = true;
475            }
476        }
477
478        let removed_node_ids: Vec<_> = target_node_id
479            .traverse(&self.tree)
480            .filter_map(|edge| match edge {
481                indextree::NodeEdge::Start(id) => Some(id),
482                indextree::NodeEdge::End(_) => None,
483            })
484            .collect();
485        let detached_node_ids = removed_node_ids.iter().copied().collect::<HashSet<_>>();
486        let mut removed_instance_keys = HashSet::default();
487        let mut removed_instance_logic_ids = HashSet::default();
488        for id in &removed_node_ids {
489            if let Some(node) = self.tree.get(*id) {
490                removed_instance_keys.insert(node.get().instance_key);
491                removed_instance_logic_ids.insert(node.get().instance_logic_id);
492                self.replay_reuse_candidates
493                    .insert(node.get().instance_key, *id);
494            }
495        }
496        target_node_id.detach(&mut self.tree);
497
498        let existing_children = parent_id.children(&self.tree).collect();
499
500        let previous_queue = std::mem::replace(&mut self.node_queue, vec![parent_id]);
501        Ok(ReplayReplaceContext {
502            parent_id,
503            next_sibling,
504            existing_children,
505            previous_queue,
506            detached_root_id: target_node_id,
507            detached_node_ids,
508            removed_instance_keys,
509            removed_instance_logic_ids,
510        })
511    }
512
513    pub(crate) fn finish_replace_subtree(
514        &mut self,
515        context: ReplayReplaceContext,
516    ) -> Result<ReplayReplaceResult, ReplayReplaceError> {
517        let ReplayReplaceContext {
518            parent_id,
519            next_sibling,
520            existing_children,
521            previous_queue,
522            detached_root_id,
523            detached_node_ids,
524            removed_instance_keys,
525            removed_instance_logic_ids,
526        } = context;
527
528        let mut inserted_root_ids = parent_id
529            .children(&self.tree)
530            .filter(|child_id| !existing_children.contains(child_id))
531            .collect::<Vec<_>>();
532        if inserted_root_ids.is_empty() {
533            self.node_queue = previous_queue;
534            return Err(ReplayReplaceError::ReplayDidNotCreateRoot);
535        }
536
537        if let Some(next_sibling) = next_sibling {
538            for inserted_root_id in &inserted_root_ids {
539                if *inserted_root_id != next_sibling {
540                    next_sibling.insert_before(*inserted_root_id, &mut self.tree);
541                }
542            }
543            inserted_root_ids = parent_id
544                .children(&self.tree)
545                .filter(|child_id| !existing_children.contains(child_id))
546                .collect::<Vec<_>>();
547        }
548
549        let detached_root_reused = inserted_root_ids.contains(&detached_root_id);
550
551        let mut inserted_instance_keys = HashSet::default();
552        let mut inserted_instance_logic_ids = HashSet::default();
553        let mut reused_instance_logic_ids = HashSet::default();
554        for inserted_root_id in &inserted_root_ids {
555            for edge in inserted_root_id.traverse(&self.tree) {
556                let indextree::NodeEdge::Start(id) = edge else {
557                    continue;
558                };
559                if let Some(node) = self.tree.get(id) {
560                    inserted_instance_keys.insert(node.get().instance_key);
561                    inserted_instance_logic_ids.insert(node.get().instance_logic_id);
562                    if detached_node_ids.contains(&id) {
563                        reused_instance_logic_ids.insert(node.get().instance_logic_id);
564                    }
565                }
566            }
567        }
568
569        let removed_instance_keys = removed_instance_keys
570            .difference(&inserted_instance_keys)
571            .copied()
572            .collect::<HashSet<_>>();
573        let removed_instance_logic_ids = removed_instance_logic_ids
574            .difference(&inserted_instance_logic_ids)
575            .copied()
576            .collect::<HashSet<_>>();
577        if !detached_root_reused {
578            let detached_node_ids = detached_root_id
579                .traverse(&self.tree)
580                .filter_map(|edge| match edge {
581                    indextree::NodeEdge::Start(id) => Some(id),
582                    indextree::NodeEdge::End(_) => None,
583                })
584                .collect::<Vec<_>>();
585            for node_id in &detached_node_ids {
586                self.metadatas.remove(node_id);
587            }
588            detached_root_id.remove_subtree(&mut self.tree);
589        }
590        self.replay_reuse_candidates.clear();
591
592        self.node_queue = previous_queue;
593        Ok(ReplayReplaceResult {
594            removed_instance_keys,
595            removed_instance_logic_ids,
596            inserted_instance_keys,
597            inserted_instance_logic_ids,
598            reused_instance_logic_ids,
599        })
600    }
601
602    /// Get current node
603    pub(crate) fn current_node(&self) -> Option<&ComponentNode> {
604        self.node_queue
605            .last()
606            .and_then(|node_id| self.get(*node_id))
607    }
608
609    /// Get mutable current node
610    pub(crate) fn current_node_mut(&mut self) -> Option<&mut ComponentNode> {
611        let node_id = self.node_queue.last()?;
612        self.get_mut(*node_id)
613    }
614
615    pub(crate) fn try_reuse_current_subtree(
616        &mut self,
617        instance_key: u64,
618        instance_logic_id: u64,
619    ) -> bool {
620        let Some(&candidate_node_id) = self.replay_reuse_candidates.get(&instance_key) else {
621            return false;
622        };
623        let Some(candidate_instance_logic_id) = self
624            .tree
625            .get(candidate_node_id)
626            .map(|node| node.get().instance_logic_id)
627        else {
628            self.replay_reuse_candidates.remove(&instance_key);
629            return false;
630        };
631        if candidate_instance_logic_id != instance_logic_id {
632            return false;
633        }
634
635        let Some(current_node_id) = self.node_queue.last().copied() else {
636            return false;
637        };
638        if current_node_id == candidate_node_id {
639            self.replay_reuse_candidates.remove(&instance_key);
640            return true;
641        }
642
643        candidate_node_id.detach(&mut self.tree);
644        current_node_id.insert_before(candidate_node_id, &mut self.tree);
645        self.metadatas.remove(&current_node_id);
646        current_node_id.remove_subtree(&mut self.tree);
647        if let Some(current_node) = self.node_queue.last_mut() {
648            *current_node = candidate_node_id;
649        }
650        self.replay_reuse_candidates.remove(&instance_key);
651        true
652    }
653
654    /// Add a new node to the tree
655    /// Nodes now store their intrinsic constraints in their metadata.
656    /// The `node_component` itself primarily holds the layout policy, render
657    /// policy, and handlers.
658    pub(crate) fn add_node(&mut self, node_component: ComponentNode) -> indextree::NodeId {
659        let new_node_id = self.tree.new_node(node_component);
660        if let Some(current_node_id) = self.node_queue.last_mut() {
661            current_node_id.append(new_node_id, &mut self.tree);
662        }
663        let metadata = ComponentNodeMetaData::none();
664        self.metadatas.insert(new_node_id, metadata);
665        self.node_queue.push(new_node_id);
666        new_node_id
667    }
668
669    /// Pop the last node from the queue
670    pub(crate) fn pop_node(&mut self) {
671        self.node_queue.pop();
672    }
673
674    /// Get a reference to the underlying tree structure.
675    ///
676    /// This is used for accessibility tree building and other introspection
677    /// needs.
678    pub(crate) fn tree(&self) -> &indextree::Arena<ComponentNode> {
679        &self.tree
680    }
681
682    /// Get a reference to the node metadatas.
683    ///
684    /// This is used for accessibility tree building and other introspection
685    /// needs.
686    pub(crate) fn metadatas(&self) -> &ComponentNodeMetaDatas {
687        &self.metadatas
688    }
689
690    pub(crate) fn metadatas_mut(&mut self) -> &mut ComponentNodeMetaDatas {
691        &mut self.metadatas
692    }
693
694    pub(crate) fn clear_layout_snapshots(&mut self) {
695        self.layout_snapshots.clear();
696    }
697
698    fn remove_layout_snapshots(&mut self, keys: &HashSet<u64>) {
699        if keys.is_empty() {
700            return;
701        }
702        for key in keys {
703            self.layout_snapshots.remove(key);
704        }
705    }
706
707    pub(crate) fn focus_owner(&self) -> &FocusOwner {
708        &self.focus_owner
709    }
710
711    pub(crate) fn focus_owner_mut(&mut self) -> &mut FocusOwner {
712        &mut self.focus_owner
713    }
714
715    pub(crate) fn accessibility_dispatch_context(
716        &mut self,
717    ) -> (&ComponentNodeTree, &ComponentNodeMetaDatas, &mut FocusOwner) {
718        (&self.tree, &self.metadatas, &mut self.focus_owner)
719    }
720
721    pub(crate) fn take_pending_focus_callback_invocations(
722        &mut self,
723    ) -> Vec<PendingFocusCallbackInvocation> {
724        let notifications = self.focus_owner.take_pending_notifications();
725        let mut invocations = Vec::new();
726
727        for notification in notifications {
728            let Some(node_id) = self
729                .focus_owner
730                .component_node_id_of(notification.handle_id)
731            else {
732                continue;
733            };
734            let Some(node_ref) = self.tree.get(node_id) else {
735                continue;
736            };
737            let node = node_ref.get();
738
739            if notification.changed
740                && let Some(handler) = &node.focus_changed_handler
741            {
742                invocations.push(PendingFocusCallbackInvocation::new(
743                    *handler,
744                    notification.state,
745                ));
746            }
747            if let Some(handler) = &node.focus_event_handler {
748                invocations.push(PendingFocusCallbackInvocation::new(
749                    *handler,
750                    notification.state,
751                ));
752            }
753        }
754
755        invocations
756    }
757
758    /// Collect per-node metadata for profiling output.
759    #[cfg(feature = "profiling")]
760    pub fn profiler_nodes(&self) -> Vec<NodeMeta> {
761        let Some(root_node) = self
762            .tree
763            .get_node_id_at(NonZero::new(1).expect("root node index must be non-zero"))
764        else {
765            return Vec::new();
766        };
767
768        let mut stack = vec![root_node];
769        let mut nodes = Vec::new();
770        while let Some(node_id) = stack.pop() {
771            if let Some(node) = self.tree.get(node_id) {
772                let parent = node.parent().map(|p| p.to_string());
773                let fn_name = node.get().fn_name.clone();
774                let metadata = self.metadatas.get(&node_id);
775                let abs_pos = metadata
776                    .as_ref()
777                    .and_then(|m| m.abs_position)
778                    .map(|p| (p.x.0, p.y.0));
779                let size = metadata
780                    .as_ref()
781                    .and_then(|m| m.computed_data)
782                    .map(|d| (d.width.0, d.height.0));
783                let layout_cache_hit = metadata.as_ref().map(|m| m.layout_cache_hit);
784
785                nodes.push(NodeMeta {
786                    node_id: node_id.to_string(),
787                    parent,
788                    fn_name: Some(fn_name.clone()),
789                    abs_pos,
790                    size,
791                    layout_cache_hit,
792                });
793            }
794            stack.extend(node_id.children(&self.tree));
795        }
796
797        nodes
798    }
799
800    /// Compute the ComponentTree into a render graph
801    ///
802    /// This method processes the component tree through three main phases:
803    /// 1. **Measure Phase**: Calculate sizes and positions for all components
804    /// 2. **Graph Generation**: Extract render fragments from component
805    ///    metadata
806    /// 3. **State Handling**: Process user interactions and events
807    ///
808    /// Returns a tuple of (graph, window_requests) where the graph contains
809    /// the render ops for the current frame.
810    #[tracing::instrument(level = "debug", skip(self, params))]
811    pub(crate) fn compute(
812        &mut self,
813        params: ComputeParams<'_>,
814        mode: ComputeMode<'_>,
815    ) -> (
816        RenderGraph,
817        WindowRequests,
818        LayoutFrameDiagnostics,
819        std::time::Duration,
820        Option<FocusDirection>,
821        bool,
822    ) {
823        let ComputeParams {
824            screen_size,
825            mut cursor_position,
826            mut pointer_changes,
827            mut keyboard_events,
828            mut ime_events,
829            retry_focus_move,
830            retry_focus_reveal,
831            modifiers,
832            layout_dirty_nodes,
833        } = params;
834        let Some(root_node) = self
835            .tree
836            .get_node_id_at(NonZero::new(1).expect("root node index must be non-zero"))
837        else {
838            return (
839                RenderGraph::default(),
840                WindowRequests::default(),
841                LayoutFrameDiagnostics::default(),
842                std::time::Duration::ZERO,
843                None,
844                false,
845            );
846        };
847        let screen_constraint = Constraint::exact(screen_size.width, screen_size.height);
848        let current_children_by_node = collect_children_by_instance_key(root_node, &self.tree);
849        let StructureReconcileResult {
850            changed_nodes: structural_dirty_nodes,
851            removed_nodes,
852        } = crate::runtime::reconcile_layout_structure(&current_children_by_node);
853        self.remove_layout_snapshots(&removed_nodes);
854
855        let mut dirty_nodes_self = layout_dirty_nodes.measure_self_nodes.clone();
856        dirty_nodes_self.extend(layout_dirty_nodes.placement_self_nodes.iter().copied());
857        let dirty_nodes_param = dirty_nodes_self.len() as u64;
858        let dirty_nodes_structural = structural_dirty_nodes.len() as u64;
859        let dirty_prepare_start = Instant::now();
860        dirty_nodes_self.extend(structural_dirty_nodes.iter().copied());
861        let dirty_nodes_effective =
862            expand_dirty_nodes_with_ancestors(root_node, &self.tree, &dirty_nodes_self);
863        let dirty_expand_ns = dirty_prepare_start.elapsed().as_nanos() as u64;
864        let mut diagnostics = LayoutDiagnosticsCollector::default();
865
866        self.focus_owner
867            .sync_from_component_tree(root_node, &self.tree);
868        self.focus_owner.commit_pending();
869
870        let layout_ctx = LayoutContext::new(
871            &mut self.layout_snapshots,
872            &layout_dirty_nodes.measure_self_nodes,
873            &layout_dirty_nodes.placement_self_nodes,
874            &dirty_nodes_effective,
875            &mut diagnostics,
876        );
877
878        let measure_timer = Instant::now();
879        debug!("Start measuring the component tree...");
880
881        match measure_node(
882            root_node,
883            &screen_constraint,
884            &self.tree,
885            &mut self.metadatas,
886            Some(&layout_ctx),
887        ) {
888            Ok(_root_computed_data) => {
889                debug!("Component tree measured in {:?}", measure_timer.elapsed());
890            }
891            Err(e) => {
892                panic!(
893                    "Root node ({root_node:?}) measurement failed: {e:?}. Aborting draw command computation."
894                );
895            }
896        }
897
898        let diagnostics_snapshot = diagnostics.snapshot(
899            dirty_nodes_param,
900            dirty_nodes_structural,
901            dirty_nodes_effective.len() as u64,
902            dirty_expand_ns,
903        );
904
905        let (compute_resource_manager, gpu) = match mode {
906            ComputeMode::Full {
907                compute_resource_manager,
908                gpu,
909            } => (compute_resource_manager, gpu),
910            #[cfg(feature = "testing")]
911            ComputeMode::LayoutOnly => {
912                populate_layout_metadata(root_node, &self.tree, &mut self.metadatas);
913                return (
914                    RenderGraph::default(),
915                    WindowRequests::default(),
916                    diagnostics_snapshot,
917                    std::time::Duration::ZERO,
918                    None,
919                    false,
920                );
921            }
922        };
923
924        let record_timer = Instant::now();
925        record_layout_commands(
926            root_node,
927            &self.tree,
928            &mut self.metadatas,
929            compute_resource_manager,
930            gpu,
931        );
932        let record_cost = record_timer.elapsed();
933        populate_layout_metadata(root_node, &self.tree, &mut self.metadatas);
934
935        let compute_draw_timer = Instant::now();
936        debug!("Start computing render graph...");
937        let graph = build_render_graph(root_node, &self.tree, &mut self.metadatas, screen_size);
938        self.focus_owner
939            .sync_layout_from_component_tree(root_node, &self.tree, &self.metadatas);
940        debug!(
941            "Render graph built in {:?}, total ops: {}",
942            compute_draw_timer.elapsed(),
943            graph.ops().len()
944        );
945
946        let input_dispatch_timer = Instant::now();
947        let mut window_requests = WindowRequests::default();
948        debug!("Start executing typed input dispatch...");
949
950        let node_ids_preorder = layout_node_ids_preorder(root_node, &self.tree);
951        let node_ids_postorder = layout_node_ids_postorder(root_node, &self.tree);
952        let pointer_change_paths = build_pointer_change_paths(
953            root_node,
954            &self.tree,
955            &self.metadatas,
956            &pointer_changes,
957            cursor_position,
958            &mut self.active_pointer_paths,
959        );
960        window_requests.cursor_icon =
961            resolve_hover_cursor_icon(root_node, &self.tree, &self.metadatas, cursor_position)
962                .unwrap_or_default();
963
964        for node_id in node_ids_preorder.iter().copied() {
965            let Some(node) = self.tree.get(node_id).map(|n| n.get()) else {
966                continue;
967            };
968            let mut dispatch_ctx = PointerInputDispatchContext {
969                tree: &self.tree,
970                metadatas: &self.metadatas,
971                cursor_position: &mut cursor_position,
972                pointer_changes: pointer_changes.as_mut_slice(),
973                pointer_change_paths: &pointer_change_paths,
974                modifiers,
975                window_requests: &mut window_requests,
976                focus_owner: &mut self.focus_owner,
977            };
978            dispatch_pointer_modifiers_for_node_pass(
979                &mut dispatch_ctx,
980                node_id,
981                PointerEventPass::Initial,
982            );
983            let handlers = &node.pointer_preview_handlers;
984            for handler in handlers {
985                let mut dispatch_ctx = PointerInputDispatchContext {
986                    tree: &self.tree,
987                    metadatas: &self.metadatas,
988                    cursor_position: &mut cursor_position,
989                    pointer_changes: pointer_changes.as_mut_slice(),
990                    pointer_change_paths: &pointer_change_paths,
991                    modifiers,
992                    window_requests: &mut window_requests,
993                    focus_owner: &mut self.focus_owner,
994                };
995                run_pointer_handler_for_node(
996                    &mut dispatch_ctx,
997                    node_id,
998                    PointerEventPass::Initial,
999                    handler.as_ref(),
1000                );
1001            }
1002        }
1003
1004        for node_id in node_ids_postorder.iter().copied() {
1005            let Some(node) = self.tree.get(node_id).map(|n| n.get()) else {
1006                continue;
1007            };
1008            let mut dispatch_ctx = PointerInputDispatchContext {
1009                tree: &self.tree,
1010                metadatas: &self.metadatas,
1011                cursor_position: &mut cursor_position,
1012                pointer_changes: pointer_changes.as_mut_slice(),
1013                pointer_change_paths: &pointer_change_paths,
1014                modifiers,
1015                window_requests: &mut window_requests,
1016                focus_owner: &mut self.focus_owner,
1017            };
1018            dispatch_pointer_modifiers_for_node_pass(
1019                &mut dispatch_ctx,
1020                node_id,
1021                PointerEventPass::Main,
1022            );
1023            let handlers = &node.pointer_handlers;
1024            for handler in handlers {
1025                let mut dispatch_ctx = PointerInputDispatchContext {
1026                    tree: &self.tree,
1027                    metadatas: &self.metadatas,
1028                    cursor_position: &mut cursor_position,
1029                    pointer_changes: pointer_changes.as_mut_slice(),
1030                    pointer_change_paths: &pointer_change_paths,
1031                    modifiers,
1032                    window_requests: &mut window_requests,
1033                    focus_owner: &mut self.focus_owner,
1034                };
1035                run_pointer_handler_for_node(
1036                    &mut dispatch_ctx,
1037                    node_id,
1038                    PointerEventPass::Main,
1039                    handler.as_ref(),
1040                );
1041            }
1042        }
1043
1044        for node_id in node_ids_preorder.iter().copied() {
1045            let Some(node) = self.tree.get(node_id).map(|n| n.get()) else {
1046                continue;
1047            };
1048            let mut dispatch_ctx = PointerInputDispatchContext {
1049                tree: &self.tree,
1050                metadatas: &self.metadatas,
1051                cursor_position: &mut cursor_position,
1052                pointer_changes: pointer_changes.as_mut_slice(),
1053                pointer_change_paths: &pointer_change_paths,
1054                modifiers,
1055                window_requests: &mut window_requests,
1056                focus_owner: &mut self.focus_owner,
1057            };
1058            dispatch_pointer_modifiers_for_node_pass(
1059                &mut dispatch_ctx,
1060                node_id,
1061                PointerEventPass::Final,
1062            );
1063            let handlers = &node.pointer_final_handlers;
1064            for handler in handlers {
1065                let mut dispatch_ctx = PointerInputDispatchContext {
1066                    tree: &self.tree,
1067                    metadatas: &self.metadatas,
1068                    cursor_position: &mut cursor_position,
1069                    pointer_changes: pointer_changes.as_mut_slice(),
1070                    pointer_change_paths: &pointer_change_paths,
1071                    modifiers,
1072                    window_requests: &mut window_requests,
1073                    focus_owner: &mut self.focus_owner,
1074                };
1075                run_pointer_handler_for_node(
1076                    &mut dispatch_ctx,
1077                    node_id,
1078                    PointerEventPass::Final,
1079                    handler.as_ref(),
1080                );
1081            }
1082        }
1083
1084        self.focus_owner.commit_pending();
1085        let pending_focus_move_retry = retry_focus_move.and_then(|direction| {
1086            match try_dispatch_focus_move_request(&self.tree, direction, &mut self.focus_owner) {
1087                FocusMoveRequestResult::Retry(direction) => Some(direction),
1088                FocusMoveRequestResult::Moved | FocusMoveRequestResult::NotHandled => None,
1089            }
1090        });
1091        let focus_chain_node_ids =
1092            collect_focus_chain_node_ids(root_node, &self.tree, &self.focus_owner);
1093
1094        let pending_focus_move_retry = if pending_focus_move_retry.is_none() {
1095            let mut keyboard_dispatch_ctx = KeyboardInputDispatchContext {
1096                tree: &self.tree,
1097                metadatas: &self.metadatas,
1098                keyboard_events: &mut keyboard_events,
1099                modifiers,
1100                window_requests: &mut window_requests,
1101                focus_owner: &mut self.focus_owner,
1102            };
1103
1104            for node_id in focus_chain_node_ids.iter().copied() {
1105                let Some(node) = keyboard_dispatch_ctx.tree.get(node_id).map(|n| n.get()) else {
1106                    continue;
1107                };
1108                for action in node.modifier.ordered_actions() {
1109                    match action {
1110                        OrderedModifierAction::KeyboardPreviewInput(modifier) => {
1111                            run_keyboard_modifier_for_node(
1112                                &mut keyboard_dispatch_ctx,
1113                                node_id,
1114                                modifier.as_ref(),
1115                            );
1116                        }
1117                        OrderedModifierAction::ImePreviewInput(modifier) => {
1118                            run_ime_modifier_for_node(
1119                                keyboard_dispatch_ctx.tree,
1120                                keyboard_dispatch_ctx.metadatas,
1121                                node_id,
1122                                modifier.as_ref(),
1123                                &mut ime_events,
1124                                keyboard_dispatch_ctx.window_requests,
1125                                keyboard_dispatch_ctx.focus_owner,
1126                            );
1127                        }
1128                        _ => {}
1129                    }
1130                }
1131                for handler in &node.keyboard_preview_handlers {
1132                    run_keyboard_handler_for_node(
1133                        &mut keyboard_dispatch_ctx,
1134                        node_id,
1135                        handler.as_ref(),
1136                    );
1137                }
1138                for handler in &node.ime_preview_handlers {
1139                    run_ime_handler_for_node(
1140                        keyboard_dispatch_ctx.tree,
1141                        keyboard_dispatch_ctx.metadatas,
1142                        node_id,
1143                        handler.as_ref(),
1144                        &mut ime_events,
1145                        keyboard_dispatch_ctx.window_requests,
1146                        keyboard_dispatch_ctx.focus_owner,
1147                    );
1148                }
1149            }
1150
1151            for node_id in focus_chain_node_ids.iter().rev().copied() {
1152                let Some(node) = keyboard_dispatch_ctx.tree.get(node_id).map(|n| n.get()) else {
1153                    continue;
1154                };
1155                for action in node.modifier.ordered_actions() {
1156                    match action {
1157                        OrderedModifierAction::KeyboardInput(modifier) => {
1158                            run_keyboard_modifier_for_node(
1159                                &mut keyboard_dispatch_ctx,
1160                                node_id,
1161                                modifier.as_ref(),
1162                            );
1163                        }
1164                        OrderedModifierAction::ImeInput(modifier) => {
1165                            run_ime_modifier_for_node(
1166                                keyboard_dispatch_ctx.tree,
1167                                keyboard_dispatch_ctx.metadatas,
1168                                node_id,
1169                                modifier.as_ref(),
1170                                &mut ime_events,
1171                                keyboard_dispatch_ctx.window_requests,
1172                                keyboard_dispatch_ctx.focus_owner,
1173                            );
1174                        }
1175                        _ => {}
1176                    }
1177                }
1178                for handler in &node.keyboard_handlers {
1179                    run_keyboard_handler_for_node(
1180                        &mut keyboard_dispatch_ctx,
1181                        node_id,
1182                        handler.as_ref(),
1183                    );
1184                }
1185                for handler in &node.ime_handlers {
1186                    run_ime_handler_for_node(
1187                        keyboard_dispatch_ctx.tree,
1188                        keyboard_dispatch_ctx.metadatas,
1189                        node_id,
1190                        handler.as_ref(),
1191                        &mut ime_events,
1192                        keyboard_dispatch_ctx.window_requests,
1193                        keyboard_dispatch_ctx.focus_owner,
1194                    );
1195                }
1196            }
1197
1198            dispatch_default_focus_keyboard_navigation(
1199                keyboard_dispatch_ctx.tree,
1200                keyboard_dispatch_ctx.keyboard_events,
1201                keyboard_dispatch_ctx.modifiers,
1202                keyboard_dispatch_ctx.focus_owner,
1203            )
1204        } else {
1205            pending_focus_move_retry
1206        };
1207        let pending_focus_reveal_retry = if pending_focus_move_retry.is_none() {
1208            dispatch_pending_focus_reveal_request(
1209                &self.tree,
1210                &self.metadatas,
1211                &mut self.focus_owner,
1212                retry_focus_reveal,
1213            )
1214        } else {
1215            false
1216        };
1217
1218        debug!(
1219            "Typed input dispatch executed in {:?}",
1220            input_dispatch_timer.elapsed()
1221        );
1222        (
1223            graph,
1224            window_requests,
1225            diagnostics_snapshot,
1226            record_cost,
1227            pending_focus_move_retry,
1228            pending_focus_reveal_retry,
1229        )
1230    }
1231}
1232
1233struct NodeInputContext {
1234    base_abs_pos: PxPosition,
1235    abs_pos: PxPosition,
1236    event_clip_rect: Option<PxRect>,
1237    node_computed_data: ComputedData,
1238    instance_logic_id: u64,
1239    instance_key: u64,
1240    fn_name: String,
1241    parent_id: Option<indextree::NodeId>,
1242}
1243
1244fn resolve_node_input_context(
1245    tree: &ComponentNodeTree,
1246    metadatas: &ComponentNodeMetaDatas,
1247    node_id: indextree::NodeId,
1248) -> Option<NodeInputContext> {
1249    let Some(node_ref) = tree.get(node_id) else {
1250        warn!("Node not found for node {node_id:?}; skipping input handling");
1251        return None;
1252    };
1253    let node = node_ref.get();
1254    if node.role != NodeRole::Layout {
1255        return None;
1256    }
1257
1258    let Some(metadata) = metadatas.get(&node_id) else {
1259        warn!("Input metadata missing for node {node_id:?}; skipping input handling");
1260        return None;
1261    };
1262    let Some(base_abs_pos) = metadata.base_abs_position else {
1263        warn!("Base absolute position missing for node {node_id:?}; skipping input handling");
1264        return None;
1265    };
1266    let Some(abs_pos) = metadata.abs_position else {
1267        warn!("Absolute position missing for node {node_id:?}; skipping input handling");
1268        return None;
1269    };
1270    let event_clip_rect = metadata.event_clip_rect;
1271    let Some(node_computed_data) = metadata.computed_data else {
1272        warn!(
1273            "Computed data not found for node {:?} during input dispatch.",
1274            node_id
1275        );
1276        return None;
1277    };
1278    let instance_logic_id = node.instance_logic_id;
1279    let instance_key = node.instance_key;
1280    let fn_name = node.fn_name.as_str().to_owned();
1281    let parent_id = node_ref.parent();
1282
1283    Some(NodeInputContext {
1284        base_abs_pos,
1285        abs_pos,
1286        event_clip_rect,
1287        node_computed_data,
1288        instance_logic_id,
1289        instance_key,
1290        fn_name,
1291        parent_id,
1292    })
1293}
1294
1295fn layout_node_ids_preorder(
1296    root_node: indextree::NodeId,
1297    tree: &ComponentNodeTree,
1298) -> Vec<indextree::NodeId> {
1299    root_node
1300        .traverse(tree)
1301        .filter_map(|edge| match edge {
1302            indextree::NodeEdge::Start(id) => tree
1303                .get(id)
1304                .filter(|node| node.get().role == NodeRole::Layout)
1305                .map(|_| id),
1306            indextree::NodeEdge::End(_) => None,
1307        })
1308        .collect()
1309}
1310
1311fn layout_node_ids_postorder(
1312    root_node: indextree::NodeId,
1313    tree: &ComponentNodeTree,
1314) -> Vec<indextree::NodeId> {
1315    root_node
1316        .reverse_traverse(tree)
1317        .filter_map(|edge| match edge {
1318            indextree::NodeEdge::Start(id) => tree
1319                .get(id)
1320                .filter(|node| node.get().role == NodeRole::Layout)
1321                .map(|_| id),
1322            indextree::NodeEdge::End(_) => None,
1323        })
1324        .collect()
1325}
1326
1327fn attach_ime_position_if_needed(window_requests: &mut WindowRequests, abs_pos: PxPosition) {
1328    if let Some(ref mut ime_request) = window_requests.ime_request
1329        && ime_request.position.is_none()
1330    {
1331        ime_request.position = Some(abs_pos + ime_request.local_position);
1332    }
1333}
1334
1335fn hit_path_node_ids(
1336    root_node: indextree::NodeId,
1337    tree: &ComponentNodeTree,
1338    metadatas: &ComponentNodeMetaDatas,
1339    position: Option<PxPosition>,
1340) -> Vec<indextree::NodeId> {
1341    fn collect_hit_path(
1342        node_id: indextree::NodeId,
1343        tree: &ComponentNodeTree,
1344        metadatas: &ComponentNodeMetaDatas,
1345        position: PxPosition,
1346    ) -> Option<Vec<indextree::NodeId>> {
1347        let children: Vec<_> = node_id.children(tree).collect();
1348        for child_id in children.into_iter().rev() {
1349            if let Some(mut child_path) = collect_hit_path(child_id, tree, metadatas, position) {
1350                let mut path = Vec::with_capacity(child_path.len() + 1);
1351                if let Some(metadata) = metadatas.get(&node_id)
1352                    && metadata.base_abs_position.is_some()
1353                    && metadata.abs_position.is_some()
1354                    && metadata.computed_data.is_some()
1355                {
1356                    path.push(node_id);
1357                }
1358                path.append(&mut child_path);
1359                return Some(path);
1360            }
1361        }
1362
1363        let metadata = metadatas.get(&node_id)?;
1364        let base_abs_pos = metadata.base_abs_position?;
1365        let abs_pos = metadata.abs_position?;
1366        let size = metadata.computed_data?;
1367        if size.width.0 <= 0 || size.height.0 <= 0 {
1368            return None;
1369        }
1370        if let Some(clip_rect) = metadata.event_clip_rect
1371            && !clip_rect.contains(position)
1372        {
1373            return None;
1374        }
1375        let bounds = PxRect::from_position_size(abs_pos, PxSize::new(size.width, size.height));
1376        let node_handles_hover = tree.get(node_id).is_some_and(|node| {
1377            node_handles_pointer_at_position(node.get(), base_abs_pos, size, position)
1378        }) || bounds.contains(position)
1379            && tree.get(node_id).is_some_and(|node| {
1380                let node = node.get();
1381                !node.pointer_preview_handlers.is_empty()
1382                    || !node.pointer_handlers.is_empty()
1383                    || !node.pointer_final_handlers.is_empty()
1384            });
1385
1386        node_handles_hover.then_some(vec![node_id])
1387    }
1388
1389    let Some(position) = position else {
1390        return Vec::new();
1391    };
1392    collect_hit_path(root_node, tree, metadatas, position).unwrap_or_default()
1393}
1394
1395fn resolve_hover_cursor_icon(
1396    root_node: indextree::NodeId,
1397    tree: &ComponentNodeTree,
1398    metadatas: &ComponentNodeMetaDatas,
1399    position: Option<PxPosition>,
1400) -> Option<winit::window::CursorIcon> {
1401    hit_path_node_ids(root_node, tree, metadatas, position)
1402        .into_iter()
1403        .rev()
1404        .find_map(|node_id| {
1405            let node_ref = tree.get(node_id)?;
1406            let metadata = metadatas.get(&node_id)?;
1407            let base_abs_pos = metadata.base_abs_position?;
1408            let size = metadata.computed_data?;
1409            resolve_node_hover_cursor_icon(node_ref.get(), base_abs_pos, size, position?)
1410        })
1411}
1412
1413fn node_handles_pointer_at_position(
1414    node: &crate::component_tree::ComponentNode,
1415    base_abs_pos: PxPosition,
1416    size: ComputedData,
1417    position: PxPosition,
1418) -> bool {
1419    let mut current_abs_pos = base_abs_pos;
1420    let size = PxSize::new(size.width, size.height);
1421    for action in node.modifier.ordered_actions() {
1422        match action {
1423            OrderedModifierAction::Placement(placement) => {
1424                current_abs_pos = placement.node().transform_position(current_abs_pos);
1425            }
1426            OrderedModifierAction::Cursor(_)
1427            | OrderedModifierAction::PointerPreviewInput(_)
1428            | OrderedModifierAction::PointerInput(_)
1429            | OrderedModifierAction::PointerFinalInput(_) => {
1430                let bounds = PxRect::from_position_size(current_abs_pos, size);
1431                if bounds.contains(position) {
1432                    return true;
1433                }
1434            }
1435            _ => {}
1436        }
1437    }
1438    false
1439}
1440
1441fn resolve_node_hover_cursor_icon(
1442    node: &crate::component_tree::ComponentNode,
1443    base_abs_pos: PxPosition,
1444    size: ComputedData,
1445    position: PxPosition,
1446) -> Option<winit::window::CursorIcon> {
1447    let mut current_abs_pos = base_abs_pos;
1448    let size = PxSize::new(size.width, size.height);
1449    let mut resolved = None;
1450    for action in node.modifier.ordered_actions() {
1451        match action {
1452            OrderedModifierAction::Placement(placement) => {
1453                current_abs_pos = placement.node().transform_position(current_abs_pos);
1454            }
1455            OrderedModifierAction::Cursor(cursor) => {
1456                let bounds = PxRect::from_position_size(current_abs_pos, size);
1457                if bounds.contains(position) {
1458                    resolved = Some(cursor.cursor_icon());
1459                }
1460            }
1461            _ => {}
1462        }
1463    }
1464    resolved
1465}
1466
1467fn build_pointer_change_paths(
1468    root_node: indextree::NodeId,
1469    tree: &ComponentNodeTree,
1470    metadatas: &ComponentNodeMetaDatas,
1471    pointer_changes: &[PointerChange],
1472    cursor_position: Option<PxPosition>,
1473    active_pointer_paths: &mut HashMap<u64, Vec<u64>>,
1474) -> Vec<Vec<u64>> {
1475    let mut paths = Vec::with_capacity(pointer_changes.len());
1476    for change in pointer_changes {
1477        let debug_position = match &change.content {
1478            CursorEventContent::Moved(position) => Some(*position),
1479            _ => cursor_position,
1480        };
1481        let path = match &change.content {
1482            CursorEventContent::Pressed(_) => {
1483                let computed_path =
1484                    hit_path_instance_keys(root_node, tree, metadatas, debug_position);
1485                if computed_path.is_empty() {
1486                    active_pointer_paths.remove(&change.pointer_id);
1487                } else {
1488                    active_pointer_paths.insert(change.pointer_id, computed_path.clone());
1489                }
1490                computed_path
1491            }
1492            CursorEventContent::Moved(position) => active_pointer_paths
1493                .get(&change.pointer_id)
1494                .cloned()
1495                .unwrap_or_else(|| {
1496                    hit_path_instance_keys(root_node, tree, metadatas, Some(*position))
1497                }),
1498            CursorEventContent::Released(_) => {
1499                let computed = active_pointer_paths
1500                    .get(&change.pointer_id)
1501                    .cloned()
1502                    .unwrap_or_else(|| {
1503                        hit_path_instance_keys(root_node, tree, metadatas, debug_position)
1504                    });
1505                active_pointer_paths.remove(&change.pointer_id);
1506                computed
1507            }
1508            CursorEventContent::Scroll(_) => active_pointer_paths
1509                .get(&change.pointer_id)
1510                .cloned()
1511                .unwrap_or_else(|| {
1512                    hit_path_instance_keys(root_node, tree, metadatas, debug_position)
1513                }),
1514        };
1515        paths.push(path);
1516    }
1517    paths
1518}
1519
1520fn hit_path_instance_keys(
1521    root_node: indextree::NodeId,
1522    tree: &ComponentNodeTree,
1523    metadatas: &ComponentNodeMetaDatas,
1524    position: Option<PxPosition>,
1525) -> Vec<u64> {
1526    hit_path_node_ids(root_node, tree, metadatas, position)
1527        .into_iter()
1528        .filter_map(|node_id| tree.get(node_id).map(|node| node.get().instance_key))
1529        .collect()
1530}
1531
1532fn collect_focus_chain_node_ids(
1533    root_node: indextree::NodeId,
1534    tree: &ComponentNodeTree,
1535    focus_owner: &FocusOwner,
1536) -> Vec<indextree::NodeId> {
1537    fn live_node(
1538        tree: &ComponentNodeTree,
1539        node_id: indextree::NodeId,
1540    ) -> Option<&indextree::Node<ComponentNode>> {
1541        tree.get(node_id).filter(|node| !node.is_removed())
1542    }
1543
1544    let Some(focused_node_id) = focus_owner.active_component_node_id() else {
1545        return Vec::new();
1546    };
1547    if live_node(tree, focused_node_id).is_none() {
1548        return Vec::new();
1549    }
1550
1551    let mut chain = Vec::new();
1552    let mut current = Some(focused_node_id);
1553    while let Some(node_id) = current {
1554        chain.push(node_id);
1555        if node_id == root_node {
1556            break;
1557        }
1558        current = live_node(tree, node_id).and_then(|node| node.parent());
1559    }
1560    if chain.last().copied() != Some(root_node) {
1561        return Vec::new();
1562    }
1563    chain.reverse();
1564    chain
1565}
1566
1567struct PointerInputDispatchContext<'a> {
1568    tree: &'a ComponentNodeTree,
1569    metadatas: &'a ComponentNodeMetaDatas,
1570    cursor_position: &'a mut Option<PxPosition>,
1571    pointer_changes: &'a mut [PointerChange],
1572    pointer_change_paths: &'a [Vec<u64>],
1573    modifiers: winit::keyboard::ModifiersState,
1574    window_requests: &'a mut WindowRequests,
1575    focus_owner: &'a mut FocusOwner,
1576}
1577
1578fn dispatch_pointer_modifiers_for_node_pass(
1579    dispatch_ctx: &mut PointerInputDispatchContext<'_>,
1580    node_id: indextree::NodeId,
1581    pass: PointerEventPass,
1582) {
1583    let Some(NodeInputContext { base_abs_pos, .. }) =
1584        resolve_node_input_context(dispatch_ctx.tree, dispatch_ctx.metadatas, node_id)
1585    else {
1586        return;
1587    };
1588    let Some(node_ref) = dispatch_ctx.tree.get(node_id) else {
1589        return;
1590    };
1591
1592    let mut current_abs_pos = base_abs_pos;
1593    for action in node_ref.get().modifier.ordered_actions() {
1594        match action {
1595            OrderedModifierAction::Placement(placement) => {
1596                current_abs_pos = placement.node().transform_position(current_abs_pos);
1597            }
1598            OrderedModifierAction::PointerPreviewInput(modifier)
1599                if pass == PointerEventPass::Initial =>
1600            {
1601                run_pointer_modifier_for_node(
1602                    dispatch_ctx,
1603                    node_id,
1604                    pass,
1605                    current_abs_pos,
1606                    modifier.as_ref(),
1607                );
1608            }
1609            OrderedModifierAction::PointerInput(modifier) if pass == PointerEventPass::Main => {
1610                run_pointer_modifier_for_node(
1611                    dispatch_ctx,
1612                    node_id,
1613                    pass,
1614                    current_abs_pos,
1615                    modifier.as_ref(),
1616                );
1617            }
1618            OrderedModifierAction::PointerFinalInput(modifier)
1619                if pass == PointerEventPass::Final =>
1620            {
1621                run_pointer_modifier_for_node(
1622                    dispatch_ctx,
1623                    node_id,
1624                    pass,
1625                    current_abs_pos,
1626                    modifier.as_ref(),
1627                );
1628            }
1629            _ => {}
1630        }
1631    }
1632}
1633
1634fn run_pointer_handler_for_node(
1635    dispatch_ctx: &mut PointerInputDispatchContext<'_>,
1636    node_id: indextree::NodeId,
1637    pass: PointerEventPass,
1638    pointer_handler: &PointerInputHandlerFn,
1639) {
1640    let Some(NodeInputContext { abs_pos, .. }) =
1641        resolve_node_input_context(dispatch_ctx.tree, dispatch_ctx.metadatas, node_id)
1642    else {
1643        return;
1644    };
1645    run_pointer_input_for_node(dispatch_ctx, node_id, pass, abs_pos, pointer_handler);
1646}
1647
1648fn run_pointer_modifier_for_node(
1649    dispatch_ctx: &mut PointerInputDispatchContext<'_>,
1650    node_id: indextree::NodeId,
1651    pass: PointerEventPass,
1652    abs_pos_override: PxPosition,
1653    pointer_modifier: &dyn PointerInputModifierNode,
1654) {
1655    run_pointer_input_for_node(dispatch_ctx, node_id, pass, abs_pos_override, |input| {
1656        pointer_modifier.on_pointer_input(input)
1657    });
1658}
1659
1660fn run_pointer_input_for_node<F>(
1661    dispatch_ctx: &mut PointerInputDispatchContext<'_>,
1662    node_id: indextree::NodeId,
1663    pass: PointerEventPass,
1664    abs_pos_override: PxPosition,
1665    dispatch: F,
1666) where
1667    F: FnOnce(PointerInput<'_>),
1668{
1669    let Some(NodeInputContext {
1670        base_abs_pos: _,
1671        abs_pos: _,
1672        event_clip_rect,
1673        node_computed_data,
1674        instance_logic_id,
1675        instance_key,
1676        fn_name,
1677        parent_id,
1678    }) = resolve_node_input_context(dispatch_ctx.tree, dispatch_ctx.metadatas, node_id)
1679    else {
1680        return;
1681    };
1682    #[cfg(not(feature = "profiling"))]
1683    let _ = parent_id;
1684
1685    let abs_pos = abs_pos_override;
1686
1687    let mut cursor_position_ref = &mut *dispatch_ctx.cursor_position;
1688    let mut dummy_cursor_position = None;
1689    if let (Some(cursor_pos), Some(clip_rect)) = (*cursor_position_ref, event_clip_rect)
1690        && !clip_rect.contains(cursor_pos)
1691    {
1692        cursor_position_ref = &mut dummy_cursor_position;
1693    }
1694    let current_cursor_position = cursor_position_ref.map(|pos| pos - abs_pos);
1695    let mut selected_change_indices = Vec::new();
1696    let mut local_pointer_changes = Vec::new();
1697    for (index, change) in dispatch_ctx.pointer_changes.iter().enumerate() {
1698        if change.is_consumed() {
1699            continue;
1700        }
1701        let Some(path) = dispatch_ctx.pointer_change_paths.get(index) else {
1702            continue;
1703        };
1704        if path.contains(&instance_key) {
1705            selected_change_indices.push(index);
1706            local_pointer_changes.push(change.clone());
1707        }
1708    }
1709
1710    #[cfg(feature = "profiling")]
1711    let mut profiler_guard = Some(ProfilerScopeGuard::new(
1712        ProfilerPhase::Input,
1713        Some(node_id),
1714        parent_id,
1715        Some(fn_name.as_str()),
1716    ));
1717    let replay_boundary_instance_key =
1718        nearest_replay_boundary_instance_key(node_id, dispatch_ctx.tree);
1719    let _node_ctx_guard =
1720        push_current_node_with_instance_logic_id(node_id, instance_logic_id, fn_name.as_str());
1721    let _instance_ctx_guard = push_current_component_instance_key(replay_boundary_instance_key);
1722    let _phase_guard = push_phase(RuntimePhase::Input);
1723    let _focus_owner_guard = bind_focus_owner(dispatch_ctx.focus_owner);
1724    let input = PointerInput {
1725        pass,
1726        computed_data: node_computed_data,
1727        cursor_position_rel: current_cursor_position,
1728        cursor_position_abs: cursor_position_ref,
1729        pointer_changes: &mut local_pointer_changes,
1730        key_modifiers: dispatch_ctx.modifiers,
1731        ime_request: &mut dispatch_ctx.window_requests.ime_request,
1732        request_window_drag: &mut dispatch_ctx.window_requests.request_window_drag,
1733    };
1734    dispatch(input);
1735    for (local_change, &original_index) in local_pointer_changes
1736        .iter()
1737        .zip(selected_change_indices.iter())
1738    {
1739        if let Some(original) = dispatch_ctx.pointer_changes.get_mut(original_index) {
1740            *original = local_change.clone();
1741        }
1742    }
1743
1744    #[cfg(feature = "profiling")]
1745    {
1746        let abs_tuple = (abs_pos.x.0, abs_pos.y.0);
1747        if let Some(g) = &mut profiler_guard {
1748            g.set_positions(Some(abs_tuple));
1749        }
1750        let _ = profiler_guard.take();
1751    }
1752    attach_ime_position_if_needed(dispatch_ctx.window_requests, abs_pos);
1753}
1754
1755fn run_keyboard_handler_for_node(
1756    dispatch_ctx: &mut KeyboardInputDispatchContext<'_>,
1757    node_id: indextree::NodeId,
1758    keyboard_handler: &KeyboardInputHandlerFn,
1759) {
1760    run_keyboard_input_for_node(dispatch_ctx, node_id, keyboard_handler);
1761}
1762
1763struct KeyboardInputDispatchContext<'a> {
1764    tree: &'a ComponentNodeTree,
1765    metadatas: &'a ComponentNodeMetaDatas,
1766    keyboard_events: &'a mut Vec<winit::event::KeyEvent>,
1767    modifiers: winit::keyboard::ModifiersState,
1768    window_requests: &'a mut WindowRequests,
1769    focus_owner: &'a mut FocusOwner,
1770}
1771
1772fn run_keyboard_modifier_for_node(
1773    dispatch_ctx: &mut KeyboardInputDispatchContext<'_>,
1774    node_id: indextree::NodeId,
1775    keyboard_modifier: &dyn KeyboardInputModifierNode,
1776) {
1777    run_keyboard_input_for_node(dispatch_ctx, node_id, |input| {
1778        keyboard_modifier.on_keyboard_input(input)
1779    });
1780}
1781
1782fn run_keyboard_input_for_node<F>(
1783    dispatch_ctx: &mut KeyboardInputDispatchContext<'_>,
1784    node_id: indextree::NodeId,
1785    dispatch: F,
1786) where
1787    F: FnOnce(KeyboardInput<'_>),
1788{
1789    let Some(NodeInputContext {
1790        abs_pos,
1791        event_clip_rect: _,
1792        node_computed_data,
1793        instance_logic_id,
1794        instance_key: _,
1795        fn_name,
1796        parent_id,
1797        ..
1798    }) = resolve_node_input_context(dispatch_ctx.tree, dispatch_ctx.metadatas, node_id)
1799    else {
1800        return;
1801    };
1802    #[cfg(not(feature = "profiling"))]
1803    let _ = parent_id;
1804
1805    #[cfg(feature = "profiling")]
1806    let mut profiler_guard = Some(ProfilerScopeGuard::new(
1807        ProfilerPhase::Input,
1808        Some(node_id),
1809        parent_id,
1810        Some(fn_name.as_str()),
1811    ));
1812    let replay_boundary_instance_key =
1813        nearest_replay_boundary_instance_key(node_id, dispatch_ctx.tree);
1814    let _node_ctx_guard =
1815        push_current_node_with_instance_logic_id(node_id, instance_logic_id, fn_name.as_str());
1816    let _instance_ctx_guard = push_current_component_instance_key(replay_boundary_instance_key);
1817    let _phase_guard = push_phase(RuntimePhase::Input);
1818    let _focus_owner_guard = bind_focus_owner(dispatch_ctx.focus_owner);
1819    let input = KeyboardInput {
1820        computed_data: node_computed_data,
1821        keyboard_events: dispatch_ctx.keyboard_events,
1822        key_modifiers: dispatch_ctx.modifiers,
1823        ime_request: &mut dispatch_ctx.window_requests.ime_request,
1824    };
1825    dispatch(input);
1826
1827    #[cfg(feature = "profiling")]
1828    {
1829        let abs_tuple = (abs_pos.x.0, abs_pos.y.0);
1830        if let Some(g) = &mut profiler_guard {
1831            g.set_positions(Some(abs_tuple));
1832        }
1833        let _ = profiler_guard.take();
1834    }
1835    attach_ime_position_if_needed(dispatch_ctx.window_requests, abs_pos);
1836}
1837
1838fn run_ime_handler_for_node(
1839    tree: &ComponentNodeTree,
1840    metadatas: &ComponentNodeMetaDatas,
1841    node_id: indextree::NodeId,
1842    ime_handler: &ImeInputHandlerFn,
1843    ime_events: &mut Vec<winit::event::Ime>,
1844    window_requests: &mut WindowRequests,
1845    focus_owner: &mut FocusOwner,
1846) {
1847    run_ime_input_for_node(
1848        tree,
1849        metadatas,
1850        node_id,
1851        ime_events,
1852        window_requests,
1853        focus_owner,
1854        ime_handler,
1855    );
1856}
1857
1858fn run_ime_modifier_for_node(
1859    tree: &ComponentNodeTree,
1860    metadatas: &ComponentNodeMetaDatas,
1861    node_id: indextree::NodeId,
1862    ime_modifier: &dyn ImeInputModifierNode,
1863    ime_events: &mut Vec<winit::event::Ime>,
1864    window_requests: &mut WindowRequests,
1865    focus_owner: &mut FocusOwner,
1866) {
1867    run_ime_input_for_node(
1868        tree,
1869        metadatas,
1870        node_id,
1871        ime_events,
1872        window_requests,
1873        focus_owner,
1874        |input| ime_modifier.on_ime_input(input),
1875    );
1876}
1877
1878fn run_ime_input_for_node<F>(
1879    tree: &ComponentNodeTree,
1880    metadatas: &ComponentNodeMetaDatas,
1881    node_id: indextree::NodeId,
1882    ime_events: &mut Vec<winit::event::Ime>,
1883    window_requests: &mut WindowRequests,
1884    focus_owner: &mut FocusOwner,
1885    dispatch: F,
1886) where
1887    F: FnOnce(ImeInput<'_>),
1888{
1889    let Some(NodeInputContext {
1890        abs_pos,
1891        event_clip_rect: _,
1892        node_computed_data,
1893        instance_logic_id,
1894        instance_key: _,
1895        fn_name,
1896        parent_id,
1897        ..
1898    }) = resolve_node_input_context(tree, metadatas, node_id)
1899    else {
1900        return;
1901    };
1902    #[cfg(not(feature = "profiling"))]
1903    let _ = parent_id;
1904
1905    #[cfg(feature = "profiling")]
1906    let mut profiler_guard = Some(ProfilerScopeGuard::new(
1907        ProfilerPhase::Input,
1908        Some(node_id),
1909        parent_id,
1910        Some(fn_name.as_str()),
1911    ));
1912    let replay_boundary_instance_key = nearest_replay_boundary_instance_key(node_id, tree);
1913    let _node_ctx_guard =
1914        push_current_node_with_instance_logic_id(node_id, instance_logic_id, fn_name.as_str());
1915    let _instance_ctx_guard = push_current_component_instance_key(replay_boundary_instance_key);
1916    let _phase_guard = push_phase(RuntimePhase::Input);
1917    let _focus_owner_guard = bind_focus_owner(focus_owner);
1918    let input = ImeInput {
1919        computed_data: node_computed_data,
1920        ime_events,
1921        ime_request: &mut window_requests.ime_request,
1922    };
1923    dispatch(input);
1924
1925    #[cfg(feature = "profiling")]
1926    {
1927        let abs_tuple = (abs_pos.x.0, abs_pos.y.0);
1928        if let Some(g) = &mut profiler_guard {
1929            g.set_positions(Some(abs_tuple));
1930        }
1931        let _ = profiler_guard.take();
1932    }
1933    attach_ime_position_if_needed(window_requests, abs_pos);
1934}
1935
1936fn dispatch_default_focus_keyboard_navigation(
1937    tree: &ComponentNodeTree,
1938    keyboard_events: &mut Vec<winit::event::KeyEvent>,
1939    modifiers: winit::keyboard::ModifiersState,
1940    focus_owner: &mut FocusOwner,
1941) -> Option<FocusDirection> {
1942    if keyboard_events.is_empty() {
1943        return None;
1944    }
1945
1946    let mut pending_focus_move_retry = None;
1947    keyboard_events.retain(|event| {
1948        if pending_focus_move_retry.is_some() {
1949            return false;
1950        }
1951        let Some(direction) = default_focus_navigation_direction(event, modifiers) else {
1952            return true;
1953        };
1954        match try_dispatch_focus_move_request(tree, direction, focus_owner) {
1955            FocusMoveRequestResult::Moved => false,
1956            FocusMoveRequestResult::Retry(direction) => {
1957                pending_focus_move_retry = Some(direction);
1958                false
1959            }
1960            FocusMoveRequestResult::NotHandled => true,
1961        }
1962    });
1963    pending_focus_move_retry
1964}
1965
1966fn default_focus_navigation_direction(
1967    event: &winit::event::KeyEvent,
1968    modifiers: winit::keyboard::ModifiersState,
1969) -> Option<FocusDirection> {
1970    if event.state != winit::event::ElementState::Pressed {
1971        return None;
1972    }
1973
1974    if modifiers.control_key() || modifiers.alt_key() || modifiers.super_key() {
1975        return None;
1976    }
1977
1978    match &event.logical_key {
1979        winit::keyboard::Key::Named(winit::keyboard::NamedKey::Tab) => {
1980            if modifiers.shift_key() {
1981                Some(FocusDirection::Previous)
1982            } else {
1983                Some(FocusDirection::Next)
1984            }
1985        }
1986        winit::keyboard::Key::Named(winit::keyboard::NamedKey::ArrowLeft) => {
1987            (!modifiers.shift_key()).then_some(FocusDirection::Left)
1988        }
1989        winit::keyboard::Key::Named(winit::keyboard::NamedKey::ArrowRight) => {
1990            (!modifiers.shift_key()).then_some(FocusDirection::Right)
1991        }
1992        winit::keyboard::Key::Named(winit::keyboard::NamedKey::ArrowUp) => {
1993            (!modifiers.shift_key()).then_some(FocusDirection::Up)
1994        }
1995        winit::keyboard::Key::Named(winit::keyboard::NamedKey::ArrowDown) => {
1996            (!modifiers.shift_key()).then_some(FocusDirection::Down)
1997        }
1998        _ => None,
1999    }
2000}
2001
2002enum FocusMoveRequestResult {
2003    NotHandled,
2004    Moved,
2005    Retry(FocusDirection),
2006}
2007
2008fn try_dispatch_focus_move_request(
2009    tree: &ComponentNodeTree,
2010    direction: FocusDirection,
2011    focus_owner: &mut FocusOwner,
2012) -> FocusMoveRequestResult {
2013    if focus_owner.move_focus(direction) {
2014        return FocusMoveRequestResult::Moved;
2015    }
2016    if dispatch_focus_beyond_bounds_request(tree, direction, focus_owner) {
2017        return FocusMoveRequestResult::Retry(direction);
2018    }
2019    FocusMoveRequestResult::NotHandled
2020}
2021
2022fn dispatch_focus_beyond_bounds_request(
2023    tree: &ComponentNodeTree,
2024    direction: FocusDirection,
2025    focus_owner: &FocusOwner,
2026) -> bool {
2027    let mut current = focus_owner.active_component_node_id();
2028    while let Some(node_id) = current {
2029        let Some(node_ref) = tree.get(node_id) else {
2030            break;
2031        };
2032        let node = node_ref.get();
2033        if let Some(handler) = &node.focus_beyond_bounds_handler
2034            && handler.call(direction)
2035        {
2036            return true;
2037        }
2038        current = node_ref.parent();
2039    }
2040    false
2041}
2042
2043fn dispatch_pending_focus_reveal_request(
2044    tree: &ComponentNodeTree,
2045    metadatas: &ComponentNodeMetaDatas,
2046    focus_owner: &mut FocusOwner,
2047    retry_active_focus: bool,
2048) -> bool {
2049    let handle_id = if retry_active_focus {
2050        focus_owner.active_handle_id()
2051    } else {
2052        focus_owner.take_pending_reveal()
2053    };
2054    let Some(handle_id) = handle_id else {
2055        return false;
2056    };
2057    dispatch_focus_reveal_request(tree, metadatas, focus_owner, handle_id)
2058}
2059
2060fn dispatch_focus_reveal_request(
2061    tree: &ComponentNodeTree,
2062    metadatas: &ComponentNodeMetaDatas,
2063    focus_owner: &FocusOwner,
2064    handle_id: FocusHandleId,
2065) -> bool {
2066    let Some(target_node_id) = focus_owner.component_node_id_of(handle_id) else {
2067        return false;
2068    };
2069    let Some(target_rect) = component_node_bounds_rect(metadatas, target_node_id) else {
2070        return false;
2071    };
2072
2073    let mut current = Some(target_node_id);
2074    while let Some(node_id) = current {
2075        let Some(node_ref) = tree.get(node_id) else {
2076            break;
2077        };
2078        let Some(viewport_rect) = component_node_viewport_rect(metadatas, node_id) else {
2079            current = node_ref.parent();
2080            continue;
2081        };
2082        let node = node_ref.get();
2083        if let Some(handler) = &node.focus_reveal_handler {
2084            let handled = handler.call(crate::focus::FocusRevealRequest::new(
2085                target_rect,
2086                viewport_rect,
2087            ));
2088            if handled {
2089                return true;
2090            }
2091        }
2092        current = node_ref.parent();
2093    }
2094    false
2095}
2096
2097fn component_node_bounds_rect(
2098    metadatas: &ComponentNodeMetaDatas,
2099    node_id: indextree::NodeId,
2100) -> Option<PxRect> {
2101    let metadata = metadatas.get(&node_id)?;
2102    let abs_position = metadata.abs_position?;
2103    let computed_data = metadata.computed_data?;
2104    Some(PxRect::from_position_size(
2105        abs_position,
2106        PxSize::new(computed_data.width, computed_data.height),
2107    ))
2108}
2109
2110fn component_node_viewport_rect(
2111    metadatas: &ComponentNodeMetaDatas,
2112    node_id: indextree::NodeId,
2113) -> Option<PxRect> {
2114    let node_rect = component_node_bounds_rect(metadatas, node_id)?;
2115    let metadata = metadatas.get(&node_id)?;
2116    Some(
2117        metadata
2118            .event_clip_rect
2119            .and_then(|clip_rect| clip_rect.intersection(&node_rect))
2120            .unwrap_or(node_rect),
2121    )
2122}
2123
2124fn expand_dirty_nodes_with_ancestors(
2125    root_node: indextree::NodeId,
2126    tree: &ComponentNodeTree,
2127    dirty_nodes_self: &HashSet<u64>,
2128) -> HashSet<u64> {
2129    if dirty_nodes_self.is_empty() {
2130        return HashSet::default();
2131    }
2132
2133    let mut parent_by_key: HashMap<u64, u64> = HashMap::default();
2134    for edge in root_node.traverse(tree) {
2135        let indextree::NodeEdge::Start(node_id) = edge else {
2136            continue;
2137        };
2138        let Some(node) = tree.get(node_id) else {
2139            continue;
2140        };
2141        let instance_key = node.get().instance_key;
2142        let Some(parent_id) = node.parent() else {
2143            continue;
2144        };
2145        if let Some(parent) = tree.get(parent_id) {
2146            parent_by_key.insert(instance_key, parent.get().instance_key);
2147        }
2148    }
2149
2150    let mut expanded = dirty_nodes_self.clone();
2151    for dirty_key in dirty_nodes_self {
2152        let mut current = *dirty_key;
2153        while let Some(parent_key) = parent_by_key.get(&current).copied() {
2154            expanded.insert(parent_key);
2155            current = parent_key;
2156        }
2157    }
2158
2159    expanded
2160}
2161
2162fn collect_children_by_instance_key(
2163    root_node: indextree::NodeId,
2164    tree: &ComponentNodeTree,
2165) -> HashMap<u64, Vec<u64>> {
2166    let mut children_by_node = HashMap::default();
2167    for edge in root_node.traverse(tree) {
2168        let indextree::NodeEdge::Start(node_id) = edge else {
2169            continue;
2170        };
2171        let Some(node) = tree.get(node_id) else {
2172            continue;
2173        };
2174        let instance_key = node.get().instance_key;
2175        let child_keys = direct_layout_children(node_id, tree)
2176            .into_iter()
2177            .filter_map(|child_id| tree.get(child_id).map(|child| child.get().instance_key))
2178            .collect();
2179        children_by_node.insert(instance_key, child_keys);
2180    }
2181    children_by_node
2182}
2183
2184fn record_layout_commands(
2185    root_node: indextree::NodeId,
2186    tree: &ComponentNodeTree,
2187    metadatas: &mut ComponentNodeMetaDatas,
2188    compute_resource_manager: &mut ComputeResourceManager,
2189    gpu: &wgpu::Device,
2190) {
2191    struct DrawModifierChainContent<'a> {
2192        draw_nodes: &'a [Arc<dyn crate::modifier::DrawModifierNode>],
2193        render_policy: &'a dyn crate::layout::RenderPolicyDyn,
2194    }
2195
2196    impl DrawModifierContent for DrawModifierChainContent<'_> {
2197        fn draw(&mut self, input: &mut RenderInput<'_>) {
2198            if let Some((draw_modifier, remaining)) = self.draw_nodes.split_first() {
2199                let mut draw_ctx = DrawModifierContext {
2200                    render_input: input,
2201                };
2202                let mut next = DrawModifierChainContent {
2203                    draw_nodes: remaining,
2204                    render_policy: self.render_policy,
2205                };
2206                draw_modifier.draw(&mut draw_ctx, &mut next);
2207            } else {
2208                self.render_policy.record_dyn(input);
2209            }
2210        }
2211    }
2212
2213    let mut stack = vec![root_node];
2214    while let Some(node_id) = stack.pop() {
2215        let Some(node) = tree.get(node_id) else {
2216            continue;
2217        };
2218        #[cfg(feature = "profiling")]
2219        let _record_profiler_guard = {
2220            let parent_id = node.parent();
2221            Some(ProfilerScopeGuard::new(
2222                ProfilerPhase::Record,
2223                Some(node_id),
2224                parent_id,
2225                Some(node.get().fn_name.as_str()),
2226            ))
2227        };
2228        let mut input = RenderInput::new(node_id, metadatas, compute_resource_manager, gpu);
2229        let node_ref = node.get();
2230        let draw_nodes: Vec<_> = node_ref
2231            .modifier
2232            .ordered_actions()
2233            .into_iter()
2234            .filter_map(|action| match action {
2235                OrderedModifierAction::Draw(node) => Some(node),
2236                _ => None,
2237            })
2238            .collect();
2239        let mut content = DrawModifierChainContent {
2240            draw_nodes: &draw_nodes,
2241            render_policy: node_ref.render_policy.as_ref(),
2242        };
2243        content.draw(&mut input);
2244        stack.extend(node_id.children(tree));
2245    }
2246}
2247
2248#[derive(Clone, Copy)]
2249struct PreparedLayoutMetadata {
2250    self_position: PxPosition,
2251    size: PxSize,
2252    node_rect: PxRect,
2253    clips_children: bool,
2254    child_clip_rect: Option<PxRect>,
2255    cumulative_opacity: f32,
2256}
2257
2258fn prepare_layout_metadata_for_node(
2259    tree: &ComponentNodeTree,
2260    metadatas: &mut ComponentNodeMetaDatas,
2261    start_pos: PxPosition,
2262    is_root: bool,
2263    node_id: indextree::NodeId,
2264    parent_clip_rect: Option<PxRect>,
2265    current_opacity: f32,
2266) -> Option<PreparedLayoutMetadata> {
2267    let metadata = metadatas.get_mut(&node_id)?;
2268    let rel_pos = match metadata.rel_position {
2269        Some(pos) => pos,
2270        None if is_root => PxPosition::ZERO,
2271        _ => {
2272            metadata.abs_position = None;
2273            metadata.event_clip_rect = None;
2274            return None;
2275        }
2276    };
2277    let base_self_position = start_pos + rel_pos;
2278    let mut self_position = base_self_position;
2279    if let Some(node) = tree.get(node_id) {
2280        for action in node.get().modifier.ordered_actions() {
2281            if let OrderedModifierAction::Placement(placement_node) = action {
2282                self_position = placement_node.node().transform_position(self_position);
2283            }
2284        }
2285    }
2286    let cumulative_opacity = current_opacity * metadata.opacity;
2287    metadata.base_abs_position = Some(base_self_position);
2288    metadata.abs_position = Some(self_position);
2289    metadata.event_clip_rect = parent_clip_rect;
2290
2291    let size = metadata
2292        .computed_data
2293        .map(|d| PxSize {
2294            width: d.width,
2295            height: d.height,
2296        })
2297        .unwrap_or_default();
2298    let node_rect = PxRect {
2299        x: self_position.x,
2300        y: self_position.y,
2301        width: size.width,
2302        height: size.height,
2303    };
2304    let clips_children = metadata.clips_children;
2305    let child_clip_rect = if clips_children {
2306        Some(
2307            parent_clip_rect
2308                .and_then(|existing| existing.intersection(&node_rect))
2309                .unwrap_or(node_rect),
2310        )
2311    } else {
2312        parent_clip_rect
2313    };
2314
2315    Some(PreparedLayoutMetadata {
2316        self_position,
2317        size,
2318        node_rect,
2319        clips_children,
2320        child_clip_rect,
2321        cumulative_opacity,
2322    })
2323}
2324
2325fn populate_layout_metadata(
2326    root_node: indextree::NodeId,
2327    tree: &ComponentNodeTree,
2328    metadatas: &mut ComponentNodeMetaDatas,
2329) {
2330    fn visit(
2331        tree: &ComponentNodeTree,
2332        metadatas: &mut ComponentNodeMetaDatas,
2333        start_pos: PxPosition,
2334        is_root: bool,
2335        node_id: indextree::NodeId,
2336        clip_rect: Option<PxRect>,
2337        current_opacity: f32,
2338    ) {
2339        let Some(prepared) = prepare_layout_metadata_for_node(
2340            tree,
2341            metadatas,
2342            start_pos,
2343            is_root,
2344            node_id,
2345            clip_rect,
2346            current_opacity,
2347        ) else {
2348            for child in node_id.children(tree) {
2349                visit(
2350                    tree,
2351                    metadatas,
2352                    start_pos,
2353                    false,
2354                    child,
2355                    clip_rect,
2356                    current_opacity,
2357                );
2358            }
2359            return;
2360        };
2361
2362        for child in node_id.children(tree) {
2363            visit(
2364                tree,
2365                metadatas,
2366                prepared.self_position,
2367                false,
2368                child,
2369                prepared.child_clip_rect,
2370                prepared.cumulative_opacity,
2371            );
2372        }
2373    }
2374
2375    visit(
2376        tree,
2377        metadatas,
2378        PxPosition::ZERO,
2379        true,
2380        root_node,
2381        None,
2382        1.0,
2383    );
2384}
2385
2386/// Sequential computation of render graph ops from the component tree.
2387#[tracing::instrument(level = "trace", skip(tree, metadatas))]
2388fn build_render_graph(
2389    node_id: indextree::NodeId,
2390    tree: &ComponentNodeTree,
2391    metadatas: &mut ComponentNodeMetaDatas,
2392    screen_size: PxSize,
2393) -> RenderGraph {
2394    let screen_rect = PxRect {
2395        x: Px(0),
2396        y: Px(0),
2397        width: screen_size.width,
2398        height: screen_size.height,
2399    };
2400
2401    let mut builder = RenderGraphBuilder::new();
2402    let mut context = RenderGraphBuildContext {
2403        tree,
2404        metadatas,
2405        builder: &mut builder,
2406        screen_rect,
2407    };
2408    build_render_graph_inner(&mut context, PxPosition::ZERO, true, node_id, None, 1.0);
2409    builder.finish()
2410}
2411
2412struct RenderGraphBuildContext<'a> {
2413    tree: &'a ComponentNodeTree,
2414    metadatas: &'a mut ComponentNodeMetaDatas,
2415    builder: &'a mut RenderGraphBuilder,
2416    screen_rect: PxRect,
2417}
2418
2419#[tracing::instrument(level = "trace", skip(context))]
2420fn build_render_graph_inner(
2421    context: &mut RenderGraphBuildContext<'_>,
2422    start_pos: PxPosition,
2423    is_root: bool,
2424    node_id: indextree::NodeId,
2425    clip_rect: Option<PxRect>,
2426    current_opacity: f32,
2427) {
2428    let Some(prepared) = prepare_layout_metadata_for_node(
2429        context.tree,
2430        context.metadatas,
2431        start_pos,
2432        is_root,
2433        node_id,
2434        clip_rect,
2435        current_opacity,
2436    ) else {
2437        for child in node_id.children(context.tree) {
2438            build_render_graph_inner(context, start_pos, false, child, clip_rect, current_opacity);
2439        }
2440        return;
2441    };
2442
2443    if prepared.clips_children {
2444        context
2445            .builder
2446            .push_clip_push(prepared.child_clip_rect.unwrap_or(PxRect::ZERO));
2447    }
2448
2449    let fragment = match context.metadatas.get_mut(&node_id) {
2450        Some(metadata) => metadata.take_fragment(),
2451        None => {
2452            warn!("Missing metadata for node {node_id:?}; skipping render graph build");
2453            return;
2454        }
2455    };
2456
2457    if prepared.size.width.0 > 0
2458        && prepared.size.height.0 > 0
2459        && !prepared.node_rect.is_orthogonal(&context.screen_rect)
2460    {
2461        context.builder.append_fragment(
2462            fragment,
2463            prepared.size,
2464            prepared.self_position,
2465            prepared.cumulative_opacity,
2466        );
2467    }
2468
2469    for child in node_id.children(context.tree) {
2470        build_render_graph_inner(
2471            context,
2472            prepared.self_position,
2473            false,
2474            child,
2475            prepared.child_clip_rect,
2476            prepared.cumulative_opacity,
2477        );
2478    }
2479
2480    if prepared.clips_children {
2481        context.builder.push_clip_pop();
2482    }
2483}
2484
2485#[cfg(test)]
2486mod tests {
2487    use super::*;
2488
2489    use crate::{
2490        component_tree::{ComponentNode, NodeRole},
2491        layout::{DefaultLayoutPolicy, NoopRenderPolicy},
2492        modifier::Modifier,
2493    };
2494
2495    fn node_with_role(
2496        name: &str,
2497        role: NodeRole,
2498        instance_logic_id: u64,
2499        instance_key: u64,
2500    ) -> ComponentNode {
2501        ComponentNode {
2502            fn_name: name.to_string(),
2503            role,
2504            instance_logic_id,
2505            instance_key,
2506            pointer_preview_handlers: Vec::new(),
2507            pointer_handlers: Vec::new(),
2508            pointer_final_handlers: Vec::new(),
2509            keyboard_preview_handlers: Vec::new(),
2510            keyboard_handlers: Vec::new(),
2511            ime_preview_handlers: Vec::new(),
2512            ime_handlers: Vec::new(),
2513            focus_requester_binding: None,
2514            focus_registration: None,
2515            focus_restorer_fallback: None,
2516            focus_traversal_policy: None,
2517            focus_changed_handler: None,
2518            focus_event_handler: None,
2519            focus_beyond_bounds_handler: None,
2520            focus_reveal_handler: None,
2521            modifier: Modifier::default(),
2522            layout_policy: Box::new(DefaultLayoutPolicy),
2523            render_policy: Box::new(NoopRenderPolicy),
2524            replay: None,
2525            props_unchanged_from_previous: false,
2526        }
2527    }
2528
2529    fn node(name: &str, instance_logic_id: u64, instance_key: u64) -> ComponentNode {
2530        node_with_role(name, NodeRole::Layout, instance_logic_id, instance_key)
2531    }
2532
2533    #[test]
2534    fn begin_replace_subtree_rejects_root_instance_key() {
2535        let mut tree = ComponentTree::new();
2536
2537        let root = tree.add_node(node("root", 1, 1));
2538        tree.pop_node();
2539
2540        let result = tree.begin_replace_subtree_by_instance_key(1);
2541        assert!(matches!(
2542            result,
2543            Err(ReplayReplaceError::RootNodeNotReplaceable)
2544        ));
2545        assert!(tree.get(root).is_some());
2546    }
2547
2548    #[test]
2549    fn finish_replace_subtree_keeps_inserted_roots_before_next_sibling() {
2550        let mut tree = ComponentTree::new();
2551
2552        let root = tree.add_node(node("root", 1, 1));
2553
2554        let _first = tree.add_node(node("first", 2, 2));
2555        let _first_child = tree.add_node(node("first_child", 3, 3));
2556        tree.pop_node();
2557        tree.pop_node();
2558
2559        let second = tree.add_node(node("second", 4, 4));
2560        tree.pop_node();
2561        tree.pop_node();
2562
2563        let context = match tree.begin_replace_subtree_by_instance_key(2) {
2564            Ok(context) => context,
2565            Err(_) => panic!("replace context should be created"),
2566        };
2567
2568        let new_a = tree.add_node(node("new_a", 5, 5));
2569        let _new_a_child = tree.add_node(node("new_a_child", 6, 6));
2570        tree.pop_node();
2571        tree.pop_node();
2572        let new_b = tree.add_node(node("new_b", 7, 7));
2573        tree.pop_node();
2574
2575        let before_finish = root.children(tree.tree()).collect::<Vec<_>>();
2576        assert_eq!(before_finish, vec![second, new_a, new_b]);
2577
2578        let replace_result = match tree.finish_replace_subtree(context) {
2579            Ok(result) => result,
2580            Err(_) => panic!("finish replace should succeed"),
2581        };
2582
2583        let root_children = root
2584            .children(tree.tree())
2585            .map(|id| tree.get(id).expect("child must exist").fn_name.clone())
2586            .collect::<Vec<_>>();
2587        assert_eq!(root_children, vec!["new_a", "new_b", "second"]);
2588
2589        assert!(replace_result.removed_instance_keys.contains(&2));
2590        assert!(replace_result.removed_instance_keys.contains(&3));
2591        assert!(replace_result.inserted_instance_keys.contains(&5));
2592        assert!(replace_result.inserted_instance_keys.contains(&6));
2593        assert!(replace_result.inserted_instance_keys.contains(&7));
2594        assert!(replace_result.removed_instance_logic_ids.contains(&2));
2595        assert!(replace_result.removed_instance_logic_ids.contains(&3));
2596        assert!(replace_result.inserted_instance_logic_ids.contains(&5));
2597        assert!(replace_result.inserted_instance_logic_ids.contains(&6));
2598        assert!(replace_result.inserted_instance_logic_ids.contains(&7));
2599
2600        assert!(tree.get(second).is_some());
2601    }
2602
2603    #[test]
2604    fn finish_replace_subtree_keeps_reused_subtree_and_excludes_it_from_removed_sets() {
2605        let mut tree = ComponentTree::new();
2606
2607        let root = tree.add_node(node("root", 1, 1));
2608
2609        let _first = tree.add_node(node("first", 2, 2));
2610        let _first_child = tree.add_node(node("first_child", 3, 3));
2611        tree.pop_node();
2612        tree.pop_node();
2613
2614        let second = tree.add_node(node("second", 4, 4));
2615        tree.pop_node();
2616        tree.pop_node();
2617
2618        let context = match tree.begin_replace_subtree_by_instance_key(2) {
2619            Ok(context) => context,
2620            Err(_) => panic!("replace context should be created"),
2621        };
2622
2623        let _replacement = tree.add_node(node("replacement", 2, 2));
2624        assert!(tree.try_reuse_current_subtree(2, 2));
2625        tree.pop_node();
2626
2627        let replace_result = match tree.finish_replace_subtree(context) {
2628            Ok(result) => result,
2629            Err(_) => panic!("finish replace should succeed"),
2630        };
2631
2632        let root_children = root
2633            .children(tree.tree())
2634            .map(|id| tree.get(id).expect("child must exist").fn_name.clone())
2635            .collect::<Vec<_>>();
2636        assert_eq!(root_children, vec!["first", "second"]);
2637        assert!(tree.find_node_id_by_instance_key(3).is_some());
2638        assert!(tree.get(second).is_some());
2639
2640        assert!(replace_result.inserted_instance_keys.contains(&2));
2641        assert!(replace_result.inserted_instance_keys.contains(&3));
2642        assert!(replace_result.reused_instance_logic_ids.contains(&2));
2643        assert!(replace_result.reused_instance_logic_ids.contains(&3));
2644        assert!(!replace_result.removed_instance_keys.contains(&2));
2645        assert!(!replace_result.removed_instance_keys.contains(&3));
2646        assert!(!replace_result.removed_instance_logic_ids.contains(&2));
2647        assert!(!replace_result.removed_instance_logic_ids.contains(&3));
2648    }
2649
2650    #[test]
2651    fn layout_node_input_traversal_skips_composition_nodes() {
2652        let mut tree = ComponentTree::new();
2653
2654        let root = tree.add_node(node_with_role("root", NodeRole::Composition, 1, 1));
2655        let layout_a = tree.add_node(node("layout_a", 2, 2));
2656        tree.pop_node();
2657
2658        let composition = tree.add_node(node_with_role("wrapper", NodeRole::Composition, 3, 3));
2659        let layout_b = tree.add_node(node("layout_b", 4, 4));
2660        tree.pop_node();
2661        tree.pop_node();
2662        tree.pop_node();
2663
2664        let preorder = layout_node_ids_preorder(root, tree.tree());
2665        let postorder = layout_node_ids_postorder(root, tree.tree());
2666
2667        assert_eq!(preorder, vec![layout_a, layout_b]);
2668        assert_eq!(postorder, vec![layout_b, layout_a]);
2669        assert_eq!(composition.children(tree.tree()).count(), 1);
2670    }
2671}