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