1use std::{cell::Cell, collections::BTreeMap, ptr::NonNull};
9
10use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
11
12use crate::{
13 NodeId, PxPosition, PxRect,
14 component_tree::{
15 ComponentNodeMetaDatas, ComponentNodeTree, NodeRole, nearest_replay_boundary_instance_key,
16 sibling_index,
17 },
18 execution_context::{with_execution_context, with_execution_context_mut},
19 prop::CallbackWith,
20 px::PxSize,
21 runtime::{
22 TesseraRuntime, focus_read_subscribers, focus_requester_read_subscribers,
23 has_persistent_focus_handle, record_replay_boundary_invalidation_for_instance_key,
24 schedule_runtime_redraw, track_focus_read_dependency,
25 track_focus_requester_read_dependency,
26 },
27};
28
29const ROOT_SCOPE_ID: FocusHandleId = 0;
30
31const FOCUS_CHANGE_DIRECTION: crate::session::SessionLocal<Cell<Option<FocusDirection>>> =
32 crate::session::SessionLocal::new();
33
34struct FocusChangeDirectionGuard(Option<FocusDirection>);
35
36impl Drop for FocusChangeDirectionGuard {
37 fn drop(&mut self) {
38 FOCUS_CHANGE_DIRECTION.set(self.0);
39 }
40}
41
42pub(crate) type FocusHandleId = u128;
43pub(crate) type FocusRequesterId = u128;
44
45fn next_focus_handle_id() -> FocusHandleId {
46 uuid::Uuid::new_v4().as_u128()
47}
48
49fn next_focus_requester_id() -> FocusRequesterId {
50 uuid::Uuid::new_v4().as_u128()
51}
52
53fn with_bound_focus_owner<R>(f: impl FnOnce(&FocusOwner) -> R) -> Option<R> {
54 let ptr = with_execution_context(|context| context.current_focus_owner_stack.last().copied())?;
55 Some(unsafe { f(ptr.as_ref()) })
58}
59
60fn with_bound_focus_owner_mut<R>(f: impl FnOnce(&mut FocusOwner) -> R) -> Option<R> {
61 let ptr = with_execution_context(|context| context.current_focus_owner_stack.last().copied())?;
62 Some(unsafe { f(&mut *ptr.as_ptr()) })
65}
66
67fn with_focus_owner<R>(f: impl FnOnce(&FocusOwner) -> R) -> R {
68 let mut f = Some(f);
69 if let Some(result) = with_bound_focus_owner(|owner| {
70 f.take().expect("focus owner callback should run once")(owner)
71 }) {
72 return result;
73 }
74 TesseraRuntime::with(|runtime| {
75 f.take().expect("focus owner callback should run once")(
76 runtime.component_tree.focus_owner(),
77 )
78 })
79}
80
81fn with_focus_owner_mut<R>(f: impl FnOnce(&mut FocusOwner) -> R) -> R {
82 let mut f = Some(f);
83 if let Some(result) = with_bound_focus_owner_mut(|owner| {
84 f.take().expect("focus owner callback should run once")(owner)
85 }) {
86 return result;
87 }
88 let result = TesseraRuntime::with_mut(|runtime| {
89 f.take().expect("focus owner callback should run once")(
90 runtime.component_tree.focus_owner_mut(),
91 )
92 });
93 flush_pending_focus_callbacks();
94 result
95}
96
97pub(crate) struct FocusOwnerBindingGuard {
98 active: bool,
99}
100
101impl Drop for FocusOwnerBindingGuard {
102 fn drop(&mut self) {
103 if !self.active {
104 return;
105 }
106 with_execution_context_mut(|context| {
107 let popped = context.current_focus_owner_stack.pop();
108 debug_assert!(popped.is_some(), "focus owner binding stack underflow");
109 });
110 self.active = false;
111 }
112}
113
114pub(crate) fn bind_focus_owner(owner: &mut FocusOwner) -> FocusOwnerBindingGuard {
115 with_execution_context_mut(|context| {
116 context.current_focus_owner_stack.push(NonNull::from(owner));
117 });
118 FocusOwnerBindingGuard { active: true }
119}
120
121#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
126pub enum FocusState {
127 #[default]
129 Inactive,
130 ActiveParent,
132 Active,
134 Captured,
136}
137
138impl FocusState {
139 pub fn has_focus(self) -> bool {
141 !matches!(self, Self::Inactive)
142 }
143
144 pub fn is_focused(self) -> bool {
146 matches!(self, Self::Active | Self::Captured)
147 }
148
149 pub fn is_captured(self) -> bool {
151 matches!(self, Self::Captured)
152 }
153}
154
155#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
160pub enum FocusDirection {
161 Next,
163 Previous,
165 Up,
167 Down,
169 Left,
171 Right,
173 Enter,
175 Exit,
177}
178
179#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
181pub enum FocusTraversalStrategy {
182 Linear,
184 Horizontal,
186 Vertical,
188 Spatial,
190}
191
192#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
197pub struct FocusTraversalPolicy {
198 pub strategy: FocusTraversalStrategy,
200 pub wrap: bool,
202 pub tab_navigation: bool,
204 pub single_tab_stop: bool,
208}
209
210impl FocusTraversalPolicy {
211 pub const fn new(strategy: FocusTraversalStrategy) -> Self {
213 Self {
214 strategy,
215 wrap: false,
216 tab_navigation: false,
217 single_tab_stop: false,
218 }
219 }
220
221 pub const fn linear() -> Self {
223 Self::new(FocusTraversalStrategy::Linear)
224 }
225
226 pub const fn horizontal() -> Self {
228 Self::new(FocusTraversalStrategy::Horizontal)
229 }
230
231 pub const fn vertical() -> Self {
233 Self::new(FocusTraversalStrategy::Vertical)
234 }
235
236 pub const fn spatial() -> Self {
238 Self::new(FocusTraversalStrategy::Spatial)
239 }
240
241 pub const fn wrap(mut self, wrap: bool) -> Self {
243 self.wrap = wrap;
244 self
245 }
246
247 pub const fn tab_navigation(mut self, tab_navigation: bool) -> Self {
250 self.tab_navigation = tab_navigation;
251 self
252 }
253
254 pub const fn single_tab_stop(mut self, single_tab_stop: bool) -> Self {
258 self.single_tab_stop = single_tab_stop;
259 self
260 }
261
262 fn scoped_direction(self, direction: FocusDirection) -> Option<FocusDirection> {
263 if self.tab_navigation && !self.single_tab_stop {
264 match direction {
265 FocusDirection::Next | FocusDirection::Previous => return Some(direction),
266 _ => {}
267 }
268 }
269
270 match self.strategy {
271 FocusTraversalStrategy::Linear => match direction {
272 FocusDirection::Left | FocusDirection::Up => Some(FocusDirection::Previous),
273 FocusDirection::Right | FocusDirection::Down => Some(FocusDirection::Next),
274 _ => None,
275 },
276 FocusTraversalStrategy::Horizontal => match direction {
277 FocusDirection::Left => Some(FocusDirection::Previous),
278 FocusDirection::Right => Some(FocusDirection::Next),
279 _ => None,
280 },
281 FocusTraversalStrategy::Vertical => match direction {
282 FocusDirection::Up => Some(FocusDirection::Previous),
283 FocusDirection::Down => Some(FocusDirection::Next),
284 _ => None,
285 },
286 FocusTraversalStrategy::Spatial => match direction {
287 FocusDirection::Left
288 | FocusDirection::Right
289 | FocusDirection::Up
290 | FocusDirection::Down => Some(direction),
291 _ => None,
292 },
293 }
294 }
295}
296
297#[derive(Clone, Copy, Debug, PartialEq)]
299pub struct FocusRevealRequest {
300 target_bounds: crate::FloatRect,
301 viewport_bounds: crate::FloatRect,
302 local_to_window: crate::LocalToWindow,
303 pub target_rect: PxRect,
305 pub viewport_rect: PxRect,
307}
308
309impl FocusRevealRequest {
310 pub(crate) fn with_geometry(
311 target_bounds: crate::FloatRect,
312 viewport_bounds: crate::FloatRect,
313 local_to_window: crate::LocalToWindow,
314 ) -> Self {
315 Self {
316 target_rect: target_bounds.outward(),
317 viewport_rect: viewport_bounds.outward(),
318 target_bounds,
319 viewport_bounds,
320 local_to_window,
321 }
322 }
323
324 pub fn local_target_bounds(self) -> crate::FloatRect {
326 self.local_to_window.inverse_rect(self.target_bounds)
327 }
328
329 pub fn local_viewport_bounds(self) -> crate::FloatRect {
331 self.local_to_window.inverse_rect(self.viewport_bounds)
332 }
333}
334
335#[derive(Clone, Copy, Debug, PartialEq, Eq)]
343pub struct FocusProperties {
344 pub can_focus: bool,
346 pub can_request_focus: bool,
348 pub skip_traversal: bool,
351 pub preferred_tab_stop: bool,
353 pub next: Option<FocusRequester>,
355 pub previous: Option<FocusRequester>,
357 pub up: Option<FocusRequester>,
359 pub down: Option<FocusRequester>,
361 pub left: Option<FocusRequester>,
363 pub right: Option<FocusRequester>,
365 pub enter: Option<FocusRequester>,
367 pub exit: Option<FocusRequester>,
369}
370
371impl FocusProperties {
372 pub fn new() -> Self {
374 Self::default()
375 }
376
377 pub fn can_focus(mut self, can_focus: bool) -> Self {
379 self.can_focus = can_focus;
380 self
381 }
382
383 pub fn can_request_focus(mut self, can_request_focus: bool) -> Self {
385 self.can_request_focus = can_request_focus;
386 self
387 }
388
389 pub fn skip_traversal(mut self, skip_traversal: bool) -> Self {
391 self.skip_traversal = skip_traversal;
392 self
393 }
394
395 pub fn preferred_tab_stop(mut self, preferred: bool) -> Self {
398 self.preferred_tab_stop = preferred;
399 self
400 }
401
402 pub fn next(mut self, requester: FocusRequester) -> Self {
404 self.next = Some(requester);
405 self
406 }
407
408 pub fn previous(mut self, requester: FocusRequester) -> Self {
410 self.previous = Some(requester);
411 self
412 }
413
414 pub fn up(mut self, requester: FocusRequester) -> Self {
416 self.up = Some(requester);
417 self
418 }
419
420 pub fn down(mut self, requester: FocusRequester) -> Self {
422 self.down = Some(requester);
423 self
424 }
425
426 pub fn left(mut self, requester: FocusRequester) -> Self {
428 self.left = Some(requester);
429 self
430 }
431
432 pub fn right(mut self, requester: FocusRequester) -> Self {
434 self.right = Some(requester);
435 self
436 }
437
438 pub fn enter(mut self, requester: FocusRequester) -> Self {
440 self.enter = Some(requester);
441 self
442 }
443
444 pub fn exit(mut self, requester: FocusRequester) -> Self {
446 self.exit = Some(requester);
447 self
448 }
449}
450
451impl Default for FocusProperties {
452 fn default() -> Self {
453 Self {
454 can_focus: true,
455 can_request_focus: true,
456 skip_traversal: false,
457 preferred_tab_stop: false,
458 next: None,
459 previous: None,
460 up: None,
461 down: None,
462 left: None,
463 right: None,
464 enter: None,
465 exit: None,
466 }
467 }
468}
469
470#[derive(Clone, Copy, Debug, PartialEq, Eq)]
471pub(crate) enum FocusRegistrationKind {
472 Target,
473 Scope,
474 Group,
475}
476
477#[derive(Clone, Copy, Debug, PartialEq, Eq)]
478pub(crate) struct FocusRegistration {
479 pub(crate) id: FocusHandleId,
480 pub(crate) kind: FocusRegistrationKind,
481 pub(crate) properties: FocusProperties,
482}
483
484impl FocusRegistration {
485 pub(crate) fn target(node: FocusNode) -> Self {
486 Self {
487 id: node.id,
488 kind: FocusRegistrationKind::Target,
489 properties: FocusProperties::default(),
490 }
491 }
492
493 pub(crate) fn scope(scope: FocusScopeNode) -> Self {
494 Self {
495 id: scope.id,
496 kind: FocusRegistrationKind::Scope,
497 properties: FocusProperties::default().can_focus(false),
498 }
499 }
500
501 pub(crate) fn group(group: FocusGroupNode) -> Self {
502 Self {
503 id: group.id,
504 kind: FocusRegistrationKind::Group,
505 properties: FocusProperties::default()
506 .can_focus(false)
507 .can_request_focus(false),
508 }
509 }
510}
511
512#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
518pub struct FocusRequester {
519 id: FocusRequesterId,
520}
521
522impl FocusRequester {
523 pub fn new() -> Self {
525 Self {
526 id: next_focus_requester_id(),
527 }
528 }
529
530 pub fn request_focus(&self) {
535 with_focus_owner_mut(|owner| owner.request_focus_by_requester(self.id));
536 }
537
538 pub fn clear_focus(&self) {
540 with_focus_owner_mut(|owner| owner.clear_focus_by_requester(self.id));
541 }
542
543 pub fn unfocus(&self) {
545 self.clear_focus();
546 }
547
548 pub fn capture_focus(&self) {
551 with_focus_owner_mut(|owner| owner.capture_focus_by_requester(self.id));
552 }
553
554 pub fn free_focus(&self) {
556 with_focus_owner_mut(|owner| owner.free_focus_by_requester(self.id));
557 }
558
559 pub fn state(&self) -> FocusState {
561 track_focus_requester_read_dependency(self.id);
562 with_focus_owner(|owner| owner.state_of_requester(self.id))
563 }
564
565 pub fn has_focus(&self) -> bool {
567 self.state().has_focus()
568 }
569
570 pub fn is_focused(&self) -> bool {
572 self.state().is_focused()
573 }
574
575 pub fn is_focus_visible(&self) -> bool {
583 track_focus_requester_read_dependency(self.id);
584 with_focus_owner(|owner| owner.is_requester_focus_visible(self.id))
585 }
586
587 pub fn is_captured(&self) -> bool {
589 self.state().is_captured()
590 }
591
592 pub(crate) fn requester_id(self) -> FocusRequesterId {
593 self.id
594 }
595}
596
597impl Default for FocusRequester {
598 fn default() -> Self {
599 Self::new()
600 }
601}
602
603#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
608pub(crate) struct FocusNode {
609 id: FocusHandleId,
610}
611
612impl FocusNode {
613 pub(crate) fn new() -> Self {
614 Self {
615 id: next_focus_handle_id(),
616 }
617 }
618
619 pub(crate) fn handle_id(self) -> FocusHandleId {
620 self.id
621 }
622
623 pub(crate) fn from_handle_id(id: FocusHandleId) -> Self {
624 Self { id }
625 }
626}
627
628impl Default for FocusNode {
629 fn default() -> Self {
630 Self::new()
631 }
632}
633
634#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
639pub struct FocusScopeNode {
640 id: FocusHandleId,
641}
642
643impl FocusScopeNode {
644 pub fn new() -> Self {
646 Self {
647 id: next_focus_handle_id(),
648 }
649 }
650
651 pub(crate) fn handle_id(self) -> FocusHandleId {
652 self.id
653 }
654
655 pub(crate) fn from_handle_id(id: FocusHandleId) -> Self {
656 Self { id }
657 }
658
659 pub fn request_focus(&self) {
662 with_focus_owner_mut(|owner| owner.request_focus(self.id));
663 }
664
665 pub fn clear_focus(&self) {
667 with_focus_owner_mut(|owner| owner.clear_focus(self.id));
668 }
669
670 pub fn restore_focus(&self) {
672 with_focus_owner_mut(|owner| owner.restore_focus(self.id));
673 }
674
675 pub fn move_focus(&self, direction: FocusDirection) -> bool {
677 with_focus_owner_mut(|owner| owner.move_focus_in_scope(self.id, direction, false))
678 }
679
680 pub fn cycle_focus(&self, direction: FocusDirection) -> bool {
682 with_focus_owner_mut(|owner| owner.move_focus_in_scope(self.id, direction, true))
683 }
684
685 pub fn state(&self) -> FocusState {
687 track_focus_read_dependency(self.id);
688 with_focus_owner(|owner| owner.state_of(self.id))
689 }
690
691 pub fn has_focus(&self) -> bool {
693 self.state().has_focus()
694 }
695
696 pub fn is_focused(&self) -> bool {
698 self.state().is_focused()
699 }
700}
701
702impl Default for FocusScopeNode {
703 fn default() -> Self {
704 Self::new()
705 }
706}
707
708#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
713pub struct FocusGroupNode {
714 id: FocusHandleId,
715}
716
717impl FocusGroupNode {
718 pub fn new() -> Self {
720 Self {
721 id: next_focus_handle_id(),
722 }
723 }
724
725 pub(crate) fn handle_id(self) -> FocusHandleId {
726 self.id
727 }
728
729 pub(crate) fn from_handle_id(id: FocusHandleId) -> Self {
730 Self { id }
731 }
732
733 pub fn move_focus(&self, direction: FocusDirection) -> bool {
735 with_focus_owner_mut(|owner| owner.move_focus_in_scope(self.id, direction, false))
736 }
737
738 pub fn cycle_focus(&self, direction: FocusDirection) -> bool {
740 with_focus_owner_mut(|owner| owner.move_focus_in_scope(self.id, direction, true))
741 }
742
743 pub fn state(&self) -> FocusState {
745 track_focus_read_dependency(self.id);
746 with_focus_owner(|owner| owner.state_of(self.id))
747 }
748
749 pub fn has_focus(&self) -> bool {
751 self.state().has_focus()
752 }
753
754 pub fn is_focused(&self) -> bool {
756 self.state().is_focused()
757 }
758}
759
760impl Default for FocusGroupNode {
761 fn default() -> Self {
762 Self::new()
763 }
764}
765
766#[derive(Clone, Copy, Debug, PartialEq, Eq)]
772pub struct FocusRestorationTarget {
773 id: FocusHandleId,
774}
775
776impl FocusRestorationTarget {
777 pub fn restore(self) -> bool {
783 with_focus_owner_mut(|owner| {
784 if !owner.owner_focused
785 || !owner.can_request_focus(self.id)
786 || owner.captured.is_some_and(|captured| captured != self.id)
787 {
788 return false;
789 }
790 owner.request_focus(self.id);
791 true
792 })
793 }
794}
795
796#[derive(Clone, Copy, Debug, Default)]
801pub struct FocusManager;
802
803impl FocusManager {
804 pub fn current() -> Self {
806 Self
807 }
808
809 pub fn save_focus(self) -> Option<FocusRestorationTarget> {
815 with_focus_owner(|owner| owner.active.map(|id| FocusRestorationTarget { id }))
816 }
817
818 pub fn focus_change_direction(self) -> Option<FocusDirection> {
822 FOCUS_CHANGE_DIRECTION.get()
823 }
824
825 pub fn defer_keyboard_until_layout(self) {
830 with_focus_owner_mut(|owner| owner.keyboard_barrier = KeyboardLayoutBarrier::Requested);
831 }
832
833 pub fn clear_focus(self, force: bool) {
835 with_focus_owner_mut(|owner| {
836 owner.clear_focus_global(force);
837 });
838 }
839
840 pub fn move_focus(self, direction: FocusDirection) -> bool {
842 with_focus_owner_mut(|owner| {
843 owner.pending_navigation = None;
844 owner.move_focus(direction)
845 })
846 }
847
848 pub fn request_move_focus(self, direction: FocusDirection) -> bool {
856 let accepted = with_focus_owner_mut(|owner| {
857 if !owner.owner_focused || owner.captured.is_some() {
858 return false;
859 }
860 owner.pending_navigation = Some(direction);
861 owner.keyboard_barrier = KeyboardLayoutBarrier::Requested;
862 true
863 });
864 if accepted {
865 schedule_runtime_redraw();
866 }
867 accepted
868 }
869}
870
871#[derive(Clone, Copy, Debug)]
872struct FocusAttachment {
873 host_replay_boundary_key: u64,
874 live_node_id: Option<NodeId>,
875 focus_rect: Option<PxRect>,
876 traversal_order: Option<u64>,
877 parent: FocusHandleId,
878 scope_parent: FocusHandleId,
879}
880
881impl FocusAttachment {
882 fn permits_focus(self) -> bool {
883 self.traversal_order.is_none() || self.focus_rect.is_some()
886 }
887
888 fn root_scope() -> Self {
889 Self {
890 host_replay_boundary_key: 0,
891 live_node_id: None,
892 focus_rect: None,
893 traversal_order: None,
894 parent: ROOT_SCOPE_ID,
895 scope_parent: ROOT_SCOPE_ID,
896 }
897 }
898}
899
900#[derive(Clone, Copy, Debug)]
901struct FocusTreeNode {
902 kind: FocusRegistrationKind,
903 attachment: Option<FocusAttachment>,
904 last_parent: FocusHandleId,
905 last_scope_parent: FocusHandleId,
906 props: FocusProperties,
907 traversal_policy: Option<FocusTraversalPolicy>,
908 state: FocusState,
909 last_focused_descendant: Option<FocusHandleId>,
910 restorer_fallback: Option<FocusRequesterId>,
911}
912
913impl FocusTreeNode {
914 fn new_root_scope() -> Self {
915 Self {
916 kind: FocusRegistrationKind::Scope,
917 attachment: Some(FocusAttachment::root_scope()),
918 last_parent: ROOT_SCOPE_ID,
919 last_scope_parent: ROOT_SCOPE_ID,
920 props: FocusProperties::default()
921 .can_focus(false)
922 .can_request_focus(false)
923 .skip_traversal(true),
924 traversal_policy: None,
925 state: FocusState::Inactive,
926 last_focused_descendant: None,
927 restorer_fallback: None,
928 }
929 }
930
931 fn new(kind: FocusRegistrationKind) -> Self {
932 Self {
933 kind,
934 attachment: None,
935 last_parent: ROOT_SCOPE_ID,
936 last_scope_parent: ROOT_SCOPE_ID,
937 props: FocusProperties::default(),
938 traversal_policy: None,
939 state: FocusState::Inactive,
940 last_focused_descendant: None,
941 restorer_fallback: None,
942 }
943 }
944
945 fn is_attached(&self) -> bool {
946 self.attachment.is_some()
947 }
948}
949
950#[derive(Clone)]
951pub(crate) struct PendingFocusCallbackInvocation {
952 callback: CallbackWith<FocusState>,
953 state: FocusState,
954 direction: Option<FocusDirection>,
955}
956
957impl PendingFocusCallbackInvocation {
958 pub(crate) fn new(
959 callback: CallbackWith<FocusState>,
960 state: FocusState,
961 direction: Option<FocusDirection>,
962 ) -> Self {
963 Self {
964 callback,
965 state,
966 direction,
967 }
968 }
969
970 pub(crate) fn invoke(self) {
971 let _direction = FocusChangeDirectionGuard(FOCUS_CHANGE_DIRECTION.replace(self.direction));
972 self.callback.call(self.state);
973 }
974}
975
976#[derive(Clone, Copy, Debug)]
977pub(crate) struct FocusNotification {
978 pub handle_id: FocusHandleId,
979 pub state: FocusState,
980 pub changed: bool,
981 pub direction: Option<FocusDirection>,
982}
983
984#[derive(Clone, Copy, Debug)]
985enum FocusCommand {
986 Request(FocusHandleId),
987 Clear(FocusHandleId),
988 Capture(FocusHandleId),
989 Free(FocusHandleId),
990 Restore(FocusHandleId),
991}
992
993#[derive(Clone, Copy)]
994struct DeferredFocusCommand {
995 command: FocusCommand,
996 reveal: bool,
997}
998
999#[derive(Clone, Copy, Default, PartialEq, Eq)]
1000enum KeyboardLayoutBarrier {
1001 #[default]
1002 None,
1003 Requested,
1004 Layout,
1005}
1006
1007type FocusOrderPath = Vec<(u64, usize)>;
1008type FocusChildren = BTreeMap<(FocusOrderPath, FocusHandleId), FocusHandleId>;
1009
1010#[derive(Default)]
1012pub(crate) struct FocusOwner {
1013 nodes: HashMap<FocusHandleId, FocusTreeNode>,
1014 children_by_parent: HashMap<FocusHandleId, FocusChildren>,
1015 requester_bindings: HashMap<FocusRequesterId, FocusHandleId>,
1016 requesters_by_handle: HashMap<FocusHandleId, Vec<FocusRequesterId>>,
1017 active: Option<FocusHandleId>,
1018 stateful_handles: HashSet<FocusHandleId>,
1019 handles_by_component: HashMap<NodeId, FocusHandleId>,
1020 order_paths: HashMap<FocusHandleId, FocusOrderPath>,
1021 captured: Option<FocusHandleId>,
1022 suspended: Option<FocusHandleId>,
1023 owner_focused: bool,
1024 focus_visible: bool,
1025 latest_focus_input: Option<crate::time::Instant>,
1026 pending: Vec<DeferredFocusCommand>,
1027 pending_notifications: Vec<FocusNotification>,
1028 pending_reveal: Option<FocusHandleId>,
1029 pending_navigation: Option<FocusDirection>,
1030 keyboard_barrier: KeyboardLayoutBarrier,
1031}
1032
1033impl FocusOwner {
1034 pub(crate) fn new() -> Self {
1035 let mut nodes = HashMap::default();
1036 nodes.insert(ROOT_SCOPE_ID, FocusTreeNode::new_root_scope());
1037 Self {
1038 nodes,
1039 children_by_parent: HashMap::default(),
1040 requester_bindings: HashMap::default(),
1041 requesters_by_handle: HashMap::default(),
1042 active: None,
1043 stateful_handles: HashSet::default(),
1044 handles_by_component: HashMap::default(),
1045 order_paths: HashMap::default(),
1046 captured: None,
1047 suspended: None,
1048 owner_focused: true,
1049 focus_visible: false,
1050 latest_focus_input: None,
1051 pending: Vec::new(),
1052 pending_notifications: Vec::new(),
1053 pending_reveal: None,
1054 pending_navigation: None,
1055 keyboard_barrier: KeyboardLayoutBarrier::None,
1056 }
1057 }
1058
1059 pub(crate) fn reset(&mut self) {
1060 *self = Self::new();
1061 }
1062
1063 pub(crate) fn begin_layout(&mut self) {
1064 if self.keyboard_barrier == KeyboardLayoutBarrier::Requested {
1065 self.keyboard_barrier = KeyboardLayoutBarrier::Layout;
1066 }
1067 }
1068
1069 pub(crate) fn finish_layout(&mut self) {
1070 if self.keyboard_barrier == KeyboardLayoutBarrier::Layout {
1071 self.keyboard_barrier = KeyboardLayoutBarrier::None;
1072 }
1073 }
1074
1075 pub(crate) fn keyboard_is_deferred(&self) -> bool {
1076 self.keyboard_barrier != KeyboardLayoutBarrier::None
1077 }
1078
1079 pub(crate) fn take_pending_navigation(&mut self) -> Option<FocusDirection> {
1080 self.pending_navigation
1081 .take()
1082 .filter(|_| self.owner_focused && self.captured.is_none())
1083 }
1084
1085 pub(crate) fn retain_navigation_retry(&mut self, direction: Option<FocusDirection>) {
1086 if self.pending_navigation.is_none() {
1087 self.pending_navigation = direction;
1088 }
1089 }
1090
1091 pub(crate) fn has_pending_navigation(&self) -> bool {
1092 self.pending_navigation.is_some()
1093 }
1094
1095 pub(crate) fn allows_navigation(&self) -> bool {
1096 self.owner_focused && self.captured.is_none()
1097 }
1098
1099 pub(crate) fn state_of(&self, id: FocusHandleId) -> FocusState {
1100 self.nodes
1101 .get(&id)
1102 .filter(|node| node.is_attached())
1103 .map(|node| node.state)
1104 .unwrap_or(FocusState::Inactive)
1105 }
1106
1107 pub(crate) fn active_component_node_id(&self) -> Option<NodeId> {
1108 let active = self.active?;
1109 self.nodes
1110 .get(&active)
1111 .and_then(|node| node.attachment)
1112 .and_then(|attachment| attachment.live_node_id)
1113 }
1114
1115 pub(crate) fn component_node_id_of(&self, id: FocusHandleId) -> Option<NodeId> {
1116 self.nodes
1117 .get(&id)
1118 .and_then(|node| node.attachment)
1119 .and_then(|attachment| attachment.live_node_id)
1120 }
1121
1122 pub(crate) fn active_handle_id(&self) -> Option<FocusHandleId> {
1123 self.active
1124 }
1125
1126 pub(crate) fn has_pending_reveal(&self) -> bool {
1127 self.pending_reveal.is_some()
1128 }
1129
1130 pub(crate) fn take_pending_reveal(&mut self) -> Option<FocusHandleId> {
1131 self.pending_reveal.take()
1132 }
1133
1134 pub(crate) fn retain_reveal_retry(&mut self) {
1135 if self.pending_reveal.is_none() {
1136 self.pending_reveal = self.active;
1137 }
1138 }
1139
1140 pub(crate) fn cancel_pending_reveal_for_scroll(&mut self) {
1141 self.pending_reveal = None;
1142 for pending in &mut self.pending {
1143 if matches!(
1144 pending.command,
1145 FocusCommand::Request(_) | FocusCommand::Restore(_)
1146 ) {
1147 pending.reveal = false;
1148 }
1149 }
1150 }
1151
1152 pub(crate) fn record_keyboard_input(
1153 &mut self,
1154 state: winit::event::ElementState,
1155 timestamp: crate::time::Instant,
1156 ) {
1157 if state == winit::event::ElementState::Pressed {
1158 self.record_focus_input(true, timestamp);
1159 }
1160 }
1161
1162 pub(crate) fn record_pointer_press(&mut self, timestamp: crate::time::Instant) {
1163 self.record_focus_input(false, timestamp);
1164 }
1165
1166 pub(crate) fn observe_pointer_press(&mut self, timestamp: crate::time::Instant) {
1167 if self
1168 .latest_focus_input
1169 .is_none_or(|latest| timestamp > latest)
1170 {
1171 self.record_pointer_press(timestamp);
1172 }
1173 }
1174
1175 pub(crate) fn record_accessibility_focus(&mut self, timestamp: crate::time::Instant) {
1176 self.record_focus_input(true, timestamp);
1177 }
1178
1179 fn record_focus_input(&mut self, visible: bool, timestamp: crate::time::Instant) {
1180 if self
1181 .latest_focus_input
1182 .is_some_and(|latest| timestamp < latest)
1183 {
1184 return;
1185 }
1186 self.latest_focus_input = Some(timestamp);
1187 if self.focus_visible == visible {
1188 return;
1189 }
1190 self.focus_visible = visible;
1191 let Some(active) = self.active else {
1192 return;
1193 };
1194 if let Some(node) = self.nodes.get(&active)
1195 && let Some(attachment) = node.attachment
1196 && attachment.host_replay_boundary_key != 0
1197 {
1198 record_replay_boundary_invalidation_for_instance_key(
1199 attachment.host_replay_boundary_key,
1200 );
1201 }
1202 if let Some(requesters) = self.requesters_by_handle.get(&active) {
1203 for requester in requesters {
1204 for reader in focus_requester_read_subscribers(*requester) {
1205 record_replay_boundary_invalidation_for_instance_key(reader);
1206 }
1207 }
1208 }
1209 }
1210
1211 pub(crate) fn is_requester_focus_visible(&self, id: FocusRequesterId) -> bool {
1212 self.owner_focused && self.focus_visible && self.state_of_requester(id).is_focused()
1213 }
1214
1215 pub(crate) fn state_of_requester(&self, id: FocusRequesterId) -> FocusState {
1216 self.requester_bindings
1217 .get(&id)
1218 .copied()
1219 .map(|handle_id| self.state_of(handle_id))
1220 .unwrap_or(FocusState::Inactive)
1221 }
1222
1223 pub(crate) fn request_focus_by_requester(&mut self, id: FocusRequesterId) {
1224 if let Some(handle_id) = self.requester_bindings.get(&id).copied() {
1225 self.request_focus(handle_id);
1226 }
1227 }
1228
1229 pub(crate) fn clear_focus_by_requester(&mut self, id: FocusRequesterId) {
1230 if let Some(handle_id) = self.requester_bindings.get(&id).copied() {
1231 self.clear_focus(handle_id);
1232 }
1233 }
1234
1235 pub(crate) fn capture_focus_by_requester(&mut self, id: FocusRequesterId) {
1236 if let Some(handle_id) = self.requester_bindings.get(&id).copied() {
1237 self.capture_focus(handle_id);
1238 }
1239 }
1240
1241 pub(crate) fn free_focus_by_requester(&mut self, id: FocusRequesterId) {
1242 if let Some(handle_id) = self.requester_bindings.get(&id).copied() {
1243 self.free_focus(handle_id);
1244 }
1245 }
1246
1247 pub(crate) fn request_focus(&mut self, id: FocusHandleId) {
1248 self.execute_or_defer(FocusCommand::Request(id));
1249 }
1250
1251 pub(crate) fn clear_focus(&mut self, id: FocusHandleId) {
1252 self.execute_or_defer(FocusCommand::Clear(id));
1253 }
1254
1255 pub(crate) fn capture_focus(&mut self, id: FocusHandleId) {
1256 self.execute_or_defer(FocusCommand::Capture(id));
1257 }
1258
1259 pub(crate) fn free_focus(&mut self, id: FocusHandleId) {
1260 self.execute_or_defer(FocusCommand::Free(id));
1261 }
1262
1263 pub(crate) fn restore_focus(&mut self, id: FocusHandleId) {
1264 self.execute_or_defer(FocusCommand::Restore(id));
1265 }
1266
1267 pub(crate) fn set_owner_focused(&mut self, focused: bool) {
1268 if self.owner_focused == focused {
1269 return;
1270 }
1271
1272 let previous_states = self.snapshot_live_states();
1273 self.owner_focused = focused;
1274 if !focused {
1275 self.pending_navigation = None;
1276 }
1277 if focused {
1278 if let Some(suspended) = self.suspended.take() {
1279 if let Some(target) = self.resolve_request_target(suspended) {
1280 self.active = Some(target);
1281 self.pending_reveal = Some(target);
1282 } else {
1283 self.suspended = Some(suspended);
1284 }
1285 }
1286 } else {
1287 self.suspended = self.active;
1288 self.active = None;
1289 self.captured = None;
1290 self.pending_reveal = None;
1291 }
1292 self.recompute_states();
1293 self.notify_state_changes(previous_states);
1294 }
1295
1296 pub(crate) fn sync_changes(
1297 &mut self,
1298 tree: &ComponentNodeTree,
1299 changed: &HashSet<NodeId>,
1300 removed: &HashSet<NodeId>,
1301 ) {
1302 if changed.is_empty() && removed.is_empty() {
1303 return;
1304 }
1305 let previous_states = self.snapshot_live_states();
1306 let mut requesters = HashMap::default();
1307 for &node_id in removed.iter().chain(changed.iter()) {
1308 let Some(handle) = self.handles_by_component.remove(&node_id) else {
1309 continue;
1310 };
1311 if let Some(node) = self.nodes.get_mut(&handle) {
1312 if let Some(attachment) = node.attachment.take() {
1313 if let Some(children) = self.children_by_parent.get_mut(&attachment.parent) {
1314 if let Some(order) = self.order_paths.get(&handle) {
1315 children.remove(&(order.clone(), handle));
1316 }
1317 }
1318 }
1319 }
1320 if let Some(bindings) = self.requesters_by_handle.remove(&handle) {
1321 for requester in bindings {
1322 let previous = self.requester_bindings.remove(&requester);
1323 requesters.entry(requester).or_insert(previous);
1324 }
1325 }
1326 }
1327 for &node_id in changed {
1328 let Some(node_ref) = tree.get(node_id).filter(|node| !node.is_removed()) else {
1329 continue;
1330 };
1331 let node = node_ref.get();
1332 let interaction = node.interaction();
1333 let Some(registration) = interaction.focus_registration else {
1334 continue;
1335 };
1336 let mut parent = ROOT_SCOPE_ID;
1337 let mut scope = ROOT_SCOPE_ID;
1338 for ancestor in node_id.ancestors(tree).skip(1) {
1339 if let Some(registration) = tree[ancestor].get().interaction().focus_registration {
1340 if parent == ROOT_SCOPE_ID {
1341 parent = registration.id;
1342 }
1343 if registration.kind == FocusRegistrationKind::Scope {
1344 scope = registration.id;
1345 break;
1346 }
1347 }
1348 }
1349 let entry = self
1350 .nodes
1351 .entry(registration.id)
1352 .or_insert_with(|| FocusTreeNode::new(registration.kind));
1353 entry.kind = registration.kind;
1354 entry.last_parent = parent;
1355 entry.last_scope_parent = scope;
1356 entry.props = registration.properties;
1357 entry.traversal_policy = interaction.focus_traversal_policy;
1358 entry.restorer_fallback = (registration.kind == FocusRegistrationKind::Scope)
1359 .then(|| {
1360 interaction
1361 .focus_restorer_fallback
1362 .map(|fallback| fallback.requester_id())
1363 })
1364 .flatten();
1365 entry.attachment = Some(FocusAttachment {
1366 host_replay_boundary_key: nearest_replay_boundary_instance_key(node_id, tree),
1367 live_node_id: Some(node_id),
1368 focus_rect: None,
1369 traversal_order: None,
1370 parent,
1371 scope_parent: scope,
1372 });
1373 self.handles_by_component.insert(node_id, registration.id);
1374 let order: Vec<_> = node_id
1375 .ancestors(tree)
1376 .filter(|id| tree[*id].parent().is_some())
1377 .map(|id| (u64::MAX, sibling_index(id, tree)))
1378 .collect::<Vec<_>>()
1379 .into_iter()
1380 .rev()
1381 .collect();
1382 self.order_paths.insert(registration.id, order.clone());
1383 self.children_by_parent
1384 .entry(parent)
1385 .or_default()
1386 .insert((order, registration.id), registration.id);
1387 self.children_by_parent.entry(registration.id).or_default();
1388 if let Some(requester) = interaction.focus_requester_binding {
1389 let requester = requester.requester_id();
1390 let previous = self.requester_bindings.insert(requester, registration.id);
1391 requesters.entry(requester).or_insert(previous);
1392 self.requesters_by_handle
1393 .entry(registration.id)
1394 .or_default()
1395 .push(requester);
1396 }
1397 }
1398 self.repair_after_sync();
1399 self.recompute_states();
1400 self.notify_state_changes(previous_states);
1401 for (requester, previous) in requesters {
1402 if self.requester_bindings.get(&requester).copied() == previous {
1403 continue;
1404 }
1405 for reader in focus_requester_read_subscribers(requester) {
1406 record_replay_boundary_invalidation_for_instance_key(reader);
1407 }
1408 }
1409 }
1410
1411 pub(crate) fn sync_geometry_changes(
1412 &mut self,
1413 tree: &ComponentNodeTree,
1414 metadatas: &ComponentNodeMetaDatas,
1415 geometry_changed: &HashSet<NodeId>,
1416 structure_changed: &HashSet<NodeId>,
1417 ) {
1418 if (geometry_changed.is_empty() && structure_changed.is_empty())
1419 || (self.handles_by_component.is_empty() && self.active.is_none())
1420 {
1421 return;
1422 }
1423 for node_id in geometry_changed.union(structure_changed) {
1424 let Some(&handle) = self.handles_by_component.get(node_id) else {
1425 continue;
1426 };
1427 let rect = metadatas.get(node_id).and_then(|metadata| {
1428 let position = metadata.abs_position?;
1429 let size = metadata.computed_data?;
1430 let transform = metadata
1431 .local_to_window
1432 .unwrap_or_else(|| crate::LocalToWindow::new(1.0, position).unwrap());
1433 let rect = transform
1434 .map_rect(crate::FloatRect::from_position_size(
1435 PxPosition::ZERO,
1436 PxSize::new(size.width, size.height),
1437 ))
1438 .outward();
1439 Some(metadata.event_clip_rect().map_or(rect, |clip| {
1440 clip.intersection(&rect).unwrap_or(PxRect::ZERO)
1441 }))
1442 });
1443 if let Some(attachment) = self
1444 .nodes
1445 .get_mut(&handle)
1446 .and_then(|node| node.attachment.as_mut())
1447 {
1448 attachment.focus_rect = rect;
1449 if attachment.traversal_order.is_some()
1450 && !metadatas.placement_order_changed.contains(node_id)
1451 {
1452 continue;
1453 }
1454 }
1455 let mut order = node_id
1456 .ancestors(tree)
1457 .filter_map(|id| {
1458 let node = tree.get(id)?;
1459 node.parent()?;
1460 if node.get().role != NodeRole::Layout
1461 && node.get().interaction().focus_registration.is_none()
1462 {
1463 return None;
1464 }
1465 Some((
1466 metadatas
1467 .get(&id)
1468 .and_then(|metadata| metadata.placement_order)
1469 .unwrap_or(u64::MAX),
1470 sibling_index(id, tree),
1471 ))
1472 })
1473 .collect::<Vec<_>>();
1474 order.reverse();
1475 let order_changed = self.order_paths.get(&handle) != Some(&order);
1476 if let Some(attachment) = self
1477 .nodes
1478 .get_mut(&handle)
1479 .and_then(|node| node.attachment.as_mut())
1480 {
1481 attachment.focus_rect = rect;
1482 attachment.traversal_order = Some(0);
1483 if !order_changed {
1484 continue;
1485 }
1486 let previous_order = self.order_paths.insert(handle, order.clone());
1487 let children = self
1488 .children_by_parent
1489 .entry(attachment.parent)
1490 .or_default();
1491 if let Some(previous) = previous_order {
1492 children.remove(&(previous, handle));
1493 }
1494 children.insert((order, handle), handle);
1495 }
1496 }
1497 if self.active.is_some_and(|id| {
1498 self.nodes.get(&id).is_some_and(|node| node.is_attached())
1499 && !self.can_request_focus(id)
1500 }) {
1501 let previous_states = self.snapshot_live_states();
1502 self.active = self
1503 .active
1504 .and_then(|id| self.restore_single_tab_stop_group(id));
1505 self.captured = None;
1506 self.pending_reveal = self.active;
1507 if let Some(active) = self.active {
1508 self.update_scope_restore_chain(active);
1509 }
1510 self.recompute_states();
1511 self.notify_state_changes(previous_states);
1512 }
1513 }
1514
1515 #[cfg(test)]
1516 pub(crate) fn sync_from_component_tree(&mut self, root_node: NodeId, tree: &ComponentNodeTree) {
1517 let changed = root_node.descendants(tree).collect::<HashSet<_>>();
1518 let removed = self
1519 .handles_by_component
1520 .keys()
1521 .copied()
1522 .filter(|node| !changed.contains(node))
1523 .collect();
1524 self.sync_changes(tree, &changed, &removed);
1525 }
1526
1527 #[cfg(test)]
1528 pub(crate) fn sync_layout_from_component_tree(
1529 &mut self,
1530 tree: &ComponentNodeTree,
1531 metadatas: &ComponentNodeMetaDatas,
1532 ) {
1533 let changed = self.handles_by_component.keys().copied().collect();
1534 self.sync_geometry_changes(tree, metadatas, &changed, &HashSet::default());
1535 }
1536
1537 pub(crate) fn commit_pending(&mut self) {
1538 if self.pending.is_empty() {
1539 return;
1540 }
1541
1542 let previous_states = self.snapshot_live_states();
1543 let commands = std::mem::take(&mut self.pending);
1544 for pending in commands {
1545 let reveal = self.pending_reveal;
1546 let applied = self.apply_command_inner(pending.command);
1547 if !pending.reveal {
1548 self.pending_reveal = reveal;
1549 }
1550 if !applied && self.should_defer_command(pending.command) {
1551 self.pending.push(pending);
1552 }
1553 }
1554 self.recompute_states();
1555 self.notify_state_changes(previous_states);
1556 }
1557
1558 pub(crate) fn take_pending_notifications(&mut self) -> Vec<FocusNotification> {
1559 std::mem::take(&mut self.pending_notifications)
1560 }
1561
1562 pub(crate) fn clear_focus_global(&mut self, force: bool) -> bool {
1563 if force || self.captured.is_none() {
1564 self.pending_navigation = None;
1565 }
1566 let previous_states = self.snapshot_live_states();
1567 let cleared = if self.active.is_some() && (force || self.captured.is_none()) {
1568 self.active = None;
1569 self.captured = None;
1570 self.pending_reveal = None;
1571 true
1572 } else {
1573 false
1574 };
1575 self.recompute_states();
1576 self.notify_state_changes(previous_states);
1577 cleared
1578 }
1579
1580 pub(crate) fn move_focus(&mut self, direction: FocusDirection) -> bool {
1581 if !self.owner_focused {
1582 return false;
1583 }
1584 let previous_states = self.snapshot_live_states();
1585 let target = match self.resolve_policy_move_target(direction) {
1586 Some(target) => target,
1587 None => self.resolve_move_target(direction),
1588 };
1589 let moved = target.is_some_and(|target| self.set_active(target));
1590 self.recompute_states();
1591 self.notify_state_changes_from(previous_states, Some(direction));
1592 moved
1593 }
1594
1595 pub(crate) fn move_focus_in_scope(
1596 &mut self,
1597 scope_id: FocusHandleId,
1598 direction: FocusDirection,
1599 wrap: bool,
1600 ) -> bool {
1601 if !self.owner_focused {
1602 return false;
1603 }
1604 let previous_states = self.snapshot_live_states();
1605 let moved = self
1606 .resolve_move_target_in_scope(scope_id, direction, wrap)
1607 .is_some_and(|target| self.set_active(target));
1608 self.recompute_states();
1609 self.notify_state_changes_from(previous_states, Some(direction));
1610 moved
1611 }
1612
1613 fn resolve_policy_move_target(
1614 &self,
1615 direction: FocusDirection,
1616 ) -> Option<Option<FocusHandleId>> {
1617 let active = self
1618 .active
1619 .filter(|current| self.can_request_focus(*current))?;
1620 let (owner_id, policy) = self.nearest_traversal_policy_owner(active)?;
1621 let scoped_direction = policy.scoped_direction(direction)?;
1622 let target = self.resolve_move_target_in_scope(owner_id, scoped_direction, policy.wrap);
1623 (target.is_some() || policy.wrap).then_some(target)
1626 }
1627
1628 fn nearest_traversal_policy_owner(
1629 &self,
1630 start: FocusHandleId,
1631 ) -> Option<(FocusHandleId, FocusTraversalPolicy)> {
1632 let mut current = Some(start);
1633 while let Some(id) = current {
1634 let node = self.nodes.get(&id)?;
1635 if matches!(
1636 node.kind,
1637 FocusRegistrationKind::Scope | FocusRegistrationKind::Group
1638 ) && let Some(policy) = node.traversal_policy
1639 {
1640 return Some((id, policy));
1641 }
1642 current = (id != ROOT_SCOPE_ID).then_some(node.last_parent);
1643 }
1644 None
1645 }
1646
1647 fn repair_after_sync(&mut self) {
1648 if self
1649 .active
1650 .is_some_and(|id| !self.nodes.get(&id).is_some_and(|node| node.is_attached()))
1651 {
1652 let previous_active = self.active;
1653 if previous_active
1654 .and_then(|id| self.restore_single_tab_stop_group(id))
1655 .is_some()
1656 || !previous_active.is_some_and(|id| self.should_wait_for_reattach(id))
1657 {
1658 let previous_active = self.active.take();
1659 self.active = previous_active.and_then(|id| self.restore_from_detached(id));
1660 self.captured = None;
1661 if let Some(active) = self.active {
1662 self.update_scope_restore_chain(active);
1663 self.pending_reveal = Some(active);
1664 }
1665 }
1666 }
1667
1668 if self
1669 .captured
1670 .is_some_and(|id| !self.nodes.get(&id).is_some_and(|node| node.is_attached()))
1671 {
1672 self.captured = None;
1673 }
1674
1675 if self.owner_focused
1676 && self.active.is_none()
1677 && let Some(suspended) = self.suspended
1678 && let Some(target) = self.resolve_request_target(suspended)
1679 {
1680 self.active = Some(target);
1681 self.suspended = None;
1682 self.pending_reveal = Some(target);
1683 }
1684
1685 if self.active.is_some_and(|id| {
1686 self.nodes.get(&id).is_some_and(|node| {
1687 node.is_attached() && (!self.can_focus(id) || !self.can_request_focus(id))
1688 })
1689 }) {
1690 self.active = self
1691 .active
1692 .and_then(|id| self.restore_single_tab_stop_group(id));
1693 self.captured = None;
1694 self.pending_reveal = self.active;
1695 if let Some(active) = self.active {
1696 self.update_scope_restore_chain(active);
1697 }
1698 }
1699 }
1700
1701 fn should_wait_for_reattach(&self, id: FocusHandleId) -> bool {
1702 let Some(node) = self.nodes.get(&id) else {
1703 return false;
1704 };
1705 if node.is_attached() {
1706 return false;
1707 }
1708 if has_persistent_focus_handle(id) {
1709 return true;
1710 }
1711 let waiting_scope_id = node.last_scope_parent;
1712 waiting_scope_id != ROOT_SCOPE_ID
1713 && self
1714 .nodes
1715 .get(&waiting_scope_id)
1716 .is_some_and(|scope| !scope.is_attached())
1717 }
1718
1719 pub(crate) fn remove_handles(
1720 &mut self,
1721 removed_handles: &HashSet<FocusHandleId>,
1722 removed_requesters: &HashSet<FocusRequesterId>,
1723 ) {
1724 if removed_handles.is_empty() && removed_requesters.is_empty() {
1725 return;
1726 }
1727
1728 let previous_states = self.snapshot_live_states();
1729 let mut previous_requester_bindings = HashMap::default();
1730 for requester_id in removed_requesters {
1731 if let Some(handle) = self.requester_bindings.remove(requester_id) {
1732 previous_requester_bindings.insert(*requester_id, handle);
1733 if let Some(requesters) = self.requesters_by_handle.get_mut(&handle) {
1734 requesters.retain(|id| id != requester_id);
1735 }
1736 }
1737 }
1738 for handle_id in removed_handles {
1741 if let Some(node) = self.nodes.get_mut(handle_id) {
1742 node.attachment = None;
1743 }
1744 }
1745
1746 let active_was_removed = self.active.filter(|id| removed_handles.contains(id));
1747 if active_was_removed.is_some() {
1748 self.active = active_was_removed.and_then(|id| self.restore_from_detached(id));
1749 self.captured = None;
1750 if let Some(active) = self.active {
1751 self.update_scope_restore_chain(active);
1752 self.pending_reveal = Some(active);
1753 } else {
1754 self.pending_reveal = None;
1755 }
1756 }
1757
1758 if self
1759 .captured
1760 .is_some_and(|id| removed_handles.contains(&id))
1761 {
1762 self.captured = None;
1763 }
1764 if self
1765 .suspended
1766 .is_some_and(|id| removed_handles.contains(&id))
1767 {
1768 self.suspended = None;
1769 }
1770
1771 for handle_id in removed_handles {
1772 if let Some(node) = self.nodes.remove(handle_id) {
1773 if let Some(children) = self.children_by_parent.get_mut(&node.last_parent) {
1774 if let Some(order) = self.order_paths.get(handle_id) {
1775 children.remove(&(order.clone(), *handle_id));
1776 }
1777 }
1778 }
1779 self.children_by_parent.remove(handle_id);
1780 self.stateful_handles.remove(handle_id);
1781 self.order_paths.remove(handle_id);
1782 if let Some(requesters) = self.requesters_by_handle.remove(handle_id) {
1783 for requester in requesters {
1784 if let Some(handle) = self.requester_bindings.remove(&requester) {
1785 previous_requester_bindings.insert(requester, handle);
1786 }
1787 }
1788 }
1789 }
1790
1791 self.recompute_states();
1792 self.notify_state_changes(previous_states);
1793 self.notify_requester_binding_changes(previous_requester_bindings);
1794 }
1795
1796 fn execute_or_defer(&mut self, command: FocusCommand) {
1797 self.pending_navigation = None;
1798 if matches!(command, FocusCommand::Request(_) | FocusCommand::Restore(_)) {
1799 self.discard_pending_focus_requests();
1800 }
1801 if !self.apply_command(command) && self.should_defer_command(command) {
1802 self.pending.push(DeferredFocusCommand {
1803 command,
1804 reveal: true,
1805 });
1806 }
1807 }
1808
1809 fn discard_pending_focus_requests(&mut self) {
1810 self.pending.retain(|pending| {
1811 !matches!(
1812 pending.command,
1813 FocusCommand::Request(_) | FocusCommand::Restore(_)
1814 )
1815 });
1816 }
1817
1818 fn should_defer_command(&self, command: FocusCommand) -> bool {
1819 let id = match command {
1820 FocusCommand::Request(id)
1821 | FocusCommand::Clear(id)
1822 | FocusCommand::Capture(id)
1823 | FocusCommand::Free(id)
1824 | FocusCommand::Restore(id) => id,
1825 };
1826 !self.nodes.get(&id).is_some_and(|node| node.is_attached())
1830 }
1831
1832 fn apply_command(&mut self, command: FocusCommand) -> bool {
1833 let previous_states = self.snapshot_live_states();
1834 let applied = self.apply_command_inner(command);
1835 self.recompute_states();
1836 self.notify_state_changes(previous_states);
1837 applied
1838 }
1839
1840 fn apply_command_inner(&mut self, command: FocusCommand) -> bool {
1841 match command {
1842 FocusCommand::Request(id) => {
1843 if !self.owner_focused {
1844 self.suspended = Some(id);
1845 return true;
1846 }
1847 let Some(target) = self.resolve_request_target(id) else {
1848 return false;
1849 };
1850 self.set_active(target)
1851 }
1852 FocusCommand::Clear(id) => self.clear_active_for(id),
1853 FocusCommand::Capture(id) => {
1854 if self.active == Some(id)
1855 && self.nodes.get(&id).is_some_and(|node| node.is_attached())
1856 {
1857 self.captured = Some(id);
1858 true
1859 } else {
1860 false
1861 }
1862 }
1863 FocusCommand::Free(id) => {
1864 if self.captured == Some(id) {
1865 self.captured = None;
1866 true
1867 } else {
1868 false
1869 }
1870 }
1871 FocusCommand::Restore(id) => {
1872 let Some(target) = self.resolve_restore_candidate(id) else {
1873 return false;
1874 };
1875 self.set_active(target)
1876 }
1877 }
1878 }
1879
1880 fn set_active(&mut self, target: FocusHandleId) -> bool {
1881 if self.captured.is_some() && self.captured != Some(target) {
1882 return false;
1883 }
1884 self.discard_pending_focus_requests();
1885 let changed = self.active != Some(target) || self.captured.is_some_and(|id| id != target);
1886 self.active = Some(target);
1887 if self.captured.is_some_and(|id| id != target) {
1888 self.captured = None;
1889 }
1890 self.update_scope_restore_chain(target);
1891 if changed {
1892 self.pending_reveal = Some(target);
1893 }
1894 changed
1895 }
1896
1897 fn clear_active_for(&mut self, id: FocusHandleId) -> bool {
1898 let Some(active) = self.active else {
1899 return false;
1900 };
1901 let affects_active = active == id || self.is_ancestor(id, active);
1902 if !affects_active {
1903 return false;
1904 }
1905 if self.captured.is_some() {
1906 return false;
1907 }
1908
1909 self.active = None;
1910 self.captured = None;
1911 self.pending_reveal = None;
1912 true
1913 }
1914
1915 fn resolve_move_target(&self, direction: FocusDirection) -> Option<FocusHandleId> {
1916 if let Some(active) = self.active
1917 && let Some(explicit) = self.resolve_explicit_direction_target(active, direction)
1918 {
1919 return Some(explicit);
1920 }
1921
1922 if matches!(
1923 direction,
1924 FocusDirection::Left
1925 | FocusDirection::Right
1926 | FocusDirection::Up
1927 | FocusDirection::Down
1928 ) && let Some(target) = self.resolve_geometric_move_target(direction)
1929 {
1930 return Some(target);
1931 }
1932
1933 let candidates = if matches!(direction, FocusDirection::Next | FocusDirection::Previous) {
1934 let mut candidates = Vec::new();
1935 self.collect_tab_focus_handles(ROOT_SCOPE_ID, &mut candidates);
1936 candidates
1937 } else {
1938 self.traversable_focus_handles()
1939 };
1940 if candidates.is_empty() {
1941 return None;
1942 }
1943
1944 let forward = matches!(
1945 direction,
1946 FocusDirection::Next
1947 | FocusDirection::Down
1948 | FocusDirection::Right
1949 | FocusDirection::Enter
1950 );
1951
1952 let Some(active) = self
1953 .active
1954 .filter(|current| self.can_request_focus(*current))
1955 else {
1956 return if forward {
1957 candidates.first().copied()
1958 } else {
1959 candidates.last().copied()
1960 };
1961 };
1962
1963 let Some(index) = candidates.iter().position(|candidate| *candidate == active) else {
1964 return if forward {
1965 candidates.first().copied()
1966 } else {
1967 candidates.last().copied()
1968 };
1969 };
1970
1971 if forward {
1972 candidates.get(index + 1).copied()
1973 } else if index > 0 {
1974 candidates.get(index - 1).copied()
1975 } else {
1976 None
1977 }
1978 }
1979
1980 fn resolve_move_target_in_scope(
1981 &self,
1982 scope_id: FocusHandleId,
1983 direction: FocusDirection,
1984 wrap: bool,
1985 ) -> Option<FocusHandleId> {
1986 let candidates = self.traversable_focus_handles_in_scope(scope_id);
1987 if candidates.is_empty() {
1988 return None;
1989 }
1990
1991 let active = self
1992 .active
1993 .filter(|current| self.can_request_focus(*current))
1994 .filter(|current| self.is_ancestor(scope_id, *current));
1995
1996 if let Some(active) = active
1997 && let Some(explicit) = self.resolve_explicit_direction_target(active, direction)
1998 && self.is_ancestor(scope_id, explicit)
1999 {
2000 return Some(explicit);
2001 }
2002
2003 if matches!(
2004 direction,
2005 FocusDirection::Left
2006 | FocusDirection::Right
2007 | FocusDirection::Up
2008 | FocusDirection::Down
2009 ) && let Some(target) =
2010 self.resolve_geometric_move_target_in_candidates(direction, &candidates, active)
2011 {
2012 return Some(target);
2013 }
2014
2015 let forward = matches!(
2016 direction,
2017 FocusDirection::Next
2018 | FocusDirection::Down
2019 | FocusDirection::Right
2020 | FocusDirection::Enter
2021 );
2022
2023 let Some(active) = active else {
2024 return if forward {
2025 candidates.first().copied()
2026 } else {
2027 candidates.last().copied()
2028 };
2029 };
2030
2031 let Some(index) = candidates.iter().position(|candidate| *candidate == active) else {
2032 return if forward {
2033 candidates.first().copied()
2034 } else {
2035 candidates.last().copied()
2036 };
2037 };
2038
2039 if forward {
2040 candidates.get(index + 1).copied().or_else(|| {
2041 wrap.then_some(candidates.first().copied())
2042 .flatten()
2043 .filter(|candidate| self.is_traversable_focus_handle(*candidate))
2044 })
2045 } else if index > 0 {
2046 candidates.get(index - 1).copied()
2047 } else if wrap {
2048 candidates
2049 .last()
2050 .copied()
2051 .filter(|candidate| self.is_traversable_focus_handle(*candidate))
2052 } else {
2053 None
2054 }
2055 }
2056
2057 fn resolve_geometric_move_target(&self, direction: FocusDirection) -> Option<FocusHandleId> {
2058 let active = self.active.and_then(|id| self.resolve_request_target(id))?;
2059 let focused_rect = self.nodes.get(&active)?.attachment?.focus_rect?;
2060 let mut best_candidate = initial_best_candidate_rect(focused_rect, direction);
2061 let mut best_handle = None;
2062
2063 for handle_id in self.traversable_focus_handles() {
2064 if handle_id == active {
2065 continue;
2066 }
2067 let Some(candidate_rect) = self
2068 .nodes
2069 .get(&handle_id)
2070 .and_then(|node| node.attachment)
2071 .and_then(|attachment| attachment.focus_rect)
2072 else {
2073 continue;
2074 };
2075 if !is_eligible_focus_rect(candidate_rect) {
2076 continue;
2077 }
2078 if is_better_focus_candidate(candidate_rect, best_candidate, focused_rect, direction) {
2079 best_candidate = candidate_rect;
2080 best_handle = Some(handle_id);
2081 }
2082 }
2083
2084 best_handle
2085 }
2086
2087 fn resolve_geometric_move_target_in_candidates(
2088 &self,
2089 direction: FocusDirection,
2090 candidates: &[FocusHandleId],
2091 active: Option<FocusHandleId>,
2092 ) -> Option<FocusHandleId> {
2093 let active = active?;
2094 let focused_rect = self.nodes.get(&active)?.attachment?.focus_rect?;
2095 let mut best_candidate = initial_best_candidate_rect(focused_rect, direction);
2096 let mut best_handle = None;
2097
2098 for &handle_id in candidates {
2099 if handle_id == active {
2100 continue;
2101 }
2102 let Some(candidate_rect) = self
2103 .nodes
2104 .get(&handle_id)
2105 .and_then(|node| node.attachment)
2106 .and_then(|attachment| attachment.focus_rect)
2107 else {
2108 continue;
2109 };
2110 if !is_eligible_focus_rect(candidate_rect) {
2111 continue;
2112 }
2113 if is_better_focus_candidate(candidate_rect, best_candidate, focused_rect, direction) {
2114 best_candidate = candidate_rect;
2115 best_handle = Some(handle_id);
2116 }
2117 }
2118
2119 best_handle
2120 }
2121
2122 fn resolve_request_target(&self, id: FocusHandleId) -> Option<FocusHandleId> {
2123 let node = self.nodes.get(&id)?;
2124 if !node.is_attached() {
2125 return None;
2126 }
2127 match node.kind {
2128 FocusRegistrationKind::Target => self.can_request_focus(id).then_some(id),
2129 FocusRegistrationKind::Scope => self
2130 .resolve_restore_candidate(id)
2131 .or_else(|| self.first_focusable_descendant(id))
2132 .or_else(|| self.can_request_focus(id).then_some(id)),
2133 FocusRegistrationKind::Group => self
2134 .first_focusable_descendant(id)
2135 .or_else(|| self.can_request_focus(id).then_some(id)),
2136 }
2137 }
2138
2139 fn resolve_requester_target(&self, requester_id: FocusRequesterId) -> Option<FocusHandleId> {
2140 self.requester_bindings.get(&requester_id).copied()
2141 }
2142
2143 fn resolve_explicit_direction_target(
2144 &self,
2145 id: FocusHandleId,
2146 direction: FocusDirection,
2147 ) -> Option<FocusHandleId> {
2148 let requester = self.nodes.get(&id).and_then(|node| match direction {
2149 FocusDirection::Next => node.props.next,
2150 FocusDirection::Previous => node.props.previous,
2151 FocusDirection::Up => node.props.up,
2152 FocusDirection::Down => node.props.down,
2153 FocusDirection::Left => node.props.left,
2154 FocusDirection::Right => node.props.right,
2155 FocusDirection::Enter => node.props.enter,
2156 FocusDirection::Exit => node.props.exit,
2157 })?;
2158 let handle_id = self.resolve_requester_target(requester.requester_id())?;
2159 self.resolve_request_target(handle_id)
2160 }
2161
2162 fn resolve_restore_candidate(&self, id: FocusHandleId) -> Option<FocusHandleId> {
2163 let scope = self.nodes.get(&id)?;
2164 if !scope.is_attached() || scope.kind != FocusRegistrationKind::Scope {
2165 return None;
2166 }
2167 scope
2168 .last_focused_descendant
2169 .filter(|candidate| *candidate != id && self.can_request_focus(*candidate))
2170 .or_else(|| {
2171 scope
2172 .restorer_fallback
2173 .and_then(|requester_id| self.resolve_requester_target(requester_id))
2174 .and_then(|candidate| self.resolve_request_target(candidate))
2175 })
2176 .or_else(|| self.first_focusable_descendant(id))
2177 }
2178
2179 fn traversable_focus_handles(&self) -> Vec<FocusHandleId> {
2180 let mut ordered = Vec::new();
2181 self.collect_traversable_focus_handles(ROOT_SCOPE_ID, &mut ordered);
2182 ordered
2183 }
2184
2185 fn collect_tab_focus_handles(&self, parent: FocusHandleId, ordered: &mut Vec<FocusHandleId>) {
2186 let Some(children) = self.children_by_parent.get(&parent) else {
2187 return;
2188 };
2189 for &child in children.values() {
2190 if self.is_single_tab_stop_group(child) {
2191 let target = self
2192 .active
2193 .filter(|active| {
2194 self.is_ancestor(child, *active) && self.can_request_focus(*active)
2195 })
2196 .or_else(|| self.tab_entry_target(child));
2197 if let Some(target) = target {
2198 ordered.push(target);
2199 }
2200 continue;
2201 }
2202 if self.is_traversable_focus_handle(child)
2203 || (self.active == Some(child) && self.can_request_focus(child))
2204 {
2205 ordered.push(child);
2206 }
2207 self.collect_tab_focus_handles(child, ordered);
2208 }
2209 }
2210
2211 fn is_single_tab_stop_group(&self, id: FocusHandleId) -> bool {
2212 self.nodes.get(&id).is_some_and(|node| {
2213 node.is_attached()
2214 && matches!(
2215 node.kind,
2216 FocusRegistrationKind::Group | FocusRegistrationKind::Scope
2217 )
2218 && node
2219 .traversal_policy
2220 .is_some_and(|policy| policy.single_tab_stop)
2221 })
2222 }
2223
2224 fn tab_entry_target(&self, group: FocusHandleId) -> Option<FocusHandleId> {
2225 let mut candidates = Vec::new();
2226 self.collect_tab_focus_handles(group, &mut candidates);
2227 candidates
2228 .iter()
2229 .copied()
2230 .find(|id| {
2231 self.is_traversable_focus_handle(*id)
2232 && self
2233 .nodes
2234 .get(id)
2235 .is_some_and(|node| node.props.preferred_tab_stop)
2236 })
2237 .or_else(|| {
2238 candidates
2239 .into_iter()
2240 .find(|id| self.is_traversable_focus_handle(*id))
2241 })
2242 }
2243
2244 fn restore_single_tab_stop_group(&self, id: FocusHandleId) -> Option<FocusHandleId> {
2245 let mut current = self.nodes.get(&id).map(|node| node.last_parent);
2246 while let Some(parent) = current {
2247 if self.is_single_tab_stop_group(parent) {
2248 return self.tab_entry_target(parent);
2249 }
2250 current = self
2251 .nodes
2252 .get(&parent)
2253 .and_then(|node| (parent != ROOT_SCOPE_ID).then_some(node.last_parent));
2254 }
2255 None
2256 }
2257
2258 fn traversable_focus_handles_in_scope(&self, scope_id: FocusHandleId) -> Vec<FocusHandleId> {
2259 let mut ordered = Vec::new();
2260 self.collect_traversable_focus_handles(scope_id, &mut ordered);
2261 ordered
2262 }
2263
2264 fn collect_traversable_focus_handles(
2265 &self,
2266 parent: FocusHandleId,
2267 ordered: &mut Vec<FocusHandleId>,
2268 ) {
2269 let Some(children) = self.children_by_parent.get(&parent) else {
2270 return;
2271 };
2272 for &child in children.values() {
2273 if self.is_traversable_focus_handle(child)
2276 || (self.active == Some(child) && self.can_request_focus(child))
2277 {
2278 ordered.push(child);
2279 }
2280 self.collect_traversable_focus_handles(child, ordered);
2281 }
2282 }
2283
2284 fn is_traversable_focus_handle(&self, id: FocusHandleId) -> bool {
2285 self.can_request_focus(id)
2286 && self
2287 .nodes
2288 .get(&id)
2289 .is_some_and(|node| !node.props.skip_traversal)
2290 }
2291
2292 fn first_focusable_descendant(&self, parent: FocusHandleId) -> Option<FocusHandleId> {
2293 let mut stack: Vec<_> = self
2294 .children_by_parent
2295 .get(&parent)
2296 .into_iter()
2297 .flat_map(|children| children.values().rev())
2298 .copied()
2299 .collect();
2300 while let Some(id) = stack.pop() {
2301 if self.can_request_focus(id) {
2302 return Some(id);
2303 }
2304 if let Some(children) = self.children_by_parent.get(&id) {
2305 stack.extend(children.values().rev().copied());
2306 }
2307 }
2308 None
2309 }
2310
2311 fn restore_from_detached(&self, id: FocusHandleId) -> Option<FocusHandleId> {
2312 if let Some(target) = self.restore_single_tab_stop_group(id) {
2313 return Some(target);
2314 }
2315 let mut current_scope = self.nodes.get(&id).map(|node| node.last_scope_parent)?;
2316 loop {
2317 if current_scope == ROOT_SCOPE_ID {
2318 break;
2319 }
2320 if let Some(candidate) = self.resolve_restore_candidate(current_scope) {
2321 return Some(candidate);
2322 }
2323 current_scope = self
2324 .nodes
2325 .get(¤t_scope)
2326 .map(|node| node.last_scope_parent)
2327 .unwrap_or(ROOT_SCOPE_ID);
2328 }
2329 None
2330 }
2331
2332 fn update_scope_restore_chain(&mut self, target: FocusHandleId) {
2333 let mut current = Some(target);
2334 while let Some(id) = current {
2335 if let Some(node) = self.nodes.get_mut(&id)
2336 && node.kind == FocusRegistrationKind::Scope
2337 {
2338 node.last_focused_descendant = Some(target);
2339 }
2340 if id == ROOT_SCOPE_ID {
2341 break;
2342 }
2343 current = self
2344 .nodes
2345 .get(&id)
2346 .and_then(|node| node.attachment)
2347 .map(|attachment| attachment.scope_parent);
2348 if current == Some(id) {
2349 break;
2350 }
2351 }
2352 if let Some(root) = self.nodes.get_mut(&ROOT_SCOPE_ID) {
2353 root.last_focused_descendant = Some(target);
2354 }
2355 }
2356
2357 fn snapshot_live_states(&self) -> HashMap<FocusHandleId, FocusState> {
2358 self.stateful_handles
2359 .iter()
2360 .filter_map(|&id| {
2361 self.nodes
2362 .get(&id)
2363 .filter(|node| node.is_attached())
2364 .map(|node| (id, node.state))
2365 })
2366 .collect()
2367 }
2368
2369 fn notify_requester_binding_changes(
2370 &self,
2371 previous_bindings: HashMap<FocusRequesterId, FocusHandleId>,
2372 ) {
2373 let mut changed = HashSet::default();
2374 for (&requester_id, &previous_handle_id) in &previous_bindings {
2375 let current = self.requester_bindings.get(&requester_id).copied();
2376 if current != Some(previous_handle_id) {
2377 changed.insert(requester_id);
2378 }
2379 }
2380 for requester_id in changed {
2381 for reader in focus_requester_read_subscribers(requester_id) {
2382 record_replay_boundary_invalidation_for_instance_key(reader);
2383 }
2384 }
2385 }
2386
2387 fn notify_state_changes(&mut self, previous_states: HashMap<FocusHandleId, FocusState>) {
2388 self.notify_state_changes_from(previous_states, None);
2389 }
2390
2391 fn notify_state_changes_from(
2392 &mut self,
2393 previous_states: HashMap<FocusHandleId, FocusState>,
2394 direction: Option<FocusDirection>,
2395 ) {
2396 let mut changed = HashSet::default();
2397 let mut events = HashSet::default();
2398 let mut changed_requesters = HashSet::default();
2399
2400 for (&id, &previous) in &previous_states {
2401 let current = self
2402 .nodes
2403 .get(&id)
2404 .filter(|node| node.is_attached())
2405 .map(|node| node.state)
2406 .unwrap_or(FocusState::Inactive);
2407 if previous != current {
2408 changed.insert(id);
2409 }
2410 if previous.has_focus() {
2411 events.insert(id);
2412 }
2413 }
2414
2415 for &id in &self.stateful_handles {
2416 let Some(node) = self.nodes.get(&id) else {
2417 continue;
2418 };
2419 if !node.is_attached() {
2420 continue;
2421 }
2422 let previous = previous_states
2423 .get(&id)
2424 .copied()
2425 .unwrap_or(FocusState::Inactive);
2426 if previous != node.state {
2427 changed.insert(id);
2428 }
2429 if node.state.has_focus() {
2430 events.insert(id);
2431 }
2432 }
2433
2434 for &id in &changed {
2435 let state = self
2436 .nodes
2437 .get(&id)
2438 .filter(|node| node.is_attached())
2439 .map(|node| node.state)
2440 .unwrap_or(FocusState::Inactive);
2441 self.pending_notifications.push(FocusNotification {
2442 handle_id: id,
2443 state,
2444 changed: true,
2445 direction,
2446 });
2447 for reader in focus_read_subscribers(id) {
2448 record_replay_boundary_invalidation_for_instance_key(reader);
2449 }
2450 if let Some(node) = self.nodes.get(&id)
2451 && let Some(attachment) = node.attachment
2452 && attachment.host_replay_boundary_key != 0
2453 {
2454 record_replay_boundary_invalidation_for_instance_key(
2455 attachment.host_replay_boundary_key,
2456 );
2457 }
2458 if let Some(requesters) = self.requesters_by_handle.get(&id) {
2459 changed_requesters.extend(requesters.iter().copied());
2460 }
2461 }
2462
2463 for id in events {
2464 if changed.contains(&id) {
2465 continue;
2466 }
2467 let state = self
2468 .nodes
2469 .get(&id)
2470 .filter(|node| node.is_attached())
2471 .map(|node| node.state)
2472 .unwrap_or(FocusState::Inactive);
2473 self.pending_notifications.push(FocusNotification {
2474 handle_id: id,
2475 state,
2476 changed: false,
2477 direction,
2478 });
2479 }
2480
2481 for requester_id in changed_requesters {
2482 for reader in focus_requester_read_subscribers(requester_id) {
2483 record_replay_boundary_invalidation_for_instance_key(reader);
2484 }
2485 }
2486 }
2487
2488 fn recompute_states(&mut self) {
2489 for id in self.stateful_handles.drain() {
2490 if let Some(node) = self.nodes.get_mut(&id) {
2491 node.state = FocusState::Inactive;
2492 }
2493 }
2494 let Some(active) = self.active else {
2495 return;
2496 };
2497 if !self
2498 .nodes
2499 .get(&active)
2500 .is_some_and(|node| node.is_attached())
2501 {
2502 return;
2503 }
2504
2505 let mut current = Some(active);
2506 let active_state = if self.captured == Some(active) {
2507 FocusState::Captured
2508 } else {
2509 FocusState::Active
2510 };
2511 let mut first = true;
2512 while let Some(id) = current {
2513 if let Some(node) = self.nodes.get_mut(&id)
2514 && node.is_attached()
2515 {
2516 self.stateful_handles.insert(id);
2517 node.state = if first {
2518 active_state
2519 } else {
2520 FocusState::ActiveParent
2521 };
2522 }
2523 if id == ROOT_SCOPE_ID {
2524 break;
2525 }
2526 current = self
2527 .nodes
2528 .get(&id)
2529 .and_then(|node| node.attachment)
2530 .map(|attachment| attachment.parent);
2531 first = false;
2532 }
2533 }
2534
2535 fn can_focus(&self, id: FocusHandleId) -> bool {
2536 self.nodes.get(&id).is_some_and(|node| {
2537 node.attachment.is_some_and(FocusAttachment::permits_focus) && node.props.can_focus
2538 })
2539 }
2540
2541 fn can_request_focus(&self, id: FocusHandleId) -> bool {
2542 self.can_focus(id)
2543 && self
2544 .nodes
2545 .get(&id)
2546 .is_some_and(|node| node.props.can_request_focus)
2547 }
2548
2549 fn is_ancestor(&self, ancestor: FocusHandleId, descendant: FocusHandleId) -> bool {
2550 let mut current = Some(descendant);
2551 while let Some(id) = current {
2552 if id == ancestor {
2553 return true;
2554 }
2555 if id == ROOT_SCOPE_ID {
2556 break;
2557 }
2558 current = self
2559 .nodes
2560 .get(&id)
2561 .and_then(|node| node.attachment)
2562 .map(|attachment| attachment.parent);
2563 }
2564 false
2565 }
2566}
2567
2568fn is_eligible_focus_rect(rect: PxRect) -> bool {
2569 rect.width.0 > 0 && rect.height.0 > 0
2570}
2571
2572fn initial_best_candidate_rect(focused_rect: PxRect, direction: FocusDirection) -> PxRect {
2573 match direction {
2574 FocusDirection::Left => PxRect::new(
2575 focused_rect.x + focused_rect.width + crate::Px::new(1),
2576 focused_rect.y,
2577 focused_rect.width,
2578 focused_rect.height,
2579 ),
2580 FocusDirection::Right => PxRect::new(
2581 focused_rect.x - focused_rect.width - crate::Px::new(1),
2582 focused_rect.y,
2583 focused_rect.width,
2584 focused_rect.height,
2585 ),
2586 FocusDirection::Up => PxRect::new(
2587 focused_rect.x,
2588 focused_rect.y + focused_rect.height + crate::Px::new(1),
2589 focused_rect.width,
2590 focused_rect.height,
2591 ),
2592 FocusDirection::Down => PxRect::new(
2593 focused_rect.x,
2594 focused_rect.y - focused_rect.height - crate::Px::new(1),
2595 focused_rect.width,
2596 focused_rect.height,
2597 ),
2598 _ => focused_rect,
2599 }
2600}
2601
2602fn is_better_focus_candidate(
2603 proposed_candidate: PxRect,
2604 current_candidate: PxRect,
2605 focused_rect: PxRect,
2606 direction: FocusDirection,
2607) -> bool {
2608 if !is_focus_candidate(proposed_candidate, focused_rect, direction) {
2609 return false;
2610 }
2611 if !is_focus_candidate(current_candidate, focused_rect, direction) {
2612 return true;
2613 }
2614 if focus_beam_beats(
2615 focused_rect,
2616 proposed_candidate,
2617 current_candidate,
2618 direction,
2619 ) {
2620 return true;
2621 }
2622 if focus_beam_beats(
2623 focused_rect,
2624 current_candidate,
2625 proposed_candidate,
2626 direction,
2627 ) {
2628 return false;
2629 }
2630 weighted_focus_distance(proposed_candidate, focused_rect, direction)
2631 < weighted_focus_distance(current_candidate, focused_rect, direction)
2632}
2633
2634fn is_focus_candidate(rect: PxRect, focused_rect: PxRect, direction: FocusDirection) -> bool {
2635 match direction {
2636 FocusDirection::Left => {
2637 (focused_rect_right(focused_rect) > focused_rect_right(rect)
2638 || focused_rect.x >= focused_rect_right(rect))
2639 && focused_rect.x > rect.x
2640 }
2641 FocusDirection::Right => {
2642 (focused_rect.x < rect.x || focused_rect_right(focused_rect) <= rect.x)
2643 && focused_rect_right(focused_rect) < focused_rect_right(rect)
2644 }
2645 FocusDirection::Up => {
2646 (focused_rect_bottom(focused_rect) > focused_rect_bottom(rect)
2647 || focused_rect.y >= focused_rect_bottom(rect))
2648 && focused_rect.y > rect.y
2649 }
2650 FocusDirection::Down => {
2651 (focused_rect.y < rect.y || focused_rect_bottom(focused_rect) <= rect.y)
2652 && focused_rect_bottom(focused_rect) < focused_rect_bottom(rect)
2653 }
2654 _ => false,
2655 }
2656}
2657
2658fn weighted_focus_distance(rect: PxRect, focused_rect: PxRect, direction: FocusDirection) -> i64 {
2659 let major = major_axis_distance(rect, focused_rect, direction);
2660 let minor = minor_axis_distance(rect, focused_rect, direction);
2661 13 * major * major + minor * minor
2662}
2663
2664fn focus_beam_beats(
2665 source: PxRect,
2666 rect1: PxRect,
2667 rect2: PxRect,
2668 direction: FocusDirection,
2669) -> bool {
2670 if rect2_in_source_beam(rect2, source, direction)
2671 || !rect2_in_source_beam(rect1, source, direction)
2672 {
2673 return false;
2674 }
2675 if !is_in_direction_of_search(rect2, source, direction) {
2676 return true;
2677 }
2678 if matches!(direction, FocusDirection::Left | FocusDirection::Right) {
2679 return true;
2680 }
2681 major_axis_distance(rect1, source, direction)
2682 < major_axis_distance_to_far_edge(rect2, source, direction)
2683}
2684
2685fn rect2_in_source_beam(rect: PxRect, source: PxRect, direction: FocusDirection) -> bool {
2686 match direction {
2687 FocusDirection::Left | FocusDirection::Right => {
2688 focused_rect_bottom(rect) > source.y && rect.y < focused_rect_bottom(source)
2689 }
2690 FocusDirection::Up | FocusDirection::Down => {
2691 focused_rect_right(rect) > source.x && rect.x < focused_rect_right(source)
2692 }
2693 _ => false,
2694 }
2695}
2696
2697fn is_in_direction_of_search(rect: PxRect, source: PxRect, direction: FocusDirection) -> bool {
2698 match direction {
2699 FocusDirection::Left => source.x >= focused_rect_right(rect),
2700 FocusDirection::Right => focused_rect_right(source) <= rect.x,
2701 FocusDirection::Up => source.y >= focused_rect_bottom(rect),
2702 FocusDirection::Down => focused_rect_bottom(source) <= rect.y,
2703 _ => false,
2704 }
2705}
2706
2707fn major_axis_distance(rect: PxRect, focused_rect: PxRect, direction: FocusDirection) -> i64 {
2708 let distance = match direction {
2709 FocusDirection::Left => focused_rect.x.0 - focused_rect_right(rect).0,
2710 FocusDirection::Right => rect.x.0 - focused_rect_right(focused_rect).0,
2711 FocusDirection::Up => focused_rect.y.0 - focused_rect_bottom(rect).0,
2712 FocusDirection::Down => rect.y.0 - focused_rect_bottom(focused_rect).0,
2713 _ => 0,
2714 };
2715 i64::from(distance.max(0))
2716}
2717
2718fn major_axis_distance_to_far_edge(rect: PxRect, source: PxRect, direction: FocusDirection) -> i64 {
2719 let distance = match direction {
2720 FocusDirection::Left => source.x.0 - rect.x.0,
2721 FocusDirection::Right => focused_rect_right(rect).0 - focused_rect_right(source).0,
2722 FocusDirection::Up => source.y.0 - rect.y.0,
2723 FocusDirection::Down => focused_rect_bottom(rect).0 - focused_rect_bottom(source).0,
2724 _ => 1,
2725 };
2726 i64::from(distance.max(1))
2727}
2728
2729fn minor_axis_distance(rect: PxRect, focused_rect: PxRect, direction: FocusDirection) -> i64 {
2730 let focused_center = match direction {
2731 FocusDirection::Left | FocusDirection::Right => {
2732 focused_rect.y.0 + focused_rect.height.0 / 2
2733 }
2734 FocusDirection::Up | FocusDirection::Down => focused_rect.x.0 + focused_rect.width.0 / 2,
2735 _ => 0,
2736 };
2737 let candidate_center = match direction {
2738 FocusDirection::Left | FocusDirection::Right => rect.y.0 + rect.height.0 / 2,
2739 FocusDirection::Up | FocusDirection::Down => rect.x.0 + rect.width.0 / 2,
2740 _ => 0,
2741 };
2742 i64::from(focused_center - candidate_center)
2743}
2744
2745fn focused_rect_right(rect: PxRect) -> crate::Px {
2746 rect.x + rect.width
2747}
2748
2749fn focused_rect_bottom(rect: PxRect) -> crate::Px {
2750 rect.y + rect.height
2751}
2752
2753pub(crate) fn flush_pending_focus_callbacks() {
2754 let callbacks = TesseraRuntime::with_mut(|runtime| {
2755 runtime
2756 .component_tree
2757 .take_pending_focus_callback_invocations()
2758 });
2759 for callback in callbacks {
2760 callback.invoke();
2761 }
2762}