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