1use std::{
2 any::Any,
3 borrow::Cow,
4 collections::VecDeque,
5 fmt::Debug,
6 rc::Rc,
7};
8
9use bitflags::bitflags;
10use cursor_icon::CursorIcon;
11use freya_engine::prelude::{
12 FontCollection,
13 FontMgr,
14};
15use futures_channel::mpsc::UnboundedSender;
16use itertools::Itertools;
17use ragnarok::NodesState;
18use rustc_hash::{
19 FxHashMap,
20 FxHashSet,
21};
22use torin::{
23 node::Node,
24 prelude::{
25 Area,
26 LayoutMeasurer,
27 LayoutNode,
28 PostMeasure,
29 Scaled,
30 Size2D,
31 },
32 torin::{
33 DirtyReason,
34 Torin,
35 },
36};
37
38use crate::{
39 accessibility::groups::AccessibilityGroups,
40 data::{
41 AccessibilityState,
42 EffectState,
43 LayerState,
44 TextStyleState,
45 },
46 element::{
47 ElementExt,
48 LayoutContext,
49 PostMeasureContext,
50 },
51 elements::rect::RectElement,
52 events::{
53 data::{
54 EventType,
55 SizedEventData,
56 StyledEventData,
57 VisibleEventData,
58 },
59 emittable::EmmitableEvent,
60 name::EventName,
61 },
62 extended_hashmap::ExtendedHashMap,
63 integration::{
64 AccessibilityDirtyNodes,
65 AccessibilityFocusStrategy,
66 AccessibilityGenerator,
67 EventsChunk,
68 },
69 layers::Layers,
70 node_id::NodeId,
71 runner::{
72 MutationAdd,
73 MutationModified,
74 MutationRemove,
75 Mutations,
76 },
77 text_cache::TextCache,
78 tree_layout_adapter::TreeAdapterFreya,
79};
80
81#[derive(Default)]
82pub struct Tree {
83 pub parents: FxHashMap<NodeId, NodeId>,
84 pub children: FxHashMap<NodeId, Vec<NodeId>>,
85 pub heights: FxHashMap<NodeId, u16>,
86
87 pub elements: FxHashMap<NodeId, Rc<dyn ElementExt>>,
88
89 layout_nodes: FxHashMap<NodeId, Node>,
91
92 pub listeners: FxHashMap<EventName, Vec<NodeId>>,
94
95 pub events: Vec<EmmitableEvent>,
97
98 pub layer_state: FxHashMap<NodeId, LayerState>,
100 pub accessibility_state: FxHashMap<NodeId, AccessibilityState>,
101 pub effect_state: FxHashMap<NodeId, EffectState>,
102 pub text_style_state: FxHashMap<NodeId, TextStyleState>,
103
104 pub layout: Torin<NodeId>,
106 pub layers: Layers,
107 pub text_cache: TextCache,
108
109 pub accessibility_groups: AccessibilityGroups,
111 pub accessibility_diff: AccessibilityDirtyNodes,
112 pub accessibility_generator: AccessibilityGenerator,
113}
114
115impl Tree {
116 fn scaled_layout_node(element: &Rc<dyn ElementExt>, scale_factor: f32) -> Node {
118 let mut layout_node = element.layout().layout.clone();
119 layout_node.depends_on_inner = element.needs_post_measure();
120 layout_node.scale(scale_factor);
121 layout_node
122 }
123
124 fn insert_element(&mut self, node_id: NodeId, element: Rc<dyn ElementExt>, scale_factor: f32) {
126 self.layout_nodes
127 .insert(node_id, Self::scaled_layout_node(&element, scale_factor));
128 self.elements.insert(node_id, element);
129 }
130
131 fn remove_element(&mut self, node_id: NodeId) -> Option<Rc<dyn ElementExt>> {
133 self.layout_nodes.remove(&node_id);
134 self.elements.remove(&node_id)
135 }
136
137 pub fn set_scale_factor(&mut self, scale_factor: f32) {
139 self.layout_nodes.clear();
140 for (node_id, element) in &self.elements {
141 self.layout_nodes
142 .insert(*node_id, Self::scaled_layout_node(element, scale_factor));
143 }
144 }
145}
146
147impl Debug for Tree {
148 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
149 f.debug_struct("Tree")
150 .field("children", &self.children.capacity())
151 .field("parents", &self.parents.capacity())
152 .field("elements", &self.elements.capacity())
153 .field("layout_nodes", &self.layout_nodes.capacity())
154 .field("heights", &self.heights.capacity())
155 .field("listeners", &self.listeners.capacity())
156 .field("layer_state", &self.layer_state.capacity())
157 .field("layout_size", &self.layout.size())
158 .field("layers", &self.layers.capacity())
159 .field("effect_state", &self.effect_state.capacity())
160 .field("accessibility_state", &self.accessibility_state.capacity())
161 .field("text_style_state", &self.text_style_state.capacity())
162 .field("text_cache", &self.text_cache)
163 .finish()
164 }
165}
166
167impl Tree {
168 pub fn size(&self) -> usize {
169 self.elements.len()
170 }
171
172 pub fn traverse_depth(&self, mut then: impl FnMut(NodeId)) {
173 let mut buffer = vec![NodeId::ROOT];
174 while let Some(node_id) = buffer.pop() {
175 if let Some(children) = self.children.get(&node_id) {
176 buffer.extend(children.iter().rev());
177 }
178 then(node_id);
179 }
180 }
181
182 pub fn cursor_icon(&self, nodes_state: &ragnarok::NodesState<NodeId>) -> CursorIcon {
185 nodes_state
186 .hovered_nodes()
187 .sorted_by_key(|node_id| {
188 std::cmp::Reverse(
189 self.layer_state
190 .get(node_id)
191 .map(|layer_state| layer_state.layer)
192 .unwrap_or_default(),
193 )
194 })
195 .find_map(|node_id| {
196 self.elements
197 .get(node_id)
198 .and_then(|element| element.effect())
199 .and_then(|effect| effect.cursor)
200 })
201 .unwrap_or_default()
202 }
203
204 pub fn cursor_visible(&self, nodes_state: &ragnarok::NodesState<NodeId>) -> bool {
206 nodes_state
207 .hovered_nodes()
208 .sorted_by_key(|node_id| {
209 std::cmp::Reverse(
210 self.layer_state
211 .get(node_id)
212 .map(|layer_state| layer_state.layer)
213 .unwrap_or_default(),
214 )
215 })
216 .find_map(|node_id| {
217 self.elements
218 .get(node_id)
219 .and_then(|element| element.effect())
220 .and_then(|effect| effect.cursor_visible)
221 })
222 .unwrap_or(true)
223 }
224
225 pub fn traverse_depth_cancel(&self, mut then: impl FnMut(NodeId) -> bool) {
226 let mut buffer = vec![NodeId::ROOT];
227 while let Some(node_id) = buffer.pop() {
228 if let Some(children) = self.children.get(&node_id) {
229 buffer.extend(children.iter().rev());
230 }
231 if then(node_id) {
232 break;
233 }
234 }
235 }
236
237 #[cfg_attr(feature = "hotpath", hotpath::measure)]
238 pub fn apply_mutations(
239 &mut self,
240 mutations: Mutations,
241 scale_factor: f32,
242 ) -> MutationsApplyResult {
243 if mutations.is_empty() && self.elements.contains_key(&NodeId::ROOT) {
245 return MutationsApplyResult {
246 needs_render: false,
247 needs_accessibility: false,
248 auto_focus: self.accessibility_diff.requested_auto_focus.take(),
249 };
250 }
251
252 let mut needs_render = !mutations.removed.is_empty();
253 let mut needs_accessibility = !mutations.removed.is_empty();
254 let mut dirty = Vec::<(NodeId, DiffModifies)>::default();
255
256 #[cfg(debug_assertions)]
257 tracing::info!("{mutations:?}");
258
259 if !self.elements.contains_key(&NodeId::ROOT) {
260 self.insert_element(NodeId::ROOT, Rc::new(RectElement::default()), scale_factor);
261 self.heights.insert(NodeId::ROOT, 0);
262 dirty.push((NodeId::ROOT, DiffModifies::all()));
263 }
264
265 hotpath::measure_block!("mutations run", {
266 for remove in mutations.removed.into_iter().sorted() {
267 let node_id = remove.node_id();
268 let mut buff = vec![remove];
269 let Some(parent_id) = self.parents.get(&node_id).copied() else {
270 continue;
271 };
272 self.layout.invalidate(parent_id);
273 needs_render = true;
274
275 while let Some(remove) = buff.pop() {
276 let node_id = remove.node_id();
277 self.layout.raw_remove(node_id);
278
279 let parent_id = self.parents.remove(&node_id).unwrap();
280
281 let old_element = self.remove_element(node_id).unwrap();
283
284 if let Some(children) = self.children.get_mut(&parent_id) {
285 match remove {
286 MutationRemove::Element { index, .. } => {
287 children.remove(index as usize);
288 }
289 MutationRemove::Scope { .. } => {
290 children.retain(|id| *id != node_id);
291 }
292 }
293 }
294
295 if let Some(children) = self.children.remove(&node_id) {
297 buff.extend(children.into_iter().enumerate().map(|(i, e)| {
298 MutationRemove::Element {
299 id: e,
300 index: i as u32,
301 }
302 }));
303 }
304
305 if let Some(events) = old_element.events_handlers() {
307 for event in events.keys() {
308 self.listeners
309 .entry(*event)
310 .or_default()
311 .retain(|id| *id != node_id);
312 }
313 }
314
315 let layer_state = self.layer_state.remove(&node_id).unwrap();
317 layer_state.remove(node_id, &mut self.layers);
318
319 let accessibility_state = self.accessibility_state.remove(&node_id).unwrap();
321 accessibility_state.remove(
322 node_id,
323 parent_id,
324 &mut self.accessibility_diff,
325 &mut self.accessibility_groups,
326 );
327
328 self.heights.remove(&node_id);
330 self.effect_state.remove(&node_id);
331 self.text_style_state.remove(&node_id);
332 self.text_cache.remove(&node_id);
333 }
334 }
335
336 for MutationAdd {
337 node_id,
338 parent_id,
339 index,
340 element,
341 } in mutations
342 .added
343 .into_iter()
344 .sorted_by_key(|m| (m.parent_id, m.index))
345 {
346 let parent_height = *self.heights.entry(parent_id).or_default();
347
348 self.parents.insert(node_id, parent_id);
349 self.heights.insert(node_id, parent_height + 1);
350
351 let parent = self.children.entry(parent_id).or_default();
352
353 if parent.len() < index as usize + 1 {
355 parent.resize(index as usize + 1, NodeId::PLACEHOLDER);
356
357 parent[index as usize] = node_id;
358 } else if parent.get(index as usize) == Some(&NodeId::PLACEHOLDER) {
359 parent[index as usize] = node_id;
360 } else {
361 parent.insert(index as usize, node_id);
362 }
363
364 if let Some(events) = element.events_handlers() {
366 for event in events.keys() {
367 self.listeners.entry(*event).or_default().push(node_id);
368 }
369 }
370
371 self.insert_element(node_id, element, scale_factor);
372 dirty.push((node_id, DiffModifies::all()));
373 }
374
375 for (parent_node_id, children) in mutations.moved {
376 let parent = self.children.entry(parent_node_id).or_default();
377 if *parent == children {
378 continue;
379 }
380 *parent = children;
381 dirty.push((
382 parent_node_id,
383 DiffModifies::REORDER_LAYOUT
384 | DiffModifies::ACCESSIBILITY
385 | DiffModifies::STYLE,
386 ));
387 }
388
389 for MutationModified {
390 node_id,
391 element,
392 flags,
393 } in mutations.modified
394 {
395 dirty.push((node_id, flags));
396
397 let old_element = self.remove_element(node_id).unwrap();
398
399 if flags.contains(DiffModifies::EVENT_HANDLERS) {
400 if let Some(events) = old_element.events_handlers() {
402 for event in events.keys() {
403 self.listeners
404 .entry(*event)
405 .or_default()
406 .retain(|id| *id != node_id);
407 }
408 }
409
410 if let Some(events) = element.events_handlers() {
412 for event in events.keys() {
413 self.listeners.entry(*event).or_default().push(node_id);
414 }
415 }
416 }
417
418 self.insert_element(node_id, element, scale_factor);
419 }
420 });
421
422 let mut layer_cascades: Vec<NodeId> = Vec::new();
424 let mut effects_cascades: Vec<NodeId> = Vec::new();
425 let mut text_style_cascades: Vec<NodeId> = Vec::new();
426 let mut styled_nodes: FxHashSet<NodeId> = FxHashSet::default();
427
428 #[cfg(debug_assertions)]
429 assert_eq!(dirty.len(), FxHashSet::from_iter(&dirty).len());
430
431 hotpath::measure_block!("dirty run", {
432 for (node_id, flags) in dirty {
433 let element = self.elements.get(&node_id).unwrap();
434 let height_b = self.heights.get(&node_id).unwrap();
435
436 if flags.contains(DiffModifies::REORDER_LAYOUT) {
437 self.layout
438 .invalidate_with_reason(node_id, DirtyReason::Reorder);
439 }
440
441 if flags.contains(DiffModifies::INNER_LAYOUT) {
442 self.layout
443 .invalidate_with_reason(node_id, DirtyReason::InnerLayout);
444 }
445
446 if flags.contains(DiffModifies::LAYOUT) {
447 self.layout.invalidate(node_id);
448 }
449
450 if !needs_render
451 && (flags.intersects(
452 DiffModifies::STYLE
453 | DiffModifies::LAYER
454 | DiffModifies::EFFECT
455 | DiffModifies::TEXT_STYLE
456 | DiffModifies::LAYOUT
457 | DiffModifies::INNER_LAYOUT
458 | DiffModifies::REORDER_LAYOUT,
459 ))
460 {
461 needs_render = true;
462 }
463
464 if !needs_accessibility && (flags.intersects(DiffModifies::ACCESSIBILITY)) {
465 needs_accessibility = true;
466 }
467
468 if flags.intersects(DiffModifies::STYLE | DiffModifies::TEXT_STYLE)
469 && self
470 .listeners
471 .get(&EventName::Styled)
472 .is_some_and(|listeners| listeners.contains(&node_id))
473 {
474 styled_nodes.insert(node_id);
475 }
476
477 if flags.contains(DiffModifies::ACCESSIBILITY) {
478 match self.accessibility_state.get_mut(&node_id) {
479 Some(accessibility_state) => accessibility_state.update(
480 node_id,
481 element,
482 &mut self.accessibility_diff,
483 &mut self.accessibility_groups,
484 ),
485 None => {
486 self.accessibility_state.insert(
487 node_id,
488 AccessibilityState::create(
489 node_id,
490 element,
491 &mut self.accessibility_diff,
492 &self.accessibility_generator,
493 &mut self.accessibility_groups,
494 ),
495 );
496 }
497 }
498 }
499
500 let handle_cascade = |cascades: &mut Vec<NodeId>| {
501 if cascades.iter_mut().any(|root| {
503 let height_a = self.heights.get(root).unwrap();
504
505 match height_a.cmp(height_b) {
506 std::cmp::Ordering::Less => {
507 self.balance_heights(&node_id, root) == Some(*root)
508 }
509 std::cmp::Ordering::Greater => {
510 let balanced_root = self.balance_heights(root, &node_id);
511 match balanced_root {
512 Some(r) if r == node_id => {
513 *root = node_id;
516 true
517 }
518 _ => false,
519 }
520 }
521 std::cmp::Ordering::Equal => false,
522 }
523 }) {
524 return;
525 }
526 cascades.push(node_id);
527 };
528
529 if flags.intersects(DiffModifies::LAYER) {
530 handle_cascade(&mut layer_cascades);
531 }
532 if flags.intersects(DiffModifies::EFFECT | DiffModifies::LAYER) {
533 let element = self.elements.get(&node_id).unwrap();
534 let run_cascade = element.effect().is_some()
536 || self
537 .parents
538 .get(&node_id)
539 .map(|parent| self.effect_state.contains_key(parent))
540 .unwrap_or_default();
541 if run_cascade {
542 handle_cascade(&mut effects_cascades);
543 }
544 }
545 if flags.intersects(DiffModifies::TEXT_STYLE) {
546 handle_cascade(&mut text_style_cascades);
547 }
548 }
549 });
550
551 hotpath::measure_block!("layer cascade", {
552 for layer_root in layer_cascades {
554 let mut buffer = VecDeque::new();
555 buffer.push_front(&layer_root);
556
557 while let Some(node_id) = buffer.pop_front() {
558 let element = self.elements.get(node_id).unwrap();
559 if let Some(parent_node_id) = self.parents.get(node_id) {
560 let entries = self
561 .layer_state
562 .get_disjoint_entries([node_id, parent_node_id], |_id| {
563 LayerState::default()
564 });
565 if let Some([layer_state, parent_layer_state]) = entries {
566 layer_state.update(
567 parent_layer_state,
568 *node_id,
569 element,
570 &mut self.layers,
571 );
572 }
573 } else {
574 assert_eq!(*node_id, NodeId::ROOT);
575 self.layer_state.insert(
576 NodeId::ROOT,
577 LayerState::create_for_root(*node_id, &mut self.layers),
578 );
579 }
580 if let Some(children) = self.children.get(node_id) {
581 buffer.extend(children);
582 }
583 }
584 }
585 });
586
587 hotpath::measure_block!("effect cascade", {
588 for effect_root in effects_cascades {
590 let mut buffer = VecDeque::new();
591 buffer.push_front(&effect_root);
592
593 while let Some(node_id) = buffer.pop_front() {
594 let element = self.elements.get(node_id).unwrap();
595 if let Some(parent_node_id) = self.parents.get(node_id) {
596 let entries = self.effect_state.get_disjoint_two_entries(
597 parent_node_id,
598 node_id,
599 |_id| EffectState::default(),
600 |left, _id| left.clone(),
601 );
602 if let [Some(parent_effect_state), Some(effect_state)] = entries {
603 let effect_data = element.effect();
604 let layer = element.layer();
605 effect_state.update(
606 *parent_node_id,
607 parent_effect_state,
608 *node_id,
609 effect_data,
610 layer,
611 );
612 }
613 } else {
614 assert_eq!(*node_id, NodeId::ROOT);
615 }
616 if let Some(children) = self.children.get(node_id) {
617 buffer.extend(children);
618 }
619 }
620 }
621 });
622
623 hotpath::measure_block!("text style cascade", {
624 for text_style_root in text_style_cascades {
626 let mut buffer = VecDeque::new();
627 buffer.push_front(&text_style_root);
628
629 while let Some(node_id) = buffer.pop_front() {
630 let element = self.elements.get(node_id).unwrap();
631 if let Some(parent_node_id) = self.parents.get(node_id) {
632 let entries = self
633 .text_style_state
634 .get_disjoint_entries([node_id, parent_node_id], |_id| {
635 TextStyleState::default()
636 });
637 if let Some([text_style_state, parent_text_style_state]) = entries {
638 let changed = text_style_state.update(
639 *node_id,
640 parent_text_style_state,
641 element,
642 &mut self.layout,
643 );
644 if changed
645 && self
646 .listeners
647 .get(&EventName::Styled)
648 .is_some_and(|listeners| listeners.contains(node_id))
649 {
650 styled_nodes.insert(*node_id);
651 }
652 }
653 } else {
654 assert_eq!(*node_id, NodeId::ROOT);
655 self.text_style_state
656 .insert(NodeId::ROOT, TextStyleState::default());
657 }
658 if let Some(children) = self.children.get(node_id) {
659 buffer.extend(children);
660 }
661 }
662 }
663
664 #[cfg(all(debug_assertions, feature = "debug-integrity"))]
665 self.verify_tree_integrity();
666 });
667
668 for node_id in styled_nodes {
669 let element = self.elements.get(&node_id).unwrap();
670 let text_style_state = self.text_style_state.get(&node_id).unwrap();
671 self.events.push(EmmitableEvent {
672 name: EventName::Styled,
673 source_event: EventName::Styled,
674 node_id,
675 data: EventType::Styled(StyledEventData {
676 style: element.style().into_owned(),
677 text_style: text_style_state.clone(),
678 }),
679 bubbles: false,
680 });
681 }
682
683 MutationsApplyResult {
684 needs_render,
685 needs_accessibility,
686 auto_focus: self.accessibility_diff.requested_auto_focus.take(),
687 }
688 }
689
690 fn balance_heights(&self, base: &NodeId, target: &NodeId) -> Option<NodeId> {
692 let target_height = self.heights.get(target)?;
693 let mut current = base;
694 loop {
695 if self.heights.get(current)? == target_height {
696 break;
697 }
698
699 let parent_current = self.parents.get(current);
700 if let Some(parent_current) = parent_current {
701 current = parent_current;
702 }
703 }
704 Some(*current)
705 }
706
707 #[allow(clippy::too_many_arguments)]
708 pub fn measure_layout(
709 &mut self,
710 size: Size2D,
711 font_collection: &mut FontCollection,
712 font_manager: &FontMgr,
713 events_sender: &UnboundedSender<EventsChunk>,
714 nodes_state: &mut NodesState<NodeId>,
715 scale_factor: f64,
716 fallback_fonts: &[Cow<'static, str>],
717 ) {
718 let tree_adapter = TreeAdapterFreya {
719 layout_nodes: &self.layout_nodes,
720 parents: &self.parents,
721 children: &self.children,
722 heights: &self.heights,
723 };
724
725 let layout_adapter = LayoutMeasurerAdapter {
726 elements: &self.elements,
727 text_style_state: &self.text_style_state,
728 font_collection,
729 font_manager,
730 events: &mut self.events,
731 scale_factor,
732 fallback_fonts,
733 text_cache: &mut self.text_cache,
734 };
735
736 self.layout.find_best_root(&tree_adapter);
737 self.layout.measure(
738 NodeId::ROOT,
739 Area::from_size(size),
740 &mut Some(layout_adapter),
741 &tree_adapter,
742 );
743 self.measure_visibility_events(nodes_state, scale_factor);
744 events_sender
745 .unbounded_send(EventsChunk::Batch(std::mem::take(&mut self.events)))
746 .unwrap();
747 }
748
749 fn measure_visibility_events(
751 &mut self,
752 nodes_state: &mut NodesState<NodeId>,
753 scale_factor: f64,
754 ) {
755 let visible_listeners = self.listeners.get(&EventName::Visible);
756 let hidden_listeners = self.listeners.get(&EventName::Hidden);
757 let listeners = visible_listeners
758 .into_iter()
759 .flatten()
760 .map(|node_id| (node_id, EventName::Visible))
761 .chain(
762 hidden_listeners
763 .into_iter()
764 .flatten()
765 .map(|node_id| (node_id, EventName::Hidden)),
766 );
767
768 let mut visible_nodes = FxHashSet::default();
769 for (node_id, event_name) in listeners {
770 let Some(layout_node) = self.layout.get(node_id) else {
771 continue;
772 };
773 let is_visible = !layout_node.hidden
774 && self.effect_state.get(node_id).is_none_or(|effect_state| {
775 effect_state.is_visible(&self.layout, &layout_node.area)
776 });
777 if is_visible {
778 visible_nodes.insert(*node_id);
779 }
780
781 let was_visible = nodes_state.is_visible(*node_id);
782 let just_changed = match event_name {
783 EventName::Visible => is_visible && !was_visible,
784 _ => !is_visible && was_visible,
785 };
786 if !just_changed {
787 continue;
788 }
789
790 let mut data = VisibleEventData::new(layout_node.area);
791 data.div(scale_factor as f32);
792 self.events.push(EmmitableEvent {
793 node_id: *node_id,
794 name: event_name,
795 data: EventType::Visible(data),
796 bubbles: false,
797 source_event: event_name,
798 });
799 }
800 nodes_state.set_visible_nodes(visible_nodes);
801 }
802
803 pub fn print_ascii(&self, node_id: NodeId, prefix: String, last: bool) {
804 let height = self.heights.get(&node_id).unwrap();
805 let layer = self.layer_state.get(&node_id).unwrap();
806
807 println!(
809 "{}{}{:?} [{}] ({})",
810 prefix,
811 if last { "└── " } else { "├── " },
812 node_id,
813 height,
814 layer.layer
815 );
816
817 if let Some(children) = self.children.get(&node_id) {
819 let len = children.len();
820 for (i, child) in children.iter().enumerate() {
821 let is_last = i == len - 1;
822 let new_prefix = format!("{}{}", prefix, if last { " " } else { "│ " });
824 self.print_ascii(*child, new_prefix, is_last);
825 }
826 }
827 }
828
829 #[cfg(all(debug_assertions, feature = "debug-integrity"))]
830 #[cfg_attr(feature = "hotpath", hotpath::measure)]
831 pub fn verify_tree_integrity(&self) {
832 let mut visited = FxHashSet::default();
833 let size = self.elements.len();
834 let mut buffer = vec![NodeId::ROOT];
835 while let Some(node_id) = buffer.pop() {
836 if visited.contains(&node_id) {
837 continue;
838 }
839 visited.insert(node_id);
840 if let Some(parent) = self.parents.get(&node_id) {
841 buffer.push(*parent);
842 }
843 if let Some(children) = self.children.get(&node_id) {
844 buffer.extend(children);
845 }
846 }
847 assert_eq!(size, visited.len());
848 assert_eq!(size, self.layout_nodes.len());
849 }
850}
851
852bitflags! {
853 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
854 pub struct DiffModifies: u32 {
855 const LAYOUT = 1 << 0;
856 const STYLE = 1 << 1;
857 const ACCESSIBILITY = 1 << 2;
858 const EVENT_HANDLERS = 1 << 3;
859 const LAYER = 1 << 4;
860 const TEXT_STYLE = 1 << 5;
861 const EFFECT = 1 << 6;
862 const INNER_LAYOUT = 1 << 7;
863 const REORDER_LAYOUT = 1 << 8;
864 }
865}
866
867pub struct MutationsApplyResult {
868 pub needs_render: bool,
869 pub needs_accessibility: bool,
870 pub auto_focus: Option<AccessibilityFocusStrategy>,
871}
872
873pub struct LayoutMeasurerAdapter<'a> {
874 pub font_collection: &'a mut FontCollection,
875 pub font_manager: &'a FontMgr,
876 elements: &'a FxHashMap<NodeId, Rc<dyn ElementExt>>,
877 text_style_state: &'a FxHashMap<NodeId, TextStyleState>,
878 events: &'a mut Vec<EmmitableEvent>,
879 scale_factor: f64,
880 fallback_fonts: &'a [Cow<'static, str>],
881 text_cache: &'a mut TextCache,
882}
883
884impl LayoutMeasurer<NodeId> for LayoutMeasurerAdapter<'_> {
885 fn measure(
886 &mut self,
887 node_id: NodeId,
888 torin_node: &torin::node::Node,
889 area_size: &Size2D,
890 ) -> Option<(Size2D, Rc<dyn Any>)> {
891 self.elements.get(&node_id)?.measure(LayoutContext {
892 node_id,
893 torin_node,
894 area_size,
895 font_collection: self.font_collection,
896 font_manager: self.font_manager,
897 text_style_state: self.text_style_state.get(&node_id).unwrap(),
898 scale_factor: self.scale_factor,
899 fallback_fonts: self.fallback_fonts,
900 text_cache: self.text_cache,
901 })
902 }
903
904 fn should_hook_measurement(&mut self, node_id: NodeId) -> bool {
905 if let Some(element) = self.elements.get(&node_id) {
906 element.should_hook_measurement()
907 } else {
908 false
909 }
910 }
911
912 fn should_measure_inner_children(&mut self, node_id: NodeId) -> bool {
913 if let Some(element) = self.elements.get(&node_id) {
914 element.should_measure_inner_children()
915 } else {
916 false
917 }
918 }
919
920 fn should_post_measure(&mut self, node_id: NodeId) -> bool {
921 self.elements
922 .get(&node_id)
923 .is_some_and(|element| element.needs_post_measure())
924 }
925
926 fn post_measure(
927 &mut self,
928 node_id: NodeId,
929 node_layout: &LayoutNode,
930 children: &[NodeId],
931 layout: &Torin<NodeId>,
932 ) -> PostMeasure<NodeId> {
933 self.elements
934 .get(&node_id)
935 .unwrap()
936 .post_measure(PostMeasureContext {
937 node_layout,
938 children,
939 layout,
940 font_collection: self.font_collection,
941 text_style_state: self.text_style_state.get(&node_id).unwrap(),
942 fallback_fonts: self.fallback_fonts,
943 scale_factor: self.scale_factor,
944 })
945 }
946
947 fn notify_layout_references(
948 &mut self,
949 node_id: NodeId,
950 area: Area,
951 visible_area: Area,
952 inner_sizes: Size2D,
953 ) {
954 let mut data = SizedEventData::new(area, visible_area, inner_sizes);
955 data.div(self.scale_factor as f32);
956 self.events.push(EmmitableEvent {
957 node_id,
958 name: EventName::Sized,
959 data: EventType::Sized(data),
960 bubbles: false,
961 source_event: EventName::Sized,
962 });
963 }
964}