azul_core/
styled_dom.rs

1use alloc::{boxed::Box, collections::btree_map::BTreeMap, string::String, vec::Vec};
2use core::{
3    fmt,
4    hash::{Hash, Hasher},
5};
6
7use azul_css::{
8    parser::CssApiWrapper, AzString, Css, CssPath, CssProperty, CssPropertyType,
9    LayoutAlignContentValue, LayoutAlignItemsValue, LayoutBorderBottomWidthValue,
10    LayoutBorderLeftWidthValue, LayoutBorderRightWidthValue, LayoutBorderTopWidthValue,
11    LayoutBottomValue, LayoutBoxSizingValue, LayoutDisplayValue, LayoutFlexDirectionValue,
12    LayoutFlexGrowValue, LayoutFlexShrinkValue, LayoutFlexWrapValue, LayoutFloatValue,
13    LayoutHeightValue, LayoutJustifyContentValue, LayoutLeftValue, LayoutMarginBottomValue,
14    LayoutMarginLeftValue, LayoutMarginRightValue, LayoutMarginTopValue, LayoutMaxHeightValue,
15    LayoutMaxWidthValue, LayoutMinHeightValue, LayoutMinWidthValue, LayoutOverflowValue,
16    LayoutPaddingBottomValue, LayoutPaddingLeftValue, LayoutPaddingRightValue,
17    LayoutPaddingTopValue, LayoutPositionValue, LayoutRightValue, LayoutTopValue, LayoutWidthValue,
18    StyleBackfaceVisibilityValue, StyleBackgroundContentVecValue, StyleBackgroundPositionVecValue,
19    StyleBackgroundRepeatVecValue, StyleBackgroundSizeVecValue, StyleBorderBottomColorValue,
20    StyleBorderBottomLeftRadiusValue, StyleBorderBottomRightRadiusValue,
21    StyleBorderBottomStyleValue, StyleBorderLeftColorValue, StyleBorderLeftStyleValue,
22    StyleBorderRightColorValue, StyleBorderRightStyleValue, StyleBorderTopColorValue,
23    StyleBorderTopLeftRadiusValue, StyleBorderTopRightRadiusValue, StyleBorderTopStyleValue,
24    StyleBoxShadowValue, StyleCursorValue, StyleFilterVecValue, StyleFontFamily,
25    StyleFontFamilyVec, StyleFontFamilyVecValue, StyleFontSize, StyleFontSizeValue,
26    StyleLetterSpacingValue, StyleLineHeightValue, StyleMixBlendModeValue, StyleOpacityValue,
27    StylePerspectiveOriginValue, StyleTabWidthValue, StyleTextAlignValue, StyleTextColor,
28    StyleTextColorValue, StyleTransformOriginValue, StyleTransformVecValue, StyleWordSpacingValue,
29};
30
31use crate::{
32    app_resources::{Au, ImageCache, ImageRef, ImmediateFontId, RendererResources},
33    callbacks::{CallbackInfo, RefAny, Update},
34    dom::{
35        CompactDom, Dom, NodeData, NodeDataInlineCssProperty, NodeDataVec, OptionTabIndex,
36        TabIndex, TagId,
37    },
38    id_tree::{Node, NodeDataContainer, NodeDataContainerRef, NodeDataContainerRefMut, NodeId},
39    style::{
40        construct_html_cascade_tree, matches_html_element, rule_ends_with, CascadeInfo,
41        CascadeInfoVec,
42    },
43    window::Menu,
44    FastBTreeSet, FastHashMap,
45};
46
47#[repr(C)]
48#[derive(Debug, Clone, PartialEq, Hash, PartialOrd, Eq, Ord)]
49pub struct ChangedCssProperty {
50    pub previous_state: StyledNodeState,
51    pub previous_prop: CssProperty,
52    pub current_state: StyledNodeState,
53    pub current_prop: CssProperty,
54}
55
56impl_vec!(
57    ChangedCssProperty,
58    ChangedCssPropertyVec,
59    ChangedCssPropertyVecDestructor
60);
61impl_vec_debug!(ChangedCssProperty, ChangedCssPropertyVec);
62impl_vec_partialord!(ChangedCssProperty, ChangedCssPropertyVec);
63impl_vec_clone!(
64    ChangedCssProperty,
65    ChangedCssPropertyVec,
66    ChangedCssPropertyVecDestructor
67);
68impl_vec_partialeq!(ChangedCssProperty, ChangedCssPropertyVec);
69
70#[repr(C, u8)]
71#[derive(Debug, Clone, PartialEq, Hash, PartialOrd, Eq, Ord)]
72pub enum CssPropertySource {
73    Css(CssPath),
74    Inline,
75}
76
77/// NOTE: multiple states can be active at
78///
79/// TODO: use bitflags here!
80#[repr(C)]
81#[derive(Clone, PartialEq, Hash, PartialOrd, Eq, Ord)]
82pub struct StyledNodeState {
83    pub normal: bool,
84    pub hover: bool,
85    pub active: bool,
86    pub focused: bool,
87}
88
89impl core::fmt::Debug for StyledNodeState {
90    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
91        let mut v = Vec::new();
92        if self.normal {
93            v.push("normal");
94        }
95        if self.hover {
96            v.push("hover");
97        }
98        if self.active {
99            v.push("active");
100        }
101        if self.focused {
102            v.push("focused");
103        }
104        write!(f, "{:?}", v)
105    }
106}
107
108impl Default for StyledNodeState {
109    fn default() -> StyledNodeState {
110        Self::new()
111    }
112}
113
114impl StyledNodeState {
115    pub const fn new() -> Self {
116        StyledNodeState {
117            normal: true,
118            hover: false,
119            active: false,
120            focused: false,
121        }
122    }
123}
124
125/// A styled Dom node
126#[repr(C)]
127#[derive(Debug, Default, Clone, PartialEq, PartialOrd)]
128pub struct StyledNode {
129    /// Current state of this styled node (used later for caching the style / layout)
130    pub state: StyledNodeState,
131    /// Optional tag ID
132    ///
133    /// NOTE: The tag ID has to be adjusted after the layout is done (due to scroll tags)
134    pub tag_id: OptionTagId,
135}
136
137impl_vec!(StyledNode, StyledNodeVec, StyledNodeVecDestructor);
138impl_vec_mut!(StyledNode, StyledNodeVec);
139impl_vec_debug!(StyledNode, StyledNodeVec);
140impl_vec_partialord!(StyledNode, StyledNodeVec);
141impl_vec_clone!(StyledNode, StyledNodeVec, StyledNodeVecDestructor);
142impl_vec_partialeq!(StyledNode, StyledNodeVec);
143
144impl StyledNodeVec {
145    pub fn as_container<'a>(&'a self) -> NodeDataContainerRef<'a, StyledNode> {
146        NodeDataContainerRef {
147            internal: self.as_ref(),
148        }
149    }
150    pub fn as_container_mut<'a>(&'a mut self) -> NodeDataContainerRefMut<'a, StyledNode> {
151        NodeDataContainerRefMut {
152            internal: self.as_mut(),
153        }
154    }
155}
156
157#[repr(C)]
158#[derive(Debug, PartialEq, Clone)]
159pub struct CssPropertyCachePtr {
160    pub ptr: Box<CssPropertyCache>,
161    pub run_destructor: bool,
162}
163
164impl CssPropertyCachePtr {
165    pub fn new(cache: CssPropertyCache) -> Self {
166        Self {
167            ptr: Box::new(cache),
168            run_destructor: true,
169        }
170    }
171    fn downcast_mut<'a>(&'a mut self) -> &'a mut CssPropertyCache {
172        &mut *self.ptr
173    }
174}
175
176impl Drop for CssPropertyCachePtr {
177    fn drop(&mut self) {
178        self.run_destructor = false;
179    }
180}
181
182// NOTE: To avoid large memory allocations, this is a "cache" that stores all the CSS properties
183// found in the DOM. This cache exists on a per-DOM basis, so it scales independent of how many
184// nodes are in the DOM.
185//
186// If each node would carry its own CSS properties, that would unnecessarily consume memory
187// because most nodes use the default properties or override only one or two properties.
188//
189// The cache can compute the property of any node at any given time, given the current node
190// state (hover, active, focused, normal). This way we don't have to duplicate the CSS properties
191// onto every single node and exchange them when the style changes. Two caches can be appended
192// to each other by simply merging their NodeIds.
193#[derive(Debug, Default, Clone, PartialEq)]
194pub struct CssPropertyCache {
195    // number of nodes in the current DOM
196    pub node_count: usize,
197
198    // properties that were overridden in callbacks (not specific to any node state)
199    pub user_overridden_properties: BTreeMap<NodeId, BTreeMap<CssPropertyType, CssProperty>>,
200
201    // non-default CSS properties that were cascaded from the parent
202    pub cascaded_normal_props: BTreeMap<NodeId, BTreeMap<CssPropertyType, CssProperty>>,
203    pub cascaded_hover_props: BTreeMap<NodeId, BTreeMap<CssPropertyType, CssProperty>>,
204    pub cascaded_active_props: BTreeMap<NodeId, BTreeMap<CssPropertyType, CssProperty>>,
205    pub cascaded_focus_props: BTreeMap<NodeId, BTreeMap<CssPropertyType, CssProperty>>,
206
207    // non-default CSS properties that were set via a CSS file
208    pub css_normal_props: BTreeMap<NodeId, BTreeMap<CssPropertyType, CssProperty>>,
209    pub css_hover_props: BTreeMap<NodeId, BTreeMap<CssPropertyType, CssProperty>>,
210    pub css_active_props: BTreeMap<NodeId, BTreeMap<CssPropertyType, CssProperty>>,
211    pub css_focus_props: BTreeMap<NodeId, BTreeMap<CssPropertyType, CssProperty>>,
212}
213
214impl CssPropertyCache {
215    /// Restyles the CSS property cache with a new CSS file
216    #[must_use]
217    pub fn restyle(
218        &mut self,
219        css: &mut Css,
220        node_data: &NodeDataContainerRef<NodeData>,
221        node_hierarchy: &NodeHierarchyItemVec,
222        non_leaf_nodes: &ParentWithNodeDepthVec,
223        html_tree: &NodeDataContainerRef<CascadeInfo>,
224    ) -> Vec<TagIdToNodeIdMapping> {
225        use azul_css::{CssDeclaration, CssPathPseudoSelector::*, LayoutDisplay};
226
227        let css_is_empty = css.is_empty();
228
229        if !css_is_empty {
230            css.sort_by_specificity();
231
232            macro_rules! filter_rules {($expected_pseudo_selector:expr, $node_id:expr) => {{
233                css
234                .rules() // can not be parallelized due to specificity order matching
235                .filter(|rule_block| rule_ends_with(&rule_block.path, $expected_pseudo_selector))
236                .filter(|rule_block| matches_html_element(
237                    &rule_block.path,
238                    $node_id,
239                    &node_hierarchy.as_container(),
240                    &node_data,
241                    &html_tree,
242                    $expected_pseudo_selector
243                ))
244                // rule matched, now copy all the styles of this rule
245                .flat_map(|matched_rule| {
246                    matched_rule.declarations
247                    .iter()
248                    .filter_map(move |declaration| {
249                        match declaration {
250                            CssDeclaration::Static(s) => Some(s),
251                            CssDeclaration::Dynamic(_d) => None, // TODO: No variable support yet!
252                        }
253                    })
254                })
255                .map(|prop| prop.clone())
256                .collect::<Vec<CssProperty>>()
257            }};}
258
259            // NOTE: This is wrong, but fast
260            //
261            // Get all nodes that end with `:hover`, `:focus` or `:active`
262            // and copy the respective styles to the `hover_css_constraints`, etc. respectively
263            //
264            // NOTE: This won't work correctly for paths with `.blah:hover > #thing`
265            // but that can be fixed later
266
267            // go through each HTML node (in parallel) and see which CSS rules match
268            let css_normal_rules: NodeDataContainer<(NodeId, Vec<CssProperty>)> = node_data
269                .transform_nodeid_multithreaded_optional(|node_id| {
270                    let r = filter_rules!(None, node_id);
271                    if r.is_empty() {
272                        None
273                    } else {
274                        Some((node_id, r))
275                    }
276                });
277
278            let css_hover_rules: NodeDataContainer<(NodeId, Vec<CssProperty>)> = node_data
279                .transform_nodeid_multithreaded_optional(|node_id| {
280                    let r = filter_rules!(Some(Hover), node_id);
281                    if r.is_empty() {
282                        None
283                    } else {
284                        Some((node_id, r))
285                    }
286                });
287
288            let css_active_rules: NodeDataContainer<(NodeId, Vec<CssProperty>)> = node_data
289                .transform_nodeid_multithreaded_optional(|node_id| {
290                    let r = filter_rules!(Some(Active), node_id);
291                    if r.is_empty() {
292                        None
293                    } else {
294                        Some((node_id, r))
295                    }
296                });
297
298            let css_focus_rules: NodeDataContainer<(NodeId, Vec<CssProperty>)> = node_data
299                .transform_nodeid_multithreaded_optional(|node_id| {
300                    let r = filter_rules!(Some(Focus), node_id);
301                    if r.is_empty() {
302                        None
303                    } else {
304                        Some((node_id, r))
305                    }
306                });
307
308            self.css_normal_props = css_normal_rules
309                .internal
310                .into_iter()
311                .map(|(n, map)| {
312                    (
313                        n,
314                        map.into_iter()
315                            .map(|prop| (prop.get_type(), prop))
316                            .collect(),
317                    )
318                })
319                .collect();
320
321            self.css_hover_props = css_hover_rules
322                .internal
323                .into_iter()
324                .map(|(n, map)| {
325                    (
326                        n,
327                        map.into_iter()
328                            .map(|prop| (prop.get_type(), prop))
329                            .collect(),
330                    )
331                })
332                .collect();
333
334            self.css_active_props = css_active_rules
335                .internal
336                .into_iter()
337                .map(|(n, map)| {
338                    (
339                        n,
340                        map.into_iter()
341                            .map(|prop| (prop.get_type(), prop))
342                            .collect(),
343                    )
344                })
345                .collect();
346
347            self.css_focus_props = css_focus_rules
348                .internal
349                .into_iter()
350                .map(|(n, map)| {
351                    (
352                        n,
353                        map.into_iter()
354                            .map(|prop| (prop.get_type(), prop))
355                            .collect(),
356                    )
357                })
358                .collect();
359        }
360
361        // Inheritance: Inherit all values of the parent to the children, but
362        // only if the property is inheritable and isn't yet set
363        for ParentWithNodeDepth { depth: _, node_id } in non_leaf_nodes.iter() {
364            let parent_id = match node_id.into_crate_internal() {
365                Some(s) => s,
366                None => continue,
367            };
368
369            // Inherit CSS properties from map A -> map B
370            // map B will be populated with all inherited CSS properties
371            macro_rules! inherit_props {
372                ($from_inherit_map:expr, $to_inherit_map:expr) => {
373                    let parent_inheritable_css_props =
374                        $from_inherit_map.get(&parent_id).and_then(|map| {
375                            let parent_inherit_props = map
376                                .iter()
377                                .filter(|(css_prop_type, _)| css_prop_type.is_inheritable())
378                                .map(|(css_prop_type, css_prop)| (*css_prop_type, css_prop.clone()))
379                                .collect::<Vec<(CssPropertyType, CssProperty)>>();
380                            if parent_inherit_props.is_empty() {
381                                None
382                            } else {
383                                Some(parent_inherit_props)
384                            }
385                        });
386
387                    match parent_inheritable_css_props {
388                        Some(pi) => {
389                            // only override the rule if the child does not already have an
390                            // inherited rule
391                            for child_id in parent_id.az_children(&node_hierarchy.as_container()) {
392                                let child_map = $to_inherit_map
393                                    .entry(child_id)
394                                    .or_insert_with(|| BTreeMap::new());
395
396                                for (inherited_rule_type, inherited_rule_value) in pi.iter() {
397                                    let _ = child_map
398                                        .entry(*inherited_rule_type)
399                                        .or_insert_with(|| inherited_rule_value.clone());
400                                }
401                            }
402                        }
403                        None => {}
404                    }
405                };
406            }
407
408            // Same as inherit_props, but filters along the inline node data instead
409            macro_rules! inherit_inline_css_props {($filter_type:ident, $to_inherit_map:expr) => {
410                let parent_inheritable_css_props = &node_data[parent_id]
411                .inline_css_props
412                .iter()
413                 // test whether the property is a [normal, hover, focus, active] property
414                .filter_map(|css_prop| if let NodeDataInlineCssProperty::$filter_type(p) = css_prop { Some(p) } else { None })
415                // test whether the property is inheritable
416                .filter(|css_prop| css_prop.get_type().is_inheritable())
417                .cloned()
418                .collect::<Vec<CssProperty>>();
419
420                if !parent_inheritable_css_props.is_empty() {
421                    // only override the rule if the child does not already have an inherited rule
422                    for child_id in parent_id.az_children(&node_hierarchy.as_container()) {
423                        let child_map = $to_inherit_map.entry(child_id).or_insert_with(|| BTreeMap::new());
424                        for inherited_rule in parent_inheritable_css_props.iter() {
425                            let _ = child_map
426                            .entry(inherited_rule.get_type())
427                            .or_insert_with(|| inherited_rule.clone());
428                        }
429                    }
430                }
431
432            };}
433
434            // strongest inheritance first
435
436            // Inherit inline CSS properties
437            inherit_inline_css_props!(Normal, self.cascaded_normal_props);
438            inherit_inline_css_props!(Hover, self.cascaded_hover_props);
439            inherit_inline_css_props!(Active, self.cascaded_active_props);
440            inherit_inline_css_props!(Focus, self.cascaded_focus_props);
441
442            // Inherit the CSS properties from the CSS file
443            if !css_is_empty {
444                inherit_props!(self.css_normal_props, self.cascaded_normal_props);
445                inherit_props!(self.css_hover_props, self.cascaded_hover_props);
446                inherit_props!(self.css_active_props, self.cascaded_active_props);
447                inherit_props!(self.css_focus_props, self.cascaded_focus_props);
448            }
449
450            // Inherit properties that were inherited in a previous iteration of the loop
451            inherit_props!(self.cascaded_normal_props, self.cascaded_normal_props);
452            inherit_props!(self.cascaded_hover_props, self.cascaded_hover_props);
453            inherit_props!(self.cascaded_active_props, self.cascaded_active_props);
454            inherit_props!(self.cascaded_focus_props, self.cascaded_focus_props);
455        }
456
457        // When restyling, the tag / node ID mappings may change, regenerate them
458        // See if the node should have a hit-testing tag ID
459        let default_node_state = StyledNodeState::default();
460
461        // In order to hit-test `:hover` and `:active` selectors,
462        // we need to insert "tag IDs" for all rectangles
463        // that have a non-normal path ending, for example if we have
464        // `#thing:hover`, then all nodes selected by `#thing`
465        // need to get a TagId, otherwise, they can't be hit-tested.
466
467        // NOTE: restyling a DOM may change the :hover nodes, which is
468        // why the tag IDs have to be re-generated on every .restyle() call!
469        node_data
470            .internal
471            .iter()
472            .enumerate()
473            .filter_map(|(node_id, node_data)| {
474                let node_id = NodeId::new(node_id);
475
476                let should_auto_insert_tabindex = node_data
477                    .get_callbacks()
478                    .iter()
479                    .any(|cb| cb.event.is_focus_callback());
480
481                let tab_index = match node_data.get_tab_index() {
482                    Some(s) => Some(*s),
483                    None => {
484                        if should_auto_insert_tabindex {
485                            Some(TabIndex::Auto)
486                        } else {
487                            None
488                        }
489                    }
490                };
491
492                let mut node_should_have_tag = false;
493
494                // workaround for "goto end" - early break if
495                // one of the conditions is true
496                loop {
497                    // check for display: none
498                    let display = self
499                        .get_display(&node_data, &node_id, &default_node_state)
500                        .and_then(|p| p.get_property_or_default())
501                        .unwrap_or_default();
502
503                    if display == LayoutDisplay::None {
504                        node_should_have_tag = false;
505                        break;
506                    }
507
508                    if node_data.has_context_menu() {
509                        node_should_have_tag = true;
510                        break;
511                    }
512
513                    if tab_index.is_some() {
514                        node_should_have_tag = true;
515                        break;
516                    }
517
518                    // check for context menu
519                    if node_data.get_context_menu().is_some() {
520                        node_should_have_tag = true;
521                        break;
522                    }
523
524                    // check for :hover
525                    let node_has_hover_props =
526                        node_data.inline_css_props.as_ref().iter().any(|p| match p {
527                            NodeDataInlineCssProperty::Hover(_) => true,
528                            _ => false,
529                        }) || self.css_hover_props.get(&node_id).is_some()
530                            || self.cascaded_hover_props.get(&node_id).is_some();
531
532                    if node_has_hover_props {
533                        node_should_have_tag = true;
534                        break;
535                    }
536
537                    // check for :active
538                    let node_has_active_props =
539                        node_data.inline_css_props.as_ref().iter().any(|p| match p {
540                            NodeDataInlineCssProperty::Active(_) => true,
541                            _ => false,
542                        }) || self.css_active_props.get(&node_id).is_some()
543                            || self.cascaded_active_props.get(&node_id).is_some();
544
545                    if node_has_active_props {
546                        node_should_have_tag = true;
547                        break;
548                    }
549
550                    // check for :focus
551                    let node_has_focus_props =
552                        node_data.inline_css_props.as_ref().iter().any(|p| match p {
553                            NodeDataInlineCssProperty::Focus(_) => true,
554                            _ => false,
555                        }) || self.css_focus_props.get(&node_id).is_some()
556                            || self.cascaded_focus_props.get(&node_id).is_some();
557
558                    if node_has_focus_props {
559                        node_should_have_tag = true;
560                        break;
561                    }
562
563                    // check whether any Hover(), Active() or Focus() callbacks are present
564                    let node_only_window_callbacks = node_data.get_callbacks().is_empty()
565                        || node_data
566                            .get_callbacks()
567                            .iter()
568                            .all(|cb| cb.event.is_window_callback());
569
570                    if !node_only_window_callbacks {
571                        node_should_have_tag = true;
572                        break;
573                    }
574
575                    // check for non-default cursor: property - needed for hit-testing cursor
576                    let node_has_non_default_cursor = self
577                        .get_cursor(&node_data, &node_id, &default_node_state)
578                        .is_some();
579
580                    if node_has_non_default_cursor {
581                        node_should_have_tag = true;
582                        break;
583                    }
584
585                    break;
586                }
587
588                if !node_should_have_tag {
589                    None
590                } else {
591                    Some(TagIdToNodeIdMapping {
592                        tag_id: AzTagId::from_crate_internal(TagId::unique()),
593                        node_id: NodeHierarchyItemId::from_crate_internal(Some(node_id)),
594                        tab_index: tab_index.into(),
595                        parent_node_ids: {
596                            let mut parents = Vec::new();
597                            let mut cur_parent = node_hierarchy.as_container()[node_id].parent_id();
598                            while let Some(c) = cur_parent.clone() {
599                                parents.push(NodeHierarchyItemId::from_crate_internal(Some(c)));
600                                cur_parent = node_hierarchy.as_container()[c].parent_id();
601                            }
602                            parents.reverse(); // parents sorted in depth-increasing order
603                            parents.into()
604                        },
605                    })
606                }
607            })
608            .collect()
609    }
610
611    pub fn get_computed_css_style_string(
612        &self,
613        node_data: &NodeData,
614        node_id: &NodeId,
615        node_state: &StyledNodeState,
616    ) -> String {
617        let mut s = String::new();
618        if let Some(p) = self.get_background_content(&node_data, node_id, node_state) {
619            s.push_str(&format!("background: {};", p.get_css_value_fmt()));
620        }
621        if let Some(p) = self.get_background_position(&node_data, node_id, node_state) {
622            s.push_str(&format!("background-position: {};", p.get_css_value_fmt()));
623        }
624        if let Some(p) = self.get_background_size(&node_data, node_id, node_state) {
625            s.push_str(&format!("background-size: {};", p.get_css_value_fmt()));
626        }
627        if let Some(p) = self.get_background_repeat(&node_data, node_id, node_state) {
628            s.push_str(&format!("background-repeat: {};", p.get_css_value_fmt()));
629        }
630        if let Some(p) = self.get_font_size(&node_data, node_id, node_state) {
631            s.push_str(&format!("font-size: {};", p.get_css_value_fmt()));
632        }
633        if let Some(p) = self.get_font_family(&node_data, node_id, node_state) {
634            s.push_str(&format!("font-family: {};", p.get_css_value_fmt()));
635        }
636        if let Some(p) = self.get_text_color(&node_data, node_id, node_state) {
637            s.push_str(&format!("color: {};", p.get_css_value_fmt()));
638        }
639        if let Some(p) = self.get_text_align(&node_data, node_id, node_state) {
640            s.push_str(&format!("text-align: {};", p.get_css_value_fmt()));
641        }
642        if let Some(p) = self.get_line_height(&node_data, node_id, node_state) {
643            s.push_str(&format!("line-height: {};", p.get_css_value_fmt()));
644        }
645        if let Some(p) = self.get_letter_spacing(&node_data, node_id, node_state) {
646            s.push_str(&format!("letter-spacing: {};", p.get_css_value_fmt()));
647        }
648        if let Some(p) = self.get_word_spacing(&node_data, node_id, node_state) {
649            s.push_str(&format!("word-spacing: {};", p.get_css_value_fmt()));
650        }
651        if let Some(p) = self.get_tab_width(&node_data, node_id, node_state) {
652            s.push_str(&format!("tab-width: {};", p.get_css_value_fmt()));
653        }
654        if let Some(p) = self.get_cursor(&node_data, node_id, node_state) {
655            s.push_str(&format!("cursor: {};", p.get_css_value_fmt()));
656        }
657        if let Some(p) = self.get_box_shadow_left(&node_data, node_id, node_state) {
658            s.push_str(&format!(
659                "-azul-box-shadow-left: {};",
660                p.get_css_value_fmt()
661            ));
662        }
663        if let Some(p) = self.get_box_shadow_right(&node_data, node_id, node_state) {
664            s.push_str(&format!(
665                "-azul-box-shadow-right: {};",
666                p.get_css_value_fmt()
667            ));
668        }
669        if let Some(p) = self.get_box_shadow_top(&node_data, node_id, node_state) {
670            s.push_str(&format!("-azul-box-shadow-top: {};", p.get_css_value_fmt()));
671        }
672        if let Some(p) = self.get_box_shadow_bottom(&node_data, node_id, node_state) {
673            s.push_str(&format!(
674                "-azul-box-shadow-bottom: {};",
675                p.get_css_value_fmt()
676            ));
677        }
678        if let Some(p) = self.get_border_top_color(&node_data, node_id, node_state) {
679            s.push_str(&format!("border-top-color: {};", p.get_css_value_fmt()));
680        }
681        if let Some(p) = self.get_border_left_color(&node_data, node_id, node_state) {
682            s.push_str(&format!("border-left-color: {};", p.get_css_value_fmt()));
683        }
684        if let Some(p) = self.get_border_right_color(&node_data, node_id, node_state) {
685            s.push_str(&format!("border-right-color: {};", p.get_css_value_fmt()));
686        }
687        if let Some(p) = self.get_border_bottom_color(&node_data, node_id, node_state) {
688            s.push_str(&format!("border-bottom-color: {};", p.get_css_value_fmt()));
689        }
690        if let Some(p) = self.get_border_top_style(&node_data, node_id, node_state) {
691            s.push_str(&format!("border-top-style: {};", p.get_css_value_fmt()));
692        }
693        if let Some(p) = self.get_border_left_style(&node_data, node_id, node_state) {
694            s.push_str(&format!("border-left-style: {};", p.get_css_value_fmt()));
695        }
696        if let Some(p) = self.get_border_right_style(&node_data, node_id, node_state) {
697            s.push_str(&format!("border-right-style: {};", p.get_css_value_fmt()));
698        }
699        if let Some(p) = self.get_border_bottom_style(&node_data, node_id, node_state) {
700            s.push_str(&format!("border-bottom-style: {};", p.get_css_value_fmt()));
701        }
702        if let Some(p) = self.get_border_top_left_radius(&node_data, node_id, node_state) {
703            s.push_str(&format!(
704                "border-top-left-radius: {};",
705                p.get_css_value_fmt()
706            ));
707        }
708        if let Some(p) = self.get_border_top_right_radius(&node_data, node_id, node_state) {
709            s.push_str(&format!(
710                "border-top-right-radius: {};",
711                p.get_css_value_fmt()
712            ));
713        }
714        if let Some(p) = self.get_border_bottom_left_radius(&node_data, node_id, node_state) {
715            s.push_str(&format!(
716                "border-bottom-left-radius: {};",
717                p.get_css_value_fmt()
718            ));
719        }
720        if let Some(p) = self.get_border_bottom_right_radius(&node_data, node_id, node_state) {
721            s.push_str(&format!(
722                "border-bottom-right-radius: {};",
723                p.get_css_value_fmt()
724            ));
725        }
726        if let Some(p) = self.get_opacity(&node_data, node_id, node_state) {
727            s.push_str(&format!("opacity: {};", p.get_css_value_fmt()));
728        }
729        if let Some(p) = self.get_transform(&node_data, node_id, node_state) {
730            s.push_str(&format!("transform: {};", p.get_css_value_fmt()));
731        }
732        if let Some(p) = self.get_transform_origin(&node_data, node_id, node_state) {
733            s.push_str(&format!("transform-origin: {};", p.get_css_value_fmt()));
734        }
735        if let Some(p) = self.get_perspective_origin(&node_data, node_id, node_state) {
736            s.push_str(&format!("perspective-origin: {};", p.get_css_value_fmt()));
737        }
738        if let Some(p) = self.get_backface_visibility(&node_data, node_id, node_state) {
739            s.push_str(&format!("backface-visibility: {};", p.get_css_value_fmt()));
740        }
741        if let Some(p) = self.get_display(&node_data, node_id, node_state) {
742            s.push_str(&format!("display: {};", p.get_css_value_fmt()));
743        }
744        if let Some(p) = self.get_float(&node_data, node_id, node_state) {
745            s.push_str(&format!("float: {};", p.get_css_value_fmt()));
746        }
747        if let Some(p) = self.get_box_sizing(&node_data, node_id, node_state) {
748            s.push_str(&format!("box-sizing: {};", p.get_css_value_fmt()));
749        }
750        if let Some(p) = self.get_width(&node_data, node_id, node_state) {
751            s.push_str(&format!("width: {};", p.get_css_value_fmt()));
752        }
753        if let Some(p) = self.get_height(&node_data, node_id, node_state) {
754            s.push_str(&format!("height: {};", p.get_css_value_fmt()));
755        }
756        if let Some(p) = self.get_min_width(&node_data, node_id, node_state) {
757            s.push_str(&format!("min-width: {};", p.get_css_value_fmt()));
758        }
759        if let Some(p) = self.get_min_height(&node_data, node_id, node_state) {
760            s.push_str(&format!("min-height: {};", p.get_css_value_fmt()));
761        }
762        if let Some(p) = self.get_max_width(&node_data, node_id, node_state) {
763            s.push_str(&format!("max-width: {};", p.get_css_value_fmt()));
764        }
765        if let Some(p) = self.get_max_height(&node_data, node_id, node_state) {
766            s.push_str(&format!("max-height: {};", p.get_css_value_fmt()));
767        }
768        if let Some(p) = self.get_position(&node_data, node_id, node_state) {
769            s.push_str(&format!("position: {};", p.get_css_value_fmt()));
770        }
771        if let Some(p) = self.get_top(&node_data, node_id, node_state) {
772            s.push_str(&format!("top: {};", p.get_css_value_fmt()));
773        }
774        if let Some(p) = self.get_bottom(&node_data, node_id, node_state) {
775            s.push_str(&format!("bottom: {};", p.get_css_value_fmt()));
776        }
777        if let Some(p) = self.get_right(&node_data, node_id, node_state) {
778            s.push_str(&format!("right: {};", p.get_css_value_fmt()));
779        }
780        if let Some(p) = self.get_left(&node_data, node_id, node_state) {
781            s.push_str(&format!("left: {};", p.get_css_value_fmt()));
782        }
783        if let Some(p) = self.get_padding_top(&node_data, node_id, node_state) {
784            s.push_str(&format!("padding-top: {};", p.get_css_value_fmt()));
785        }
786        if let Some(p) = self.get_padding_bottom(&node_data, node_id, node_state) {
787            s.push_str(&format!("padding-bottom: {};", p.get_css_value_fmt()));
788        }
789        if let Some(p) = self.get_padding_left(&node_data, node_id, node_state) {
790            s.push_str(&format!("padding-left: {};", p.get_css_value_fmt()));
791        }
792        if let Some(p) = self.get_padding_right(&node_data, node_id, node_state) {
793            s.push_str(&format!("padding-right: {};", p.get_css_value_fmt()));
794        }
795        if let Some(p) = self.get_margin_top(&node_data, node_id, node_state) {
796            s.push_str(&format!("margin-top: {};", p.get_css_value_fmt()));
797        }
798        if let Some(p) = self.get_margin_bottom(&node_data, node_id, node_state) {
799            s.push_str(&format!("margin-bottom: {};", p.get_css_value_fmt()));
800        }
801        if let Some(p) = self.get_margin_left(&node_data, node_id, node_state) {
802            s.push_str(&format!("margin-left: {};", p.get_css_value_fmt()));
803        }
804        if let Some(p) = self.get_margin_right(&node_data, node_id, node_state) {
805            s.push_str(&format!("margin-right: {};", p.get_css_value_fmt()));
806        }
807        if let Some(p) = self.get_border_top_width(&node_data, node_id, node_state) {
808            s.push_str(&format!("border-top-width: {};", p.get_css_value_fmt()));
809        }
810        if let Some(p) = self.get_border_left_width(&node_data, node_id, node_state) {
811            s.push_str(&format!("border-left-width: {};", p.get_css_value_fmt()));
812        }
813        if let Some(p) = self.get_border_right_width(&node_data, node_id, node_state) {
814            s.push_str(&format!("border-right-width: {};", p.get_css_value_fmt()));
815        }
816        if let Some(p) = self.get_border_bottom_width(&node_data, node_id, node_state) {
817            s.push_str(&format!("border-bottom-width: {};", p.get_css_value_fmt()));
818        }
819        if let Some(p) = self.get_overflow_x(&node_data, node_id, node_state) {
820            s.push_str(&format!("overflow-x: {};", p.get_css_value_fmt()));
821        }
822        if let Some(p) = self.get_overflow_y(&node_data, node_id, node_state) {
823            s.push_str(&format!("overflow-y: {};", p.get_css_value_fmt()));
824        }
825        if let Some(p) = self.get_flex_direction(&node_data, node_id, node_state) {
826            s.push_str(&format!("flex-direction: {};", p.get_css_value_fmt()));
827        }
828        if let Some(p) = self.get_flex_wrap(&node_data, node_id, node_state) {
829            s.push_str(&format!("flex-wrap: {};", p.get_css_value_fmt()));
830        }
831        if let Some(p) = self.get_flex_grow(&node_data, node_id, node_state) {
832            s.push_str(&format!("flex-grow: {};", p.get_css_value_fmt()));
833        }
834        if let Some(p) = self.get_flex_shrink(&node_data, node_id, node_state) {
835            s.push_str(&format!("flex-shrink: {};", p.get_css_value_fmt()));
836        }
837        if let Some(p) = self.get_justify_content(&node_data, node_id, node_state) {
838            s.push_str(&format!("justify-content: {};", p.get_css_value_fmt()));
839        }
840        if let Some(p) = self.get_align_items(&node_data, node_id, node_state) {
841            s.push_str(&format!("align-items: {};", p.get_css_value_fmt()));
842        }
843        if let Some(p) = self.get_align_content(&node_data, node_id, node_state) {
844            s.push_str(&format!("align-content: {};", p.get_css_value_fmt()));
845        }
846        s
847    }
848}
849
850/// Calculated hash of a font-family
851#[derive(Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
852pub struct StyleFontFamilyHash(pub u64);
853
854impl ::core::fmt::Debug for StyleFontFamilyHash {
855    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
856        write!(f, "StyleFontFamilyHash({})", self.0)
857    }
858}
859
860impl StyleFontFamilyHash {
861    pub(crate) fn new(family: &StyleFontFamily) -> Self {
862        use highway::{HighwayHash, HighwayHasher, Key};
863        let mut hasher = HighwayHasher::new(Key([0; 4]));
864        family.hash(&mut hasher);
865        Self(hasher.finalize64())
866    }
867}
868
869/// Calculated hash of a font-family
870#[derive(Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
871pub struct StyleFontFamiliesHash(pub u64);
872
873impl ::core::fmt::Debug for StyleFontFamiliesHash {
874    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
875        write!(f, "StyleFontFamiliesHash({})", self.0)
876    }
877}
878
879impl StyleFontFamiliesHash {
880    pub fn new(families: &[StyleFontFamily]) -> Self {
881        use highway::{HighwayHash, HighwayHasher, Key};
882        let mut hasher = HighwayHasher::new(Key([0; 4]));
883        for f in families.iter() {
884            f.hash(&mut hasher);
885        }
886        Self(hasher.finalize64())
887    }
888}
889
890impl CssPropertyCache {
891    pub fn empty(node_count: usize) -> Self {
892        Self {
893            node_count,
894            user_overridden_properties: BTreeMap::new(),
895
896            cascaded_normal_props: BTreeMap::new(),
897            cascaded_hover_props: BTreeMap::new(),
898            cascaded_active_props: BTreeMap::new(),
899            cascaded_focus_props: BTreeMap::new(),
900
901            css_normal_props: BTreeMap::new(),
902            css_hover_props: BTreeMap::new(),
903            css_active_props: BTreeMap::new(),
904            css_focus_props: BTreeMap::new(),
905        }
906    }
907
908    pub fn append(&mut self, other: &mut Self) {
909        macro_rules! append_css_property_vec {
910            ($field_name:ident) => {{
911                let mut s = BTreeMap::new();
912                core::mem::swap(&mut s, &mut other.$field_name);
913                for (node_id, property_map) in s.into_iter() {
914                    self.$field_name
915                        .insert(node_id + self.node_count, property_map);
916                }
917            }};
918        }
919
920        append_css_property_vec!(user_overridden_properties);
921        append_css_property_vec!(cascaded_normal_props);
922        append_css_property_vec!(cascaded_hover_props);
923        append_css_property_vec!(cascaded_active_props);
924        append_css_property_vec!(cascaded_focus_props);
925        append_css_property_vec!(css_normal_props);
926        append_css_property_vec!(css_hover_props);
927        append_css_property_vec!(css_active_props);
928        append_css_property_vec!(css_focus_props);
929
930        self.node_count += other.node_count;
931    }
932
933    pub fn is_horizontal_overflow_visible(
934        &self,
935        node_data: &NodeData,
936        node_id: &NodeId,
937        node_state: &StyledNodeState,
938    ) -> bool {
939        self.get_overflow_x(node_data, node_id, node_state)
940            .and_then(|p| p.get_property_or_default())
941            .unwrap_or_default()
942            .is_overflow_visible()
943    }
944
945    pub fn is_vertical_overflow_visible(
946        &self,
947        node_data: &NodeData,
948        node_id: &NodeId,
949        node_state: &StyledNodeState,
950    ) -> bool {
951        self.get_overflow_y(node_data, node_id, node_state)
952            .and_then(|p| p.get_property_or_default())
953            .unwrap_or_default()
954            .is_overflow_visible()
955    }
956
957    pub fn is_horizontal_overflow_hidden(
958        &self,
959        node_data: &NodeData,
960        node_id: &NodeId,
961        node_state: &StyledNodeState,
962    ) -> bool {
963        self.get_overflow_x(node_data, node_id, node_state)
964            .and_then(|p| p.get_property_or_default())
965            .unwrap_or_default()
966            .is_overflow_hidden()
967    }
968
969    pub fn is_vertical_overflow_hidden(
970        &self,
971        node_data: &NodeData,
972        node_id: &NodeId,
973        node_state: &StyledNodeState,
974    ) -> bool {
975        self.get_overflow_y(node_data, node_id, node_state)
976            .and_then(|p| p.get_property_or_default())
977            .unwrap_or_default()
978            .is_overflow_hidden()
979    }
980
981    pub fn get_text_color_or_default(
982        &self,
983        node_data: &NodeData,
984        node_id: &NodeId,
985        node_state: &StyledNodeState,
986    ) -> StyleTextColor {
987        use crate::ui_solver::DEFAULT_TEXT_COLOR;
988        self.get_text_color(node_data, node_id, node_state)
989            .and_then(|fs| fs.get_property().cloned())
990            .unwrap_or(DEFAULT_TEXT_COLOR)
991    }
992
993    /// Returns the font ID of the
994    pub fn get_font_id_or_default(
995        &self,
996        node_data: &NodeData,
997        node_id: &NodeId,
998        node_state: &StyledNodeState,
999    ) -> StyleFontFamilyVec {
1000        use crate::ui_solver::DEFAULT_FONT_ID;
1001        let default_font_id = vec![StyleFontFamily::System(AzString::from_const_str(
1002            DEFAULT_FONT_ID,
1003        ))]
1004        .into();
1005        let font_family_opt = self.get_font_family(node_data, node_id, node_state);
1006
1007        font_family_opt
1008            .as_ref()
1009            .and_then(|family| Some(family.get_property()?.clone()))
1010            .unwrap_or(default_font_id)
1011    }
1012
1013    pub fn get_font_size_or_default(
1014        &self,
1015        node_data: &NodeData,
1016        node_id: &NodeId,
1017        node_state: &StyledNodeState,
1018    ) -> StyleFontSize {
1019        use crate::ui_solver::DEFAULT_FONT_SIZE;
1020        self.get_font_size(node_data, node_id, node_state)
1021            .and_then(|fs| fs.get_property().cloned())
1022            .unwrap_or(DEFAULT_FONT_SIZE)
1023    }
1024
1025    pub fn has_border(
1026        &self,
1027        node_data: &NodeData,
1028        node_id: &NodeId,
1029        node_state: &StyledNodeState,
1030    ) -> bool {
1031        self.get_border_left_width(node_data, node_id, node_state)
1032            .is_some()
1033            || self
1034                .get_border_right_width(node_data, node_id, node_state)
1035                .is_some()
1036            || self
1037                .get_border_top_width(node_data, node_id, node_state)
1038                .is_some()
1039            || self
1040                .get_border_bottom_width(node_data, node_id, node_state)
1041                .is_some()
1042    }
1043
1044    pub fn has_box_shadow(
1045        &self,
1046        node_data: &NodeData,
1047        node_id: &NodeId,
1048        node_state: &StyledNodeState,
1049    ) -> bool {
1050        self.get_box_shadow_left(node_data, node_id, node_state)
1051            .is_some()
1052            || self
1053                .get_box_shadow_right(node_data, node_id, node_state)
1054                .is_some()
1055            || self
1056                .get_box_shadow_top(node_data, node_id, node_state)
1057                .is_some()
1058            || self
1059                .get_box_shadow_bottom(node_data, node_id, node_state)
1060                .is_some()
1061    }
1062
1063    pub fn get_property<'a>(
1064        &'a self,
1065        node_data: &'a NodeData,
1066        node_id: &NodeId,
1067        node_state: &StyledNodeState,
1068        css_property_type: &CssPropertyType,
1069    ) -> Option<&CssProperty> {
1070        // NOTE: This function is slow, but it is going to be called on every
1071        // node in parallel, so it should be rather fast in the end
1072
1073        // First test if there is some user-defined override for the property
1074        if let Some(p) = self
1075            .user_overridden_properties
1076            .get(node_id)
1077            .and_then(|n| n.get(css_property_type))
1078        {
1079            return Some(p);
1080        }
1081
1082        if !(node_state.normal || node_state.active || node_state.hover || node_state.focused) {
1083            return None;
1084        }
1085
1086        // If that fails, see if there is an inline CSS property that matches
1087        // :focus > :active > :hover > :normal
1088        if node_state.focused {
1089            if let Some(p) = self
1090                .css_focus_props
1091                .get(node_id)
1092                .and_then(|map| map.get(css_property_type))
1093            {
1094                return Some(p);
1095            }
1096
1097            if let Some(p) = node_data
1098                .inline_css_props
1099                .as_ref()
1100                .iter()
1101                .find_map(|css_prop| {
1102                    if let NodeDataInlineCssProperty::Focus(p) = css_prop {
1103                        if p.get_type() == *css_property_type {
1104                            return Some(p);
1105                        }
1106                    }
1107                    None
1108                })
1109            {
1110                return Some(p);
1111            }
1112
1113            if let Some(p) = self
1114                .cascaded_focus_props
1115                .get(node_id)
1116                .and_then(|map| map.get(css_property_type))
1117            {
1118                return Some(p);
1119            }
1120        }
1121
1122        if node_state.active {
1123            if let Some(p) = self
1124                .css_active_props
1125                .get(node_id)
1126                .and_then(|map| map.get(css_property_type))
1127            {
1128                return Some(p);
1129            }
1130
1131            if let Some(p) = node_data
1132                .inline_css_props
1133                .as_ref()
1134                .iter()
1135                .find_map(|css_prop| {
1136                    if let NodeDataInlineCssProperty::Active(p) = css_prop {
1137                        if p.get_type() == *css_property_type {
1138                            return Some(p);
1139                        }
1140                    }
1141                    None
1142                })
1143            {
1144                return Some(p);
1145            }
1146
1147            if let Some(p) = self
1148                .cascaded_active_props
1149                .get(node_id)
1150                .and_then(|map| map.get(css_property_type))
1151            {
1152                return Some(p);
1153            }
1154        }
1155
1156        if node_state.hover {
1157            if let Some(p) = self
1158                .css_hover_props
1159                .get(node_id)
1160                .and_then(|map| map.get(css_property_type))
1161            {
1162                return Some(p);
1163            }
1164
1165            if let Some(p) = node_data
1166                .inline_css_props
1167                .as_ref()
1168                .iter()
1169                .find_map(|css_prop| {
1170                    if let NodeDataInlineCssProperty::Hover(p) = css_prop {
1171                        if p.get_type() == *css_property_type {
1172                            return Some(p);
1173                        }
1174                    }
1175                    None
1176                })
1177            {
1178                return Some(p);
1179            }
1180
1181            if let Some(p) = self
1182                .cascaded_hover_props
1183                .get(node_id)
1184                .and_then(|map| map.get(css_property_type))
1185            {
1186                return Some(p);
1187            }
1188        }
1189
1190        if node_state.normal {
1191            if let Some(p) = self
1192                .css_normal_props
1193                .get(node_id)
1194                .and_then(|map| map.get(css_property_type))
1195            {
1196                return Some(p);
1197            }
1198
1199            if let Some(p) = node_data
1200                .inline_css_props
1201                .as_ref()
1202                .iter()
1203                .find_map(|css_prop| {
1204                    if let NodeDataInlineCssProperty::Normal(p) = css_prop {
1205                        if p.get_type() == *css_property_type {
1206                            return Some(p);
1207                        }
1208                    }
1209                    None
1210                })
1211            {
1212                return Some(p);
1213            }
1214
1215            if let Some(p) = self
1216                .cascaded_normal_props
1217                .get(node_id)
1218                .and_then(|map| map.get(css_property_type))
1219            {
1220                return Some(p);
1221            }
1222        }
1223
1224        // Nothing found, use the default
1225        None
1226    }
1227
1228    pub fn get_background_content<'a>(
1229        &'a self,
1230        node_data: &'a NodeData,
1231        node_id: &NodeId,
1232        node_state: &StyledNodeState,
1233    ) -> Option<&'a StyleBackgroundContentVecValue> {
1234        self.get_property(
1235            node_data,
1236            node_id,
1237            node_state,
1238            &CssPropertyType::BackgroundContent,
1239        )
1240        .and_then(|p| p.as_background_content())
1241    }
1242    pub fn get_background_position<'a>(
1243        &'a self,
1244        node_data: &'a NodeData,
1245        node_id: &NodeId,
1246        node_state: &StyledNodeState,
1247    ) -> Option<&'a StyleBackgroundPositionVecValue> {
1248        self.get_property(
1249            node_data,
1250            node_id,
1251            node_state,
1252            &CssPropertyType::BackgroundPosition,
1253        )
1254        .and_then(|p| p.as_background_position())
1255    }
1256    pub fn get_background_size<'a>(
1257        &'a self,
1258        node_data: &'a NodeData,
1259        node_id: &NodeId,
1260        node_state: &StyledNodeState,
1261    ) -> Option<&'a StyleBackgroundSizeVecValue> {
1262        self.get_property(
1263            node_data,
1264            node_id,
1265            node_state,
1266            &CssPropertyType::BackgroundSize,
1267        )
1268        .and_then(|p| p.as_background_size())
1269    }
1270    pub fn get_background_repeat<'a>(
1271        &'a self,
1272        node_data: &'a NodeData,
1273        node_id: &NodeId,
1274        node_state: &StyledNodeState,
1275    ) -> Option<&'a StyleBackgroundRepeatVecValue> {
1276        self.get_property(
1277            node_data,
1278            node_id,
1279            node_state,
1280            &CssPropertyType::BackgroundRepeat,
1281        )
1282        .and_then(|p| p.as_background_repeat())
1283    }
1284    pub fn get_font_size<'a>(
1285        &'a self,
1286        node_data: &'a NodeData,
1287        node_id: &NodeId,
1288        node_state: &StyledNodeState,
1289    ) -> Option<&'a StyleFontSizeValue> {
1290        self.get_property(node_data, node_id, node_state, &CssPropertyType::FontSize)
1291            .and_then(|p| p.as_font_size())
1292    }
1293    pub fn get_font_family<'a>(
1294        &'a self,
1295        node_data: &'a NodeData,
1296        node_id: &NodeId,
1297        node_state: &StyledNodeState,
1298    ) -> Option<&'a StyleFontFamilyVecValue> {
1299        self.get_property(node_data, node_id, node_state, &CssPropertyType::FontFamily)
1300            .and_then(|p| p.as_font_family())
1301    }
1302    pub fn get_text_color<'a>(
1303        &'a self,
1304        node_data: &'a NodeData,
1305        node_id: &NodeId,
1306        node_state: &StyledNodeState,
1307    ) -> Option<&'a StyleTextColorValue> {
1308        self.get_property(node_data, node_id, node_state, &CssPropertyType::TextColor)
1309            .and_then(|p| p.as_text_color())
1310    }
1311    pub fn get_text_align<'a>(
1312        &'a self,
1313        node_data: &'a NodeData,
1314        node_id: &NodeId,
1315        node_state: &StyledNodeState,
1316    ) -> Option<&'a StyleTextAlignValue> {
1317        self.get_property(node_data, node_id, node_state, &CssPropertyType::TextAlign)
1318            .and_then(|p| p.as_text_align())
1319    }
1320    pub fn get_line_height<'a>(
1321        &'a self,
1322        node_data: &'a NodeData,
1323        node_id: &NodeId,
1324        node_state: &StyledNodeState,
1325    ) -> Option<&'a StyleLineHeightValue> {
1326        self.get_property(node_data, node_id, node_state, &CssPropertyType::LineHeight)
1327            .and_then(|p| p.as_line_height())
1328    }
1329    pub fn get_letter_spacing<'a>(
1330        &'a self,
1331        node_data: &'a NodeData,
1332        node_id: &NodeId,
1333        node_state: &StyledNodeState,
1334    ) -> Option<&'a StyleLetterSpacingValue> {
1335        self.get_property(
1336            node_data,
1337            node_id,
1338            node_state,
1339            &CssPropertyType::LetterSpacing,
1340        )
1341        .and_then(|p| p.as_letter_spacing())
1342    }
1343    pub fn get_word_spacing<'a>(
1344        &'a self,
1345        node_data: &'a NodeData,
1346        node_id: &NodeId,
1347        node_state: &StyledNodeState,
1348    ) -> Option<&'a StyleWordSpacingValue> {
1349        self.get_property(
1350            node_data,
1351            node_id,
1352            node_state,
1353            &CssPropertyType::WordSpacing,
1354        )
1355        .and_then(|p| p.as_word_spacing())
1356    }
1357    pub fn get_tab_width<'a>(
1358        &'a self,
1359        node_data: &'a NodeData,
1360        node_id: &NodeId,
1361        node_state: &StyledNodeState,
1362    ) -> Option<&'a StyleTabWidthValue> {
1363        self.get_property(node_data, node_id, node_state, &CssPropertyType::TabWidth)
1364            .and_then(|p| p.as_tab_width())
1365    }
1366    pub fn get_cursor<'a>(
1367        &'a self,
1368        node_data: &'a NodeData,
1369        node_id: &NodeId,
1370        node_state: &StyledNodeState,
1371    ) -> Option<&'a StyleCursorValue> {
1372        self.get_property(node_data, node_id, node_state, &CssPropertyType::Cursor)
1373            .and_then(|p| p.as_cursor())
1374    }
1375    pub fn get_box_shadow_left<'a>(
1376        &'a self,
1377        node_data: &'a NodeData,
1378        node_id: &NodeId,
1379        node_state: &StyledNodeState,
1380    ) -> Option<&'a StyleBoxShadowValue> {
1381        self.get_property(
1382            node_data,
1383            node_id,
1384            node_state,
1385            &CssPropertyType::BoxShadowLeft,
1386        )
1387        .and_then(|p| p.as_box_shadow_left())
1388    }
1389    pub fn get_box_shadow_right<'a>(
1390        &'a self,
1391        node_data: &'a NodeData,
1392        node_id: &NodeId,
1393        node_state: &StyledNodeState,
1394    ) -> Option<&'a StyleBoxShadowValue> {
1395        self.get_property(
1396            node_data,
1397            node_id,
1398            node_state,
1399            &CssPropertyType::BoxShadowRight,
1400        )
1401        .and_then(|p| p.as_box_shadow_right())
1402    }
1403    pub fn get_box_shadow_top<'a>(
1404        &'a self,
1405        node_data: &'a NodeData,
1406        node_id: &NodeId,
1407        node_state: &StyledNodeState,
1408    ) -> Option<&'a StyleBoxShadowValue> {
1409        self.get_property(
1410            node_data,
1411            node_id,
1412            node_state,
1413            &CssPropertyType::BoxShadowTop,
1414        )
1415        .and_then(|p| p.as_box_shadow_top())
1416    }
1417    pub fn get_box_shadow_bottom<'a>(
1418        &'a self,
1419        node_data: &'a NodeData,
1420        node_id: &NodeId,
1421        node_state: &StyledNodeState,
1422    ) -> Option<&'a StyleBoxShadowValue> {
1423        self.get_property(
1424            node_data,
1425            node_id,
1426            node_state,
1427            &CssPropertyType::BoxShadowBottom,
1428        )
1429        .and_then(|p| p.as_box_shadow_bottom())
1430    }
1431    pub fn get_border_top_color<'a>(
1432        &'a self,
1433        node_data: &'a NodeData,
1434        node_id: &NodeId,
1435        node_state: &StyledNodeState,
1436    ) -> Option<&'a StyleBorderTopColorValue> {
1437        self.get_property(
1438            node_data,
1439            node_id,
1440            node_state,
1441            &CssPropertyType::BorderTopColor,
1442        )
1443        .and_then(|p| p.as_border_top_color())
1444    }
1445    pub fn get_border_left_color<'a>(
1446        &'a self,
1447        node_data: &'a NodeData,
1448        node_id: &NodeId,
1449        node_state: &StyledNodeState,
1450    ) -> Option<&'a StyleBorderLeftColorValue> {
1451        self.get_property(
1452            node_data,
1453            node_id,
1454            node_state,
1455            &CssPropertyType::BorderLeftColor,
1456        )
1457        .and_then(|p| p.as_border_left_color())
1458    }
1459    pub fn get_border_right_color<'a>(
1460        &'a self,
1461        node_data: &'a NodeData,
1462        node_id: &NodeId,
1463        node_state: &StyledNodeState,
1464    ) -> Option<&'a StyleBorderRightColorValue> {
1465        self.get_property(
1466            node_data,
1467            node_id,
1468            node_state,
1469            &CssPropertyType::BorderRightColor,
1470        )
1471        .and_then(|p| p.as_border_right_color())
1472    }
1473    pub fn get_border_bottom_color<'a>(
1474        &'a self,
1475        node_data: &'a NodeData,
1476        node_id: &NodeId,
1477        node_state: &StyledNodeState,
1478    ) -> Option<&'a StyleBorderBottomColorValue> {
1479        self.get_property(
1480            node_data,
1481            node_id,
1482            node_state,
1483            &CssPropertyType::BorderBottomColor,
1484        )
1485        .and_then(|p| p.as_border_bottom_color())
1486    }
1487    pub fn get_border_top_style<'a>(
1488        &'a self,
1489        node_data: &'a NodeData,
1490        node_id: &NodeId,
1491        node_state: &StyledNodeState,
1492    ) -> Option<&'a StyleBorderTopStyleValue> {
1493        self.get_property(
1494            node_data,
1495            node_id,
1496            node_state,
1497            &CssPropertyType::BorderTopStyle,
1498        )
1499        .and_then(|p| p.as_border_top_style())
1500    }
1501    pub fn get_border_left_style<'a>(
1502        &'a self,
1503        node_data: &'a NodeData,
1504        node_id: &NodeId,
1505        node_state: &StyledNodeState,
1506    ) -> Option<&'a StyleBorderLeftStyleValue> {
1507        self.get_property(
1508            node_data,
1509            node_id,
1510            node_state,
1511            &CssPropertyType::BorderLeftStyle,
1512        )
1513        .and_then(|p| p.as_border_left_style())
1514    }
1515    pub fn get_border_right_style<'a>(
1516        &'a self,
1517        node_data: &'a NodeData,
1518        node_id: &NodeId,
1519        node_state: &StyledNodeState,
1520    ) -> Option<&'a StyleBorderRightStyleValue> {
1521        self.get_property(
1522            node_data,
1523            node_id,
1524            node_state,
1525            &CssPropertyType::BorderRightStyle,
1526        )
1527        .and_then(|p| p.as_border_right_style())
1528    }
1529    pub fn get_border_bottom_style<'a>(
1530        &'a self,
1531        node_data: &'a NodeData,
1532        node_id: &NodeId,
1533        node_state: &StyledNodeState,
1534    ) -> Option<&'a StyleBorderBottomStyleValue> {
1535        self.get_property(
1536            node_data,
1537            node_id,
1538            node_state,
1539            &CssPropertyType::BorderBottomStyle,
1540        )
1541        .and_then(|p| p.as_border_bottom_style())
1542    }
1543    pub fn get_border_top_left_radius<'a>(
1544        &'a self,
1545        node_data: &'a NodeData,
1546        node_id: &NodeId,
1547        node_state: &StyledNodeState,
1548    ) -> Option<&'a StyleBorderTopLeftRadiusValue> {
1549        self.get_property(
1550            node_data,
1551            node_id,
1552            node_state,
1553            &CssPropertyType::BorderTopLeftRadius,
1554        )
1555        .and_then(|p| p.as_border_top_left_radius())
1556    }
1557    pub fn get_border_top_right_radius<'a>(
1558        &'a self,
1559        node_data: &'a NodeData,
1560        node_id: &NodeId,
1561        node_state: &StyledNodeState,
1562    ) -> Option<&'a StyleBorderTopRightRadiusValue> {
1563        self.get_property(
1564            node_data,
1565            node_id,
1566            node_state,
1567            &CssPropertyType::BorderTopRightRadius,
1568        )
1569        .and_then(|p| p.as_border_top_right_radius())
1570    }
1571    pub fn get_border_bottom_left_radius<'a>(
1572        &'a self,
1573        node_data: &'a NodeData,
1574        node_id: &NodeId,
1575        node_state: &StyledNodeState,
1576    ) -> Option<&'a StyleBorderBottomLeftRadiusValue> {
1577        self.get_property(
1578            node_data,
1579            node_id,
1580            node_state,
1581            &CssPropertyType::BorderBottomLeftRadius,
1582        )
1583        .and_then(|p| p.as_border_bottom_left_radius())
1584    }
1585    pub fn get_border_bottom_right_radius<'a>(
1586        &'a self,
1587        node_data: &'a NodeData,
1588        node_id: &NodeId,
1589        node_state: &StyledNodeState,
1590    ) -> Option<&'a StyleBorderBottomRightRadiusValue> {
1591        self.get_property(
1592            node_data,
1593            node_id,
1594            node_state,
1595            &CssPropertyType::BorderBottomRightRadius,
1596        )
1597        .and_then(|p| p.as_border_bottom_right_radius())
1598    }
1599    pub fn get_opacity<'a>(
1600        &'a self,
1601        node_data: &'a NodeData,
1602        node_id: &NodeId,
1603        node_state: &StyledNodeState,
1604    ) -> Option<&'a StyleOpacityValue> {
1605        self.get_property(node_data, node_id, node_state, &CssPropertyType::Opacity)
1606            .and_then(|p| p.as_opacity())
1607    }
1608    pub fn get_transform<'a>(
1609        &'a self,
1610        node_data: &'a NodeData,
1611        node_id: &NodeId,
1612        node_state: &StyledNodeState,
1613    ) -> Option<&'a StyleTransformVecValue> {
1614        self.get_property(node_data, node_id, node_state, &CssPropertyType::Transform)
1615            .and_then(|p| p.as_transform())
1616    }
1617    pub fn get_transform_origin<'a>(
1618        &'a self,
1619        node_data: &'a NodeData,
1620        node_id: &NodeId,
1621        node_state: &StyledNodeState,
1622    ) -> Option<&'a StyleTransformOriginValue> {
1623        self.get_property(
1624            node_data,
1625            node_id,
1626            node_state,
1627            &CssPropertyType::TransformOrigin,
1628        )
1629        .and_then(|p| p.as_transform_origin())
1630    }
1631    pub fn get_perspective_origin<'a>(
1632        &'a self,
1633        node_data: &'a NodeData,
1634        node_id: &NodeId,
1635        node_state: &StyledNodeState,
1636    ) -> Option<&'a StylePerspectiveOriginValue> {
1637        self.get_property(
1638            node_data,
1639            node_id,
1640            node_state,
1641            &CssPropertyType::PerspectiveOrigin,
1642        )
1643        .and_then(|p| p.as_perspective_origin())
1644    }
1645    pub fn get_backface_visibility<'a>(
1646        &'a self,
1647        node_data: &'a NodeData,
1648        node_id: &NodeId,
1649        node_state: &StyledNodeState,
1650    ) -> Option<&'a StyleBackfaceVisibilityValue> {
1651        self.get_property(
1652            node_data,
1653            node_id,
1654            node_state,
1655            &CssPropertyType::BackfaceVisibility,
1656        )
1657        .and_then(|p| p.as_backface_visibility())
1658    }
1659    pub fn get_display<'a>(
1660        &'a self,
1661        node_data: &'a NodeData,
1662        node_id: &NodeId,
1663        node_state: &StyledNodeState,
1664    ) -> Option<&'a LayoutDisplayValue> {
1665        self.get_property(node_data, node_id, node_state, &CssPropertyType::Display)
1666            .and_then(|p| p.as_display())
1667    }
1668    pub fn get_float<'a>(
1669        &'a self,
1670        node_data: &'a NodeData,
1671        node_id: &NodeId,
1672        node_state: &StyledNodeState,
1673    ) -> Option<&'a LayoutFloatValue> {
1674        self.get_property(node_data, node_id, node_state, &CssPropertyType::Float)
1675            .and_then(|p| p.as_float())
1676    }
1677    pub fn get_box_sizing<'a>(
1678        &'a self,
1679        node_data: &'a NodeData,
1680        node_id: &NodeId,
1681        node_state: &StyledNodeState,
1682    ) -> Option<&'a LayoutBoxSizingValue> {
1683        self.get_property(node_data, node_id, node_state, &CssPropertyType::BoxSizing)
1684            .and_then(|p| p.as_box_sizing())
1685    }
1686    pub fn get_width<'a>(
1687        &'a self,
1688        node_data: &'a NodeData,
1689        node_id: &NodeId,
1690        node_state: &StyledNodeState,
1691    ) -> Option<&'a LayoutWidthValue> {
1692        self.get_property(node_data, node_id, node_state, &CssPropertyType::Width)
1693            .and_then(|p| p.as_width())
1694    }
1695    pub fn get_height<'a>(
1696        &'a self,
1697        node_data: &'a NodeData,
1698        node_id: &NodeId,
1699        node_state: &StyledNodeState,
1700    ) -> Option<&'a LayoutHeightValue> {
1701        self.get_property(node_data, node_id, node_state, &CssPropertyType::Height)
1702            .and_then(|p| p.as_height())
1703    }
1704    pub fn get_min_width<'a>(
1705        &'a self,
1706        node_data: &'a NodeData,
1707        node_id: &NodeId,
1708        node_state: &StyledNodeState,
1709    ) -> Option<&'a LayoutMinWidthValue> {
1710        self.get_property(node_data, node_id, node_state, &CssPropertyType::MinWidth)
1711            .and_then(|p| p.as_min_width())
1712    }
1713    pub fn get_min_height<'a>(
1714        &'a self,
1715        node_data: &'a NodeData,
1716        node_id: &NodeId,
1717        node_state: &StyledNodeState,
1718    ) -> Option<&'a LayoutMinHeightValue> {
1719        self.get_property(node_data, node_id, node_state, &CssPropertyType::MinHeight)
1720            .and_then(|p| p.as_min_height())
1721    }
1722    pub fn get_max_width<'a>(
1723        &'a self,
1724        node_data: &'a NodeData,
1725        node_id: &NodeId,
1726        node_state: &StyledNodeState,
1727    ) -> Option<&'a LayoutMaxWidthValue> {
1728        self.get_property(node_data, node_id, node_state, &CssPropertyType::MaxWidth)
1729            .and_then(|p| p.as_max_width())
1730    }
1731    pub fn get_max_height<'a>(
1732        &'a self,
1733        node_data: &'a NodeData,
1734        node_id: &NodeId,
1735        node_state: &StyledNodeState,
1736    ) -> Option<&'a LayoutMaxHeightValue> {
1737        self.get_property(node_data, node_id, node_state, &CssPropertyType::MaxHeight)
1738            .and_then(|p| p.as_max_height())
1739    }
1740    pub fn get_position<'a>(
1741        &'a self,
1742        node_data: &'a NodeData,
1743        node_id: &NodeId,
1744        node_state: &StyledNodeState,
1745    ) -> Option<&'a LayoutPositionValue> {
1746        self.get_property(node_data, node_id, node_state, &CssPropertyType::Position)
1747            .and_then(|p| p.as_position())
1748    }
1749    pub fn get_top<'a>(
1750        &'a self,
1751        node_data: &'a NodeData,
1752        node_id: &NodeId,
1753        node_state: &StyledNodeState,
1754    ) -> Option<&'a LayoutTopValue> {
1755        self.get_property(node_data, node_id, node_state, &CssPropertyType::Top)
1756            .and_then(|p| p.as_top())
1757    }
1758    pub fn get_bottom<'a>(
1759        &'a self,
1760        node_data: &'a NodeData,
1761        node_id: &NodeId,
1762        node_state: &StyledNodeState,
1763    ) -> Option<&'a LayoutBottomValue> {
1764        self.get_property(node_data, node_id, node_state, &CssPropertyType::Bottom)
1765            .and_then(|p| p.as_bottom())
1766    }
1767    pub fn get_right<'a>(
1768        &'a self,
1769        node_data: &'a NodeData,
1770        node_id: &NodeId,
1771        node_state: &StyledNodeState,
1772    ) -> Option<&'a LayoutRightValue> {
1773        self.get_property(node_data, node_id, node_state, &CssPropertyType::Right)
1774            .and_then(|p| p.as_right())
1775    }
1776    pub fn get_left<'a>(
1777        &'a self,
1778        node_data: &'a NodeData,
1779        node_id: &NodeId,
1780        node_state: &StyledNodeState,
1781    ) -> Option<&'a LayoutLeftValue> {
1782        self.get_property(node_data, node_id, node_state, &CssPropertyType::Left)
1783            .and_then(|p| p.as_left())
1784    }
1785    pub fn get_padding_top<'a>(
1786        &'a self,
1787        node_data: &'a NodeData,
1788        node_id: &NodeId,
1789        node_state: &StyledNodeState,
1790    ) -> Option<&'a LayoutPaddingTopValue> {
1791        self.get_property(node_data, node_id, node_state, &CssPropertyType::PaddingTop)
1792            .and_then(|p| p.as_padding_top())
1793    }
1794    pub fn get_padding_bottom<'a>(
1795        &'a self,
1796        node_data: &'a NodeData,
1797        node_id: &NodeId,
1798        node_state: &StyledNodeState,
1799    ) -> Option<&'a LayoutPaddingBottomValue> {
1800        self.get_property(
1801            node_data,
1802            node_id,
1803            node_state,
1804            &CssPropertyType::PaddingBottom,
1805        )
1806        .and_then(|p| p.as_padding_bottom())
1807    }
1808    pub fn get_padding_left<'a>(
1809        &'a self,
1810        node_data: &'a NodeData,
1811        node_id: &NodeId,
1812        node_state: &StyledNodeState,
1813    ) -> Option<&'a LayoutPaddingLeftValue> {
1814        self.get_property(
1815            node_data,
1816            node_id,
1817            node_state,
1818            &CssPropertyType::PaddingLeft,
1819        )
1820        .and_then(|p| p.as_padding_left())
1821    }
1822    pub fn get_padding_right<'a>(
1823        &'a self,
1824        node_data: &'a NodeData,
1825        node_id: &NodeId,
1826        node_state: &StyledNodeState,
1827    ) -> Option<&'a LayoutPaddingRightValue> {
1828        self.get_property(
1829            node_data,
1830            node_id,
1831            node_state,
1832            &CssPropertyType::PaddingRight,
1833        )
1834        .and_then(|p| p.as_padding_right())
1835    }
1836    pub fn get_margin_top<'a>(
1837        &'a self,
1838        node_data: &'a NodeData,
1839        node_id: &NodeId,
1840        node_state: &StyledNodeState,
1841    ) -> Option<&'a LayoutMarginTopValue> {
1842        self.get_property(node_data, node_id, node_state, &CssPropertyType::MarginTop)
1843            .and_then(|p| p.as_margin_top())
1844    }
1845    pub fn get_margin_bottom<'a>(
1846        &'a self,
1847        node_data: &'a NodeData,
1848        node_id: &NodeId,
1849        node_state: &StyledNodeState,
1850    ) -> Option<&'a LayoutMarginBottomValue> {
1851        self.get_property(
1852            node_data,
1853            node_id,
1854            node_state,
1855            &CssPropertyType::MarginBottom,
1856        )
1857        .and_then(|p| p.as_margin_bottom())
1858    }
1859    pub fn get_margin_left<'a>(
1860        &'a self,
1861        node_data: &'a NodeData,
1862        node_id: &NodeId,
1863        node_state: &StyledNodeState,
1864    ) -> Option<&'a LayoutMarginLeftValue> {
1865        self.get_property(node_data, node_id, node_state, &CssPropertyType::MarginLeft)
1866            .and_then(|p| p.as_margin_left())
1867    }
1868    pub fn get_margin_right<'a>(
1869        &'a self,
1870        node_data: &'a NodeData,
1871        node_id: &NodeId,
1872        node_state: &StyledNodeState,
1873    ) -> Option<&'a LayoutMarginRightValue> {
1874        self.get_property(
1875            node_data,
1876            node_id,
1877            node_state,
1878            &CssPropertyType::MarginRight,
1879        )
1880        .and_then(|p| p.as_margin_right())
1881    }
1882    pub fn get_border_top_width<'a>(
1883        &'a self,
1884        node_data: &'a NodeData,
1885        node_id: &NodeId,
1886        node_state: &StyledNodeState,
1887    ) -> Option<&'a LayoutBorderTopWidthValue> {
1888        self.get_property(
1889            node_data,
1890            node_id,
1891            node_state,
1892            &CssPropertyType::BorderTopWidth,
1893        )
1894        .and_then(|p| p.as_border_top_width())
1895    }
1896    pub fn get_border_left_width<'a>(
1897        &'a self,
1898        node_data: &'a NodeData,
1899        node_id: &NodeId,
1900        node_state: &StyledNodeState,
1901    ) -> Option<&'a LayoutBorderLeftWidthValue> {
1902        self.get_property(
1903            node_data,
1904            node_id,
1905            node_state,
1906            &CssPropertyType::BorderLeftWidth,
1907        )
1908        .and_then(|p| p.as_border_left_width())
1909    }
1910    pub fn get_border_right_width<'a>(
1911        &'a self,
1912        node_data: &'a NodeData,
1913        node_id: &NodeId,
1914        node_state: &StyledNodeState,
1915    ) -> Option<&'a LayoutBorderRightWidthValue> {
1916        self.get_property(
1917            node_data,
1918            node_id,
1919            node_state,
1920            &CssPropertyType::BorderRightWidth,
1921        )
1922        .and_then(|p| p.as_border_right_width())
1923    }
1924    pub fn get_border_bottom_width<'a>(
1925        &'a self,
1926        node_data: &'a NodeData,
1927        node_id: &NodeId,
1928        node_state: &StyledNodeState,
1929    ) -> Option<&'a LayoutBorderBottomWidthValue> {
1930        self.get_property(
1931            node_data,
1932            node_id,
1933            node_state,
1934            &CssPropertyType::BorderBottomWidth,
1935        )
1936        .and_then(|p| p.as_border_bottom_width())
1937    }
1938    pub fn get_overflow_x<'a>(
1939        &'a self,
1940        node_data: &'a NodeData,
1941        node_id: &NodeId,
1942        node_state: &StyledNodeState,
1943    ) -> Option<&'a LayoutOverflowValue> {
1944        self.get_property(node_data, node_id, node_state, &CssPropertyType::OverflowX)
1945            .and_then(|p| p.as_overflow_x())
1946    }
1947    pub fn get_overflow_y<'a>(
1948        &'a self,
1949        node_data: &'a NodeData,
1950        node_id: &NodeId,
1951        node_state: &StyledNodeState,
1952    ) -> Option<&'a LayoutOverflowValue> {
1953        self.get_property(node_data, node_id, node_state, &CssPropertyType::OverflowY)
1954            .and_then(|p| p.as_overflow_y())
1955    }
1956    pub fn get_flex_direction<'a>(
1957        &'a self,
1958        node_data: &'a NodeData,
1959        node_id: &NodeId,
1960        node_state: &StyledNodeState,
1961    ) -> Option<&'a LayoutFlexDirectionValue> {
1962        self.get_property(
1963            node_data,
1964            node_id,
1965            node_state,
1966            &CssPropertyType::FlexDirection,
1967        )
1968        .and_then(|p| p.as_direction())
1969    }
1970    pub fn get_flex_wrap<'a>(
1971        &'a self,
1972        node_data: &'a NodeData,
1973        node_id: &NodeId,
1974        node_state: &StyledNodeState,
1975    ) -> Option<&'a LayoutFlexWrapValue> {
1976        self.get_property(node_data, node_id, node_state, &CssPropertyType::FlexWrap)
1977            .and_then(|p| p.as_flex_wrap())
1978    }
1979    pub fn get_flex_grow<'a>(
1980        &'a self,
1981        node_data: &'a NodeData,
1982        node_id: &NodeId,
1983        node_state: &StyledNodeState,
1984    ) -> Option<&'a LayoutFlexGrowValue> {
1985        self.get_property(node_data, node_id, node_state, &CssPropertyType::FlexGrow)
1986            .and_then(|p| p.as_flex_grow())
1987    }
1988    pub fn get_flex_shrink<'a>(
1989        &'a self,
1990        node_data: &'a NodeData,
1991        node_id: &NodeId,
1992        node_state: &StyledNodeState,
1993    ) -> Option<&'a LayoutFlexShrinkValue> {
1994        self.get_property(node_data, node_id, node_state, &CssPropertyType::FlexShrink)
1995            .and_then(|p| p.as_flex_shrink())
1996    }
1997    pub fn get_justify_content<'a>(
1998        &'a self,
1999        node_data: &'a NodeData,
2000        node_id: &NodeId,
2001        node_state: &StyledNodeState,
2002    ) -> Option<&'a LayoutJustifyContentValue> {
2003        self.get_property(
2004            node_data,
2005            node_id,
2006            node_state,
2007            &CssPropertyType::JustifyContent,
2008        )
2009        .and_then(|p| p.as_justify_content())
2010    }
2011    pub fn get_align_items<'a>(
2012        &'a self,
2013        node_data: &'a NodeData,
2014        node_id: &NodeId,
2015        node_state: &StyledNodeState,
2016    ) -> Option<&'a LayoutAlignItemsValue> {
2017        self.get_property(node_data, node_id, node_state, &CssPropertyType::AlignItems)
2018            .and_then(|p| p.as_align_items())
2019    }
2020    pub fn get_align_content<'a>(
2021        &'a self,
2022        node_data: &'a NodeData,
2023        node_id: &NodeId,
2024        node_state: &StyledNodeState,
2025    ) -> Option<&'a LayoutAlignContentValue> {
2026        self.get_property(
2027            node_data,
2028            node_id,
2029            node_state,
2030            &CssPropertyType::AlignContent,
2031        )
2032        .and_then(|p| p.as_align_content())
2033    }
2034    pub fn get_mix_blend_mode<'a>(
2035        &'a self,
2036        node_data: &'a NodeData,
2037        node_id: &NodeId,
2038        node_state: &StyledNodeState,
2039    ) -> Option<&'a StyleMixBlendModeValue> {
2040        self.get_property(
2041            node_data,
2042            node_id,
2043            node_state,
2044            &CssPropertyType::MixBlendMode,
2045        )
2046        .and_then(|p| p.as_mix_blend_mode())
2047    }
2048    pub fn get_filter<'a>(
2049        &'a self,
2050        node_data: &'a NodeData,
2051        node_id: &NodeId,
2052        node_state: &StyledNodeState,
2053    ) -> Option<&'a StyleFilterVecValue> {
2054        self.get_property(node_data, node_id, node_state, &CssPropertyType::Filter)
2055            .and_then(|p| p.as_filter())
2056    }
2057    pub fn get_backdrop_filter<'a>(
2058        &'a self,
2059        node_data: &'a NodeData,
2060        node_id: &NodeId,
2061        node_state: &StyledNodeState,
2062    ) -> Option<&'a StyleFilterVecValue> {
2063        self.get_property(node_data, node_id, node_state, &CssPropertyType::Filter)
2064            .and_then(|p| p.as_backdrop_filter())
2065    }
2066    pub fn get_text_shadow<'a>(
2067        &'a self,
2068        node_data: &'a NodeData,
2069        node_id: &NodeId,
2070        node_state: &StyledNodeState,
2071    ) -> Option<&'a StyleBoxShadowValue> {
2072        self.get_property(node_data, node_id, node_state, &CssPropertyType::TextShadow)
2073            .and_then(|p| p.as_text_shadow())
2074    }
2075}
2076
2077#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
2078#[repr(C)]
2079pub struct DomId {
2080    pub inner: usize,
2081}
2082
2083impl fmt::Display for DomId {
2084    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2085        write!(f, "{}", self.inner)
2086    }
2087}
2088
2089impl DomId {
2090    pub const ROOT_ID: DomId = DomId { inner: 0 };
2091}
2092
2093impl Default for DomId {
2094    fn default() -> DomId {
2095        DomId::ROOT_ID
2096    }
2097}
2098
2099impl_option!(
2100    DomId,
2101    OptionDomId,
2102    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
2103);
2104
2105#[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
2106#[repr(C)]
2107pub struct NodeHierarchyItemId {
2108    pub inner: usize,
2109}
2110
2111impl fmt::Debug for NodeHierarchyItemId {
2112    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2113        match self.into_crate_internal() {
2114            Some(n) => write!(f, "Some(NodeId({}))", n),
2115            None => write!(f, "None"),
2116        }
2117    }
2118}
2119
2120impl fmt::Display for NodeHierarchyItemId {
2121    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2122        write!(f, "{:?}", self)
2123    }
2124}
2125
2126impl NodeHierarchyItemId {
2127    pub const NONE: NodeHierarchyItemId = NodeHierarchyItemId { inner: 0 };
2128}
2129
2130impl_option!(
2131    NodeHierarchyItemId,
2132    OptionNodeId,
2133    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
2134);
2135
2136impl_vec!(NodeHierarchyItemId, NodeIdVec, NodeIdVecDestructor);
2137impl_vec_mut!(NodeHierarchyItemId, NodeIdVec);
2138impl_vec_debug!(NodeHierarchyItemId, NodeIdVec);
2139impl_vec_ord!(NodeHierarchyItemId, NodeIdVec);
2140impl_vec_eq!(NodeHierarchyItemId, NodeIdVec);
2141impl_vec_hash!(NodeHierarchyItemId, NodeIdVec);
2142impl_vec_partialord!(NodeHierarchyItemId, NodeIdVec);
2143impl_vec_clone!(NodeHierarchyItemId, NodeIdVec, NodeIdVecDestructor);
2144impl_vec_partialeq!(NodeHierarchyItemId, NodeIdVec);
2145
2146impl NodeHierarchyItemId {
2147    #[inline]
2148    pub const fn into_crate_internal(&self) -> Option<NodeId> {
2149        NodeId::from_usize(self.inner)
2150    }
2151
2152    #[inline]
2153    pub const fn from_crate_internal(t: Option<NodeId>) -> Self {
2154        Self {
2155            inner: NodeId::into_usize(&t),
2156        }
2157    }
2158}
2159
2160#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
2161#[repr(C)]
2162pub struct AzTagId {
2163    pub inner: u64,
2164}
2165
2166impl_option!(
2167    AzTagId,
2168    OptionTagId,
2169    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
2170);
2171
2172impl AzTagId {
2173    pub const fn into_crate_internal(&self) -> TagId {
2174        TagId(self.inner)
2175    }
2176    pub const fn from_crate_internal(t: TagId) -> Self {
2177        AzTagId { inner: t.0 }
2178    }
2179}
2180
2181#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
2182#[repr(C)]
2183pub struct NodeHierarchyItem {
2184    pub parent: usize,
2185    pub previous_sibling: usize,
2186    pub next_sibling: usize,
2187    pub last_child: usize,
2188}
2189
2190impl NodeHierarchyItem {
2191    pub const fn zeroed() -> Self {
2192        Self {
2193            parent: 0,
2194            previous_sibling: 0,
2195            next_sibling: 0,
2196            last_child: 0,
2197        }
2198    }
2199}
2200
2201impl From<Node> for NodeHierarchyItem {
2202    fn from(node: Node) -> NodeHierarchyItem {
2203        NodeHierarchyItem {
2204            parent: NodeId::into_usize(&node.parent),
2205            previous_sibling: NodeId::into_usize(&node.previous_sibling),
2206            next_sibling: NodeId::into_usize(&node.next_sibling),
2207            last_child: NodeId::into_usize(&node.last_child),
2208        }
2209    }
2210}
2211
2212impl NodeHierarchyItem {
2213    pub fn parent_id(&self) -> Option<NodeId> {
2214        NodeId::from_usize(self.parent)
2215    }
2216    pub fn previous_sibling_id(&self) -> Option<NodeId> {
2217        NodeId::from_usize(self.previous_sibling)
2218    }
2219    pub fn next_sibling_id(&self) -> Option<NodeId> {
2220        NodeId::from_usize(self.next_sibling)
2221    }
2222    pub fn first_child_id(&self, current_node_id: NodeId) -> Option<NodeId> {
2223        self.last_child_id().map(|_| current_node_id + 1)
2224    }
2225    pub fn last_child_id(&self) -> Option<NodeId> {
2226        NodeId::from_usize(self.last_child)
2227    }
2228}
2229
2230impl_vec!(
2231    NodeHierarchyItem,
2232    NodeHierarchyItemVec,
2233    NodeHierarchyItemVecDestructor
2234);
2235impl_vec_mut!(NodeHierarchyItem, NodeHierarchyItemVec);
2236impl_vec_debug!(AzNode, NodeHierarchyItemVec);
2237impl_vec_partialord!(AzNode, NodeHierarchyItemVec);
2238impl_vec_clone!(
2239    NodeHierarchyItem,
2240    NodeHierarchyItemVec,
2241    NodeHierarchyItemVecDestructor
2242);
2243impl_vec_partialeq!(AzNode, NodeHierarchyItemVec);
2244
2245impl NodeHierarchyItemVec {
2246    pub fn as_container<'a>(&'a self) -> NodeDataContainerRef<'a, NodeHierarchyItem> {
2247        NodeDataContainerRef {
2248            internal: self.as_ref(),
2249        }
2250    }
2251    pub fn as_container_mut<'a>(&'a mut self) -> NodeDataContainerRefMut<'a, NodeHierarchyItem> {
2252        NodeDataContainerRefMut {
2253            internal: self.as_mut(),
2254        }
2255    }
2256}
2257
2258impl<'a> NodeDataContainerRef<'a, NodeHierarchyItem> {
2259    #[inline]
2260    pub fn subtree_len(&self, parent_id: NodeId) -> usize {
2261        let self_item_index = parent_id.index();
2262        let next_item_index = match self[parent_id].next_sibling_id() {
2263            None => self.len(),
2264            Some(s) => s.index(),
2265        };
2266        next_item_index - self_item_index - 1
2267    }
2268}
2269
2270#[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
2271#[repr(C)]
2272pub struct ParentWithNodeDepth {
2273    pub depth: usize,
2274    pub node_id: NodeHierarchyItemId,
2275}
2276
2277impl core::fmt::Debug for ParentWithNodeDepth {
2278    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
2279        write!(
2280            f,
2281            "{{ depth: {}, node: {:?} }}",
2282            self.depth,
2283            self.node_id.into_crate_internal()
2284        )
2285    }
2286}
2287
2288impl_vec!(
2289    ParentWithNodeDepth,
2290    ParentWithNodeDepthVec,
2291    ParentWithNodeDepthVecDestructor
2292);
2293impl_vec_mut!(ParentWithNodeDepth, ParentWithNodeDepthVec);
2294impl_vec_debug!(ParentWithNodeDepth, ParentWithNodeDepthVec);
2295impl_vec_partialord!(ParentWithNodeDepth, ParentWithNodeDepthVec);
2296impl_vec_clone!(
2297    ParentWithNodeDepth,
2298    ParentWithNodeDepthVec,
2299    ParentWithNodeDepthVecDestructor
2300);
2301impl_vec_partialeq!(ParentWithNodeDepth, ParentWithNodeDepthVec);
2302
2303#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd)]
2304#[repr(C)]
2305pub struct TagIdToNodeIdMapping {
2306    // Hit-testing tag ID (not all nodes have a tag, only nodes that are hit-testable)
2307    pub tag_id: AzTagId,
2308    /// Node ID of the node that has a tag
2309    pub node_id: NodeHierarchyItemId,
2310    /// Whether this node has a tab-index field
2311    pub tab_index: OptionTabIndex,
2312    /// Parents of this NodeID, sorted in depth order, necessary for efficient hit-testing
2313    pub parent_node_ids: NodeIdVec,
2314}
2315
2316impl_vec!(
2317    TagIdToNodeIdMapping,
2318    TagIdToNodeIdMappingVec,
2319    TagIdToNodeIdMappingVecDestructor
2320);
2321impl_vec_mut!(TagIdToNodeIdMapping, TagIdToNodeIdMappingVec);
2322impl_vec_debug!(TagIdToNodeIdMapping, TagIdToNodeIdMappingVec);
2323impl_vec_partialord!(TagIdToNodeIdMapping, TagIdToNodeIdMappingVec);
2324impl_vec_clone!(
2325    TagIdToNodeIdMapping,
2326    TagIdToNodeIdMappingVec,
2327    TagIdToNodeIdMappingVecDestructor
2328);
2329impl_vec_partialeq!(TagIdToNodeIdMapping, TagIdToNodeIdMappingVec);
2330
2331#[derive(Debug, Clone, PartialEq, PartialOrd)]
2332#[repr(C)]
2333pub struct ContentGroup {
2334    /// The parent of the current node group, i.e. either the root node (0)
2335    /// or the last positioned node ()
2336    pub root: NodeHierarchyItemId,
2337    /// Node ids in order of drawing
2338    pub children: ContentGroupVec,
2339}
2340
2341impl_vec!(ContentGroup, ContentGroupVec, ContentGroupVecDestructor);
2342impl_vec_mut!(ContentGroup, ContentGroupVec);
2343impl_vec_debug!(ContentGroup, ContentGroupVec);
2344impl_vec_partialord!(ContentGroup, ContentGroupVec);
2345impl_vec_clone!(ContentGroup, ContentGroupVec, ContentGroupVecDestructor);
2346impl_vec_partialeq!(ContentGroup, ContentGroupVec);
2347
2348#[derive(Debug, PartialEq, Clone)]
2349#[repr(C)]
2350pub struct StyledDom {
2351    pub root: NodeHierarchyItemId,
2352    pub node_hierarchy: NodeHierarchyItemVec,
2353    pub node_data: NodeDataVec,
2354    pub styled_nodes: StyledNodeVec,
2355    pub cascade_info: CascadeInfoVec,
2356    pub nodes_with_window_callbacks: NodeIdVec,
2357    pub nodes_with_not_callbacks: NodeIdVec,
2358    pub nodes_with_datasets: NodeIdVec,
2359    pub tag_ids_to_node_ids: TagIdToNodeIdMappingVec,
2360    pub non_leaf_nodes: ParentWithNodeDepthVec,
2361    pub css_property_cache: CssPropertyCachePtr,
2362}
2363
2364impl Default for StyledDom {
2365    fn default() -> Self {
2366        let root_node: NodeHierarchyItem = Node::ROOT.into();
2367        let root_node_id: NodeHierarchyItemId =
2368            NodeHierarchyItemId::from_crate_internal(Some(NodeId::ZERO));
2369        Self {
2370            root: root_node_id,
2371            node_hierarchy: vec![root_node].into(),
2372            node_data: vec![NodeData::body()].into(),
2373            styled_nodes: vec![StyledNode::default()].into(),
2374            cascade_info: vec![CascadeInfo {
2375                index_in_parent: 0,
2376                is_last_child: true,
2377            }]
2378            .into(),
2379            tag_ids_to_node_ids: Vec::new().into(),
2380            non_leaf_nodes: vec![ParentWithNodeDepth {
2381                depth: 0,
2382                node_id: root_node_id,
2383            }]
2384            .into(),
2385            nodes_with_window_callbacks: Vec::new().into(),
2386            nodes_with_not_callbacks: Vec::new().into(),
2387            nodes_with_datasets: Vec::new().into(),
2388            css_property_cache: CssPropertyCachePtr::new(CssPropertyCache::empty(1)),
2389        }
2390    }
2391}
2392
2393impl StyledDom {
2394    // NOTE: After calling this function, the DOM will be reset to an empty DOM.
2395    // This is for memory optimization, so that the DOM does not need to be cloned.
2396    //
2397    // The CSS will be left in-place, but will be re-ordered
2398    pub fn new(dom: &mut Dom, mut css: CssApiWrapper) -> Self {
2399        use core::mem;
2400
2401        use crate::dom::EventFilter;
2402
2403        let mut swap_dom = Dom::body();
2404
2405        mem::swap(dom, &mut swap_dom);
2406
2407        let compact_dom: CompactDom = swap_dom.into();
2408        let non_leaf_nodes = compact_dom
2409            .node_hierarchy
2410            .as_ref()
2411            .get_parents_sorted_by_depth();
2412        let node_hierarchy: NodeHierarchyItemVec = compact_dom
2413            .node_hierarchy
2414            .as_ref()
2415            .internal
2416            .iter()
2417            .map(|i| (*i).into())
2418            .collect::<Vec<NodeHierarchyItem>>()
2419            .into();
2420
2421        let mut styled_nodes = vec![
2422            StyledNode {
2423                tag_id: OptionTagId::None,
2424                state: StyledNodeState::new()
2425            };
2426            compact_dom.len()
2427        ];
2428
2429        // fill out the css property cache: compute the inline properties first so that
2430        // we can early-return in case the css is empty
2431
2432        let mut css_property_cache = CssPropertyCache::empty(compact_dom.node_data.len());
2433
2434        let html_tree =
2435            construct_html_cascade_tree(&compact_dom.node_hierarchy.as_ref(), &non_leaf_nodes[..]);
2436
2437        let non_leaf_nodes = non_leaf_nodes
2438            .iter()
2439            .map(|(depth, node_id)| ParentWithNodeDepth {
2440                depth: *depth,
2441                node_id: NodeHierarchyItemId::from_crate_internal(Some(*node_id)),
2442            })
2443            .collect::<Vec<_>>();
2444
2445        let non_leaf_nodes: ParentWithNodeDepthVec = non_leaf_nodes.into();
2446
2447        // apply all the styles from the CSS
2448        let tag_ids = css_property_cache.restyle(
2449            &mut css.css,
2450            &compact_dom.node_data.as_ref(),
2451            &node_hierarchy,
2452            &non_leaf_nodes,
2453            &html_tree.as_ref(),
2454        );
2455
2456        tag_ids
2457            .iter()
2458            .filter_map(|tag_id_node_id_mapping| {
2459                tag_id_node_id_mapping
2460                    .node_id
2461                    .into_crate_internal()
2462                    .map(|node_id| (node_id, tag_id_node_id_mapping.tag_id))
2463            })
2464            .for_each(|(nid, tag_id)| {
2465                styled_nodes[nid.index()].tag_id = OptionTagId::Some(tag_id);
2466            });
2467
2468        // Pre-filter all EventFilter::Window and EventFilter::Not nodes
2469        // since we need them in the CallbacksOfHitTest::new function
2470        let nodes_with_window_callbacks = compact_dom
2471            .node_data
2472            .as_ref()
2473            .internal
2474            .iter()
2475            .enumerate()
2476            .filter_map(|(node_id, c)| {
2477                let node_has_none_callbacks = c.get_callbacks().iter().any(|cb| match cb.event {
2478                    EventFilter::Window(_) => true,
2479                    _ => false,
2480                });
2481                if node_has_none_callbacks {
2482                    Some(NodeHierarchyItemId::from_crate_internal(Some(NodeId::new(
2483                        node_id,
2484                    ))))
2485                } else {
2486                    None
2487                }
2488            })
2489            .collect::<Vec<_>>();
2490
2491        let nodes_with_not_callbacks = compact_dom
2492            .node_data
2493            .as_ref()
2494            .internal
2495            .iter()
2496            .enumerate()
2497            .filter_map(|(node_id, c)| {
2498                let node_has_none_callbacks = c.get_callbacks().iter().any(|cb| match cb.event {
2499                    EventFilter::Not(_) => true,
2500                    _ => false,
2501                });
2502                if node_has_none_callbacks {
2503                    Some(NodeHierarchyItemId::from_crate_internal(Some(NodeId::new(
2504                        node_id,
2505                    ))))
2506                } else {
2507                    None
2508                }
2509            })
2510            .collect::<Vec<_>>();
2511
2512        // collect nodes with either dataset or callback properties
2513        let nodes_with_datasets = compact_dom
2514            .node_data
2515            .as_ref()
2516            .internal
2517            .iter()
2518            .enumerate()
2519            .filter_map(|(node_id, c)| {
2520                if !c.get_callbacks().is_empty() || c.get_dataset().is_some() {
2521                    Some(NodeHierarchyItemId::from_crate_internal(Some(NodeId::new(
2522                        node_id,
2523                    ))))
2524                } else {
2525                    None
2526                }
2527            })
2528            .collect::<Vec<_>>();
2529
2530        StyledDom {
2531            root: NodeHierarchyItemId::from_crate_internal(Some(compact_dom.root)),
2532            node_hierarchy,
2533            node_data: compact_dom.node_data.internal.into(),
2534            cascade_info: html_tree.internal.into(),
2535            styled_nodes: styled_nodes.into(),
2536            tag_ids_to_node_ids: tag_ids.into(),
2537            nodes_with_window_callbacks: nodes_with_window_callbacks.into(),
2538            nodes_with_not_callbacks: nodes_with_not_callbacks.into(),
2539            nodes_with_datasets: nodes_with_datasets.into(),
2540            non_leaf_nodes,
2541            css_property_cache: CssPropertyCachePtr::new(css_property_cache),
2542        }
2543    }
2544
2545    /// Appends another `StyledDom` as a child to the `self.root`
2546    /// without re-styling the DOM itself
2547    pub fn append_child(&mut self, mut other: Self) {
2548        // shift all the node ids in other by self.len()
2549        let self_len = self.node_hierarchy.as_ref().len();
2550        let other_len = other.node_hierarchy.as_ref().len();
2551        let self_tag_len = self.tag_ids_to_node_ids.as_ref().len();
2552        let self_root_id = self.root.into_crate_internal().unwrap_or(NodeId::ZERO);
2553        let other_root_id = other.root.into_crate_internal().unwrap_or(NodeId::ZERO);
2554
2555        // iterate through the direct root children and adjust the cascade_info
2556        let current_root_children_count = self_root_id
2557            .az_children(&self.node_hierarchy.as_container())
2558            .count();
2559
2560        other.cascade_info.as_mut()[other_root_id.index()].index_in_parent =
2561            current_root_children_count as u32;
2562        other.cascade_info.as_mut()[other_root_id.index()].is_last_child = true;
2563
2564        self.cascade_info.append(&mut other.cascade_info);
2565
2566        // adjust node hierarchy
2567        for other in other.node_hierarchy.as_mut().iter_mut() {
2568            other.parent += self_len;
2569            other.previous_sibling += if other.previous_sibling == 0 {
2570                0
2571            } else {
2572                self_len
2573            };
2574            other.next_sibling += if other.next_sibling == 0 { 0 } else { self_len };
2575            other.last_child += if other.last_child == 0 { 0 } else { self_len };
2576        }
2577
2578        other.node_hierarchy.as_container_mut()[other_root_id].parent =
2579            NodeId::into_usize(&Some(self_root_id));
2580        let current_last_child = self.node_hierarchy.as_container()[self_root_id].last_child_id();
2581        other.node_hierarchy.as_container_mut()[other_root_id].previous_sibling =
2582            NodeId::into_usize(&current_last_child);
2583        if let Some(current_last) = current_last_child {
2584            if self.node_hierarchy.as_container_mut()[current_last]
2585                .next_sibling_id()
2586                .is_some()
2587            {
2588                self.node_hierarchy.as_container_mut()[current_last].next_sibling +=
2589                    other_root_id.index() + 1;
2590            } else {
2591                self.node_hierarchy.as_container_mut()[current_last].next_sibling =
2592                    self_len + other_root_id.index() + 1;
2593            }
2594        }
2595        self.node_hierarchy.as_container_mut()[self_root_id].last_child =
2596            self_len + other_root_id.index() + 1;
2597
2598        self.node_hierarchy.append(&mut other.node_hierarchy);
2599        self.node_data.append(&mut other.node_data);
2600        self.styled_nodes.append(&mut other.styled_nodes);
2601        self.get_css_property_cache_mut()
2602            .append(other.get_css_property_cache_mut());
2603
2604        for tag_id_node_id in other.tag_ids_to_node_ids.iter_mut() {
2605            tag_id_node_id.tag_id.inner += self_tag_len as u64;
2606            tag_id_node_id.node_id.inner += self_len;
2607        }
2608
2609        self.tag_ids_to_node_ids
2610            .append(&mut other.tag_ids_to_node_ids);
2611
2612        for nid in other.nodes_with_window_callbacks.iter_mut() {
2613            nid.inner += self_len;
2614        }
2615        self.nodes_with_window_callbacks
2616            .append(&mut other.nodes_with_window_callbacks);
2617
2618        for nid in other.nodes_with_not_callbacks.iter_mut() {
2619            nid.inner += self_len;
2620        }
2621        self.nodes_with_not_callbacks
2622            .append(&mut other.nodes_with_not_callbacks);
2623
2624        for nid in other.nodes_with_datasets.iter_mut() {
2625            nid.inner += self_len;
2626        }
2627        self.nodes_with_datasets
2628            .append(&mut other.nodes_with_datasets);
2629
2630        // edge case: if the other StyledDom consists of only one node
2631        // then it is not a parent itself
2632        if other_len != 1 {
2633            for other_non_leaf_node in other.non_leaf_nodes.iter_mut() {
2634                other_non_leaf_node.node_id.inner += self_len;
2635                other_non_leaf_node.depth += 1;
2636            }
2637            self.non_leaf_nodes.append(&mut other.non_leaf_nodes);
2638            self.non_leaf_nodes.sort_by(|a, b| a.depth.cmp(&b.depth));
2639        }
2640    }
2641
2642    /// Inject scroll bar DIVs with relevant event handlers into the DOM
2643    ///
2644    /// This function essentially takes a DOM and inserts a wrapper DIV
2645    /// on every parent. First, all scrollbars are set to "display:none;"
2646    /// with a special library-internal marker that indicates that this
2647    /// DIV is a scrollbar. Then later on in the layout code, the items
2648    /// are set to "display: flex / block" as necessary, because
2649    /// this way scrollbars aren't treated as "special" objects (the event
2650    /// handling for scrollbars are just regular callback handlers).
2651    pub fn inject_scroll_bars(&mut self) {
2652        use azul_css::parser::CssApiWrapper;
2653
2654        // allocate 14 nodes for every node
2655        //
2656        // 0: root component
2657        // 1: |- vertical container (flex-direction: column-reverse, flex-grow: 1)
2658        // 2:    |- horizontal scrollbar (height: 15px, flex-direction: row)
2659        // 3:    |  |- left thumb
2660        // 4:    |  |- middle content
2661        // 5:    |  |   |- thumb track
2662        // 6:    |  |- right thumb
2663        // 7:    |- content container (flex-direction: row-reverse, flex-grow: 1)
2664        // 8:       |- vertical scrollbar (width: 15px, flex-direction: column)
2665        // 9:       |   |- top thumb
2666        // 10:      |   |- middle content
2667        // 11:      |   |    |- thumb track
2668        // 12:      |   |- bottom thumb
2669        // 13:      |- content container (flex-direction: row, flex-grow: 1)
2670        // 14:          |- self.root
2671        //                  |- ... self.children
2672
2673        let dom_to_inject = Dom::div()
2674        // .with_class("__azul-native-scroll-root-component".into())
2675        .with_inline_style("display:flex; flex-grow:1; flex-direction:column;".into())
2676        .with_children(vec![
2677
2678            Dom::div()
2679            // .with_class("__azul-native-scroll-vertical-container".into())
2680            .with_inline_style("display:flex; flex-grow:1; flex-direction:column-reverse;".into())
2681            .with_children(vec![
2682
2683                Dom::div()
2684                // .with_class("__azul-native-scroll-horizontal-scrollbar".into())
2685                .with_inline_style("display:flex; flex-grow:1; flex-direction:row; height:15px; background:grey;".into())
2686                .with_children(vec![
2687                    Dom::div(),
2688                    // .with_class("__azul-native-scroll-horizontal-scrollbar-track-left".into()),
2689                    Dom::div()
2690                    // .with_class("__azul-native-scroll-horizontal-scrollbar-track-middle".into())
2691                    .with_children(vec![
2692                        Dom::div()
2693                        // .with_class("__azul-native-scroll-horizontal-scrollbar-track-thumb".into())
2694                    ].into()),
2695                    Dom::div()
2696                    // .with_class("__azul-native-scroll-horizontal-scrollbar-track-right".into()),
2697                ].into()),
2698
2699                Dom::div()
2700                // .with_class("__azul-native-scroll-content-container-1".into())
2701                .with_inline_style("display:flex; flex-grow:1; flex-direction:row-reverse;".into())
2702                .with_children(vec![
2703
2704                    Dom::div()
2705                    // .with_class("__azul-native-scroll-vertical-scrollbar".into())
2706                    .with_inline_style("display:flex; flex-grow:1; flex-direction:column; width:15px; background:grey;".into())
2707                    .with_children(vec![
2708                       Dom::div(),
2709                       // .with_class("__azul-native-scroll-vertical-scrollbar-track-top".into()),
2710                       Dom::div()
2711                       // .with_class("__azul-native-scroll-vertical-scrollbar-track-middle".into())
2712                       .with_children(vec![
2713                           Dom::div()
2714                           // .with_class("__azul-native-scroll-vertical-scrollbar-track-thumb".into())
2715                       ].into()),
2716                       Dom::div()
2717                       // .with_class("__azul-native-scroll-vertical-scrollbar-track-bottom".into()),
2718                    ].into()),
2719
2720                    Dom::div()
2721                    // .with_class("__azul-native-scroll-content-container-1".into())
2722                    .with_inline_style("display:flex; flex-grow:1; flex-direction:column;".into())
2723                    .with_children(vec![
2724                        Dom::div() // <- this div is where the new children will be injected into
2725                    ].into())
2726                ].into())
2727            ].into())
2728        ].into())
2729        .style(CssApiWrapper::empty());
2730
2731        // allocate new nodes
2732        let nodes_to_allocate =
2733            self.node_data.len() + (self.non_leaf_nodes.len() * dom_to_inject.node_data.len());
2734
2735        // pre-allocate a new DOM tree with self.nodes.len() * dom_to_inject.nodes.len() nodes
2736
2737        let mut new_styled_dom = StyledDom {
2738            root: self.root,
2739            node_hierarchy: vec![NodeHierarchyItem::zeroed(); nodes_to_allocate].into(),
2740            node_data: vec![NodeData::default(); nodes_to_allocate].into(),
2741            styled_nodes: vec![StyledNode::default(); nodes_to_allocate].into(),
2742            cascade_info: vec![CascadeInfo::default(); nodes_to_allocate].into(),
2743            nodes_with_window_callbacks: self.nodes_with_window_callbacks.clone(),
2744            nodes_with_not_callbacks: self.nodes_with_not_callbacks.clone(),
2745            nodes_with_datasets: self.nodes_with_datasets.clone(),
2746            tag_ids_to_node_ids: self.tag_ids_to_node_ids.clone(),
2747            non_leaf_nodes: self.non_leaf_nodes.clone(),
2748            css_property_cache: self.css_property_cache.clone(),
2749        };
2750
2751        // inject self.root as the nth node
2752        let inject_as_id = 0;
2753
2754        #[cfg(feature = "std")]
2755        {
2756            println!(
2757                "inject scroll bars:\r\n{}",
2758                dom_to_inject.get_html_string("", "", true)
2759            );
2760        }
2761
2762        // *self = new_styled_dom;
2763    }
2764
2765    /// Inject a menu bar into the root component
2766    pub fn inject_menu_bar(mut self, menu_bar: &Menu) -> Self {
2767        use azul_css::parser::CssApiWrapper;
2768
2769        use crate::window::MenuItem;
2770
2771        let menu_dom = menu_bar
2772            .items
2773            .as_ref()
2774            .iter()
2775            .map(|mi| match mi {
2776                MenuItem::String(smi) => Dom::text(smi.label.clone().into_library_owned_string())
2777                    .with_inline_style("font-family:sans-serif;".into()),
2778                MenuItem::Separator => {
2779                    Dom::div().with_inline_style("padding:1px;background:grey;".into())
2780                }
2781                MenuItem::BreakLine => Dom::div(),
2782            })
2783            .collect::<Dom>()
2784            .with_inline_style(
2785                "
2786            height:20px;
2787            display:flex;
2788            flex-direction:row;"
2789                    .into(),
2790            )
2791            .style(CssApiWrapper::empty());
2792
2793        let mut core_container = Dom::body().style(CssApiWrapper::empty());
2794        core_container.append_child(menu_dom);
2795        core_container.append_child(self);
2796        core_container
2797    }
2798
2799    /// Same as `append_child()`, but as a builder method
2800    pub fn with_child(&mut self, other: Self) -> Self {
2801        let mut s = self.swap_with_default();
2802        s.append_child(other);
2803        s
2804    }
2805
2806    pub fn restyle(&mut self, mut css: CssApiWrapper) {
2807        let new_tag_ids = self.css_property_cache.downcast_mut().restyle(
2808            &mut css.css,
2809            &self.node_data.as_container(),
2810            &self.node_hierarchy,
2811            &self.non_leaf_nodes,
2812            &self.cascade_info.as_container(),
2813        );
2814
2815        // Restyling may change the tag IDs
2816        let mut styled_nodes_mut = self.styled_nodes.as_container_mut();
2817
2818        styled_nodes_mut
2819            .internal
2820            .iter_mut()
2821            .for_each(|styled_node| {
2822                styled_node.tag_id = None.into();
2823            });
2824
2825        new_tag_ids
2826            .iter()
2827            .filter_map(|tag_id_node_id_mapping| {
2828                tag_id_node_id_mapping
2829                    .node_id
2830                    .into_crate_internal()
2831                    .map(|node_id| (node_id, tag_id_node_id_mapping.tag_id))
2832            })
2833            .for_each(|(nid, tag_id)| {
2834                styled_nodes_mut[nid].tag_id = Some(tag_id).into();
2835            });
2836
2837        self.tag_ids_to_node_ids = new_tag_ids.into();
2838    }
2839
2840    /// Inserts default On::Scroll and On::Tab handle for scroll-able
2841    /// and tabindex-able nodes.
2842    #[inline]
2843    pub fn insert_default_system_callbacks(&mut self, config: DefaultCallbacksCfg) {
2844        use crate::{
2845            callbacks::Callback,
2846            dom::{CallbackData, EventFilter, FocusEventFilter, HoverEventFilter},
2847        };
2848
2849        let scroll_refany = RefAny::new(DefaultScrollCallbackData {
2850            smooth_scroll: config.smooth_scroll,
2851        });
2852
2853        for n in self.node_data.iter_mut() {
2854            // TODO: ScrollStart / ScrollEnd?
2855            if !n
2856                .callbacks
2857                .iter()
2858                .any(|cb| cb.event == EventFilter::Hover(HoverEventFilter::Scroll))
2859            {
2860                n.callbacks.push(CallbackData {
2861                    event: EventFilter::Hover(HoverEventFilter::Scroll),
2862                    data: scroll_refany.clone(),
2863                    callback: Callback {
2864                        cb: default_on_scroll,
2865                    },
2866                });
2867            }
2868        }
2869
2870        if !config.enable_autotab {
2871            return;
2872        }
2873
2874        let tab_data = RefAny::new(DefaultTabIndexCallbackData {});
2875        for focusable_node in self.tag_ids_to_node_ids.iter() {
2876            if focusable_node.tab_index.is_some() {
2877                let focusable_node_id = match focusable_node.node_id.into_crate_internal() {
2878                    Some(s) => s,
2879                    None => continue,
2880                };
2881
2882                let mut node_data = &mut self.node_data.as_container_mut()[focusable_node_id];
2883                if !node_data
2884                    .callbacks
2885                    .iter()
2886                    .any(|cb| cb.event == EventFilter::Focus(FocusEventFilter::VirtualKeyDown))
2887                {
2888                    node_data.callbacks.push(CallbackData {
2889                        event: EventFilter::Focus(FocusEventFilter::VirtualKeyDown),
2890                        data: tab_data.clone(),
2891                        callback: Callback {
2892                            cb: default_on_tabindex,
2893                        },
2894                    });
2895                }
2896            }
2897        }
2898    }
2899
2900    #[inline]
2901    pub fn node_count(&self) -> usize {
2902        self.node_data.len()
2903    }
2904
2905    #[inline]
2906    pub fn get_css_property_cache<'a>(&'a self) -> &'a CssPropertyCache {
2907        &*self.css_property_cache.ptr
2908    }
2909
2910    #[inline]
2911    pub fn get_css_property_cache_mut<'a>(&'a mut self) -> &'a mut CssPropertyCache {
2912        &mut *self.css_property_cache.ptr
2913    }
2914
2915    #[inline]
2916    pub fn get_styled_node_state(&self, node_id: &NodeId) -> StyledNodeState {
2917        self.styled_nodes.as_container()[*node_id].state.clone()
2918    }
2919
2920    /// Scans the display list for all font IDs + their font size
2921    pub fn scan_for_font_keys(
2922        &self,
2923        resources: &RendererResources,
2924    ) -> FastHashMap<ImmediateFontId, FastBTreeSet<Au>> {
2925        use crate::{app_resources::font_size_to_au, dom::NodeType::*};
2926
2927        let keys = self
2928            .node_data
2929            .as_ref()
2930            .iter()
2931            .enumerate()
2932            .filter_map(|(node_id, node_data)| {
2933                let node_id = NodeId::new(node_id);
2934                match node_data.get_node_type() {
2935                    Text(_) => {
2936                        let css_font_ids = self.get_css_property_cache().get_font_id_or_default(
2937                            &node_data,
2938                            &node_id,
2939                            &self.styled_nodes.as_container()[node_id].state,
2940                        );
2941
2942                        let font_size = self.get_css_property_cache().get_font_size_or_default(
2943                            &node_data,
2944                            &node_id,
2945                            &self.styled_nodes.as_container()[node_id].state,
2946                        );
2947
2948                        let style_font_families_hash =
2949                            StyleFontFamiliesHash::new(css_font_ids.as_ref());
2950
2951                        let existing_font_key = resources
2952                            .get_font_family(&style_font_families_hash)
2953                            .and_then(|font_family_hash| {
2954                                resources
2955                                    .get_font_key(&font_family_hash)
2956                                    .map(|font_key| (font_family_hash, font_key))
2957                            });
2958
2959                        let font_id = match existing_font_key {
2960                            Some((hash, key)) => ImmediateFontId::Resolved((*hash, *key)),
2961                            None => ImmediateFontId::Unresolved(css_font_ids),
2962                        };
2963
2964                        Some((font_id, font_size_to_au(font_size)))
2965                    }
2966                    _ => None,
2967                }
2968            })
2969            .collect::<Vec<_>>();
2970
2971        let mut map = FastHashMap::default();
2972
2973        for (font_id, au) in keys.into_iter() {
2974            map.entry(font_id)
2975                .or_insert_with(|| FastBTreeSet::default())
2976                .insert(au);
2977        }
2978
2979        map
2980    }
2981
2982    /// Scans the display list for all image keys
2983    pub fn scan_for_image_keys(&self, css_image_cache: &ImageCache) -> FastBTreeSet<ImageRef> {
2984        use azul_css::StyleBackgroundContentVec;
2985
2986        use crate::{app_resources::OptionImageMask, dom::NodeType::*};
2987
2988        #[derive(Default)]
2989        struct ScanImageVec {
2990            node_type_image: Option<ImageRef>,
2991            background_image: Vec<ImageRef>,
2992            clip_mask: Option<ImageRef>,
2993        }
2994
2995        let default_backgrounds: StyleBackgroundContentVec = Vec::new().into();
2996
2997        let images = self
2998            .node_data
2999            .as_container()
3000            .internal
3001            .iter()
3002            .enumerate()
3003            .map(|(node_id, node_data)| {
3004                let node_id = NodeId::new(node_id);
3005                let mut v = ScanImageVec::default();
3006
3007                // If the node has an image content, it needs to be uploaded
3008                if let Image(id) = node_data.get_node_type() {
3009                    v.node_type_image = Some(id.clone());
3010                }
3011
3012                // If the node has a CSS background image, it needs to be uploaded
3013                let opt_background_image = self.get_css_property_cache().get_background_content(
3014                    &node_data,
3015                    &node_id,
3016                    &self.styled_nodes.as_container()[node_id].state,
3017                );
3018
3019                if let Some(style_backgrounds) = opt_background_image {
3020                    v.background_image = style_backgrounds
3021                        .get_property()
3022                        .unwrap_or(&default_backgrounds)
3023                        .iter()
3024                        .filter_map(|bg| {
3025                            use azul_css::StyleBackgroundContent::*;
3026                            let css_image_id = match bg {
3027                                Image(i) => i,
3028                                _ => return None,
3029                            };
3030                            let image_ref = css_image_cache.get_css_image_id(css_image_id)?;
3031                            Some(image_ref.clone())
3032                        })
3033                        .collect();
3034                }
3035
3036                // If the node has a clip mask, it needs to be uploaded
3037                if let Some(clip_mask) = node_data.get_clip_mask() {
3038                    v.clip_mask = Some(clip_mask.image.clone());
3039                }
3040
3041                v
3042            })
3043            .collect::<Vec<_>>();
3044
3045        let mut set = FastBTreeSet::new();
3046
3047        for scan_image in images.into_iter() {
3048            if let Some(n) = scan_image.node_type_image {
3049                set.insert(n);
3050            }
3051            if let Some(n) = scan_image.clip_mask {
3052                set.insert(n);
3053            }
3054            for bg in scan_image.background_image {
3055                set.insert(bg);
3056            }
3057        }
3058
3059        set
3060    }
3061
3062    #[must_use]
3063    pub fn restyle_nodes_hover(
3064        &mut self,
3065        nodes: &[NodeId],
3066        new_hover_state: bool,
3067    ) -> BTreeMap<NodeId, Vec<ChangedCssProperty>> {
3068        // save the old node state
3069        let old_node_states = nodes
3070            .iter()
3071            .map(|nid| self.styled_nodes.as_container()[*nid].state.clone())
3072            .collect::<Vec<_>>();
3073
3074        for nid in nodes.iter() {
3075            self.styled_nodes.as_container_mut()[*nid].state.hover = new_hover_state;
3076        }
3077
3078        let css_property_cache = self.get_css_property_cache();
3079        let styled_nodes = self.styled_nodes.as_container();
3080        let node_data = self.node_data.as_container();
3081
3082        let default_map = BTreeMap::default();
3083
3084        // scan all properties that could have changed because of addition / removal
3085        let v = nodes
3086            .iter()
3087            .zip(old_node_states.iter())
3088            .filter_map(|(node_id, old_node_state)| {
3089                let mut keys_normal: Vec<_> = css_property_cache
3090                    .css_hover_props
3091                    .get(node_id)
3092                    .unwrap_or(&default_map)
3093                    .keys()
3094                    .collect();
3095                let mut keys_inherited: Vec<_> = css_property_cache
3096                    .cascaded_hover_props
3097                    .get(node_id)
3098                    .unwrap_or(&default_map)
3099                    .keys()
3100                    .collect();
3101                let keys_inline: Vec<CssPropertyType> = node_data[*node_id]
3102                    .inline_css_props
3103                    .iter()
3104                    .filter_map(|prop| match prop {
3105                        NodeDataInlineCssProperty::Hover(h) => Some(h.get_type()),
3106                        _ => None,
3107                    })
3108                    .collect();
3109                let mut keys_inline_ref = keys_inline.iter().map(|r| r).collect();
3110
3111                keys_normal.append(&mut keys_inherited);
3112                keys_normal.append(&mut keys_inline_ref);
3113
3114                let node_properties_that_could_have_changed = keys_normal;
3115
3116                if node_properties_that_could_have_changed.is_empty() {
3117                    return None;
3118                }
3119
3120                let new_node_state = &styled_nodes[*node_id].state;
3121                let node_data = &node_data[*node_id];
3122
3123                let changes = node_properties_that_could_have_changed
3124                    .into_iter()
3125                    .filter_map(|prop| {
3126                        // calculate both the old and the new state
3127                        let old = css_property_cache.get_property(
3128                            node_data,
3129                            node_id,
3130                            old_node_state,
3131                            prop,
3132                        );
3133                        let new = css_property_cache.get_property(
3134                            node_data,
3135                            node_id,
3136                            new_node_state,
3137                            prop,
3138                        );
3139                        if old == new {
3140                            None
3141                        } else {
3142                            Some(ChangedCssProperty {
3143                                previous_state: old_node_state.clone(),
3144                                previous_prop: match old {
3145                                    None => CssProperty::auto(*prop),
3146                                    Some(s) => s.clone(),
3147                                },
3148                                current_state: new_node_state.clone(),
3149                                current_prop: match new {
3150                                    None => CssProperty::auto(*prop),
3151                                    Some(s) => s.clone(),
3152                                },
3153                            })
3154                        }
3155                    })
3156                    .collect::<Vec<_>>();
3157
3158                if changes.is_empty() {
3159                    None
3160                } else {
3161                    Some((*node_id, changes))
3162                }
3163            })
3164            .collect::<Vec<_>>();
3165
3166        v.into_iter().collect()
3167    }
3168
3169    #[must_use]
3170    pub fn restyle_nodes_active(
3171        &mut self,
3172        nodes: &[NodeId],
3173        new_active_state: bool,
3174    ) -> BTreeMap<NodeId, Vec<ChangedCssProperty>> {
3175        // save the old node state
3176        let old_node_states = nodes
3177            .iter()
3178            .map(|nid| self.styled_nodes.as_container()[*nid].state.clone())
3179            .collect::<Vec<_>>();
3180
3181        for nid in nodes.iter() {
3182            self.styled_nodes.as_container_mut()[*nid].state.active = new_active_state;
3183        }
3184
3185        let css_property_cache = self.get_css_property_cache();
3186        let styled_nodes = self.styled_nodes.as_container();
3187        let node_data = self.node_data.as_container();
3188
3189        let default_map = BTreeMap::default();
3190
3191        // scan all properties that could have changed because of addition / removal
3192        let v = nodes
3193            .iter()
3194            .zip(old_node_states.iter())
3195            .filter_map(|(node_id, old_node_state)| {
3196                let mut keys_normal: Vec<_> = css_property_cache
3197                    .css_active_props
3198                    .get(node_id)
3199                    .unwrap_or(&default_map)
3200                    .keys()
3201                    .collect();
3202
3203                let mut keys_inherited: Vec<_> = css_property_cache
3204                    .cascaded_active_props
3205                    .get(node_id)
3206                    .unwrap_or(&default_map)
3207                    .keys()
3208                    .collect();
3209
3210                let keys_inline: Vec<CssPropertyType> = node_data[*node_id]
3211                    .inline_css_props
3212                    .iter()
3213                    .filter_map(|prop| match prop {
3214                        NodeDataInlineCssProperty::Active(h) => Some(h.get_type()),
3215                        _ => None,
3216                    })
3217                    .collect();
3218                let mut keys_inline_ref = keys_inline.iter().map(|r| r).collect();
3219
3220                keys_normal.append(&mut keys_inherited);
3221                keys_normal.append(&mut keys_inline_ref);
3222
3223                let node_properties_that_could_have_changed = keys_normal;
3224
3225                if node_properties_that_could_have_changed.is_empty() {
3226                    return None;
3227                }
3228
3229                let new_node_state = &styled_nodes[*node_id].state;
3230                let node_data = &node_data[*node_id];
3231
3232                let changes = node_properties_that_could_have_changed
3233                    .into_iter()
3234                    .filter_map(|prop| {
3235                        // calculate both the old and the new state
3236                        let old = css_property_cache.get_property(
3237                            node_data,
3238                            node_id,
3239                            old_node_state,
3240                            prop,
3241                        );
3242                        let new = css_property_cache.get_property(
3243                            node_data,
3244                            node_id,
3245                            new_node_state,
3246                            prop,
3247                        );
3248                        if old == new {
3249                            None
3250                        } else {
3251                            Some(ChangedCssProperty {
3252                                previous_state: old_node_state.clone(),
3253                                previous_prop: match old {
3254                                    None => CssProperty::auto(*prop),
3255                                    Some(s) => s.clone(),
3256                                },
3257                                current_state: new_node_state.clone(),
3258                                current_prop: match new {
3259                                    None => CssProperty::auto(*prop),
3260                                    Some(s) => s.clone(),
3261                                },
3262                            })
3263                        }
3264                    })
3265                    .collect::<Vec<_>>();
3266
3267                if changes.is_empty() {
3268                    None
3269                } else {
3270                    Some((*node_id, changes))
3271                }
3272            })
3273            .collect::<Vec<_>>();
3274
3275        v.into_iter().collect()
3276    }
3277
3278    #[must_use]
3279    pub fn restyle_nodes_focus(
3280        &mut self,
3281        nodes: &[NodeId],
3282        new_focus_state: bool,
3283    ) -> BTreeMap<NodeId, Vec<ChangedCssProperty>> {
3284        // save the old node state
3285        let old_node_states = nodes
3286            .iter()
3287            .map(|nid| self.styled_nodes.as_container()[*nid].state.clone())
3288            .collect::<Vec<_>>();
3289
3290        for nid in nodes.iter() {
3291            self.styled_nodes.as_container_mut()[*nid].state.focused = new_focus_state;
3292        }
3293
3294        let css_property_cache = self.get_css_property_cache();
3295        let styled_nodes = self.styled_nodes.as_container();
3296        let node_data = self.node_data.as_container();
3297
3298        let default_map = BTreeMap::default();
3299
3300        // scan all properties that could have changed because of addition / removal
3301        let v = nodes
3302            .iter()
3303            .zip(old_node_states.iter())
3304            .filter_map(|(node_id, old_node_state)| {
3305                let mut keys_normal: Vec<_> = css_property_cache
3306                    .css_focus_props
3307                    .get(node_id)
3308                    .unwrap_or(&default_map)
3309                    .keys()
3310                    .collect();
3311
3312                let mut keys_inherited: Vec<_> = css_property_cache
3313                    .cascaded_focus_props
3314                    .get(node_id)
3315                    .unwrap_or(&default_map)
3316                    .keys()
3317                    .collect();
3318
3319                let keys_inline: Vec<CssPropertyType> = node_data[*node_id]
3320                    .inline_css_props
3321                    .iter()
3322                    .filter_map(|prop| match prop {
3323                        NodeDataInlineCssProperty::Focus(h) => Some(h.get_type()),
3324                        _ => None,
3325                    })
3326                    .collect();
3327                let mut keys_inline_ref = keys_inline.iter().map(|r| r).collect();
3328
3329                keys_normal.append(&mut keys_inherited);
3330                keys_normal.append(&mut keys_inline_ref);
3331
3332                let node_properties_that_could_have_changed = keys_normal;
3333
3334                if node_properties_that_could_have_changed.is_empty() {
3335                    return None;
3336                }
3337
3338                let new_node_state = &styled_nodes[*node_id].state;
3339                let node_data = &node_data[*node_id];
3340
3341                let changes = node_properties_that_could_have_changed
3342                    .into_iter()
3343                    .filter_map(|prop| {
3344                        // calculate both the old and the new state
3345                        let old = css_property_cache.get_property(
3346                            node_data,
3347                            node_id,
3348                            old_node_state,
3349                            prop,
3350                        );
3351                        let new = css_property_cache.get_property(
3352                            node_data,
3353                            node_id,
3354                            new_node_state,
3355                            prop,
3356                        );
3357                        if old == new {
3358                            None
3359                        } else {
3360                            Some(ChangedCssProperty {
3361                                previous_state: old_node_state.clone(),
3362                                previous_prop: match old {
3363                                    None => CssProperty::auto(*prop),
3364                                    Some(s) => s.clone(),
3365                                },
3366                                current_state: new_node_state.clone(),
3367                                current_prop: match new {
3368                                    None => CssProperty::auto(*prop),
3369                                    Some(s) => s.clone(),
3370                                },
3371                            })
3372                        }
3373                    })
3374                    .collect::<Vec<_>>();
3375
3376                if changes.is_empty() {
3377                    None
3378                } else {
3379                    Some((*node_id, changes))
3380                }
3381            })
3382            .collect::<Vec<_>>();
3383
3384        v.into_iter().collect()
3385    }
3386
3387    // Inserts a property into the self.user_overridden_properties
3388    #[must_use]
3389    pub fn restyle_user_property(
3390        &mut self,
3391        node_id: &NodeId,
3392        new_properties: &[CssProperty],
3393    ) -> BTreeMap<NodeId, Vec<ChangedCssProperty>> {
3394        let mut map = BTreeMap::default();
3395
3396        if new_properties.is_empty() {
3397            return map;
3398        }
3399
3400        let node_data = self.node_data.as_container();
3401        let node_data = &node_data[*node_id];
3402
3403        let node_states = &self.styled_nodes.as_container();
3404        let old_node_state = &node_states[*node_id].state;
3405
3406        let changes: Vec<ChangedCssProperty> = {
3407            let css_property_cache = self.get_css_property_cache();
3408
3409            new_properties
3410                .iter()
3411                .filter_map(|new_prop| {
3412                    let old_prop = css_property_cache.get_property(
3413                        node_data,
3414                        node_id,
3415                        old_node_state,
3416                        &new_prop.get_type(),
3417                    );
3418
3419                    let old_prop = match old_prop {
3420                        None => CssProperty::auto(new_prop.get_type()),
3421                        Some(s) => s.clone(),
3422                    };
3423
3424                    if old_prop == *new_prop {
3425                        None
3426                    } else {
3427                        Some(ChangedCssProperty {
3428                            previous_state: old_node_state.clone(),
3429                            previous_prop: old_prop,
3430                            // overriding a user property does not change the state
3431                            current_state: old_node_state.clone(),
3432                            current_prop: new_prop.clone(),
3433                        })
3434                    }
3435                })
3436                .collect()
3437        };
3438
3439        let css_property_cache_mut = self.get_css_property_cache_mut();
3440
3441        for new_prop in new_properties.iter() {
3442            if new_prop.is_initial() {
3443                let mut should_remove_map = false;
3444                if let Some(map) = css_property_cache_mut
3445                    .user_overridden_properties
3446                    .get_mut(node_id)
3447                {
3448                    // CssProperty::Initial = remove overridden property
3449                    map.remove(&new_prop.get_type());
3450                    should_remove_map = map.is_empty();
3451                }
3452                if should_remove_map {
3453                    css_property_cache_mut
3454                        .user_overridden_properties
3455                        .remove(node_id);
3456                }
3457            } else {
3458                css_property_cache_mut
3459                    .user_overridden_properties
3460                    .entry(*node_id)
3461                    .or_insert_with(|| BTreeMap::new())
3462                    .insert(new_prop.get_type(), new_prop.clone());
3463            }
3464        }
3465
3466        if !changes.is_empty() {
3467            map.insert(*node_id, changes);
3468        }
3469
3470        map
3471    }
3472
3473    /// Scans the `StyledDom` for iframe callbacks
3474    pub fn scan_for_iframe_callbacks(&self) -> Vec<NodeId> {
3475        use crate::dom::NodeType;
3476        self.node_data
3477            .as_ref()
3478            .iter()
3479            .enumerate()
3480            .filter_map(|(node_id, node_data)| match node_data.get_node_type() {
3481                NodeType::IFrame(_) => Some(NodeId::new(node_id)),
3482                _ => None,
3483            })
3484            .collect()
3485    }
3486
3487    /// Scans the `StyledDom` for OpenGL callbacks
3488    pub(crate) fn scan_for_gltexture_callbacks(&self) -> Vec<NodeId> {
3489        use crate::dom::NodeType;
3490        self.node_data
3491            .as_ref()
3492            .iter()
3493            .enumerate()
3494            .filter_map(|(node_id, node_data)| {
3495                use crate::app_resources::DecodedImage;
3496                match node_data.get_node_type() {
3497                    NodeType::Image(image_ref) => {
3498                        if let DecodedImage::Callback(_) = image_ref.get_data() {
3499                            Some(NodeId::new(node_id))
3500                        } else {
3501                            None
3502                        }
3503                    }
3504                    _ => None,
3505                }
3506            })
3507            .collect()
3508    }
3509
3510    /// Returns a HTML-formatted version of the DOM for easier debugging, i.e.
3511    ///
3512    /// ```rust,no_run,ignore
3513    /// Dom::div().with_id("hello")
3514    ///     .with_child(Dom::div().with_id("test"))
3515    /// ```
3516    ///
3517    /// will return:
3518    ///
3519    /// ```xml,no_run,ignore
3520    /// <div id="hello">
3521    ///      <div id="test" />
3522    /// </div>
3523    /// ```
3524    pub fn get_html_string(&self, custom_head: &str, custom_body: &str, test_mode: bool) -> String {
3525        let css_property_cache = self.get_css_property_cache();
3526
3527        let mut output = String::new();
3528
3529        // After which nodes should a close tag be printed?
3530        let mut should_print_close_tag_after_node = BTreeMap::new();
3531
3532        let should_print_close_tag_debug = self
3533            .non_leaf_nodes
3534            .iter()
3535            .filter_map(|p| {
3536                let parent_node_id = p.node_id.into_crate_internal()?;
3537                let mut total_last_child = None;
3538                recursive_get_last_child(
3539                    parent_node_id,
3540                    &self.node_hierarchy.as_ref(),
3541                    &mut total_last_child,
3542                );
3543                let total_last_child = total_last_child?;
3544                Some((parent_node_id, (total_last_child, p.depth)))
3545            })
3546            .collect::<BTreeMap<_, _>>();
3547
3548        for (parent_id, (last_child, parent_depth)) in should_print_close_tag_debug {
3549            should_print_close_tag_after_node
3550                .entry(last_child)
3551                .or_insert_with(|| Vec::new())
3552                .push((parent_id, parent_depth));
3553        }
3554
3555        let mut all_node_depths = self
3556            .non_leaf_nodes
3557            .iter()
3558            .filter_map(|p| {
3559                let parent_node_id = p.node_id.into_crate_internal()?;
3560                Some((parent_node_id, p.depth))
3561            })
3562            .collect::<BTreeMap<_, _>>();
3563
3564        for (parent_node_id, parent_depth) in self
3565            .non_leaf_nodes
3566            .iter()
3567            .filter_map(|p| Some((p.node_id.into_crate_internal()?, p.depth)))
3568        {
3569            for child_id in parent_node_id.az_children(&self.node_hierarchy.as_container()) {
3570                all_node_depths.insert(child_id, parent_depth + 1);
3571            }
3572        }
3573
3574        for node_id in self.node_hierarchy.as_container().linear_iter() {
3575            let depth = all_node_depths[&node_id];
3576
3577            let node_data = &self.node_data.as_container()[node_id];
3578            let node_state = &self.styled_nodes.as_container()[node_id].state;
3579            let tabs = String::from("    ").repeat(depth);
3580
3581            output.push_str("\r\n");
3582            output.push_str(&tabs);
3583            output.push_str(&node_data.debug_print_start(css_property_cache, &node_id, node_state));
3584
3585            if let Some(content) = node_data.get_node_type().format().as_ref() {
3586                output.push_str(content);
3587            }
3588
3589            let node_has_children = self.node_hierarchy.as_container()[node_id]
3590                .first_child_id(node_id)
3591                .is_some();
3592            if !node_has_children {
3593                let node_data = &self.node_data.as_container()[node_id];
3594                output.push_str(&node_data.debug_print_end());
3595            }
3596
3597            if let Some(close_tag_vec) = should_print_close_tag_after_node.get(&node_id) {
3598                let mut close_tag_vec = close_tag_vec.clone();
3599                close_tag_vec.sort_by(|a, b| b.1.cmp(&a.1)); // sort by depth descending
3600                for (close_tag_parent_id, close_tag_depth) in close_tag_vec {
3601                    let node_data = &self.node_data.as_container()[close_tag_parent_id];
3602                    let tabs = String::from("    ").repeat(close_tag_depth);
3603                    output.push_str("\r\n");
3604                    output.push_str(&tabs);
3605                    output.push_str(&node_data.debug_print_end());
3606                }
3607            }
3608        }
3609
3610        if !test_mode {
3611            format!(
3612                include_str!("./default.html"),
3613                custom_head = custom_head,
3614                output = output,
3615                custom_body = custom_body
3616            )
3617        } else {
3618            output
3619        }
3620    }
3621
3622    /// Returns the node ID of all sub-children of a node
3623    pub fn get_subtree(&self, parent: NodeId) -> Vec<NodeId> {
3624        let mut total_last_child = None;
3625        recursive_get_last_child(parent, &self.node_hierarchy.as_ref(), &mut total_last_child);
3626        if let Some(last) = total_last_child {
3627            (parent.index()..=last.index())
3628                .map(|id| NodeId::new(id))
3629                .collect()
3630        } else {
3631            Vec::new()
3632        }
3633    }
3634
3635    // Same as get_subtree, but only returns parents
3636    pub fn get_subtree_parents(&self, parent: NodeId) -> Vec<NodeId> {
3637        let mut total_last_child = None;
3638        recursive_get_last_child(parent, &self.node_hierarchy.as_ref(), &mut total_last_child);
3639        if let Some(last) = total_last_child {
3640            (parent.index()..=last.index())
3641                .filter_map(|id| {
3642                    if self.node_hierarchy.as_ref()[id].last_child_id().is_some() {
3643                        Some(NodeId::new(id))
3644                    } else {
3645                        None
3646                    }
3647                })
3648                .collect()
3649        } else {
3650            Vec::new()
3651        }
3652    }
3653
3654    pub fn get_rects_in_rendering_order(&self) -> ContentGroup {
3655        Self::determine_rendering_order(
3656            &self.non_leaf_nodes.as_ref(),
3657            &self.node_hierarchy.as_container(),
3658            &self.styled_nodes.as_container(),
3659            &self.node_data.as_container(),
3660            &self.get_css_property_cache(),
3661        )
3662    }
3663
3664    /// Returns the rendering order of the items (the rendering
3665    /// order doesn't have to be the original order)
3666    fn determine_rendering_order<'a>(
3667        non_leaf_nodes: &[ParentWithNodeDepth],
3668        node_hierarchy: &NodeDataContainerRef<'a, NodeHierarchyItem>,
3669        styled_nodes: &NodeDataContainerRef<StyledNode>,
3670        node_data_container: &NodeDataContainerRef<NodeData>,
3671        css_property_cache: &CssPropertyCache,
3672    ) -> ContentGroup {
3673        let children_sorted = non_leaf_nodes
3674            .iter()
3675            .filter_map(|parent| {
3676                Some((
3677                    parent.node_id,
3678                    sort_children_by_position(
3679                        parent.node_id.into_crate_internal()?,
3680                        node_hierarchy,
3681                        styled_nodes,
3682                        node_data_container,
3683                        css_property_cache,
3684                    ),
3685                ))
3686            })
3687            .collect::<Vec<_>>();
3688
3689        let children_sorted: BTreeMap<NodeHierarchyItemId, Vec<NodeHierarchyItemId>> =
3690            children_sorted.into_iter().collect();
3691
3692        let mut root_content_group = ContentGroup {
3693            root: NodeHierarchyItemId::from_crate_internal(Some(NodeId::ZERO)),
3694            children: Vec::new().into(),
3695        };
3696
3697        fill_content_group_children(&mut root_content_group, &children_sorted);
3698
3699        root_content_group
3700    }
3701
3702    pub fn swap_with_default(&mut self) -> Self {
3703        let mut new = Self::default();
3704        core::mem::swap(self, &mut new);
3705        new
3706    }
3707
3708    pub fn set_menu_bar(&mut self, menu: Menu) {
3709        if let Some(root) = self.root.into_crate_internal() {
3710            self.node_data.as_mut()[root.index()].set_menu_bar(menu)
3711        }
3712    }
3713
3714    pub fn set_context_menu(&mut self, menu: Menu) {
3715        if let Some(root) = self.root.into_crate_internal() {
3716            self.node_data.as_mut()[root.index()].set_context_menu(menu);
3717
3718            // add a new hit-testing tag for root node
3719            let mut new_tags = self.tag_ids_to_node_ids.clone().into_library_owned_vec();
3720
3721            let tag_id = match self.styled_nodes.as_mut()[root.index()].tag_id {
3722                OptionTagId::Some(s) => s,
3723                OptionTagId::None => AzTagId::from_crate_internal(TagId::unique()),
3724            };
3725
3726            new_tags.push(TagIdToNodeIdMapping {
3727                tag_id,
3728                node_id: self.root,
3729                tab_index: OptionTabIndex::None,
3730                parent_node_ids: NodeIdVec::from_const_slice(&[]),
3731            });
3732
3733            self.styled_nodes.as_mut()[root.index()].tag_id = OptionTagId::Some(tag_id);
3734            self.tag_ids_to_node_ids = new_tags.into();
3735        }
3736    }
3737
3738    // Computes the diff between the two DOMs
3739    // pub fn diff(&self, other: &Self) -> StyledDomDiff { /**/ }
3740}
3741
3742#[derive(Debug, Clone, PartialEq)]
3743pub struct DefaultCallbacksCfg {
3744    pub smooth_scroll: bool,
3745    pub enable_autotab: bool,
3746}
3747
3748#[derive(Debug, Copy, Clone, PartialEq)]
3749pub struct DefaultScrollCallbackData {
3750    pub smooth_scroll: bool,
3751}
3752
3753#[derive(Debug, Copy, Clone, PartialEq)]
3754pub struct DefaultTabIndexCallbackData {}
3755
3756/// Default On::TabIndex event handler
3757extern "C" fn default_on_tabindex(data: &mut RefAny, info: &mut CallbackInfo) -> Update {
3758    let mut data = match data.downcast_mut::<DefaultTabIndexCallbackData>() {
3759        Some(s) => s,
3760        None => return Update::DoNothing,
3761    };
3762
3763    Update::DoNothing
3764}
3765
3766/// Default On::Scroll event handler
3767extern "C" fn default_on_scroll(data: &mut RefAny, info: &mut CallbackInfo) -> Update {
3768    let mut data = match data.downcast_mut::<DefaultScrollCallbackData>() {
3769        Some(s) => s,
3770        None => return Update::DoNothing,
3771    };
3772
3773    let mouse_state = info.get_current_mouse_state();
3774
3775    let (scroll_x, scroll_y) = match (
3776        mouse_state.scroll_y.into_option(),
3777        mouse_state.scroll_x.into_option(),
3778    ) {
3779        (None, None) => return Update::DoNothing,
3780        (x, y) => (x.unwrap_or(0.0), y.unwrap_or(0.0)),
3781    };
3782
3783    let hit_node_id = info.get_hit_node();
3784
3785    let new_scroll_position = match info.get_scroll_position(hit_node_id) {
3786        Some(mut s) => {
3787            s.x += scroll_x;
3788            s.y += scroll_y;
3789            s
3790        }
3791        None => return Update::DoNothing,
3792    };
3793
3794    info.set_scroll_position(hit_node_id, new_scroll_position);
3795
3796    Update::DoNothing
3797}
3798
3799fn fill_content_group_children(
3800    group: &mut ContentGroup,
3801    children_sorted: &BTreeMap<NodeHierarchyItemId, Vec<NodeHierarchyItemId>>,
3802) {
3803    if let Some(c) = children_sorted.get(&group.root) {
3804        // returns None for leaf nodes
3805        group.children = c
3806            .iter()
3807            .map(|child| ContentGroup {
3808                root: *child,
3809                children: Vec::new().into(),
3810            })
3811            .collect::<Vec<ContentGroup>>()
3812            .into();
3813
3814        for c in group.children.as_mut() {
3815            fill_content_group_children(c, children_sorted);
3816        }
3817    }
3818}
3819
3820fn sort_children_by_position<'a>(
3821    parent: NodeId,
3822    node_hierarchy: &NodeDataContainerRef<'a, NodeHierarchyItem>,
3823    rectangles: &NodeDataContainerRef<StyledNode>,
3824    node_data_container: &NodeDataContainerRef<NodeData>,
3825    css_property_cache: &CssPropertyCache,
3826) -> Vec<NodeHierarchyItemId> {
3827    use azul_css::LayoutPosition::*;
3828
3829    let children_positions = parent
3830        .az_children(node_hierarchy)
3831        .map(|nid| {
3832            let position = css_property_cache
3833                .get_position(&node_data_container[nid], &nid, &rectangles[nid].state)
3834                .and_then(|p| p.clone().get_property_or_default())
3835                .unwrap_or_default();
3836            let id = NodeHierarchyItemId::from_crate_internal(Some(nid));
3837            (id, position)
3838        })
3839        .collect::<Vec<_>>();
3840
3841    let mut not_absolute_children = children_positions
3842        .iter()
3843        .filter_map(|(node_id, position)| {
3844            if *position != Absolute {
3845                Some(*node_id)
3846            } else {
3847                None
3848            }
3849        })
3850        .collect::<Vec<_>>();
3851
3852    let mut absolute_children = children_positions
3853        .iter()
3854        .filter_map(|(node_id, position)| {
3855            if *position == Absolute {
3856                Some(*node_id)
3857            } else {
3858                None
3859            }
3860        })
3861        .collect::<Vec<_>>();
3862
3863    // Append the position:absolute children after the regular children
3864    not_absolute_children.append(&mut absolute_children);
3865    not_absolute_children
3866}
3867
3868// calls get_last_child() recursively until the last child of the last child of the ... has been
3869// found
3870fn recursive_get_last_child(
3871    node_id: NodeId,
3872    node_hierarchy: &[NodeHierarchyItem],
3873    target: &mut Option<NodeId>,
3874) {
3875    match node_hierarchy[node_id.index()].last_child_id() {
3876        None => return,
3877        Some(s) => {
3878            *target = Some(s);
3879            recursive_get_last_child(s, node_hierarchy, target);
3880        }
3881    }
3882}