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