tessera_ui/
component_tree.rs

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