1use crate::{cache::CachedData, prelude::*};
2#[cfg(feature = "rayon")]
3use dashmap::{DashMap, ReadOnlyView};
4use hashbrown::HashMap;
5#[cfg(feature = "rayon")]
6use rayon::prelude::*;
7use vizia_storage::{LayoutParentIterator, TreeBreadthIterator};
8use vizia_style::{
9 matches_selector,
10 precomputed_hash::PrecomputedHash,
11 selectors::{
12 attr::{AttrSelectorOperation, CaseSensitivity, NamespaceConstraint},
13 bloom::BloomFilter,
14 context::{MatchingForInvalidation, NeedsSelectorFlags, SelectorCaches},
15 matching::ElementSelectorFlags,
16 parser::{Component, NthType},
17 OpaqueElement, SelectorImpl,
18 },
19 Element, MatchingContext, MatchingMode, PseudoClass, QuirksMode, SelectorIdent, Selectors,
20};
21
22#[derive(Clone)]
24pub(crate) struct Node<'s, 't> {
25 entity: Entity,
26 store: &'s Style,
27 tree: &'t Tree<Entity>,
28}
29
30impl std::fmt::Debug for Node<'_, '_> {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 write!(f, "{}", self.entity)
33 }
34}
35
36impl Element for Node<'_, '_> {
38 type Impl = Selectors;
39
40 fn opaque(&self) -> OpaqueElement {
41 OpaqueElement::new(self)
42 }
43
44 fn is_html_slot_element(&self) -> bool {
45 false
46 }
47
48 fn parent_node_is_shadow_root(&self) -> bool {
49 false
50 }
51
52 fn containing_shadow_host(&self) -> Option<Self> {
53 None
54 }
55
56 fn parent_element(&self) -> Option<Self> {
57 self.tree.get_layout_parent(self.entity).map(|parent| Node {
58 entity: parent,
59 store: self.store,
60 tree: self.tree,
61 })
62 }
63
64 fn prev_sibling_element(&self) -> Option<Self> {
65 self.tree.get_prev_layout_sibling(self.entity).map(|parent| Node {
66 entity: parent,
67 store: self.store,
68 tree: self.tree,
69 })
70 }
71
72 fn next_sibling_element(&self) -> Option<Self> {
73 self.tree.get_next_layout_sibling(self.entity).map(|parent| Node {
74 entity: parent,
75 store: self.store,
76 tree: self.tree,
77 })
78 }
79
80 fn is_empty(&self) -> bool {
81 !self.tree.has_children(self.entity)
82 }
83
84 fn is_root(&self) -> bool {
85 self.entity == Entity::root()
86 }
87
88 fn is_html_element_in_html_document(&self) -> bool {
89 false
90 }
91
92 fn has_local_name(&self, local_name: &SelectorIdent) -> bool {
93 if let Some(element) = self.store.element.get(self.entity) {
94 return element == &local_name.precomputed_hash();
95 }
96
97 false
98 }
99
100 fn has_namespace(&self, _ns: &<Self::Impl as SelectorImpl>::BorrowedNamespaceUrl) -> bool {
101 false
102 }
103
104 fn is_part(&self, _name: &<Self::Impl as SelectorImpl>::Identifier) -> bool {
105 false
106 }
107
108 fn imported_part(
109 &self,
110 _name: &<Self::Impl as SelectorImpl>::Identifier,
111 ) -> Option<<Self::Impl as SelectorImpl>::Identifier> {
112 None
113 }
114
115 fn is_pseudo_element(&self) -> bool {
116 false
117 }
118
119 fn is_same_type(&self, other: &Self) -> bool {
120 if let Some(element) = self.store.element.get(self.entity) {
121 if let Some(other_element) = self.store.element.get(other.entity) {
122 return element == other_element;
123 }
124 }
125
126 false
127 }
128
129 fn is_link(&self) -> bool {
130 false
131 }
132
133 fn has_id(
134 &self,
135 name: &<Self::Impl as SelectorImpl>::Identifier,
136 _case_sensitivity: CaseSensitivity,
137 ) -> bool {
138 if let Some(id) = self.store.ids.get(self.entity) {
139 *id == name.0
140 } else {
141 false
142 }
143 }
144
145 fn has_class(
146 &self,
147 name: &<Self::Impl as SelectorImpl>::Identifier,
148 _case_sensitivity: CaseSensitivity,
149 ) -> bool {
150 if let Some(classes) = self.store.classes.get(self.entity) {
151 return classes.contains(&name.0);
152 }
153
154 false
155 }
156
157 fn attr_matches(
158 &self,
159 _ns: &NamespaceConstraint<&<Self::Impl as SelectorImpl>::NamespaceUrl>,
160 _local_name: &<Self::Impl as SelectorImpl>::LocalName,
161 _operation: &AttrSelectorOperation<&<Self::Impl as SelectorImpl>::AttrValue>,
162 ) -> bool {
163 false
164 }
165
166 fn match_pseudo_element(
167 &self,
168 _pe: &<Self::Impl as SelectorImpl>::PseudoElement,
169 _context: &mut MatchingContext<'_, Self::Impl>,
170 ) -> bool {
171 false
172 }
173
174 fn match_non_ts_pseudo_class(
175 &self,
176 pc: &<Self::Impl as SelectorImpl>::NonTSPseudoClass,
177 _context: &mut MatchingContext<'_, Self::Impl>,
178 ) -> bool {
179 if let Some(psudeo_class_flag) = self.store.pseudo_classes.get(self.entity) {
180 match pc {
181 PseudoClass::Hover => psudeo_class_flag.contains(PseudoClassFlags::HOVER),
182 PseudoClass::Active => psudeo_class_flag.contains(PseudoClassFlags::ACTIVE),
183 PseudoClass::Over => psudeo_class_flag.contains(PseudoClassFlags::OVER),
184 PseudoClass::Focus => psudeo_class_flag.contains(PseudoClassFlags::FOCUS),
185 PseudoClass::FocusVisible => {
186 psudeo_class_flag.contains(PseudoClassFlags::FOCUS_VISIBLE)
187 }
188 PseudoClass::FocusWithin => {
189 psudeo_class_flag.contains(PseudoClassFlags::FOCUS_WITHIN)
190 }
191 PseudoClass::Enabled => {
192 self.store.disabled.get(self.entity).map(|disabled| !*disabled).unwrap_or(true)
193 }
194 PseudoClass::Disabled => {
195 self.store.disabled.get(self.entity).copied().unwrap_or_default()
196 }
197 PseudoClass::ReadOnly => psudeo_class_flag.contains(PseudoClassFlags::READ_ONLY),
198 PseudoClass::ReadWrite => psudeo_class_flag.contains(PseudoClassFlags::READ_WRITE),
199 PseudoClass::PlaceholderShown => {
200 psudeo_class_flag.contains(PseudoClassFlags::PLACEHOLDER_SHOWN)
201 }
202 PseudoClass::Default => psudeo_class_flag.contains(PseudoClassFlags::DEFAULT),
203 PseudoClass::Checked => psudeo_class_flag.contains(PseudoClassFlags::CHECKED),
204 PseudoClass::Indeterminate => {
205 psudeo_class_flag.contains(PseudoClassFlags::INDETERMINATE)
206 }
207 PseudoClass::Blank => psudeo_class_flag.contains(PseudoClassFlags::BLANK),
208 PseudoClass::Valid => psudeo_class_flag.contains(PseudoClassFlags::VALID),
209 PseudoClass::Invalid => psudeo_class_flag.contains(PseudoClassFlags::INVALID),
210 PseudoClass::InRange => psudeo_class_flag.contains(PseudoClassFlags::IN_RANGE),
211 PseudoClass::OutOfRange => {
212 psudeo_class_flag.contains(PseudoClassFlags::OUT_OF_RANGE)
213 }
214 PseudoClass::Required => psudeo_class_flag.contains(PseudoClassFlags::REQUIRED),
215 PseudoClass::Optional => psudeo_class_flag.contains(PseudoClassFlags::OPTIONAL),
216 PseudoClass::UserValid => psudeo_class_flag.contains(PseudoClassFlags::USER_VALID),
217 PseudoClass::UserInvalid => {
218 psudeo_class_flag.contains(PseudoClassFlags::USER_INVALID)
219 }
220 PseudoClass::Lang(_) => todo!(),
221 PseudoClass::Dir(_) => todo!(),
222 PseudoClass::Custom(name) => {
223 println!("custom: {}", name);
224 todo!()
225 }
226 }
227 } else {
228 false
229 }
230 }
231
232 fn first_element_child(&self) -> Option<Self> {
233 None
234 }
235
236 fn apply_selector_flags(&self, _flags: ElementSelectorFlags) {}
237
238 fn has_custom_state(&self, _name: &<Self::Impl as SelectorImpl>::Identifier) -> bool {
239 false
240 }
241
242 fn add_element_unique_hashes(
243 &self,
244 _filter: &mut vizia_style::selectors::bloom::BloomFilter,
245 ) -> bool {
246 false
247 }
248}
249
250pub(crate) fn inline_inheritance_system(cx: &mut Context, redraw_entities: &mut Vec<Entity>) {
252 for entity in cx.tree.into_iter() {
253 if let Some(parent) = cx.tree.get_layout_parent(entity) {
254 if cx.style.disabled.inherit_inline(entity, parent)
255 | cx.style.caret_color.inherit_inline(entity, parent)
256 | cx.style.selection_color.inherit_inline(entity, parent)
257 {
258 redraw_entities.push(entity);
259 }
260
261 if cx.style.font_color.inherit_inline(entity, parent)
262 | cx.style.font_size.inherit_inline(entity, parent)
263 | cx.style.font_family.inherit_inline(entity, parent)
264 | cx.style.font_weight.inherit_inline(entity, parent)
265 | cx.style.font_slant.inherit_inline(entity, parent)
266 | cx.style.font_width.inherit_inline(entity, parent)
267 | cx.style.text_decoration_line.inherit_inline(entity, parent)
268 | cx.style.text_stroke_width.inherit_inline(entity, parent)
269 | cx.style.text_stroke_style.inherit_inline(entity, parent)
270 | cx.style.font_variation_settings.inherit_inline(entity, parent)
271 {
272 cx.style.needs_text_update(entity);
273 }
274 }
275 }
276}
277
278pub(crate) fn shared_inheritance_system(cx: &mut Context, redraw_entities: &mut Vec<Entity>) {
280 for entity in cx.tree.into_iter() {
281 if let Some(parent) = cx.tree.get_layout_parent(entity) {
282 if cx.style.font_color.inherit_shared(entity, parent)
283 | cx.style.font_size.inherit_shared(entity, parent)
284 | cx.style.font_family.inherit_shared(entity, parent)
285 | cx.style.font_weight.inherit_shared(entity, parent)
286 | cx.style.font_slant.inherit_shared(entity, parent)
287 | cx.style.font_width.inherit_shared(entity, parent)
288 | cx.style.text_decoration_line.inherit_shared(entity, parent)
289 | cx.style.text_stroke_width.inherit_shared(entity, parent)
290 | cx.style.text_stroke_style.inherit_shared(entity, parent)
291 | cx.style.font_variation_settings.inherit_shared(entity, parent)
292 {
293 cx.style.needs_text_update(entity);
294 }
295
296 if cx.style.caret_color.inherit_shared(entity, parent)
297 | cx.style.selection_color.inherit_shared(entity, parent)
298 {
299 redraw_entities.push(entity);
300 }
301 }
302 }
303}
304
305fn link_style_data(
306 style: &mut Style,
307 cache: &mut CachedData,
308 tree: &Tree<Entity>,
309 entity: Entity,
310 redraw_entities: &mut Vec<Entity>,
311 matched_rules: &[(Rule, u32)],
312) {
313 let mut should_relayout = false;
314 let mut should_redraw = false;
315 let mut should_reflow = false;
316
317 if style.display.link(entity, matched_rules) {
319 should_relayout = true;
320 should_redraw = true;
321 }
322
323 if style.visibility.link(entity, matched_rules) {
324 should_relayout = true;
325 should_redraw = true;
326 }
327
328 if style.z_index.link(entity, matched_rules) {
329 should_redraw = true;
330 }
331
332 if style.overflowx.link(entity, matched_rules) {
333 should_redraw = true;
334 }
335
336 if style.overflowy.link(entity, matched_rules) {
337 should_redraw = true;
338 }
339
340 if style.clip_path.link(entity, matched_rules) {
341 should_redraw = true;
342 }
343
344 if style.backdrop_filter.link(entity, matched_rules) {
345 should_redraw = true;
346 }
347
348 if style.blend_mode.link(entity, matched_rules) {
349 should_redraw = true;
350 }
351
352 if style.opacity.link(entity, matched_rules) {
354 should_redraw = true;
355 }
356
357 if style.grid_columns.link(entity, matched_rules) {
359 should_relayout = true;
360 }
361
362 if style.grid_rows.link(entity, matched_rules) {
363 should_relayout = true;
364 }
365
366 if style.column_start.link(entity, matched_rules) {
367 should_relayout = true;
368 }
369
370 if style.column_span.link(entity, matched_rules) {
371 should_relayout = true;
372 }
373
374 if style.row_start.link(entity, matched_rules) {
375 should_relayout = true;
376 }
377
378 if style.row_span.link(entity, matched_rules) {
379 should_relayout = true;
380 }
381
382 if style.left.link(entity, matched_rules) {
385 should_relayout = true;
386 should_redraw = true;
387 }
388
389 if style.right.link(entity, matched_rules) {
390 should_relayout = true;
391 should_redraw = true;
392 }
393
394 if style.top.link(entity, matched_rules) {
395 should_relayout = true;
396 should_redraw = true;
397 }
398
399 if style.bottom.link(entity, matched_rules) {
400 should_relayout = true;
401 should_redraw = true;
402 }
403
404 if style.width.link(entity, matched_rules) {
406 should_relayout = true;
407 should_redraw = true;
408 }
409
410 if style.height.link(entity, matched_rules) {
411 should_relayout = true;
412 should_redraw = true;
413 }
414
415 if style.max_width.link(entity, matched_rules) {
417 should_relayout = true;
418 should_redraw = true;
419 }
420
421 if style.min_width.link(entity, matched_rules) {
422 should_relayout = true;
423 should_redraw = true;
424 }
425
426 if style.max_height.link(entity, matched_rules) {
427 should_relayout = true;
428 should_redraw = true;
429 }
430
431 if style.min_height.link(entity, matched_rules) {
432 should_relayout = true;
433 should_redraw = true;
434 }
435
436 if style.max_horizontal_gap.link(entity, matched_rules) {
438 should_relayout = true;
439 should_redraw = true;
440 }
441
442 if style.min_horizontal_gap.link(entity, matched_rules) {
443 should_relayout = true;
444 should_redraw = true;
445 }
446
447 if style.max_vertical_gap.link(entity, matched_rules) {
448 should_relayout = true;
449 should_redraw = true;
450 }
451
452 if style.min_vertical_gap.link(entity, matched_rules) {
453 should_relayout = true;
454 should_redraw = true;
455 }
456
457 if style.border_width.link(entity, matched_rules) {
459 should_relayout = true;
460 should_redraw = true;
461 cache.path.remove(entity);
462 }
463
464 if style.border_color.link(entity, matched_rules) {
465 should_redraw = true;
466 }
467
468 if style.border_style.link(entity, matched_rules) {
469 should_redraw = true;
470 }
471
472 if style.corner_top_left_shape.link(entity, matched_rules) {
475 should_redraw = true;
476 }
477
478 if style.corner_top_right_shape.link(entity, matched_rules) {
479 should_redraw = true;
480 }
481
482 if style.corner_bottom_left_shape.link(entity, matched_rules) {
483 should_redraw = true;
484 }
485
486 if style.corner_bottom_right_shape.link(entity, matched_rules) {
487 should_redraw = true;
488 }
489
490 if style.corner_top_left_radius.link(entity, matched_rules) {
491 should_redraw = true;
492 }
493
494 if style.corner_top_right_radius.link(entity, matched_rules) {
495 should_redraw = true;
496 }
497
498 if style.corner_bottom_left_radius.link(entity, matched_rules) {
499 should_redraw = true;
500 }
501
502 if style.corner_bottom_right_radius.link(entity, matched_rules) {
503 should_redraw = true;
504 }
505
506 if style.outline_width.link(entity, matched_rules) {
507 should_redraw = true;
508 }
509
510 if style.outline_color.link(entity, matched_rules) {
511 should_redraw = true;
512 }
513
514 if style.outline_offset.link(entity, matched_rules) {
515 should_redraw = true;
516 }
517
518 if style.layout_type.link(entity, matched_rules) {
519 should_relayout = true;
520 should_redraw = true;
521 }
522
523 if style.position_type.link(entity, matched_rules) {
524 should_relayout = true;
525 should_redraw = true;
526 }
527
528 if style.alignment.link(entity, matched_rules) {
529 should_relayout = true;
530 should_redraw = true;
531 }
532
533 if style.background_color.link(entity, matched_rules) {
535 should_redraw = true;
536 }
537
538 if style.background_image.link(entity, matched_rules) {
539 should_redraw = true;
540 }
541
542 if style.background_size.link(entity, matched_rules) {
543 should_redraw = true;
544 }
545
546 if style.font_color.link(entity, matched_rules) {
548 should_redraw = true;
549 should_reflow = true;
550 }
551
552 if style.font_size.link(entity, matched_rules) {
553 should_relayout = true;
554 should_redraw = true;
555 should_reflow = true;
556 }
557
558 if style.font_family.link(entity, matched_rules) {
559 should_relayout = true;
560 should_redraw = true;
561 should_reflow = true;
562 }
563
564 if style.font_weight.link(entity, matched_rules) {
565 should_redraw = true;
566 should_relayout = true;
567 should_reflow = true;
568 }
569
570 if style.font_slant.link(entity, matched_rules) {
571 should_redraw = true;
572 should_relayout = true;
573 should_reflow = true;
574 }
575
576 if style.font_width.link(entity, matched_rules) {
577 should_redraw = true;
578 should_relayout = true;
579 should_reflow = true;
580 }
581
582 if style.font_variation_settings.link(entity, matched_rules) {
583 should_redraw = true;
584 should_relayout = true;
585 should_reflow = true;
586 }
587
588 if style.text_wrap.link(entity, matched_rules) {
589 should_redraw = true;
590 should_relayout = true;
591 should_reflow = true;
592 }
593
594 if style.text_align.link(entity, matched_rules) {
595 should_redraw = true;
596 should_reflow = true;
597 }
598
599 if style.text_overflow.link(entity, matched_rules) {
600 should_redraw = true;
601 should_reflow = true;
602 }
603
604 if style.line_clamp.link(entity, matched_rules) {
605 should_redraw = true;
606 should_reflow = true;
607 }
608
609 if style.selection_color.link(entity, matched_rules) {
610 should_redraw = true;
611 }
612
613 if style.caret_color.link(entity, matched_rules) {
614 should_redraw = true;
615 }
616
617 if style.text_decoration_line.link(entity, matched_rules) {
618 should_redraw = true;
619 should_reflow = true;
620 }
621
622 if style.text_stroke_width.link(entity, matched_rules) {
623 should_redraw = true;
624 should_reflow = true;
625 }
626
627 if style.text_stroke_style.link(entity, matched_rules) {
628 should_redraw = true;
629 should_reflow = true;
630 }
631
632 if style.underline_style.link(entity, matched_rules) {
633 should_redraw = true;
634 should_reflow = true;
635 }
636
637 if style.underline_color.link(entity, matched_rules) {
638 should_redraw = true;
639 should_reflow = true;
640 }
641
642 if style.overline_style.link(entity, matched_rules) {
643 should_redraw = true;
644 should_reflow = true;
645 }
646
647 if style.overline_color.link(entity, matched_rules) {
648 should_redraw = true;
649 should_reflow = true;
650 }
651
652 if style.strikethrough_style.link(entity, matched_rules) {
653 should_redraw = true;
654 should_reflow = true;
655 }
656
657 if style.strikethrough_color.link(entity, matched_rules) {
658 should_redraw = true;
659 should_reflow = true;
660 }
661
662 if style.shadow.link(entity, matched_rules) {
664 should_redraw = true;
665 }
666
667 if style.padding_left.link(entity, matched_rules) {
668 should_relayout = true;
669 should_redraw = true;
670 }
671
672 if style.padding_right.link(entity, matched_rules) {
673 should_relayout = true;
674 should_redraw = true;
675 }
676
677 if style.padding_top.link(entity, matched_rules) {
678 should_relayout = true;
679 should_redraw = true;
680 }
681
682 if style.padding_bottom.link(entity, matched_rules) {
683 should_relayout = true;
684 should_redraw = true;
685 }
686
687 if style.vertical_gap.link(entity, matched_rules) {
688 should_relayout = true;
689 should_redraw = true;
690 }
691
692 if style.horizontal_gap.link(entity, matched_rules) {
693 should_relayout = true;
694 should_redraw = true;
695 }
696
697 if style.cursor.link(entity, matched_rules) {
698 should_redraw = true;
699 }
700
701 if style.pointer_events.link(entity, matched_rules) {
702 should_redraw = true;
703 }
704
705 if style.transform.link(entity, matched_rules) {
707 should_redraw = true;
708 }
709
710 if style.transform_origin.link(entity, matched_rules) {
711 should_redraw = true;
712 }
713
714 if style.translate.link(entity, matched_rules) {
715 should_redraw = true;
716 }
717
718 if style.rotate.link(entity, matched_rules) {
719 should_redraw = true;
720 }
721
722 if style.scale.link(entity, matched_rules) {
723 should_redraw = true;
724 }
725
726 if style.fill.link(entity, matched_rules) {
727 should_redraw = true;
728 }
729
730 if should_relayout {
732 style.system_flags.set(SystemFlags::RELAYOUT, true);
733 }
734
735 if should_redraw {
736 redraw_entities.push(entity);
737 }
738
739 if should_reflow {
740 let iter = LayoutParentIterator::new(tree, entity);
741 for parent in iter {
742 if style.display.get(parent).copied().unwrap_or_default() != Display::None {
743 style.needs_text_update(parent);
744 break;
745 }
746 }
747 }
748}
749
750pub(crate) fn compute_matched_rules(
752 entity: Entity,
753 store: &Style,
754 tree: &Tree<Entity>,
755 bloom: &BloomFilter,
756) -> Vec<(Rule, u32)> {
757 let mut matched_rules = Vec::with_capacity(16);
758
759 let mut cache = SelectorCaches::default();
760 let mut context = MatchingContext::new(
761 MatchingMode::Normal,
762 Some(bloom),
763 &mut cache,
764 QuirksMode::NoQuirks,
765 NeedsSelectorFlags::Yes,
766 MatchingForInvalidation::No,
767 );
768
769 let node = Node { entity, store, tree };
770
771 for (rule_id, rule) in store.rules.iter() {
772 let matches = matches_selector(&rule.selector, 0, Some(&rule.hashes), &node, &mut context);
773
774 if matches {
775 matched_rules.push((*rule_id, rule.selector.specificity()));
776 }
777 }
778
779 matched_rules.sort_by_key(|(_, s)| *s);
780 matched_rules.reverse();
781 matched_rules
782}
783
784fn has_same_selector(style: &Style, entity1: Entity, entity2: Entity) -> bool {
785 if let Some(element1) = style.element.get(entity1) {
786 if let Some(element2) = style.element.get(entity2) {
787 if element1 != element2 {
788 return false;
789 };
790 }
791 }
792
793 let id1 = if let Some(id) = style.ids.get(entity1) { id } else { "" };
794 let id2 = if let Some(id) = style.ids.get(entity2) { id } else { "" };
795
796 if id1 != id2 {
797 return false;
798 }
799
800 if let Some(classes1) = style.classes.get(entity1) {
801 if let Some(classes2) = style.classes.get(entity2) {
802 if !classes2.is_subset(classes1) || !classes1.is_subset(classes2) {
803 return false;
804 }
805 }
806 }
807
808 if let Some(psudeo_class_flag1) = style.pseudo_classes.get(entity1) {
809 if let Some(psudeo_class_flag2) = style.pseudo_classes.get(entity2) {
810 if psudeo_class_flag2.bits() != psudeo_class_flag1.bits() {
811 return false;
812 }
813 }
814 }
815
816 true
817}
818
819fn has_nth_child_rule(style: &Style, rules: &[(Rule, u32)]) -> bool {
820 for (rule, _) in rules {
821 let Some(style_rule) = style.rules.get(rule) else { continue };
822 for component in style_rule.selector.iter() {
823 let Component::Nth(n) = component else { continue };
824 if let NthType::Child | NthType::LastChild | NthType::OnlyChild = n.ty {
825 return true;
826 }
827 }
828 }
829 false
830}
831
832pub(crate) fn compute_element_hash(
833 entity: Entity,
834 tree: &Tree<Entity>,
835 style: &Style,
836 bloom: &mut BloomFilter,
837) {
838 let parent_iter = LayoutParentIterator::new(tree, entity);
839
840 for ancestor in parent_iter {
841 if let Some(element) = style.element.get(ancestor) {
842 bloom.insert_hash(*element);
843 }
844
845 if let Some(id) = style.ids.get(ancestor) {
846 bloom.insert_hash(fxhash::hash32(id));
847 }
848
849 if let Some(classes) = style.classes.get(ancestor) {
850 for class in classes {
851 bloom.insert_hash(fxhash::hash32(class));
852 }
853 }
854 }
855}
856
857struct MatchedRulesCache {
858 pub entity: Entity,
859 pub rules: Vec<(Rule, u32)>,
860}
861
862struct MatchedRules {
863 #[cfg(feature = "rayon")]
864 cache: ReadOnlyView<Entity, Vec<MatchedRulesCache>>,
865 #[cfg(not(feature = "rayon"))]
866 cache: HashMap<Entity, Vec<MatchedRulesCache>>,
867 rules: HashMap<Entity, (Entity, usize)>,
869}
870
871impl MatchedRules {
872 #[cfg(not(feature = "rayon"))]
873 fn build(entities: &[Entity], style: &Style, tree: &Tree<Entity>) -> Self {
874 let filter = &mut BloomFilter::default();
875
876 let mut cache = HashMap::new();
877 let rules = entities
878 .iter()
879 .filter_map(|entity| Self::build_inner(*entity, style, tree, filter, &mut cache))
880 .collect();
881
882 Self { rules, cache }
883 }
884
885 #[cfg(feature = "rayon")]
886 fn build_parallel(entities: &[Entity], style: &Style, tree: &Tree<Entity>) -> Self {
887 let num_threads = std::thread::available_parallelism().map_or(1, |n| n.get());
888
889 let min_len = entities.len().div_ceil(num_threads);
893
894 let cache = DashMap::new();
895 let rules = entities
896 .par_iter()
897 .with_min_len(min_len)
898 .map_init(BloomFilter::default, |filter, entity| {
899 Self::build_inner(*entity, style, tree, filter, &cache)
900 })
901 .flatten_iter()
902 .collect();
903
904 Self { rules, cache: cache.into_read_only() }
905 }
906
907 fn build_inner(
908 entity: Entity,
909 style: &Style,
910 tree: &Tree<Entity>,
911 filter: &mut BloomFilter,
912 #[cfg(feature = "rayon")] rule_cache: &DashMap<Entity, Vec<MatchedRulesCache>>,
913 #[cfg(not(feature = "rayon"))] rule_cache: &mut HashMap<Entity, Vec<MatchedRulesCache>>,
914 ) -> Option<(Entity, (Entity, usize))> {
915 compute_element_hash(entity, tree, style, filter);
916
917 let parent = tree.get_layout_parent(entity).unwrap_or(Entity::root());
918
919 let mut matched_index = None;
920
921 if !tree.is_first_child(entity) && !tree.is_last_child(entity) {
922 if let Some(cache) = rule_cache.get(&parent) {
923 matched_index = cache.iter().position(|entry| {
924 has_same_selector(style, entry.entity, entity)
925 && !has_nth_child_rule(style, &entry.rules)
926 });
927 }
928 }
929
930 if matched_index.is_none() {
931 let rules = compute_matched_rules(entity, style, tree, filter);
932 if !rules.is_empty() {
933 #[cfg(feature = "rayon")]
934 {
935 let mut entry = rule_cache.entry(parent).or_default();
936 entry.value_mut().push(MatchedRulesCache { entity, rules });
937 matched_index = Some(entry.value().len() - 1);
938 }
939 #[cfg(not(feature = "rayon"))]
940 {
941 let entry = rule_cache.entry(parent).or_default();
942 entry.push(MatchedRulesCache { entity, rules });
943 matched_index = Some(entry.len() - 1);
944 }
945 }
946 }
947
948 matched_index.map(|i| (entity, (parent, i)))
949 }
950
951 fn get(&self, entity: &Entity) -> Option<&[(Rule, u32)]> {
952 let (parent, i) = self.rules.get(entity)?;
953 let parent_cache = self.cache.get(parent)?;
954 let entry = parent_cache.get(*i)?;
955 if entry.rules.is_empty() {
956 None
957 } else {
958 Some(&entry.rules)
959 }
960 }
961}
962
963pub(crate) fn style_system(cx: &mut Context) {
965 let mut redraw_entities = Vec::new();
966
967 inline_inheritance_system(cx, &mut redraw_entities);
968
969 if cx.style.restyle.is_empty() {
970 return;
971 }
972
973 let entities = TreeBreadthIterator::full(&cx.tree)
974 .filter(|e| cx.style.restyle.contains(*e))
975 .collect::<Vec<_>>();
976
977 let matched_rules = {
978 #[cfg(feature = "rayon")]
979 {
980 MatchedRules::build_parallel(&entities, &cx.style, &cx.tree)
981 }
982 #[cfg(not(feature = "rayon"))]
983 {
984 MatchedRules::build(&entities, &cx.style, &cx.tree)
985 }
986 };
987
988 for entity in entities {
990 if let Some(matched_rules) = matched_rules.get(&entity) {
991 link_style_data(
992 &mut cx.style,
993 &mut cx.cache,
994 &cx.tree,
995 entity,
996 &mut redraw_entities,
997 matched_rules,
998 );
999 }
1000 }
1001 cx.style.restyle.clear();
1002
1003 shared_inheritance_system(cx, &mut redraw_entities);
1004
1005 for entity in redraw_entities {
1006 cx.needs_redraw(entity);
1007 }
1008}