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