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