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 css::{Css, CssPath},
9 props::{
10 basic::{StyleFontFamily, StyleFontFamilyVec, StyleFontSize},
11 property::{
12 BoxDecorationBreakValue, BreakInsideValue, CaretAnimationDurationValue,
13 CaretColorValue, ColumnCountValue, ColumnFillValue, ColumnRuleColorValue,
14 ColumnRuleStyleValue, ColumnRuleWidthValue, ColumnSpanValue, ColumnWidthValue,
15 ContentValue, CounterIncrementValue, CounterResetValue, CssProperty, CssPropertyType,
16 FlowFromValue, FlowIntoValue, LayoutAlignContentValue, LayoutAlignItemsValue,
17 LayoutAlignSelfValue, LayoutBorderBottomWidthValue, LayoutBorderLeftWidthValue,
18 LayoutBorderRightWidthValue, LayoutBorderTopWidthValue, LayoutBoxSizingValue,
19 LayoutClearValue, LayoutColumnGapValue, LayoutDisplayValue, LayoutFlexBasisValue,
20 LayoutFlexDirectionValue, LayoutFlexGrowValue, LayoutFlexShrinkValue,
21 LayoutFlexWrapValue, LayoutFloatValue, LayoutGapValue, LayoutGridAutoColumnsValue,
22 LayoutGridAutoFlowValue, LayoutGridAutoRowsValue, LayoutGridColumnValue,
23 LayoutGridRowValue, LayoutGridTemplateColumnsValue, LayoutGridTemplateRowsValue,
24 LayoutHeightValue, LayoutInsetBottomValue, LayoutJustifyContentValue,
25 LayoutJustifyItemsValue, LayoutJustifySelfValue, LayoutLeftValue,
26 LayoutMarginBottomValue, LayoutMarginLeftValue, LayoutMarginRightValue,
27 LayoutMarginTopValue, LayoutMaxHeightValue, LayoutMaxWidthValue, LayoutMinHeightValue,
28 LayoutMinWidthValue, LayoutOverflowValue, LayoutPaddingBottomValue,
29 LayoutPaddingLeftValue, LayoutPaddingRightValue, LayoutPaddingTopValue,
30 LayoutPositionValue, LayoutRightValue, LayoutRowGapValue, LayoutScrollbarWidthValue,
31 LayoutTextJustifyValue, LayoutTopValue, LayoutWidthValue, LayoutWritingModeValue,
32 LayoutZIndexValue, OrphansValue, PageBreakValue, ScrollbarStyleValue,
33 SelectionBackgroundColorValue, SelectionColorValue, ShapeImageThresholdValue,
34 ShapeMarginValue, ShapeOutsideValue, StringSetValue, StyleBackfaceVisibilityValue,
35 StyleBackgroundContentVecValue, StyleBackgroundPositionVecValue,
36 StyleBackgroundRepeatVecValue, StyleBackgroundSizeVecValue,
37 StyleBorderBottomColorValue, StyleBorderBottomLeftRadiusValue,
38 StyleBorderBottomRightRadiusValue, StyleBorderBottomStyleValue,
39 StyleBorderLeftColorValue, StyleBorderLeftStyleValue, StyleBorderRightColorValue,
40 StyleBorderRightStyleValue, StyleBorderTopColorValue, StyleBorderTopLeftRadiusValue,
41 StyleBorderTopRightRadiusValue, StyleBorderTopStyleValue, StyleBoxShadowValue,
42 StyleCursorValue, StyleDirectionValue, StyleFilterVecValue, StyleFontFamilyVecValue,
43 StyleFontSizeValue, StyleFontValue, StyleHyphensValue, StyleLetterSpacingValue,
44 StyleLineHeightValue, StyleMixBlendModeValue, StyleOpacityValue,
45 StylePerspectiveOriginValue, StyleScrollbarColorValue, StyleTabWidthValue,
46 StyleTextAlignValue, StyleTextColorValue, StyleTransformOriginValue,
47 StyleTransformVecValue, StyleVisibilityValue, StyleWhiteSpaceValue,
48 StyleWordSpacingValue, WidowsValue,
49 },
50 style::StyleTextColor,
51 },
52 AzString,
53};
54
55use crate::{
56 callbacks::Update,
57 dom::{Dom, DomId, NodeData, NodeDataVec, OptionTabIndex, OptionTagId, TabIndex, TagId},
58 id::{
59 Node, NodeDataContainer, NodeDataContainerRef, NodeDataContainerRefMut, NodeHierarchy,
60 NodeId,
61 },
62 menu::Menu,
63 prop_cache::{CssPropertyCache, CssPropertyCachePtr},
64 refany::RefAny,
65 resources::{Au, ImageCache, ImageRef, ImmediateFontId, RendererResources},
66 style::{
67 construct_html_cascade_tree, matches_html_element, rule_ends_with, CascadeInfo,
68 CascadeInfoVec,
69 },
70 FastBTreeSet, FastHashMap,
71};
72
73#[repr(C)]
74#[derive(Debug, Clone, PartialEq, Hash, PartialOrd, Eq, Ord)]
75pub struct ChangedCssProperty {
76 pub previous_state: StyledNodeState,
77 pub previous_prop: CssProperty,
78 pub current_state: StyledNodeState,
79 pub current_prop: CssProperty,
80}
81
82impl_vec!(
83 ChangedCssProperty,
84 ChangedCssPropertyVec,
85 ChangedCssPropertyVecDestructor,
86 ChangedCssPropertyVecDestructorType
87);
88impl_vec_debug!(ChangedCssProperty, ChangedCssPropertyVec);
89impl_vec_partialord!(ChangedCssProperty, ChangedCssPropertyVec);
90impl_vec_clone!(
91 ChangedCssProperty,
92 ChangedCssPropertyVec,
93 ChangedCssPropertyVecDestructor
94);
95impl_vec_partialeq!(ChangedCssProperty, ChangedCssPropertyVec);
96
97#[derive(Debug, Clone, PartialEq)]
99pub struct FocusChange {
100 pub lost_focus: Option<NodeId>,
102 pub gained_focus: Option<NodeId>,
104}
105
106#[derive(Debug, Clone, PartialEq)]
108pub struct HoverChange {
109 pub left_nodes: Vec<NodeId>,
111 pub entered_nodes: Vec<NodeId>,
113}
114
115#[derive(Debug, Clone, PartialEq)]
117pub struct ActiveChange {
118 pub deactivated: Vec<NodeId>,
120 pub activated: Vec<NodeId>,
122}
123
124#[derive(Debug, Clone, Default)]
126pub struct RestyleResult {
127 pub changed_nodes: BTreeMap<NodeId, Vec<ChangedCssProperty>>,
129 pub needs_layout: bool,
131 pub needs_display_list: bool,
133 pub gpu_only_changes: bool,
136}
137
138impl RestyleResult {
139 pub fn has_changes(&self) -> bool {
141 !self.changed_nodes.is_empty()
142 }
143
144 pub fn merge(&mut self, other: RestyleResult) {
146 for (node_id, changes) in other.changed_nodes {
147 self.changed_nodes.entry(node_id).or_default().extend(changes);
148 }
149 self.needs_layout = self.needs_layout || other.needs_layout;
150 self.needs_display_list = self.needs_display_list || other.needs_display_list;
151 self.gpu_only_changes = self.gpu_only_changes && other.gpu_only_changes;
152 }
153}
154
155#[repr(C, u8)]
156#[derive(Debug, Clone, PartialEq, Hash, PartialOrd, Eq, Ord)]
157pub enum CssPropertySource {
158 Css(CssPath),
159 Inline,
160}
161
162#[repr(C)]
167#[derive(Clone, Copy, PartialEq, Hash, PartialOrd, Eq, Ord, Default)]
168pub struct StyledNodeState {
169 pub hover: bool,
171 pub active: bool,
173 pub focused: bool,
175 pub disabled: bool,
177 pub checked: bool,
179 pub focus_within: bool,
181 pub visited: bool,
183}
184
185impl core::fmt::Debug for StyledNodeState {
186 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
187 let mut v = Vec::new();
188 if self.hover {
189 v.push("hover");
190 }
191 if self.active {
192 v.push("active");
193 }
194 if self.focused {
195 v.push("focused");
196 }
197 if self.disabled {
198 v.push("disabled");
199 }
200 if self.checked {
201 v.push("checked");
202 }
203 if self.focus_within {
204 v.push("focus_within");
205 }
206 if self.visited {
207 v.push("visited");
208 }
209 if v.is_empty() {
210 v.push("normal");
211 }
212 write!(f, "{:?}", v)
213 }
214}
215
216impl StyledNodeState {
217 pub const fn new() -> Self {
219 StyledNodeState {
220 hover: false,
221 active: false,
222 focused: false,
223 disabled: false,
224 checked: false,
225 focus_within: false,
226 visited: false,
227 }
228 }
229
230 pub fn has_state(&self, state_type: u8) -> bool {
232 match state_type {
233 0 => true, 1 => self.hover,
235 2 => self.active,
236 3 => self.focused,
237 4 => self.disabled,
238 5 => self.checked,
239 6 => self.focus_within,
240 7 => self.visited,
241 _ => false,
242 }
243 }
244
245 pub fn is_normal(&self) -> bool {
247 !self.hover
248 && !self.active
249 && !self.focused
250 && !self.disabled
251 && !self.checked
252 && !self.focus_within
253 && !self.visited
254 }
255
256 pub fn to_pseudo_state_flags(&self) -> azul_css::dynamic_selector::PseudoStateFlags {
258 azul_css::dynamic_selector::PseudoStateFlags {
259 hover: self.hover,
260 active: self.active,
261 focused: self.focused,
262 disabled: self.disabled,
263 checked: self.checked,
264 focus_within: self.focus_within,
265 visited: self.visited,
266 }
267 }
268
269 pub fn from_pseudo_state_flags(flags: &azul_css::dynamic_selector::PseudoStateFlags) -> Self {
271 StyledNodeState {
272 hover: flags.hover,
273 active: flags.active,
274 focused: flags.focused,
275 disabled: flags.disabled,
276 checked: flags.checked,
277 focus_within: flags.focus_within,
278 visited: flags.visited,
279 }
280 }
281}
282
283#[repr(C)]
285#[derive(Debug, Default, Clone, PartialEq, PartialOrd)]
286pub struct StyledNode {
287 pub styled_node_state: StyledNodeState,
289 pub tag_id: OptionTagId,
293}
294
295impl_vec!(
296 StyledNode,
297 StyledNodeVec,
298 StyledNodeVecDestructor,
299 StyledNodeVecDestructorType
300);
301impl_vec_mut!(StyledNode, StyledNodeVec);
302impl_vec_debug!(StyledNode, StyledNodeVec);
303impl_vec_partialord!(StyledNode, StyledNodeVec);
304impl_vec_clone!(StyledNode, StyledNodeVec, StyledNodeVecDestructor);
305impl_vec_partialeq!(StyledNode, StyledNodeVec);
306
307impl StyledNodeVec {
308 pub fn as_container<'a>(&'a self) -> NodeDataContainerRef<'a, StyledNode> {
310 NodeDataContainerRef {
311 internal: self.as_ref(),
312 }
313 }
314 pub fn as_container_mut<'a>(&'a mut self) -> NodeDataContainerRefMut<'a, StyledNode> {
316 NodeDataContainerRefMut {
317 internal: self.as_mut(),
318 }
319 }
320}
321
322#[test]
323fn test_it() {
324 let s = "
325 html, body, p {
326 margin: 0;
327 padding: 0;
328 }
329 #div1 {
330 border: solid black;
331 height: 2in;
332 position: absolute;
333 top: 1in;
334 width: 3in;
335 }
336 div div {
337 background: blue;
338 height: 1in;
339 position: fixed;
340 width: 1in;
341 }
342 ";
343
344 let css = azul_css::parser2::new_from_str(s);
345 let _styled_dom = Dom::create_body()
346 .with_children(
347 vec![Dom::create_div()
348 .with_ids_and_classes(
349 vec![crate::dom::IdOrClass::Id("div1".to_string().into())].into(),
350 )
351 .with_children(vec![Dom::create_div()].into())]
352 .into(),
353 )
354 .style(css.0);
355}
356
357#[derive(Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
359pub struct StyleFontFamilyHash(pub u64);
360
361impl ::core::fmt::Debug for StyleFontFamilyHash {
362 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
363 write!(f, "StyleFontFamilyHash({})", self.0)
364 }
365}
366
367impl StyleFontFamilyHash {
368 pub fn new(family: &StyleFontFamily) -> Self {
370 use highway::{HighwayHash, HighwayHasher, Key};
371 let mut hasher = HighwayHasher::new(Key([0; 4]));
372 family.hash(&mut hasher);
373 Self(hasher.finalize64())
374 }
375}
376
377#[derive(Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
379pub struct StyleFontFamiliesHash(pub u64);
380
381impl ::core::fmt::Debug for StyleFontFamiliesHash {
382 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
383 write!(f, "StyleFontFamiliesHash({})", self.0)
384 }
385}
386
387impl StyleFontFamiliesHash {
388 pub fn new(families: &[StyleFontFamily]) -> Self {
390 use highway::{HighwayHash, HighwayHasher, Key};
391 let mut hasher = HighwayHasher::new(Key([0; 4]));
392 for f in families.iter() {
393 f.hash(&mut hasher);
394 }
395 Self(hasher.finalize64())
396 }
397}
398
399#[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
441#[repr(C)]
442pub struct NodeHierarchyItemId {
443 inner: usize,
446}
447
448impl fmt::Debug for NodeHierarchyItemId {
449 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
450 match self.into_crate_internal() {
451 Some(n) => write!(f, "Some(NodeId({}))", n),
452 None => write!(f, "None"),
453 }
454 }
455}
456
457impl fmt::Display for NodeHierarchyItemId {
458 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
459 write!(f, "{:?}", self)
460 }
461}
462
463impl NodeHierarchyItemId {
464 pub const NONE: NodeHierarchyItemId = NodeHierarchyItemId { inner: 0 };
466
467 #[inline]
474 pub const fn from_raw(value: usize) -> Self {
475 Self { inner: value }
476 }
477
478 #[inline]
484 pub const fn into_raw(&self) -> usize {
485 self.inner
486 }
487}
488
489impl_option!(
490 NodeHierarchyItemId,
491 OptionNodeHierarchyItemId,
492 [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
493);
494
495impl_vec!(
496 NodeHierarchyItemId,
497 NodeIdVec,
498 NodeIdVecDestructor,
499 NodeIdVecDestructorType
500);
501impl_vec_mut!(NodeHierarchyItemId, NodeIdVec);
502impl_vec_debug!(NodeHierarchyItemId, NodeIdVec);
503impl_vec_ord!(NodeHierarchyItemId, NodeIdVec);
504impl_vec_eq!(NodeHierarchyItemId, NodeIdVec);
505impl_vec_hash!(NodeHierarchyItemId, NodeIdVec);
506impl_vec_partialord!(NodeHierarchyItemId, NodeIdVec);
507impl_vec_clone!(NodeHierarchyItemId, NodeIdVec, NodeIdVecDestructor);
508impl_vec_partialeq!(NodeHierarchyItemId, NodeIdVec);
509
510impl NodeHierarchyItemId {
511 #[inline]
513 pub const fn into_crate_internal(&self) -> Option<NodeId> {
514 NodeId::from_usize(self.inner)
515 }
516
517 #[inline]
519 pub const fn from_crate_internal(t: Option<NodeId>) -> Self {
520 Self {
521 inner: NodeId::into_raw(&t),
522 }
523 }
524}
525
526impl From<Option<NodeId>> for NodeHierarchyItemId {
527 #[inline]
528 fn from(opt: Option<NodeId>) -> Self {
529 NodeHierarchyItemId::from_crate_internal(opt)
530 }
531}
532
533impl From<NodeHierarchyItemId> for Option<NodeId> {
534 #[inline]
535 fn from(id: NodeHierarchyItemId) -> Self {
536 id.into_crate_internal()
537 }
538}
539
540#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
541#[repr(C)]
542pub struct NodeHierarchyItem {
543 pub parent: usize,
544 pub previous_sibling: usize,
545 pub next_sibling: usize,
546 pub last_child: usize,
547}
548
549impl NodeHierarchyItem {
550 pub const fn zeroed() -> Self {
552 Self {
553 parent: 0,
554 previous_sibling: 0,
555 next_sibling: 0,
556 last_child: 0,
557 }
558 }
559}
560
561impl From<Node> for NodeHierarchyItem {
562 fn from(node: Node) -> NodeHierarchyItem {
563 NodeHierarchyItem {
564 parent: NodeId::into_raw(&node.parent),
565 previous_sibling: NodeId::into_raw(&node.previous_sibling),
566 next_sibling: NodeId::into_raw(&node.next_sibling),
567 last_child: NodeId::into_raw(&node.last_child),
568 }
569 }
570}
571
572impl NodeHierarchyItem {
573 pub fn parent_id(&self) -> Option<NodeId> {
575 NodeId::from_usize(self.parent)
576 }
577 pub fn previous_sibling_id(&self) -> Option<NodeId> {
579 NodeId::from_usize(self.previous_sibling)
580 }
581 pub fn next_sibling_id(&self) -> Option<NodeId> {
583 NodeId::from_usize(self.next_sibling)
584 }
585 pub fn first_child_id(&self, current_node_id: NodeId) -> Option<NodeId> {
587 self.last_child_id().map(|_| current_node_id + 1)
588 }
589 pub fn last_child_id(&self) -> Option<NodeId> {
591 NodeId::from_usize(self.last_child)
592 }
593}
594
595impl_vec!(
596 NodeHierarchyItem,
597 NodeHierarchyItemVec,
598 NodeHierarchyItemVecDestructor,
599 NodeHierarchyItemVecDestructorType
600);
601impl_vec_mut!(NodeHierarchyItem, NodeHierarchyItemVec);
602impl_vec_debug!(AzNode, NodeHierarchyItemVec);
603impl_vec_partialord!(AzNode, NodeHierarchyItemVec);
604impl_vec_clone!(
605 NodeHierarchyItem,
606 NodeHierarchyItemVec,
607 NodeHierarchyItemVecDestructor
608);
609impl_vec_partialeq!(AzNode, NodeHierarchyItemVec);
610
611impl NodeHierarchyItemVec {
612 pub fn as_container<'a>(&'a self) -> NodeDataContainerRef<'a, NodeHierarchyItem> {
614 NodeDataContainerRef {
615 internal: self.as_ref(),
616 }
617 }
618 pub fn as_container_mut<'a>(&'a mut self) -> NodeDataContainerRefMut<'a, NodeHierarchyItem> {
620 NodeDataContainerRefMut {
621 internal: self.as_mut(),
622 }
623 }
624}
625
626impl<'a> NodeDataContainerRef<'a, NodeHierarchyItem> {
627 #[inline]
629 pub fn subtree_len(&self, parent_id: NodeId) -> usize {
630 let self_item_index = parent_id.index();
631 let next_item_index = match self[parent_id].next_sibling_id() {
632 None => self.len(),
633 Some(s) => s.index(),
634 };
635 next_item_index - self_item_index - 1
636 }
637}
638
639#[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
640#[repr(C)]
641pub struct ParentWithNodeDepth {
642 pub depth: usize,
643 pub node_id: NodeHierarchyItemId,
644}
645
646impl core::fmt::Debug for ParentWithNodeDepth {
647 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
648 write!(
649 f,
650 "{{ depth: {}, node: {:?} }}",
651 self.depth,
652 self.node_id.into_crate_internal()
653 )
654 }
655}
656
657impl_vec!(
658 ParentWithNodeDepth,
659 ParentWithNodeDepthVec,
660 ParentWithNodeDepthVecDestructor,
661 ParentWithNodeDepthVecDestructorType
662);
663impl_vec_mut!(ParentWithNodeDepth, ParentWithNodeDepthVec);
664impl_vec_debug!(ParentWithNodeDepth, ParentWithNodeDepthVec);
665impl_vec_partialord!(ParentWithNodeDepth, ParentWithNodeDepthVec);
666impl_vec_clone!(
667 ParentWithNodeDepth,
668 ParentWithNodeDepthVec,
669 ParentWithNodeDepthVecDestructor
670);
671impl_vec_partialeq!(ParentWithNodeDepth, ParentWithNodeDepthVec);
672
673#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd)]
674#[repr(C)]
675pub struct TagIdToNodeIdMapping {
676 pub tag_id: TagId,
678 pub node_id: NodeHierarchyItemId,
680 pub tab_index: OptionTabIndex,
682 pub parent_node_ids: NodeIdVec,
684}
685
686impl_vec!(
687 TagIdToNodeIdMapping,
688 TagIdToNodeIdMappingVec,
689 TagIdToNodeIdMappingVecDestructor,
690 TagIdToNodeIdMappingVecDestructorType
691);
692impl_vec_mut!(TagIdToNodeIdMapping, TagIdToNodeIdMappingVec);
693impl_vec_debug!(TagIdToNodeIdMapping, TagIdToNodeIdMappingVec);
694impl_vec_partialord!(TagIdToNodeIdMapping, TagIdToNodeIdMappingVec);
695impl_vec_clone!(
696 TagIdToNodeIdMapping,
697 TagIdToNodeIdMappingVec,
698 TagIdToNodeIdMappingVecDestructor
699);
700impl_vec_partialeq!(TagIdToNodeIdMapping, TagIdToNodeIdMappingVec);
701
702#[derive(Debug, Clone, PartialEq, PartialOrd)]
703#[repr(C)]
704pub struct ContentGroup {
705 pub root: NodeHierarchyItemId,
708 pub children: ContentGroupVec,
710}
711
712impl_vec!(
713 ContentGroup,
714 ContentGroupVec,
715 ContentGroupVecDestructor,
716 ContentGroupVecDestructorType
717);
718impl_vec_mut!(ContentGroup, ContentGroupVec);
719impl_vec_debug!(ContentGroup, ContentGroupVec);
720impl_vec_partialord!(ContentGroup, ContentGroupVec);
721impl_vec_clone!(ContentGroup, ContentGroupVec, ContentGroupVecDestructor);
722impl_vec_partialeq!(ContentGroup, ContentGroupVec);
723
724#[derive(Debug, PartialEq, Clone)]
725#[repr(C)]
726pub struct StyledDom {
727 pub root: NodeHierarchyItemId,
728 pub node_hierarchy: NodeHierarchyItemVec,
729 pub node_data: NodeDataVec,
730 pub styled_nodes: StyledNodeVec,
731 pub cascade_info: CascadeInfoVec,
732 pub nodes_with_window_callbacks: NodeIdVec,
733 pub nodes_with_not_callbacks: NodeIdVec,
734 pub nodes_with_datasets: NodeIdVec,
735 pub tag_ids_to_node_ids: TagIdToNodeIdMappingVec,
736 pub non_leaf_nodes: ParentWithNodeDepthVec,
737 pub css_property_cache: CssPropertyCachePtr,
738 pub dom_id: DomId,
740}
741impl_option!(
742 StyledDom,
743 OptionStyledDom,
744 copy = false,
745 [Debug, Clone, PartialEq]
746);
747
748impl Default for StyledDom {
749 fn default() -> Self {
750 let root_node: NodeHierarchyItem = Node::ROOT.into();
751 let root_node_id: NodeHierarchyItemId =
752 NodeHierarchyItemId::from_crate_internal(Some(NodeId::ZERO));
753 Self {
754 root: root_node_id,
755 node_hierarchy: vec![root_node].into(),
756 node_data: vec![NodeData::create_body()].into(),
757 styled_nodes: vec![StyledNode::default()].into(),
758 cascade_info: vec![CascadeInfo {
759 index_in_parent: 0,
760 is_last_child: true,
761 }]
762 .into(),
763 tag_ids_to_node_ids: Vec::new().into(),
764 non_leaf_nodes: vec![ParentWithNodeDepth {
765 depth: 0,
766 node_id: root_node_id,
767 }]
768 .into(),
769 nodes_with_window_callbacks: Vec::new().into(),
770 nodes_with_not_callbacks: Vec::new().into(),
771 nodes_with_datasets: Vec::new().into(),
772 css_property_cache: CssPropertyCachePtr::new(CssPropertyCache::empty(1)),
773 dom_id: DomId::ROOT_ID,
774 }
775 }
776}
777
778impl StyledDom {
779 pub fn create(dom: &mut Dom, mut css: Css) -> Self {
786 use core::mem;
787
788 use crate::dom::EventFilter;
789
790 let mut swap_dom = Dom::create_body();
791
792 mem::swap(dom, &mut swap_dom);
793
794 let compact_dom: CompactDom = swap_dom.into();
795 let non_leaf_nodes = compact_dom
796 .node_hierarchy
797 .as_ref()
798 .get_parents_sorted_by_depth();
799 let node_hierarchy: NodeHierarchyItemVec = compact_dom
800 .node_hierarchy
801 .as_ref()
802 .internal
803 .iter()
804 .map(|i| (*i).into())
805 .collect::<Vec<NodeHierarchyItem>>()
806 .into();
807
808 let mut styled_nodes = vec![
809 StyledNode {
810 tag_id: OptionTagId::None,
811 styled_node_state: StyledNodeState::new()
812 };
813 compact_dom.len()
814 ];
815
816 let mut css_property_cache = CssPropertyCache::empty(compact_dom.node_data.len());
820
821 let html_tree =
822 construct_html_cascade_tree(&compact_dom.node_hierarchy.as_ref(), &non_leaf_nodes[..]);
823
824 let non_leaf_nodes = non_leaf_nodes
825 .iter()
826 .map(|(depth, node_id)| ParentWithNodeDepth {
827 depth: *depth,
828 node_id: NodeHierarchyItemId::from_crate_internal(Some(*node_id)),
829 })
830 .collect::<Vec<_>>();
831
832 let non_leaf_nodes: ParentWithNodeDepthVec = non_leaf_nodes.into();
833
834 let tag_ids = css_property_cache.restyle(
836 &mut css,
837 &compact_dom.node_data.as_ref(),
838 &node_hierarchy,
839 &non_leaf_nodes,
840 &html_tree.as_ref(),
841 );
842
843 css_property_cache.apply_ua_css(compact_dom.node_data.as_ref().internal);
847
848 css_property_cache.compute_inherited_values(
852 node_hierarchy.as_container().internal,
853 compact_dom.node_data.as_ref().internal,
854 );
855
856 tag_ids
857 .iter()
858 .filter_map(|tag_id_node_id_mapping| {
859 tag_id_node_id_mapping
860 .node_id
861 .into_crate_internal()
862 .map(|node_id| (node_id, tag_id_node_id_mapping.tag_id))
863 })
864 .for_each(|(nid, tag_id)| {
865 styled_nodes[nid.index()].tag_id = OptionTagId::Some(tag_id);
866 });
867
868 let nodes_with_window_callbacks = compact_dom
871 .node_data
872 .as_ref()
873 .internal
874 .iter()
875 .enumerate()
876 .filter_map(|(node_id, c)| {
877 let node_has_none_callbacks = c.get_callbacks().iter().any(|cb| match cb.event {
878 EventFilter::Window(_) => true,
879 _ => false,
880 });
881 if node_has_none_callbacks {
882 Some(NodeHierarchyItemId::from_crate_internal(Some(NodeId::new(
883 node_id,
884 ))))
885 } else {
886 None
887 }
888 })
889 .collect::<Vec<_>>();
890
891 let nodes_with_not_callbacks = compact_dom
892 .node_data
893 .as_ref()
894 .internal
895 .iter()
896 .enumerate()
897 .filter_map(|(node_id, c)| {
898 let node_has_none_callbacks = c.get_callbacks().iter().any(|cb| match cb.event {
899 EventFilter::Not(_) => true,
900 _ => false,
901 });
902 if node_has_none_callbacks {
903 Some(NodeHierarchyItemId::from_crate_internal(Some(NodeId::new(
904 node_id,
905 ))))
906 } else {
907 None
908 }
909 })
910 .collect::<Vec<_>>();
911
912 let nodes_with_datasets = compact_dom
914 .node_data
915 .as_ref()
916 .internal
917 .iter()
918 .enumerate()
919 .filter_map(|(node_id, c)| {
920 if !c.get_callbacks().is_empty() || c.get_dataset().is_some() {
921 Some(NodeHierarchyItemId::from_crate_internal(Some(NodeId::new(
922 node_id,
923 ))))
924 } else {
925 None
926 }
927 })
928 .collect::<Vec<_>>();
929
930 let mut styled_dom = StyledDom {
931 root: NodeHierarchyItemId::from_crate_internal(Some(compact_dom.root)),
932 node_hierarchy,
933 node_data: compact_dom.node_data.internal.into(),
934 cascade_info: html_tree.internal.into(),
935 styled_nodes: styled_nodes.into(),
936 tag_ids_to_node_ids: tag_ids.into(),
937 nodes_with_window_callbacks: nodes_with_window_callbacks.into(),
938 nodes_with_not_callbacks: nodes_with_not_callbacks.into(),
939 nodes_with_datasets: nodes_with_datasets.into(),
940 non_leaf_nodes,
941 css_property_cache: CssPropertyCachePtr::new(css_property_cache),
942 dom_id: DomId::ROOT_ID, };
944
945 #[cfg(feature = "table_layout")]
949 if let Err(e) = crate::dom_table::generate_anonymous_table_elements(&mut styled_dom) {
950 eprintln!(
951 "Warning: Failed to generate anonymous table elements: {:?}",
952 e
953 );
954 }
955
956 styled_dom
957 }
958
959 pub fn append_child(&mut self, mut other: Self) {
962 let self_len = self.node_hierarchy.as_ref().len();
964 let other_len = other.node_hierarchy.as_ref().len();
965 let self_tag_len = self.tag_ids_to_node_ids.as_ref().len();
966 let self_root_id = self.root.into_crate_internal().unwrap_or(NodeId::ZERO);
967 let other_root_id = other.root.into_crate_internal().unwrap_or(NodeId::ZERO);
968
969 let current_root_children_count = self_root_id
971 .az_children(&self.node_hierarchy.as_container())
972 .count();
973
974 other.cascade_info.as_mut()[other_root_id.index()].index_in_parent =
975 current_root_children_count as u32;
976 other.cascade_info.as_mut()[other_root_id.index()].is_last_child = true;
977
978 self.cascade_info.append(&mut other.cascade_info);
979
980 for other in other.node_hierarchy.as_mut().iter_mut() {
983 if other.parent != 0 {
984 other.parent += self_len;
985 }
986 if other.previous_sibling != 0 {
987 other.previous_sibling += self_len;
988 }
989 if other.next_sibling != 0 {
990 other.next_sibling += self_len;
991 }
992 if other.last_child != 0 {
993 other.last_child += self_len;
994 }
995 }
996
997 other.node_hierarchy.as_container_mut()[other_root_id].parent =
998 NodeId::into_raw(&Some(self_root_id));
999 let current_last_child = self.node_hierarchy.as_container()[self_root_id].last_child_id();
1000 other.node_hierarchy.as_container_mut()[other_root_id].previous_sibling =
1001 NodeId::into_raw(¤t_last_child);
1002 if let Some(current_last) = current_last_child {
1003 if self.node_hierarchy.as_container_mut()[current_last]
1004 .next_sibling_id()
1005 .is_some()
1006 {
1007 self.node_hierarchy.as_container_mut()[current_last].next_sibling +=
1008 other_root_id.index() + other_len;
1009 } else {
1010 self.node_hierarchy.as_container_mut()[current_last].next_sibling =
1011 NodeId::into_raw(&Some(NodeId::new(self_len + other_root_id.index())));
1012 }
1013 }
1014 self.node_hierarchy.as_container_mut()[self_root_id].last_child =
1015 NodeId::into_raw(&Some(NodeId::new(self_len + other_root_id.index())));
1016
1017 self.node_hierarchy.append(&mut other.node_hierarchy);
1018 self.node_data.append(&mut other.node_data);
1019 self.styled_nodes.append(&mut other.styled_nodes);
1020 self.get_css_property_cache_mut()
1021 .append(other.get_css_property_cache_mut());
1022
1023 for tag_id_node_id in other.tag_ids_to_node_ids.iter_mut() {
1024 tag_id_node_id.tag_id.inner += self_tag_len as u64;
1025 tag_id_node_id.node_id.inner += self_len;
1026 }
1027
1028 self.tag_ids_to_node_ids
1029 .append(&mut other.tag_ids_to_node_ids);
1030
1031 for nid in other.nodes_with_window_callbacks.iter_mut() {
1032 nid.inner += self_len;
1033 }
1034 self.nodes_with_window_callbacks
1035 .append(&mut other.nodes_with_window_callbacks);
1036
1037 for nid in other.nodes_with_not_callbacks.iter_mut() {
1038 nid.inner += self_len;
1039 }
1040 self.nodes_with_not_callbacks
1041 .append(&mut other.nodes_with_not_callbacks);
1042
1043 for nid in other.nodes_with_datasets.iter_mut() {
1044 nid.inner += self_len;
1045 }
1046 self.nodes_with_datasets
1047 .append(&mut other.nodes_with_datasets);
1048
1049 if other_len != 1 {
1052 for other_non_leaf_node in other.non_leaf_nodes.iter_mut() {
1053 other_non_leaf_node.node_id.inner += self_len;
1054 other_non_leaf_node.depth += 1;
1055 }
1056 self.non_leaf_nodes.append(&mut other.non_leaf_nodes);
1057 self.non_leaf_nodes.sort_by(|a, b| a.depth.cmp(&b.depth));
1058 }
1059 }
1060
1061 pub fn with_child(mut self, other: Self) -> Self {
1063 self.append_child(other);
1064 self
1065 }
1066
1067 pub fn set_context_menu(&mut self, context_menu: Menu) {
1069 if let Some(root_id) = self.root.into_crate_internal() {
1070 self.node_data.as_container_mut()[root_id].set_context_menu(context_menu);
1071 }
1072 }
1073
1074 pub fn with_context_menu(mut self, context_menu: Menu) -> Self {
1076 self.set_context_menu(context_menu);
1077 self
1078 }
1079
1080 pub fn set_menu_bar(&mut self, menu_bar: Menu) {
1082 if let Some(root_id) = self.root.into_crate_internal() {
1083 self.node_data.as_container_mut()[root_id].set_menu_bar(menu_bar);
1084 }
1085 }
1086
1087 pub fn with_menu_bar(mut self, menu_bar: Menu) -> Self {
1089 self.set_menu_bar(menu_bar);
1090 self
1091 }
1092
1093 pub fn restyle(&mut self, mut css: Css) {
1095 let new_tag_ids = self.css_property_cache.downcast_mut().restyle(
1096 &mut css,
1097 &self.node_data.as_container(),
1098 &self.node_hierarchy,
1099 &self.non_leaf_nodes,
1100 &self.cascade_info.as_container(),
1101 );
1102
1103 self.css_property_cache
1105 .downcast_mut()
1106 .apply_ua_css(self.node_data.as_container().internal);
1107
1108 self.css_property_cache
1110 .downcast_mut()
1111 .compute_inherited_values(
1112 self.node_hierarchy.as_container().internal,
1113 self.node_data.as_container().internal,
1114 );
1115
1116 let mut styled_nodes_mut = self.styled_nodes.as_container_mut();
1118
1119 styled_nodes_mut
1120 .internal
1121 .iter_mut()
1122 .for_each(|styled_node| {
1123 styled_node.tag_id = None.into();
1124 });
1125
1126 new_tag_ids
1127 .iter()
1128 .filter_map(|tag_id_node_id_mapping| {
1129 tag_id_node_id_mapping
1130 .node_id
1131 .into_crate_internal()
1132 .map(|node_id| (node_id, tag_id_node_id_mapping.tag_id))
1133 })
1134 .for_each(|(nid, tag_id)| {
1135 styled_nodes_mut[nid].tag_id = Some(tag_id).into();
1136 });
1137
1138 self.tag_ids_to_node_ids = new_tag_ids.into();
1139 }
1140
1141 #[inline]
1143 pub fn node_count(&self) -> usize {
1144 self.node_data.len()
1145 }
1146
1147 #[inline]
1149 pub fn get_css_property_cache<'a>(&'a self) -> &'a CssPropertyCache {
1150 &*self.css_property_cache.ptr
1151 }
1152
1153 #[inline]
1155 pub fn get_css_property_cache_mut<'a>(&'a mut self) -> &'a mut CssPropertyCache {
1156 &mut *self.css_property_cache.ptr
1157 }
1158
1159 #[inline]
1161 pub fn get_styled_node_state(&self, node_id: &NodeId) -> StyledNodeState {
1162 self.styled_nodes.as_container()[*node_id]
1163 .styled_node_state
1164 .clone()
1165 }
1166
1167 pub fn scan_for_image_keys(&self, css_image_cache: &ImageCache) -> FastBTreeSet<ImageRef> {
1169 use azul_css::props::style::StyleBackgroundContentVec;
1170
1171 use crate::{dom::NodeType::*, resources::OptionImageMask};
1172
1173 #[derive(Default)]
1174 struct ScanImageVec {
1175 node_type_image: Option<ImageRef>,
1176 background_image: Vec<ImageRef>,
1177 clip_mask: Option<ImageRef>,
1178 }
1179
1180 let default_backgrounds: StyleBackgroundContentVec = Vec::new().into();
1181
1182 let images = self
1183 .node_data
1184 .as_container()
1185 .internal
1186 .iter()
1187 .enumerate()
1188 .map(|(node_id, node_data)| {
1189 let node_id = NodeId::new(node_id);
1190 let mut v = ScanImageVec::default();
1191
1192 if let Image(id) = node_data.get_node_type() {
1194 v.node_type_image = Some(id.clone());
1195 }
1196
1197 let opt_background_image = self.get_css_property_cache().get_background_content(
1199 &node_data,
1200 &node_id,
1201 &self.styled_nodes.as_container()[node_id].styled_node_state,
1202 );
1203
1204 if let Some(style_backgrounds) = opt_background_image {
1205 v.background_image = style_backgrounds
1206 .get_property()
1207 .unwrap_or(&default_backgrounds)
1208 .iter()
1209 .filter_map(|bg| {
1210 use azul_css::props::style::StyleBackgroundContent::*;
1211 let css_image_id = match bg {
1212 Image(i) => i,
1213 _ => return None,
1214 };
1215 let image_ref = css_image_cache.get_css_image_id(css_image_id)?;
1216 Some(image_ref.clone())
1217 })
1218 .collect();
1219 }
1220
1221 if let Some(clip_mask) = node_data.get_clip_mask() {
1223 v.clip_mask = Some(clip_mask.image.clone());
1224 }
1225
1226 v
1227 })
1228 .collect::<Vec<_>>();
1229
1230 let mut set = FastBTreeSet::new();
1231
1232 for scan_image in images.into_iter() {
1233 if let Some(n) = scan_image.node_type_image {
1234 set.insert(n);
1235 }
1236 if let Some(n) = scan_image.clip_mask {
1237 set.insert(n);
1238 }
1239 for bg in scan_image.background_image {
1240 set.insert(bg);
1241 }
1242 }
1243
1244 set
1245 }
1246
1247 #[must_use]
1249 pub fn restyle_nodes_hover(
1250 &mut self,
1251 nodes: &[NodeId],
1252 new_hover_state: bool,
1253 ) -> BTreeMap<NodeId, Vec<ChangedCssProperty>> {
1254 let old_node_states = nodes
1256 .iter()
1257 .map(|nid| {
1258 self.styled_nodes.as_container()[*nid]
1259 .styled_node_state
1260 .clone()
1261 })
1262 .collect::<Vec<_>>();
1263
1264 for nid in nodes.iter() {
1265 self.styled_nodes.as_container_mut()[*nid]
1266 .styled_node_state
1267 .hover = new_hover_state;
1268 }
1269
1270 let css_property_cache = self.get_css_property_cache();
1271 let styled_nodes = self.styled_nodes.as_container();
1272 let node_data = self.node_data.as_container();
1273
1274 let default_map = BTreeMap::default();
1275
1276 let v = nodes
1278 .iter()
1279 .zip(old_node_states.iter())
1280 .filter_map(|(node_id, old_node_state)| {
1281 let mut keys_normal: Vec<_> = css_property_cache
1282 .css_hover_props
1283 .get(node_id)
1284 .unwrap_or(&default_map)
1285 .keys()
1286 .collect();
1287 let mut keys_inherited: Vec<_> = css_property_cache
1288 .cascaded_hover_props
1289 .get(node_id)
1290 .unwrap_or(&default_map)
1291 .keys()
1292 .collect();
1293 let keys_inline: Vec<CssPropertyType> = {
1294 use azul_css::dynamic_selector::{DynamicSelector, PseudoStateType};
1295 node_data[*node_id]
1296 .css_props
1297 .iter()
1298 .filter_map(|prop| {
1299 let is_hover = prop.apply_if.as_slice().iter().any(|c| {
1300 matches!(c, DynamicSelector::PseudoState(PseudoStateType::Hover))
1301 });
1302 if is_hover {
1303 Some(prop.property.get_type())
1304 } else {
1305 None
1306 }
1307 })
1308 .collect()
1309 };
1310 let mut keys_inline_ref = keys_inline.iter().map(|r| r).collect();
1311
1312 keys_normal.append(&mut keys_inherited);
1313 keys_normal.append(&mut keys_inline_ref);
1314
1315 let node_properties_that_could_have_changed = keys_normal;
1316
1317 if node_properties_that_could_have_changed.is_empty() {
1318 return None;
1319 }
1320
1321 let new_node_state = &styled_nodes[*node_id].styled_node_state;
1322 let node_data = &node_data[*node_id];
1323
1324 let changes = node_properties_that_could_have_changed
1325 .into_iter()
1326 .filter_map(|prop| {
1327 let old = css_property_cache.get_property(
1329 node_data,
1330 node_id,
1331 old_node_state,
1332 prop,
1333 );
1334 let new = css_property_cache.get_property(
1335 node_data,
1336 node_id,
1337 new_node_state,
1338 prop,
1339 );
1340 if old == new {
1341 None
1342 } else {
1343 Some(ChangedCssProperty {
1344 previous_state: old_node_state.clone(),
1345 previous_prop: match old {
1346 None => CssProperty::auto(*prop),
1347 Some(s) => s.clone(),
1348 },
1349 current_state: new_node_state.clone(),
1350 current_prop: match new {
1351 None => CssProperty::auto(*prop),
1352 Some(s) => s.clone(),
1353 },
1354 })
1355 }
1356 })
1357 .collect::<Vec<_>>();
1358
1359 if changes.is_empty() {
1360 None
1361 } else {
1362 Some((*node_id, changes))
1363 }
1364 })
1365 .collect::<Vec<_>>();
1366
1367 v.into_iter().collect()
1368 }
1369
1370 #[must_use]
1372 pub fn restyle_nodes_active(
1373 &mut self,
1374 nodes: &[NodeId],
1375 new_active_state: bool,
1376 ) -> BTreeMap<NodeId, Vec<ChangedCssProperty>> {
1377 let old_node_states = nodes
1379 .iter()
1380 .map(|nid| {
1381 self.styled_nodes.as_container()[*nid]
1382 .styled_node_state
1383 .clone()
1384 })
1385 .collect::<Vec<_>>();
1386
1387 for nid in nodes.iter() {
1388 self.styled_nodes.as_container_mut()[*nid]
1389 .styled_node_state
1390 .active = new_active_state;
1391 }
1392
1393 let css_property_cache = self.get_css_property_cache();
1394 let styled_nodes = self.styled_nodes.as_container();
1395 let node_data = self.node_data.as_container();
1396
1397 let default_map = BTreeMap::default();
1398
1399 let v = nodes
1401 .iter()
1402 .zip(old_node_states.iter())
1403 .filter_map(|(node_id, old_node_state)| {
1404 let mut keys_normal: Vec<_> = css_property_cache
1405 .css_active_props
1406 .get(node_id)
1407 .unwrap_or(&default_map)
1408 .keys()
1409 .collect();
1410
1411 let mut keys_inherited: Vec<_> = css_property_cache
1412 .cascaded_active_props
1413 .get(node_id)
1414 .unwrap_or(&default_map)
1415 .keys()
1416 .collect();
1417
1418 let keys_inline: Vec<CssPropertyType> = {
1419 use azul_css::dynamic_selector::{DynamicSelector, PseudoStateType};
1420 node_data[*node_id]
1421 .css_props
1422 .iter()
1423 .filter_map(|prop| {
1424 let is_active = prop.apply_if.as_slice().iter().any(|c| {
1425 matches!(c, DynamicSelector::PseudoState(PseudoStateType::Active))
1426 });
1427 if is_active {
1428 Some(prop.property.get_type())
1429 } else {
1430 None
1431 }
1432 })
1433 .collect()
1434 };
1435 let mut keys_inline_ref = keys_inline.iter().map(|r| r).collect();
1436
1437 keys_normal.append(&mut keys_inherited);
1438 keys_normal.append(&mut keys_inline_ref);
1439
1440 let node_properties_that_could_have_changed = keys_normal;
1441
1442 if node_properties_that_could_have_changed.is_empty() {
1443 return None;
1444 }
1445
1446 let new_node_state = &styled_nodes[*node_id].styled_node_state;
1447 let node_data = &node_data[*node_id];
1448
1449 let changes = node_properties_that_could_have_changed
1450 .into_iter()
1451 .filter_map(|prop| {
1452 let old = css_property_cache.get_property(
1454 node_data,
1455 node_id,
1456 old_node_state,
1457 prop,
1458 );
1459 let new = css_property_cache.get_property(
1460 node_data,
1461 node_id,
1462 new_node_state,
1463 prop,
1464 );
1465 if old == new {
1466 None
1467 } else {
1468 Some(ChangedCssProperty {
1469 previous_state: old_node_state.clone(),
1470 previous_prop: match old {
1471 None => CssProperty::auto(*prop),
1472 Some(s) => s.clone(),
1473 },
1474 current_state: new_node_state.clone(),
1475 current_prop: match new {
1476 None => CssProperty::auto(*prop),
1477 Some(s) => s.clone(),
1478 },
1479 })
1480 }
1481 })
1482 .collect::<Vec<_>>();
1483
1484 if changes.is_empty() {
1485 None
1486 } else {
1487 Some((*node_id, changes))
1488 }
1489 })
1490 .collect::<Vec<_>>();
1491
1492 v.into_iter().collect()
1493 }
1494
1495 #[must_use]
1497 pub fn restyle_nodes_focus(
1498 &mut self,
1499 nodes: &[NodeId],
1500 new_focus_state: bool,
1501 ) -> BTreeMap<NodeId, Vec<ChangedCssProperty>> {
1502
1503 let old_node_states = nodes
1505 .iter()
1506 .map(|nid| {
1507 let state = self.styled_nodes.as_container()[*nid]
1508 .styled_node_state
1509 .clone();
1510 state
1511 })
1512 .collect::<Vec<_>>();
1513
1514 for nid in nodes.iter() {
1515 self.styled_nodes.as_container_mut()[*nid]
1516 .styled_node_state
1517 .focused = new_focus_state;
1518 }
1519
1520 let css_property_cache = self.get_css_property_cache();
1521 let styled_nodes = self.styled_nodes.as_container();
1522 let node_data = self.node_data.as_container();
1523
1524 let default_map = BTreeMap::default();
1525
1526 let v = nodes
1528 .iter()
1529 .zip(old_node_states.iter())
1530 .filter_map(|(node_id, old_node_state)| {
1531 let mut keys_normal: Vec<_> = css_property_cache
1532 .css_focus_props
1533 .get(node_id)
1534 .unwrap_or(&default_map)
1535 .keys()
1536 .collect();
1537
1538
1539 let mut keys_inherited: Vec<_> = css_property_cache
1540 .cascaded_focus_props
1541 .get(node_id)
1542 .unwrap_or(&default_map)
1543 .keys()
1544 .collect();
1545
1546
1547 let keys_inline: Vec<CssPropertyType> = {
1548 use azul_css::dynamic_selector::{DynamicSelector, PseudoStateType};
1549 node_data[*node_id]
1550 .css_props
1551 .iter()
1552 .filter_map(|prop| {
1553 let is_focus = prop.apply_if.as_slice().iter().any(|c| {
1554 matches!(c, DynamicSelector::PseudoState(PseudoStateType::Focus))
1555 });
1556 if is_focus {
1557 Some(prop.property.get_type())
1558 } else {
1559 None
1560 }
1561 })
1562 .collect()
1563 };
1564 let mut keys_inline_ref = keys_inline.iter().map(|r| r).collect();
1565
1566 keys_normal.append(&mut keys_inherited);
1567 keys_normal.append(&mut keys_inline_ref);
1568
1569 let node_properties_that_could_have_changed = keys_normal;
1570
1571
1572 if node_properties_that_could_have_changed.is_empty() {
1573 return None;
1574 }
1575
1576 let new_node_state = &styled_nodes[*node_id].styled_node_state;
1577 let node_data = &node_data[*node_id];
1578
1579 let changes = node_properties_that_could_have_changed
1580 .into_iter()
1581 .filter_map(|prop| {
1582 let old = css_property_cache.get_property(
1584 node_data,
1585 node_id,
1586 old_node_state,
1587 prop,
1588 );
1589 let new = css_property_cache.get_property(
1590 node_data,
1591 node_id,
1592 new_node_state,
1593 prop,
1594 );
1595 if old == new {
1596 None
1597 } else {
1598 Some(ChangedCssProperty {
1599 previous_state: old_node_state.clone(),
1600 previous_prop: match old {
1601 None => CssProperty::auto(*prop),
1602 Some(s) => s.clone(),
1603 },
1604 current_state: new_node_state.clone(),
1605 current_prop: match new {
1606 None => CssProperty::auto(*prop),
1607 Some(s) => s.clone(),
1608 },
1609 })
1610 }
1611 })
1612 .collect::<Vec<_>>();
1613
1614 if changes.is_empty() {
1615 None
1616 } else {
1617 Some((*node_id, changes))
1618 }
1619 })
1620 .collect::<Vec<_>>();
1621
1622 v.into_iter().collect()
1623 }
1624
1625 #[must_use]
1639 pub fn restyle_on_state_change(
1640 &mut self,
1641 focus_changes: Option<FocusChange>,
1642 hover_changes: Option<HoverChange>,
1643 active_changes: Option<ActiveChange>,
1644 ) -> RestyleResult {
1645
1646 let mut result = RestyleResult::default();
1647 result.gpu_only_changes = true; let mut process_changes = |changes: BTreeMap<NodeId, Vec<ChangedCssProperty>>| {
1651 for (node_id, props) in changes {
1652 for change in &props {
1653 let prop_type = change.current_prop.get_type();
1654
1655 if prop_type.can_trigger_relayout() {
1657 result.needs_layout = true;
1658 result.gpu_only_changes = false;
1659 }
1660
1661 if !prop_type.is_gpu_only_property() {
1663 result.gpu_only_changes = false;
1664 }
1665
1666 result.needs_display_list = true;
1668 }
1669
1670 result.changed_nodes.entry(node_id).or_default().extend(props);
1671 }
1672 };
1673
1674 if let Some(focus) = focus_changes {
1676 if let Some(old) = focus.lost_focus {
1677 let changes = self.restyle_nodes_focus(&[old], false);
1678 process_changes(changes);
1679 }
1680 if let Some(new) = focus.gained_focus {
1681 let changes = self.restyle_nodes_focus(&[new], true);
1682 process_changes(changes);
1683 }
1684 }
1685
1686 if let Some(hover) = hover_changes {
1688 if !hover.left_nodes.is_empty() {
1689 let changes = self.restyle_nodes_hover(&hover.left_nodes, false);
1690 process_changes(changes);
1691 }
1692 if !hover.entered_nodes.is_empty() {
1693 let changes = self.restyle_nodes_hover(&hover.entered_nodes, true);
1694 process_changes(changes);
1695 }
1696 }
1697
1698 if let Some(active) = active_changes {
1700 if !active.deactivated.is_empty() {
1701 let changes = self.restyle_nodes_active(&active.deactivated, false);
1702 process_changes(changes);
1703 }
1704 if !active.activated.is_empty() {
1705 let changes = self.restyle_nodes_active(&active.activated, true);
1706 process_changes(changes);
1707 }
1708 }
1709
1710 if result.changed_nodes.is_empty() {
1712 result.needs_display_list = false;
1713 result.gpu_only_changes = false;
1714 }
1715
1716 if result.needs_layout {
1718 result.needs_display_list = true;
1719 result.gpu_only_changes = false;
1720 }
1721
1722 result
1723 }
1724
1725 #[must_use]
1728 pub fn restyle_user_property(
1729 &mut self,
1730 node_id: &NodeId,
1731 new_properties: &[CssProperty],
1732 ) -> BTreeMap<NodeId, Vec<ChangedCssProperty>> {
1733 let mut map = BTreeMap::default();
1734
1735 if new_properties.is_empty() {
1736 return map;
1737 }
1738
1739 let node_data = self.node_data.as_container();
1740 let node_data = &node_data[*node_id];
1741
1742 let node_states = &self.styled_nodes.as_container();
1743 let old_node_state = &node_states[*node_id].styled_node_state;
1744
1745 let changes: Vec<ChangedCssProperty> = {
1746 let css_property_cache = self.get_css_property_cache();
1747
1748 new_properties
1749 .iter()
1750 .filter_map(|new_prop| {
1751 let old_prop = css_property_cache.get_property(
1752 node_data,
1753 node_id,
1754 old_node_state,
1755 &new_prop.get_type(),
1756 );
1757
1758 let old_prop = match old_prop {
1759 None => CssProperty::auto(new_prop.get_type()),
1760 Some(s) => s.clone(),
1761 };
1762
1763 if old_prop == *new_prop {
1764 None
1765 } else {
1766 Some(ChangedCssProperty {
1767 previous_state: old_node_state.clone(),
1768 previous_prop: old_prop,
1769 current_state: old_node_state.clone(),
1771 current_prop: new_prop.clone(),
1772 })
1773 }
1774 })
1775 .collect()
1776 };
1777
1778 let css_property_cache_mut = self.get_css_property_cache_mut();
1779
1780 for new_prop in new_properties.iter() {
1781 if new_prop.is_initial() {
1782 let mut should_remove_map = false;
1783 if let Some(map) = css_property_cache_mut
1784 .user_overridden_properties
1785 .get_mut(node_id)
1786 {
1787 map.remove(&new_prop.get_type());
1789 should_remove_map = map.is_empty();
1790 }
1791 if should_remove_map {
1792 css_property_cache_mut
1793 .user_overridden_properties
1794 .remove(node_id);
1795 }
1796 } else {
1797 css_property_cache_mut
1798 .user_overridden_properties
1799 .entry(*node_id)
1800 .or_insert_with(|| BTreeMap::new())
1801 .insert(new_prop.get_type(), new_prop.clone());
1802 }
1803 }
1804
1805 if !changes.is_empty() {
1806 map.insert(*node_id, changes);
1807 }
1808
1809 map
1810 }
1811
1812 pub fn scan_for_iframe_callbacks(&self) -> Vec<NodeId> {
1814 use crate::dom::NodeType;
1815 self.node_data
1816 .as_ref()
1817 .iter()
1818 .enumerate()
1819 .filter_map(|(node_id, node_data)| match node_data.get_node_type() {
1820 NodeType::IFrame(_) => Some(NodeId::new(node_id)),
1821 _ => None,
1822 })
1823 .collect()
1824 }
1825
1826 pub fn scan_for_gltexture_callbacks(&self) -> Vec<NodeId> {
1828 use crate::dom::NodeType;
1829 self.node_data
1830 .as_ref()
1831 .iter()
1832 .enumerate()
1833 .filter_map(|(node_id, node_data)| {
1834 use crate::resources::DecodedImage;
1835 match node_data.get_node_type() {
1836 NodeType::Image(image_ref) => {
1837 if let DecodedImage::Callback(_) = image_ref.get_data() {
1838 Some(NodeId::new(node_id))
1839 } else {
1840 None
1841 }
1842 }
1843 _ => None,
1844 }
1845 })
1846 .collect()
1847 }
1848
1849 pub fn get_html_string(&self, custom_head: &str, custom_body: &str, test_mode: bool) -> String {
1859 let css_property_cache = self.get_css_property_cache();
1860
1861 let mut output = String::new();
1862
1863 let mut should_print_close_tag_after_node = BTreeMap::new();
1865
1866 let should_print_close_tag_debug = self
1867 .non_leaf_nodes
1868 .iter()
1869 .filter_map(|p| {
1870 let parent_node_id = p.node_id.into_crate_internal()?;
1871 let mut total_last_child = None;
1872 recursive_get_last_child(
1873 parent_node_id,
1874 &self.node_hierarchy.as_ref(),
1875 &mut total_last_child,
1876 );
1877 let total_last_child = total_last_child?;
1878 Some((parent_node_id, (total_last_child, p.depth)))
1879 })
1880 .collect::<BTreeMap<_, _>>();
1881
1882 for (parent_id, (last_child, parent_depth)) in should_print_close_tag_debug {
1883 should_print_close_tag_after_node
1884 .entry(last_child)
1885 .or_insert_with(|| Vec::new())
1886 .push((parent_id, parent_depth));
1887 }
1888
1889 let mut all_node_depths = self
1890 .non_leaf_nodes
1891 .iter()
1892 .filter_map(|p| {
1893 let parent_node_id = p.node_id.into_crate_internal()?;
1894 Some((parent_node_id, p.depth))
1895 })
1896 .collect::<BTreeMap<_, _>>();
1897
1898 for (parent_node_id, parent_depth) in self
1899 .non_leaf_nodes
1900 .iter()
1901 .filter_map(|p| Some((p.node_id.into_crate_internal()?, p.depth)))
1902 {
1903 for child_id in parent_node_id.az_children(&self.node_hierarchy.as_container()) {
1904 all_node_depths.insert(child_id, parent_depth + 1);
1905 }
1906 }
1907
1908 for node_id in self.node_hierarchy.as_container().linear_iter() {
1909 let depth = all_node_depths[&node_id];
1910
1911 let node_data = &self.node_data.as_container()[node_id];
1912 let node_state = &self.styled_nodes.as_container()[node_id].styled_node_state;
1913 let tabs = String::from(" ").repeat(depth);
1914
1915 output.push_str("\r\n");
1916 output.push_str(&tabs);
1917 output.push_str(&node_data.debug_print_start(css_property_cache, &node_id, node_state));
1918
1919 if let Some(content) = node_data.get_node_type().format().as_ref() {
1920 output.push_str(content);
1921 }
1922
1923 let node_has_children = self.node_hierarchy.as_container()[node_id]
1924 .first_child_id(node_id)
1925 .is_some();
1926 if !node_has_children {
1927 let node_data = &self.node_data.as_container()[node_id];
1928 output.push_str(&node_data.debug_print_end());
1929 }
1930
1931 if let Some(close_tag_vec) = should_print_close_tag_after_node.get(&node_id) {
1932 let mut close_tag_vec = close_tag_vec.clone();
1933 close_tag_vec.sort_by(|a, b| b.1.cmp(&a.1)); for (close_tag_parent_id, close_tag_depth) in close_tag_vec {
1935 let node_data = &self.node_data.as_container()[close_tag_parent_id];
1936 let tabs = String::from(" ").repeat(close_tag_depth);
1937 output.push_str("\r\n");
1938 output.push_str(&tabs);
1939 output.push_str(&node_data.debug_print_end());
1940 }
1941 }
1942 }
1943
1944 if !test_mode {
1945 format!(
1946 "
1947 <html>
1948 <head>
1949 <style>* {{ margin:0px; padding:0px; }}</style>
1950 {custom_head}
1951 </head>
1952 {output}
1953 {custom_body}
1954 </html>
1955 "
1956 )
1957 } else {
1958 output
1959 }
1960 }
1961
1962 pub fn get_subtree(&self, parent: NodeId) -> Vec<NodeId> {
1964 let mut total_last_child = None;
1965 recursive_get_last_child(parent, &self.node_hierarchy.as_ref(), &mut total_last_child);
1966 if let Some(last) = total_last_child {
1967 (parent.index()..=last.index())
1968 .map(|id| NodeId::new(id))
1969 .collect()
1970 } else {
1971 Vec::new()
1972 }
1973 }
1974
1975 pub fn get_subtree_parents(&self, parent: NodeId) -> Vec<NodeId> {
1978 let mut total_last_child = None;
1979 recursive_get_last_child(parent, &self.node_hierarchy.as_ref(), &mut total_last_child);
1980 if let Some(last) = total_last_child {
1981 (parent.index()..=last.index())
1982 .filter_map(|id| {
1983 if self.node_hierarchy.as_ref()[id].last_child_id().is_some() {
1984 Some(NodeId::new(id))
1985 } else {
1986 None
1987 }
1988 })
1989 .collect()
1990 } else {
1991 Vec::new()
1992 }
1993 }
1994
1995 pub fn get_rects_in_rendering_order(&self) -> ContentGroup {
1997 Self::determine_rendering_order(
1998 &self.non_leaf_nodes.as_ref(),
1999 &self.node_hierarchy.as_container(),
2000 &self.styled_nodes.as_container(),
2001 &self.node_data.as_container(),
2002 &self.get_css_property_cache(),
2003 )
2004 }
2005
2006 fn determine_rendering_order<'a>(
2009 non_leaf_nodes: &[ParentWithNodeDepth],
2010 node_hierarchy: &NodeDataContainerRef<'a, NodeHierarchyItem>,
2011 styled_nodes: &NodeDataContainerRef<StyledNode>,
2012 node_data_container: &NodeDataContainerRef<NodeData>,
2013 css_property_cache: &CssPropertyCache,
2014 ) -> ContentGroup {
2015 let children_sorted = non_leaf_nodes
2016 .iter()
2017 .filter_map(|parent| {
2018 Some((
2019 parent.node_id,
2020 sort_children_by_position(
2021 parent.node_id.into_crate_internal()?,
2022 node_hierarchy,
2023 styled_nodes,
2024 node_data_container,
2025 css_property_cache,
2026 ),
2027 ))
2028 })
2029 .collect::<Vec<_>>();
2030
2031 let children_sorted: BTreeMap<NodeHierarchyItemId, Vec<NodeHierarchyItemId>> =
2032 children_sorted.into_iter().collect();
2033
2034 let mut root_content_group = ContentGroup {
2035 root: NodeHierarchyItemId::from_crate_internal(Some(NodeId::ZERO)),
2036 children: Vec::new().into(),
2037 };
2038
2039 fill_content_group_children(&mut root_content_group, &children_sorted);
2040
2041 root_content_group
2042 }
2043
2044 pub fn swap_with_default(&mut self) -> Self {
2046 let mut new = Self::default();
2047 core::mem::swap(self, &mut new);
2048 new
2049 }
2050
2051 }
2054
2055#[derive(Debug, PartialEq, PartialOrd, Eq)]
2057pub struct CompactDom {
2058 pub node_hierarchy: NodeHierarchy,
2060 pub node_data: NodeDataContainer<NodeData>,
2062 pub root: NodeId,
2064}
2065
2066impl CompactDom {
2067 #[inline(always)]
2069 pub fn len(&self) -> usize {
2070 self.node_hierarchy.as_ref().len()
2071 }
2072}
2073
2074impl From<Dom> for CompactDom {
2075 fn from(dom: Dom) -> Self {
2076 convert_dom_into_compact_dom(dom)
2077 }
2078}
2079
2080pub fn convert_dom_into_compact_dom(mut dom: Dom) -> CompactDom {
2082 fn convert_dom_into_compact_dom_internal(
2084 dom: &mut Dom,
2085 node_hierarchy: &mut [Node],
2086 node_data: &mut Vec<NodeData>,
2087 parent_node_id: NodeId,
2088 node: Node,
2089 cur_node_id: &mut usize,
2090 ) {
2091 node_hierarchy[parent_node_id.index()] = node.clone();
2102
2103 let copy = dom.root.copy_special();
2104
2105 node_data[parent_node_id.index()] = copy;
2106
2107 *cur_node_id += 1;
2108
2109 let mut previous_sibling_id = None;
2110 let children_len = dom.children.len();
2111 for (child_index, child_dom) in dom.children.as_mut().iter_mut().enumerate() {
2112 let child_node_id = NodeId::new(*cur_node_id);
2113 let is_last_child = (child_index + 1) == children_len;
2114 let child_dom_is_empty = child_dom.children.is_empty();
2115 let child_node = Node {
2116 parent: Some(parent_node_id),
2117 previous_sibling: previous_sibling_id,
2118 next_sibling: if is_last_child {
2119 None
2120 } else {
2121 Some(child_node_id + child_dom.estimated_total_children + 1)
2122 },
2123 last_child: if child_dom_is_empty {
2124 None
2125 } else {
2126 Some(child_node_id + child_dom.estimated_total_children)
2127 },
2128 };
2129 previous_sibling_id = Some(child_node_id);
2130 convert_dom_into_compact_dom_internal(
2132 child_dom,
2133 node_hierarchy,
2134 node_data,
2135 child_node_id,
2136 child_node,
2137 cur_node_id,
2138 );
2139 }
2140 }
2141
2142 const DEFAULT_NODE_DATA: NodeData = NodeData::create_div();
2144
2145 let sum_nodes = dom.fixup_children_estimated();
2146
2147 let mut node_hierarchy = vec![Node::ROOT; sum_nodes + 1];
2148 let mut node_data = vec![NodeData::create_div(); sum_nodes + 1];
2149 let mut cur_node_id = 0;
2150
2151 let root_node_id = NodeId::ZERO;
2152 let root_node = Node {
2153 parent: None,
2154 previous_sibling: None,
2155 next_sibling: None,
2156 last_child: if dom.children.is_empty() {
2157 None
2158 } else {
2159 Some(root_node_id + dom.estimated_total_children)
2160 },
2161 };
2162
2163 convert_dom_into_compact_dom_internal(
2164 &mut dom,
2165 &mut node_hierarchy,
2166 &mut node_data,
2167 root_node_id,
2168 root_node,
2169 &mut cur_node_id,
2170 );
2171
2172 CompactDom {
2173 node_hierarchy: NodeHierarchy {
2174 internal: node_hierarchy,
2175 },
2176 node_data: NodeDataContainer {
2177 internal: node_data,
2178 },
2179 root: root_node_id,
2180 }
2181}
2182
2183fn fill_content_group_children(
2184 group: &mut ContentGroup,
2185 children_sorted: &BTreeMap<NodeHierarchyItemId, Vec<NodeHierarchyItemId>>,
2186) {
2187 if let Some(c) = children_sorted.get(&group.root) {
2188 group.children = c
2190 .iter()
2191 .map(|child| ContentGroup {
2192 root: *child,
2193 children: Vec::new().into(),
2194 })
2195 .collect::<Vec<ContentGroup>>()
2196 .into();
2197
2198 for c in group.children.as_mut() {
2199 fill_content_group_children(c, children_sorted);
2200 }
2201 }
2202}
2203
2204fn sort_children_by_position<'a>(
2205 parent: NodeId,
2206 node_hierarchy: &NodeDataContainerRef<'a, NodeHierarchyItem>,
2207 rectangles: &NodeDataContainerRef<StyledNode>,
2208 node_data_container: &NodeDataContainerRef<NodeData>,
2209 css_property_cache: &CssPropertyCache,
2210) -> Vec<NodeHierarchyItemId> {
2211 use azul_css::props::layout::LayoutPosition::*;
2212
2213 let children_positions = parent
2214 .az_children(node_hierarchy)
2215 .map(|nid| {
2216 let position = css_property_cache
2217 .get_position(
2218 &node_data_container[nid],
2219 &nid,
2220 &rectangles[nid].styled_node_state,
2221 )
2222 .and_then(|p| p.clone().get_property_or_default())
2223 .unwrap_or_default();
2224 let id = NodeHierarchyItemId::from_crate_internal(Some(nid));
2225 (id, position)
2226 })
2227 .collect::<Vec<_>>();
2228
2229 let mut not_absolute_children = children_positions
2230 .iter()
2231 .filter_map(|(node_id, position)| {
2232 if *position != Absolute {
2233 Some(*node_id)
2234 } else {
2235 None
2236 }
2237 })
2238 .collect::<Vec<_>>();
2239
2240 let mut absolute_children = children_positions
2241 .iter()
2242 .filter_map(|(node_id, position)| {
2243 if *position == Absolute {
2244 Some(*node_id)
2245 } else {
2246 None
2247 }
2248 })
2249 .collect::<Vec<_>>();
2250
2251 not_absolute_children.append(&mut absolute_children);
2253 not_absolute_children
2254}
2255
2256fn recursive_get_last_child(
2259 node_id: NodeId,
2260 node_hierarchy: &[NodeHierarchyItem],
2261 target: &mut Option<NodeId>,
2262) {
2263 match node_hierarchy[node_id.index()].last_child_id() {
2264 None => return,
2265 Some(s) => {
2266 *target = Some(s);
2267 recursive_get_last_child(s, node_hierarchy, target);
2268 }
2269 }
2270}
2271
2272pub fn is_before_in_document_order(
2286 hierarchy: &NodeHierarchyItemVec,
2287 node_a: NodeId,
2288 node_b: NodeId,
2289) -> bool {
2290 if node_a == node_b {
2291 return false;
2292 }
2293
2294 let hierarchy = hierarchy.as_container();
2295
2296 let path_a = get_path_to_root(&hierarchy, node_a);
2298 let path_b = get_path_to_root(&hierarchy, node_b);
2299
2300 let min_len = path_a.len().min(path_b.len());
2302
2303 for i in 0..min_len {
2304 if path_a[i] != path_b[i] {
2305 let child_towards_a = path_a[i];
2307 let child_towards_b = path_b[i];
2308
2309 return child_towards_a.index() < child_towards_b.index();
2312 }
2313 }
2314
2315 path_a.len() < path_b.len()
2317}
2318
2319fn get_path_to_root(
2321 hierarchy: &NodeDataContainerRef<'_, NodeHierarchyItem>,
2322 node: NodeId,
2323) -> Vec<NodeId> {
2324 let mut path = Vec::new();
2325 let mut current = Some(node);
2326
2327 while let Some(node_id) = current {
2328 path.push(node_id);
2329 current = hierarchy.get(node_id).and_then(|h| h.parent_id());
2330 }
2331
2332 path.reverse();
2334 path
2335}
2336
2337pub fn collect_nodes_in_document_order(
2350 hierarchy: &NodeHierarchyItemVec,
2351 start_node: NodeId,
2352 end_node: NodeId,
2353) -> Vec<NodeId> {
2354 if start_node == end_node {
2355 return vec![start_node];
2356 }
2357
2358 let hierarchy_container = hierarchy.as_container();
2359 let hierarchy_slice = hierarchy.as_ref();
2360
2361 let mut result = Vec::new();
2362 let mut in_range = false;
2363
2364 let mut stack: Vec<NodeId> = vec![NodeId::ZERO]; while let Some(current) = stack.pop() {
2369 if current == start_node {
2371 in_range = true;
2372 }
2373
2374 if in_range {
2376 result.push(current);
2377 }
2378
2379 if current == end_node {
2381 break;
2382 }
2383
2384 if let Some(item) = hierarchy_container.get(current) {
2387 if let Some(first_child) = item.first_child_id(current) {
2389 let mut children = Vec::new();
2391 let mut child = Some(first_child);
2392 while let Some(child_id) = child {
2393 children.push(child_id);
2394 child = hierarchy_container.get(child_id).and_then(|h| h.next_sibling_id());
2395 }
2396 for child_id in children.into_iter().rev() {
2398 stack.push(child_id);
2399 }
2400 }
2401 }
2402 }
2403
2404 result
2405}