Skip to main content

freya_core/
tree.rs

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