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 unsafe { (*self.snapshots).get_cloned(&instance_key) }
201 }
202
203 #[inline]
204 pub(crate) fn insert_snapshot(&self, instance_key: u64, entry: LayoutSnapshotEntry) {
205 unsafe {
207 (*self.snapshots).insert(instance_key, entry);
208 }
209 }
210
211 #[inline]
212 pub(crate) fn remove_snapshot(&self, instance_key: u64) {
213 unsafe {
215 (*self.snapshots).remove(&instance_key);
216 }
217 }
218
219 #[inline]
220 pub(crate) fn inc_measure_node_calls(&self) {
221 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
287pub(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
310pub struct ComponentTree {
312 tree: indextree::Arena<ComponentNode>,
314 metadatas: ComponentNodeMetaDatas,
316 layout_snapshots: LayoutSnapshotMap,
317 node_queue: Vec<indextree::NodeId>,
319 replay_reuse_candidates: HashMap<u64, indextree::NodeId>,
321 active_pointer_paths: HashMap<u64, Vec<u64>>,
324 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 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 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 pub fn reset(&mut self) {
390 self.clear();
391 self.focus_owner.reset();
392 }
393
394 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 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 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 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 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(¤t_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 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 pub(crate) fn pop_node(&mut self) {
671 self.node_queue.pop();
672 }
673
674 pub(crate) fn tree(&self) -> &indextree::Arena<ComponentNode> {
679 &self.tree
680 }
681
682 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 #[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 #[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(¤t_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(¤t).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#[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}