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