1use std::{
2 any::Any,
3 borrow::Cow,
4 collections::{
5 VecDeque,
6 hash_map::Entry,
7 },
8 fmt::Debug,
9 rc::Rc,
10};
11
12use bitflags::bitflags;
13use freya_engine::prelude::{
14 FontCollection,
15 FontMgr,
16};
17use futures_channel::mpsc::UnboundedSender;
18use itertools::Itertools;
19use rustc_hash::{
20 FxHashMap,
21 FxHashSet,
22};
23use torin::{
24 prelude::{
25 Area,
26 LayoutMeasurer,
27 LayoutNode,
28 PostMeasure,
29 Size2D,
30 },
31 torin::{
32 DirtyReason,
33 Torin,
34 },
35};
36
37use crate::{
38 accessibility::groups::AccessibilityGroups,
39 data::{
40 AccessibilityState,
41 EffectState,
42 LayerState,
43 TextStyleState,
44 },
45 element::{
46 ElementExt,
47 LayoutContext,
48 PostMeasureContext,
49 },
50 elements::rect::RectElement,
51 events::{
52 data::{
53 EventType,
54 SizedEventData,
55 },
56 emittable::EmmitableEvent,
57 name::EventName,
58 },
59 extended_hashmap::ExtendedHashMap,
60 integration::{
61 AccessibilityDirtyNodes,
62 AccessibilityGenerator,
63 EventsChunk,
64 },
65 layers::Layers,
66 node_id::NodeId,
67 runner::{
68 MutationAdd,
69 MutationModified,
70 MutationMove,
71 MutationRemove,
72 Mutations,
73 },
74 text_cache::TextCache,
75 tree_layout_adapter::TreeAdapterFreya,
76};
77
78#[derive(Default)]
79pub struct Tree {
80 pub parents: FxHashMap<NodeId, NodeId>,
81 pub children: FxHashMap<NodeId, Vec<NodeId>>,
82 pub heights: FxHashMap<NodeId, u16>,
83
84 pub elements: FxHashMap<NodeId, Rc<dyn ElementExt>>,
85
86 pub listeners: FxHashMap<EventName, Vec<NodeId>>,
88
89 pub layer_state: FxHashMap<NodeId, LayerState>,
91 pub accessibility_state: FxHashMap<NodeId, AccessibilityState>,
92 pub effect_state: FxHashMap<NodeId, EffectState>,
93 pub text_style_state: FxHashMap<NodeId, TextStyleState>,
94
95 pub layout: Torin<NodeId>,
97 pub layers: Layers,
98 pub text_cache: TextCache,
99
100 pub accessibility_groups: AccessibilityGroups,
102 pub accessibility_diff: AccessibilityDirtyNodes,
103 pub accessibility_generator: AccessibilityGenerator,
104}
105
106impl Debug for Tree {
107 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108 f.debug_struct("Tree")
109 .field("children", &self.children.capacity())
110 .field("parents", &self.parents.capacity())
111 .field("elements", &self.elements.capacity())
112 .field("heights", &self.heights.capacity())
113 .field("listeners", &self.listeners.capacity())
114 .field("layer_state", &self.layer_state.capacity())
115 .field("layout_size", &self.layout.size())
116 .field("layers", &self.layers.capacity())
117 .field("effect_state", &self.effect_state.capacity())
118 .field("accessibility_state", &self.accessibility_state.capacity())
119 .field("text_style_state", &self.text_style_state.capacity())
120 .field("text_cache", &self.text_cache)
121 .finish()
122 }
123}
124
125impl Tree {
126 pub fn size(&self) -> usize {
127 self.elements.len()
128 }
129
130 pub fn traverse_depth(&self, mut then: impl FnMut(NodeId)) {
131 let mut buffer = vec![NodeId::ROOT];
132 while let Some(node_id) = buffer.pop() {
133 if let Some(children) = self.children.get(&node_id) {
134 buffer.extend(children.iter().rev());
135 }
136 then(node_id);
137 }
138 }
139
140 pub fn traverse_depth_cancel(&self, mut then: impl FnMut(NodeId) -> bool) {
141 let mut buffer = vec![NodeId::ROOT];
142 while let Some(node_id) = buffer.pop() {
143 if let Some(children) = self.children.get(&node_id) {
144 buffer.extend(children.iter().rev());
145 }
146 if then(node_id) {
147 break;
148 }
149 }
150 }
151
152 #[cfg_attr(feature = "hotpath", hotpath::measure)]
153 pub fn apply_mutations(&mut self, mutations: Mutations) -> MutationsApplyResult {
154 let mut needs_render = !mutations.removed.is_empty();
155 let mut needs_accessibility = !mutations.removed.is_empty();
156 let mut dirty = Vec::<(NodeId, DiffModifies)>::default();
157
158 #[cfg(debug_assertions)]
159 tracing::info!("{mutations:?}");
160
161 if let Entry::Vacant(e) = self.elements.entry(NodeId::ROOT) {
162 e.insert(Rc::new(RectElement::default()));
163 self.heights.insert(NodeId::ROOT, 0);
164 dirty.push((NodeId::ROOT, DiffModifies::all()));
165 }
166
167 hotpath::measure_block!("mutations run", {
168 for remove in mutations.removed.into_iter().sorted() {
169 let node_id = remove.node_id();
170 let mut buff = vec![remove];
171 let Some(parent_id) = self.parents.get(&node_id).copied() else {
172 continue;
173 };
174 self.layout.invalidate(parent_id);
175 needs_render = true;
176
177 while let Some(remove) = buff.pop() {
178 let node_id = remove.node_id();
179 self.layout.raw_remove(node_id);
180
181 let parent_id = self.parents.remove(&node_id).unwrap();
182
183 let old_element = self.elements.remove(&node_id).unwrap();
185
186 if let Some(children) = self.children.get_mut(&parent_id) {
187 match remove {
188 MutationRemove::Element { index, .. } => {
189 children.remove(index as usize);
190 }
191 MutationRemove::Scope { .. } => {
192 children.retain(|id| *id != node_id);
193 }
194 }
195 }
196
197 if let Some(children) = self.children.remove(&node_id) {
199 buff.extend(children.into_iter().enumerate().map(|(i, e)| {
200 MutationRemove::Element {
201 id: e,
202 index: i as u32,
203 }
204 }));
205 }
206
207 if let Some(events) = old_element.events_handlers() {
209 for event in events.keys() {
210 self.listeners
211 .entry(*event)
212 .or_default()
213 .retain(|id| *id != node_id);
214 }
215 }
216
217 let layer_state = self.layer_state.remove(&node_id).unwrap();
219 layer_state.remove(node_id, &mut self.layers);
220
221 let accessibility_state = self.accessibility_state.remove(&node_id).unwrap();
223 accessibility_state.remove(
224 node_id,
225 parent_id,
226 &mut self.accessibility_diff,
227 &mut self.accessibility_groups,
228 );
229
230 self.heights.remove(&node_id);
232 self.effect_state.remove(&node_id);
233 self.text_style_state.remove(&node_id);
234 self.text_cache.remove(&node_id);
235 }
236 }
237
238 for MutationAdd {
239 node_id,
240 parent_id,
241 index,
242 element,
243 } in mutations
244 .added
245 .into_iter()
246 .sorted_by_key(|m| (m.parent_id, m.index))
247 {
248 let parent_height = *self.heights.entry(parent_id).or_default();
249
250 self.parents.insert(node_id, parent_id);
251 self.heights.insert(node_id, parent_height + 1);
252
253 let parent = self.children.entry(parent_id).or_default();
254
255 if parent.len() < index as usize + 1 {
257 parent.resize(index as usize + 1, NodeId::PLACEHOLDER);
258
259 parent[index as usize] = node_id;
260 } else if parent.get(index as usize) == Some(&NodeId::PLACEHOLDER) {
261 parent[index as usize] = node_id;
262 } else {
263 parent.insert(index as usize, node_id);
264 }
265
266 if let Some(events) = element.events_handlers() {
268 for event in events.keys() {
269 self.listeners.entry(*event).or_default().push(node_id);
270 }
271 }
272
273 self.elements.insert(node_id, element);
274 dirty.push((node_id, DiffModifies::all()));
275 }
276
277 for (parent_node_id, movements) in mutations.moved {
278 let parent = self.children.get_mut(&parent_node_id).unwrap();
279 for MutationMove { index: to, node_id } in
280 movements.into_iter().sorted_by_key(|m| m.index)
281 {
282 let from = parent.iter().position(|id| *id == node_id).unwrap();
283 parent.remove(from);
284 parent.insert(to as usize, node_id);
285 }
286 let mut diff = DiffModifies::empty();
287 diff.insert(DiffModifies::REORDER_LAYOUT);
288 diff.insert(DiffModifies::ACCESSIBILITY);
289 diff.insert(DiffModifies::STYLE);
290 dirty.push((parent_node_id, diff));
291 }
292
293 for MutationModified {
294 node_id,
295 element,
296 flags,
297 } in mutations.modified
298 {
299 dirty.push((node_id, flags));
300
301 let old_element = self.elements.remove(&node_id).unwrap();
302
303 if flags.contains(DiffModifies::EVENT_HANDLERS) {
304 if let Some(events) = old_element.events_handlers() {
306 for event in events.keys() {
307 self.listeners
308 .entry(*event)
309 .or_default()
310 .retain(|id| *id != node_id);
311 }
312 }
313
314 if let Some(events) = element.events_handlers() {
316 for event in events.keys() {
317 self.listeners.entry(*event).or_default().push(node_id);
318 }
319 }
320 }
321
322 self.elements.insert(node_id, element);
323 }
324 });
325
326 let mut layer_cascades: Vec<NodeId> = Vec::new();
328 let mut effects_cascades: Vec<NodeId> = Vec::new();
329 let mut text_style_cascades: Vec<NodeId> = Vec::new();
330
331 assert_eq!(dirty.len(), FxHashSet::from_iter(&dirty).len());
332
333 hotpath::measure_block!("dirty run", {
334 for (node_id, flags) in dirty {
335 let element = self.elements.get(&node_id).unwrap();
336 let height_b = self.heights.get(&node_id).unwrap();
337
338 if flags.contains(DiffModifies::REORDER_LAYOUT) {
339 self.layout
340 .invalidate_with_reason(node_id, DirtyReason::Reorder);
341 }
342
343 if flags.contains(DiffModifies::INNER_LAYOUT) {
344 self.layout
345 .invalidate_with_reason(node_id, DirtyReason::InnerLayout);
346 }
347
348 if flags.contains(DiffModifies::LAYOUT) {
349 self.layout.invalidate(node_id);
350 }
351
352 if !needs_render
353 && (flags.intersects(
354 DiffModifies::STYLE
355 | DiffModifies::LAYER
356 | DiffModifies::EFFECT
357 | DiffModifies::TEXT_STYLE
358 | DiffModifies::LAYOUT
359 | DiffModifies::INNER_LAYOUT
360 | DiffModifies::REORDER_LAYOUT,
361 ))
362 {
363 needs_render = true;
364 }
365
366 if !needs_accessibility && (flags.intersects(DiffModifies::ACCESSIBILITY)) {
367 needs_accessibility = true;
368 }
369
370 if flags.contains(DiffModifies::ACCESSIBILITY) {
371 match self.accessibility_state.get_mut(&node_id) {
372 Some(accessibility_state) => accessibility_state.update(
373 node_id,
374 element,
375 &mut self.accessibility_diff,
376 &mut self.accessibility_groups,
377 ),
378 None => {
379 self.accessibility_state.insert(
380 node_id,
381 AccessibilityState::create(
382 node_id,
383 element,
384 &mut self.accessibility_diff,
385 &self.accessibility_generator,
386 &mut self.accessibility_groups,
387 ),
388 );
389 }
390 }
391 }
392
393 let handle_cascade = |cascades: &mut Vec<NodeId>| {
394 if cascades.iter_mut().any(|root| {
396 let height_a = self.heights.get(root).unwrap();
397
398 match height_a.cmp(height_b) {
399 std::cmp::Ordering::Less => {
400 self.balance_heights(&node_id, root) == Some(*root)
401 }
402 std::cmp::Ordering::Greater => {
403 let balanced_root = self.balance_heights(root, &node_id);
404 match balanced_root {
405 Some(r) if r == node_id => {
406 *root = node_id;
409 true
410 }
411 _ => false,
412 }
413 }
414 std::cmp::Ordering::Equal => false,
415 }
416 }) {
417 return;
418 }
419 cascades.push(node_id);
420 };
421
422 if flags.intersects(DiffModifies::LAYER) {
423 handle_cascade(&mut layer_cascades);
424 }
425 if flags.intersects(DiffModifies::EFFECT | DiffModifies::LAYER) {
426 let element = self.elements.get(&node_id).unwrap();
427 let run_cascade = element.effect().is_some()
429 || self
430 .parents
431 .get(&node_id)
432 .map(|parent| self.effect_state.contains_key(parent))
433 .unwrap_or_default();
434 if run_cascade {
435 handle_cascade(&mut effects_cascades);
436 }
437 }
438 if flags.intersects(DiffModifies::TEXT_STYLE) {
439 handle_cascade(&mut text_style_cascades);
440 }
441 }
442 });
443
444 hotpath::measure_block!("layer cascade", {
445 for layer_root in layer_cascades {
447 let mut buffer = VecDeque::new();
448 buffer.push_front(&layer_root);
449
450 while let Some(node_id) = buffer.pop_front() {
451 let element = self.elements.get(node_id).unwrap();
452 if let Some(parent_node_id) = self.parents.get(node_id) {
453 let entries = self
454 .layer_state
455 .get_disjoint_entries([node_id, parent_node_id], |_id| {
456 LayerState::default()
457 });
458 if let Some([layer_state, parent_layer_state]) = entries {
459 layer_state.update(
460 parent_layer_state,
461 *node_id,
462 element,
463 &mut self.layers,
464 );
465 }
466 } else {
467 assert_eq!(*node_id, NodeId::ROOT);
468 self.layer_state.insert(
469 NodeId::ROOT,
470 LayerState::create_for_root(*node_id, &mut self.layers),
471 );
472 }
473 if let Some(children) = self.children.get(node_id) {
474 buffer.extend(children);
475 }
476 }
477 }
478 });
479
480 hotpath::measure_block!("effect cascade", {
481 for effect_root in effects_cascades {
483 let mut buffer = VecDeque::new();
484 buffer.push_front(&effect_root);
485
486 while let Some(node_id) = buffer.pop_front() {
487 let element = self.elements.get(node_id).unwrap();
488 if let Some(parent_node_id) = self.parents.get(node_id) {
489 let entries = self.effect_state.get_disjoint_two_entries(
490 parent_node_id,
491 node_id,
492 |_id| EffectState::default(),
493 |left, _id| left.clone(),
494 );
495 if let [Some(parent_effect_state), Some(effect_state)] = entries {
496 let effect_data = element.effect();
497 let layer = element.layer();
498 effect_state.update(
499 *parent_node_id,
500 parent_effect_state,
501 *node_id,
502 effect_data,
503 layer,
504 );
505 }
506 } else {
507 assert_eq!(*node_id, NodeId::ROOT);
508 }
509 if let Some(children) = self.children.get(node_id) {
510 buffer.extend(children);
511 }
512 }
513 }
514 });
515
516 hotpath::measure_block!("text style cascade", {
517 for text_style_root in text_style_cascades {
519 let mut buffer = VecDeque::new();
520 buffer.push_front(&text_style_root);
521
522 while let Some(node_id) = buffer.pop_front() {
523 let element = self.elements.get(node_id).unwrap();
524 if let Some(parent_node_id) = self.parents.get(node_id) {
525 let entries = self
526 .text_style_state
527 .get_disjoint_entries([node_id, parent_node_id], |_id| {
528 TextStyleState::default()
529 });
530 if let Some([text_style_state, parent_text_style_state]) = entries {
531 text_style_state.update(
532 *node_id,
533 parent_text_style_state,
534 element,
535 &mut self.layout,
536 );
537 }
538 } else {
539 assert_eq!(*node_id, NodeId::ROOT);
540 self.text_style_state
541 .insert(NodeId::ROOT, TextStyleState::default());
542 }
543 if let Some(children) = self.children.get(node_id) {
544 buffer.extend(children);
545 }
546 }
547 }
548
549 #[cfg(all(debug_assertions, feature = "debug-integrity"))]
550 self.verify_tree_integrity();
551 });
552
553 MutationsApplyResult {
554 needs_render,
555 needs_accessibility,
556 }
557 }
558
559 fn balance_heights(&self, base: &NodeId, target: &NodeId) -> Option<NodeId> {
561 let target_height = self.heights.get(target)?;
562 let mut current = base;
563 loop {
564 if self.heights.get(current)? == target_height {
565 break;
566 }
567
568 let parent_current = self.parents.get(current);
569 if let Some(parent_current) = parent_current {
570 current = parent_current;
571 }
572 }
573 Some(*current)
574 }
575
576 pub fn measure_layout(
577 &mut self,
578 size: Size2D,
579 font_collection: &mut FontCollection,
580 font_manager: &FontMgr,
581 events_sender: &UnboundedSender<EventsChunk>,
582 scale_factor: f64,
583 fallback_fonts: &[Cow<'static, str>],
584 ) {
585 let mut tree_adapter = TreeAdapterFreya {
586 elements: &self.elements,
587 parents: &self.parents,
588 children: &self.children,
589 heights: &self.heights,
590 scale_factor,
591 };
592
593 let mut events = Vec::new();
594
595 let layout_adapter = LayoutMeasurerAdapter {
596 elements: &self.elements,
597 text_style_state: &self.text_style_state,
598 font_collection,
599 font_manager,
600 events: &mut events,
601 scale_factor,
602 fallback_fonts,
603 text_cache: &mut self.text_cache,
604 };
605
606 self.layout.find_best_root(&mut tree_adapter);
607 self.layout.measure(
608 NodeId::ROOT,
609 Area::from_size(size),
610 &mut Some(layout_adapter),
611 &mut tree_adapter,
612 );
613 events_sender
614 .unbounded_send(EventsChunk::Batch(events))
615 .unwrap();
616 }
617
618 pub fn print_ascii(&self, node_id: NodeId, prefix: String, last: bool) {
619 let height = self.heights.get(&node_id).unwrap();
620 let layer = self.layer_state.get(&node_id).unwrap();
621
622 println!(
624 "{}{}{:?} [{}] ({})",
625 prefix,
626 if last { "└── " } else { "├── " },
627 node_id,
628 height,
629 layer.layer
630 );
631
632 if let Some(children) = self.children.get(&node_id) {
634 let len = children.len();
635 for (i, child) in children.iter().enumerate() {
636 let is_last = i == len - 1;
637 let new_prefix = format!("{}{}", prefix, if last { " " } else { "│ " });
639 self.print_ascii(*child, new_prefix, is_last);
640 }
641 }
642 }
643
644 #[cfg(all(debug_assertions, feature = "debug-integrity"))]
645 #[cfg_attr(feature = "hotpath", hotpath::measure)]
646 pub fn verify_tree_integrity(&self) {
647 let mut visited = FxHashSet::default();
648 let size = self.elements.len();
649 let mut buffer = vec![NodeId::ROOT];
650 while let Some(node_id) = buffer.pop() {
651 if visited.contains(&node_id) {
652 continue;
653 }
654 visited.insert(node_id);
655 if let Some(parent) = self.parents.get(&node_id) {
656 buffer.push(*parent);
657 }
658 if let Some(children) = self.children.get(&node_id) {
659 buffer.extend(children);
660 }
661 }
662 assert_eq!(size, visited.len())
663 }
664}
665
666bitflags! {
667 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
668 pub struct DiffModifies: u32 {
669 const LAYOUT = 1 << 0;
670 const STYLE = 1 << 1;
671 const ACCESSIBILITY = 1 << 2;
672 const EVENT_HANDLERS = 1 << 3;
673 const LAYER = 1 << 4;
674 const TEXT_STYLE = 1 << 5;
675 const EFFECT = 1 << 6;
676 const INNER_LAYOUT = 1 << 7;
677 const REORDER_LAYOUT = 1 << 8;
678 }
679}
680
681pub struct MutationsApplyResult {
682 pub needs_render: bool,
683 pub needs_accessibility: bool,
684}
685
686pub struct LayoutMeasurerAdapter<'a> {
687 pub font_collection: &'a mut FontCollection,
688 pub font_manager: &'a FontMgr,
689 elements: &'a FxHashMap<NodeId, Rc<dyn ElementExt>>,
690 text_style_state: &'a FxHashMap<NodeId, TextStyleState>,
691 events: &'a mut Vec<EmmitableEvent>,
692 scale_factor: f64,
693 fallback_fonts: &'a [Cow<'static, str>],
694 text_cache: &'a mut TextCache,
695}
696
697impl LayoutMeasurer<NodeId> for LayoutMeasurerAdapter<'_> {
698 fn measure(
699 &mut self,
700 node_id: NodeId,
701 torin_node: &torin::node::Node,
702 area_size: &Size2D,
703 ) -> Option<(Size2D, Rc<dyn Any>)> {
704 self.elements.get(&node_id)?.measure(LayoutContext {
705 node_id,
706 torin_node,
707 area_size,
708 font_collection: self.font_collection,
709 font_manager: self.font_manager,
710 text_style_state: self.text_style_state.get(&node_id).unwrap(),
711 scale_factor: self.scale_factor,
712 fallback_fonts: self.fallback_fonts,
713 text_cache: self.text_cache,
714 })
715 }
716
717 fn should_hook_measurement(&mut self, node_id: NodeId) -> bool {
718 if let Some(element) = self.elements.get(&node_id) {
719 element.should_hook_measurement()
720 } else {
721 false
722 }
723 }
724
725 fn should_measure_inner_children(&mut self, node_id: NodeId) -> bool {
726 if let Some(element) = self.elements.get(&node_id) {
727 element.should_measure_inner_children()
728 } else {
729 false
730 }
731 }
732
733 fn should_post_measure(&mut self, node_id: NodeId) -> bool {
734 self.elements
735 .get(&node_id)
736 .is_some_and(|element| element.needs_post_measure())
737 }
738
739 fn post_measure(
740 &mut self,
741 node_id: NodeId,
742 node_layout: &LayoutNode,
743 children: &[NodeId],
744 layout: &Torin<NodeId>,
745 ) -> PostMeasure<NodeId> {
746 self.elements
747 .get(&node_id)
748 .unwrap()
749 .post_measure(PostMeasureContext {
750 node_layout,
751 children,
752 layout,
753 font_collection: self.font_collection,
754 text_style_state: self.text_style_state.get(&node_id).unwrap(),
755 fallback_fonts: self.fallback_fonts,
756 scale_factor: self.scale_factor,
757 })
758 }
759
760 fn notify_layout_references(
761 &mut self,
762 node_id: NodeId,
763 area: Area,
764 visible_area: Area,
765 inner_sizes: Size2D,
766 ) {
767 let mut data = SizedEventData::new(area, visible_area, inner_sizes);
768 data.div(self.scale_factor as f32);
769 self.events.push(EmmitableEvent {
770 node_id,
771 name: EventName::Sized,
772 data: EventType::Sized(data),
773 bubbles: false,
774 source_event: EventName::Sized,
775 });
776 }
777}