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