1use crate::context::StackLimitChecker;
9use crate::dom::{TElement, TNode, TShadowRoot};
10use crate::invalidation::element::invalidation_map::{
11 Dependency, DependencyInvalidationKind, NormalDependencyInvalidationKind,
12 RelativeDependencyInvalidationKind,
13};
14use selectors::matching::matches_compound_selector_from;
15use selectors::matching::{CompoundSelectorMatchingResult, MatchingContext};
16use selectors::parser::{Combinator, Component};
17use selectors::OpaqueElement;
18use smallvec::SmallVec;
19use std::fmt;
20use std::fmt::Write;
21
22struct SiblingInfo<E>
23where
24 E: TElement,
25{
26 affected: E,
27 prev_sibling: Option<E>,
28 next_sibling: Option<E>,
29}
30
31pub struct SiblingTraversalMap<E>
41where
42 E: TElement,
43{
44 info: Option<SiblingInfo<E>>,
45}
46
47impl<E> Default for SiblingTraversalMap<E>
48where
49 E: TElement,
50{
51 fn default() -> Self {
52 Self { info: None }
53 }
54}
55
56impl<E> SiblingTraversalMap<E>
57where
58 E: TElement,
59{
60 pub fn new(affected: E, prev_sibling: Option<E>, next_sibling: Option<E>) -> Self {
62 Self {
63 info: Some(SiblingInfo {
64 affected,
65 prev_sibling,
66 next_sibling,
67 }),
68 }
69 }
70
71 pub fn next_sibling_for(&self, element: &E) -> Option<E> {
73 if let Some(ref info) = self.info {
74 if *element == info.affected {
75 return info.next_sibling;
76 }
77 }
78 element.next_sibling_element()
79 }
80
81 pub fn prev_sibling_for(&self, element: &E) -> Option<E> {
83 if let Some(ref info) = self.info {
84 if *element == info.affected {
85 return info.prev_sibling;
86 }
87 }
88 element.prev_sibling_element()
89 }
90}
91
92pub trait InvalidationProcessor<'a, 'b, E>
94where
95 E: TElement,
96{
97 fn invalidates_on_pseudo_element(&self) -> bool {
101 false
102 }
103
104 fn light_tree_only(&self) -> bool {
108 false
109 }
110
111 fn check_outer_dependency(&mut self, dependency: &Dependency, element: E, scope: Option<OpaqueElement>) -> bool;
134
135 fn matching_context(&mut self) -> &mut MatchingContext<'b, E::Impl>;
137
138 fn sibling_traversal_map(&self) -> &SiblingTraversalMap<E>;
140
141 fn collect_invalidations(
145 &mut self,
146 element: E,
147 self_invalidations: &mut InvalidationVector<'a>,
148 descendant_invalidations: &mut DescendantInvalidationLists<'a>,
149 sibling_invalidations: &mut InvalidationVector<'a>,
150 ) -> bool;
151
152 fn should_process_descendants(&mut self, element: E) -> bool;
155
156 fn recursion_limit_exceeded(&mut self, element: E);
159
160 fn invalidated_self(&mut self, element: E);
162
163 fn invalidated_sibling(&mut self, sibling: E, of: E);
166
167 fn invalidated_descendants(&mut self, element: E, child: E);
169
170 fn found_relative_selector_invalidation(
174 &mut self,
175 _element: E,
176 _kind: RelativeDependencyInvalidationKind,
177 _relative_dependency: &'a Dependency,
178 ) {
179 debug_assert!(false, "Reached relative selector dependency");
180 }
181}
182
183#[derive(Debug, Default)]
185pub struct DescendantInvalidationLists<'a> {
186 pub dom_descendants: InvalidationVector<'a>,
191 pub slotted_descendants: InvalidationVector<'a>,
193 pub parts: InvalidationVector<'a>,
195}
196
197impl<'a> DescendantInvalidationLists<'a> {
198 fn is_empty(&self) -> bool {
199 self.dom_descendants.is_empty()
200 && self.slotted_descendants.is_empty()
201 && self.parts.is_empty()
202 }
203}
204
205pub struct TreeStyleInvalidator<'a, 'b, 'c, E, P: 'a>
208where
209 'b: 'a,
210 E: TElement,
211 P: InvalidationProcessor<'b, 'c, E>,
212{
213 element: E,
214 stack_limit_checker: Option<&'a StackLimitChecker>,
215 processor: &'a mut P,
216 _marker: std::marker::PhantomData<(&'b (), &'c ())>,
217}
218
219pub type InvalidationVector<'a> = SmallVec<[Invalidation<'a>; 10]>;
221
222#[derive(Clone, Copy, Debug, Eq, PartialEq)]
224enum DescendantInvalidationKind {
225 Dom,
227 Slotted,
229 Part,
231}
232
233#[derive(Clone, Copy, Debug, Eq, PartialEq)]
238enum InvalidationKind {
239 Descendant(DescendantInvalidationKind),
240 Sibling,
241}
242
243#[derive(Clone)]
246pub struct Invalidation<'a> {
247 dependency: &'a Dependency,
252 host: Option<OpaqueElement>,
258 scope: Option<OpaqueElement>,
260 offset: usize,
267 matched_by_any_previous: bool,
274}
275
276impl<'a> Invalidation<'a> {
277 pub fn new(dependency: &'a Dependency, host: Option<OpaqueElement>, scope: Option<OpaqueElement>) -> Self {
279 debug_assert!(
280 dependency.selector_offset == dependency.selector.len() + 1 ||
281 dependency.invalidation_kind() !=
282 DependencyInvalidationKind::Normal(NormalDependencyInvalidationKind::Element),
283 "No point to this, if the dependency matched the element we should just invalidate it"
284 );
285 Self {
286 dependency,
287 host,
288 scope,
289 offset: dependency.selector.len() + 1 - dependency.selector_offset,
291 matched_by_any_previous: false,
292 }
293 }
294
295 fn effective_for_next(&self) -> bool {
298 if self.offset == 0 {
299 return true;
300 }
301
302 match self
307 .dependency
308 .selector
309 .combinator_at_parse_order(self.offset - 1)
310 {
311 Combinator::Descendant | Combinator::LaterSibling | Combinator::PseudoElement => true,
312 Combinator::Part
313 | Combinator::SlotAssignment
314 | Combinator::NextSibling
315 | Combinator::Child => false,
316 }
317 }
318
319 fn kind(&self) -> InvalidationKind {
320 if self.offset == 0 {
321 return InvalidationKind::Descendant(DescendantInvalidationKind::Dom);
322 }
323
324 match self
325 .dependency
326 .selector
327 .combinator_at_parse_order(self.offset - 1)
328 {
329 Combinator::Child | Combinator::Descendant | Combinator::PseudoElement => {
330 InvalidationKind::Descendant(DescendantInvalidationKind::Dom)
331 },
332 Combinator::Part => InvalidationKind::Descendant(DescendantInvalidationKind::Part),
333 Combinator::SlotAssignment => {
334 InvalidationKind::Descendant(DescendantInvalidationKind::Slotted)
335 },
336 Combinator::NextSibling | Combinator::LaterSibling => InvalidationKind::Sibling,
337 }
338 }
339}
340
341impl<'a> fmt::Debug for Invalidation<'a> {
342 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
343 use cssparser::ToCss;
344
345 f.write_str("Invalidation(")?;
346 for component in self
347 .dependency
348 .selector
349 .iter_raw_parse_order_from(self.offset)
350 {
351 if matches!(*component, Component::Combinator(..)) {
352 break;
353 }
354 component.to_css(f)?;
355 }
356 f.write_char(')')
357 }
358}
359
360struct SingleInvalidationResult {
362 invalidated_self: bool,
364 matched: bool,
367}
368
369pub struct InvalidationResult {
371 invalidated_self: bool,
373 invalidated_descendants: bool,
375 invalidated_siblings: bool,
377}
378
379impl InvalidationResult {
380 pub fn empty() -> Self {
382 Self {
383 invalidated_self: false,
384 invalidated_descendants: false,
385 invalidated_siblings: false,
386 }
387 }
388
389 pub fn has_invalidated_self(&self) -> bool {
391 self.invalidated_self
392 }
393
394 pub fn has_invalidated_descendants(&self) -> bool {
396 self.invalidated_descendants
397 }
398
399 pub fn has_invalidated_siblings(&self) -> bool {
401 self.invalidated_siblings
402 }
403}
404
405impl<'a, 'b, 'c, E, P: 'a> TreeStyleInvalidator<'a, 'b, 'c, E, P>
406where
407 'b: 'a,
408 E: TElement,
409 P: InvalidationProcessor<'b, 'c, E>,
410{
411 pub fn new(
413 element: E,
414 stack_limit_checker: Option<&'a StackLimitChecker>,
415 processor: &'a mut P,
416 ) -> Self {
417 Self {
418 element,
419 stack_limit_checker,
420 processor,
421 _marker: std::marker::PhantomData,
422 }
423 }
424
425 pub fn invalidate(mut self) -> InvalidationResult {
427 debug!("StyleTreeInvalidator::invalidate({:?})", self.element);
428
429 let mut self_invalidations = InvalidationVector::new();
430 let mut descendant_invalidations = DescendantInvalidationLists::default();
431 let mut sibling_invalidations = InvalidationVector::new();
432
433 let mut invalidated_self = self.processor.collect_invalidations(
434 self.element,
435 &mut self_invalidations,
436 &mut descendant_invalidations,
437 &mut sibling_invalidations,
438 );
439
440 debug!("Collected invalidations (self: {}): ", invalidated_self);
441 debug!(
442 " > self: {}, {:?}",
443 self_invalidations.len(),
444 self_invalidations
445 );
446 debug!(" > descendants: {:?}", descendant_invalidations);
447 debug!(
448 " > siblings: {}, {:?}",
449 sibling_invalidations.len(),
450 sibling_invalidations
451 );
452
453 let invalidated_self_from_collection = invalidated_self;
454
455 invalidated_self |= self.process_descendant_invalidations(
456 &self_invalidations,
457 &mut descendant_invalidations,
458 &mut sibling_invalidations,
459 DescendantInvalidationKind::Dom,
460 );
461
462 if invalidated_self && !invalidated_self_from_collection {
463 self.processor.invalidated_self(self.element);
464 }
465
466 let invalidated_descendants = self.invalidate_descendants(&descendant_invalidations);
467 let invalidated_siblings = self.invalidate_siblings(&mut sibling_invalidations);
468
469 InvalidationResult {
470 invalidated_self,
471 invalidated_descendants,
472 invalidated_siblings,
473 }
474 }
475
476 fn invalidate_siblings(&mut self, sibling_invalidations: &mut InvalidationVector<'b>) -> bool {
482 if sibling_invalidations.is_empty() {
483 return false;
484 }
485
486 let mut current = self
487 .processor
488 .sibling_traversal_map()
489 .next_sibling_for(&self.element);
490 let mut any_invalidated = false;
491
492 while let Some(sibling) = current {
493 let mut sibling_invalidator =
494 TreeStyleInvalidator::new(sibling, self.stack_limit_checker, self.processor);
495
496 let mut invalidations_for_descendants = DescendantInvalidationLists::default();
497 let invalidated_sibling = sibling_invalidator.process_sibling_invalidations(
498 &mut invalidations_for_descendants,
499 sibling_invalidations,
500 );
501
502 if invalidated_sibling {
503 sibling_invalidator
504 .processor
505 .invalidated_sibling(sibling, self.element);
506 }
507
508 any_invalidated |= invalidated_sibling;
509
510 any_invalidated |=
511 sibling_invalidator.invalidate_descendants(&invalidations_for_descendants);
512
513 if sibling_invalidations.is_empty() {
514 break;
515 }
516
517 current = self
518 .processor
519 .sibling_traversal_map()
520 .next_sibling_for(&sibling);
521 }
522
523 any_invalidated
524 }
525
526 fn invalidate_pseudo_element_or_nac(
527 &mut self,
528 child: E,
529 invalidations: &[Invalidation<'b>],
530 ) -> bool {
531 let mut sibling_invalidations = InvalidationVector::new();
532
533 let result = self.invalidate_child(
534 child,
535 invalidations,
536 &mut sibling_invalidations,
537 DescendantInvalidationKind::Dom,
538 );
539
540 result
548 }
549
550 fn invalidate_child(
553 &mut self,
554 child: E,
555 invalidations: &[Invalidation<'b>],
556 sibling_invalidations: &mut InvalidationVector<'b>,
557 descendant_invalidation_kind: DescendantInvalidationKind,
558 ) -> bool {
559 let mut invalidations_for_descendants = DescendantInvalidationLists::default();
560
561 let mut invalidated_child = false;
562 let invalidated_descendants = {
563 let mut child_invalidator =
564 TreeStyleInvalidator::new(child, self.stack_limit_checker, self.processor);
565
566 invalidated_child |= child_invalidator.process_sibling_invalidations(
567 &mut invalidations_for_descendants,
568 sibling_invalidations,
569 );
570
571 invalidated_child |= child_invalidator.process_descendant_invalidations(
572 invalidations,
573 &mut invalidations_for_descendants,
574 sibling_invalidations,
575 descendant_invalidation_kind,
576 );
577
578 if invalidated_child {
579 child_invalidator.processor.invalidated_self(child);
580 }
581
582 child_invalidator.invalidate_descendants(&invalidations_for_descendants)
583 };
584
585 if invalidated_child || invalidated_descendants {
591 self.processor.invalidated_descendants(self.element, child);
592 }
593
594 invalidated_child || invalidated_descendants
595 }
596
597 fn invalidate_nac(&mut self, invalidations: &[Invalidation<'b>]) -> bool {
598 let mut any_nac_root = false;
599
600 let element = self.element;
601 element.each_anonymous_content_child(|nac| {
602 any_nac_root |= self.invalidate_pseudo_element_or_nac(nac, invalidations);
603 });
604
605 any_nac_root
606 }
607
608 fn invalidate_dom_descendants_of(
611 &mut self,
612 parent: E::ConcreteNode,
613 invalidations: &[Invalidation<'b>],
614 ) -> bool {
615 let mut any_descendant = false;
616
617 let mut sibling_invalidations = InvalidationVector::new();
618 for child in parent.dom_children() {
619 let child = match child.as_element() {
620 Some(e) => e,
621 None => continue,
622 };
623
624 any_descendant |= self.invalidate_child(
625 child,
626 invalidations,
627 &mut sibling_invalidations,
628 DescendantInvalidationKind::Dom,
629 );
630 }
631
632 any_descendant
633 }
634
635 fn invalidate_parts_in_shadow_tree(
636 &mut self,
637 shadow: <E::ConcreteNode as TNode>::ConcreteShadowRoot,
638 invalidations: &[Invalidation<'b>],
639 ) -> bool {
640 debug_assert!(!invalidations.is_empty());
641
642 let mut any = false;
643 let mut sibling_invalidations = InvalidationVector::new();
644
645 for node in shadow.as_node().dom_descendants() {
646 let element = match node.as_element() {
647 Some(e) => e,
648 None => continue,
649 };
650
651 if element.has_part_attr() {
652 any |= self.invalidate_child(
653 element,
654 invalidations,
655 &mut sibling_invalidations,
656 DescendantInvalidationKind::Part,
657 );
658 debug_assert!(
659 sibling_invalidations.is_empty(),
660 "::part() shouldn't have sibling combinators to the right, \
661 this makes no sense! {:?}",
662 sibling_invalidations
663 );
664 }
665
666 if let Some(shadow) = element.shadow_root() {
667 if element.exports_any_part() {
668 any |= self.invalidate_parts_in_shadow_tree(shadow, invalidations)
669 }
670 }
671 }
672
673 any
674 }
675
676 fn invalidate_parts(&mut self, invalidations: &[Invalidation<'b>]) -> bool {
677 if invalidations.is_empty() {
678 return false;
679 }
680
681 let shadow = match self.element.shadow_root() {
682 Some(s) => s,
683 None => return false,
684 };
685
686 self.invalidate_parts_in_shadow_tree(shadow, invalidations)
687 }
688
689 fn invalidate_slotted_elements(&mut self, invalidations: &[Invalidation<'b>]) -> bool {
690 if invalidations.is_empty() {
691 return false;
692 }
693
694 let slot = self.element;
695 self.invalidate_slotted_elements_in_slot(slot, invalidations)
696 }
697
698 fn invalidate_slotted_elements_in_slot(
699 &mut self,
700 slot: E,
701 invalidations: &[Invalidation<'b>],
702 ) -> bool {
703 let mut any = false;
704
705 let mut sibling_invalidations = InvalidationVector::new();
706 for node in slot.slotted_nodes() {
707 let element = match node.as_element() {
708 Some(e) => e,
709 None => continue,
710 };
711
712 if element.is_html_slot_element() {
713 any |= self.invalidate_slotted_elements_in_slot(element, invalidations);
714 } else {
715 any |= self.invalidate_child(
716 element,
717 invalidations,
718 &mut sibling_invalidations,
719 DescendantInvalidationKind::Slotted,
720 );
721 }
722
723 debug_assert!(
724 sibling_invalidations.is_empty(),
725 "::slotted() shouldn't have sibling combinators to the right, \
726 this makes no sense! {:?}",
727 sibling_invalidations
728 );
729 }
730
731 any
732 }
733
734 fn invalidate_non_slotted_descendants(&mut self, invalidations: &[Invalidation<'b>]) -> bool {
735 if invalidations.is_empty() {
736 return false;
737 }
738
739 if self.processor.light_tree_only() {
740 let node = self.element.as_node();
741 return self.invalidate_dom_descendants_of(node, invalidations);
742 }
743
744 let mut any_descendant = false;
745
746 if let Some(root) = self.element.shadow_root() {
755 any_descendant |= self.invalidate_dom_descendants_of(root.as_node(), invalidations);
756 }
757
758 any_descendant |= self.invalidate_dom_descendants_of(self.element.as_node(), invalidations);
759
760 any_descendant |= self.invalidate_nac(invalidations);
761
762 any_descendant
763 }
764
765 fn invalidate_descendants(&mut self, invalidations: &DescendantInvalidationLists<'b>) -> bool {
768 if invalidations.is_empty() {
769 return false;
770 }
771
772 debug!(
773 "StyleTreeInvalidator::invalidate_descendants({:?})",
774 self.element
775 );
776 debug!(" > {:?}", invalidations);
777
778 let should_process = self.processor.should_process_descendants(self.element);
779
780 if !should_process {
781 return false;
782 }
783
784 if let Some(checker) = self.stack_limit_checker {
785 if checker.limit_exceeded() {
786 self.processor.recursion_limit_exceeded(self.element);
787 return true;
788 }
789 }
790
791 let mut any_descendant = false;
792
793 any_descendant |= self.invalidate_non_slotted_descendants(&invalidations.dom_descendants);
794 any_descendant |= self.invalidate_slotted_elements(&invalidations.slotted_descendants);
795 any_descendant |= self.invalidate_parts(&invalidations.parts);
796
797 any_descendant
798 }
799
800 fn process_sibling_invalidations(
812 &mut self,
813 descendant_invalidations: &mut DescendantInvalidationLists<'b>,
814 sibling_invalidations: &mut InvalidationVector<'b>,
815 ) -> bool {
816 let mut i = 0;
817 let mut new_sibling_invalidations = InvalidationVector::new();
818 let mut invalidated_self = false;
819
820 while i < sibling_invalidations.len() {
821 let result = self.process_invalidation(
822 &sibling_invalidations[i],
823 descendant_invalidations,
824 &mut new_sibling_invalidations,
825 InvalidationKind::Sibling,
826 );
827
828 invalidated_self |= result.invalidated_self;
829 sibling_invalidations[i].matched_by_any_previous |= result.matched;
830 if sibling_invalidations[i].effective_for_next() {
831 i += 1;
832 } else {
833 sibling_invalidations.remove(i);
834 }
835 }
836
837 sibling_invalidations.extend(new_sibling_invalidations.drain(..));
838 invalidated_self
839 }
840
841 fn process_descendant_invalidations(
847 &mut self,
848 invalidations: &[Invalidation<'b>],
849 descendant_invalidations: &mut DescendantInvalidationLists<'b>,
850 sibling_invalidations: &mut InvalidationVector<'b>,
851 descendant_invalidation_kind: DescendantInvalidationKind,
852 ) -> bool {
853 let mut invalidated = false;
854
855 for invalidation in invalidations {
856 let result = self.process_invalidation(
857 invalidation,
858 descendant_invalidations,
859 sibling_invalidations,
860 InvalidationKind::Descendant(descendant_invalidation_kind),
861 );
862
863 invalidated |= result.invalidated_self;
864 if invalidation.effective_for_next() {
865 let mut invalidation = invalidation.clone();
866 invalidation.matched_by_any_previous |= result.matched;
867 debug_assert_eq!(
868 descendant_invalidation_kind,
869 DescendantInvalidationKind::Dom,
870 "Slotted or part invalidations don't propagate."
871 );
872 descendant_invalidations.dom_descendants.push(invalidation);
873 }
874 }
875
876 invalidated
877 }
878
879 fn process_invalidation(
886 &mut self,
887 invalidation: &Invalidation<'b>,
888 descendant_invalidations: &mut DescendantInvalidationLists<'b>,
889 sibling_invalidations: &mut InvalidationVector<'b>,
890 invalidation_kind: InvalidationKind,
891 ) -> SingleInvalidationResult {
892 debug!(
893 "TreeStyleInvalidator::process_invalidation({:?}, {:?}, {:?})",
894 self.element, invalidation, invalidation_kind
895 );
896
897 let matching_result = {
898 let context = self.processor.matching_context();
899 context.current_host = invalidation.host;
900
901 context.nest_for_scope_condition(invalidation.scope,|ctx| {
902 matches_compound_selector_from(
903 &invalidation.dependency.selector,
904 invalidation.offset,
905 ctx,
906 &self.element,
907 )
908 })
909 };
910
911 let next_invalidation = match matching_result {
912 CompoundSelectorMatchingResult::NotMatched => {
913 return SingleInvalidationResult {
914 invalidated_self: false,
915 matched: false,
916 }
917 },
918 CompoundSelectorMatchingResult::FullyMatched => {
919 debug!(" > Invalidation matched completely");
920 let mut cur_dependency = invalidation.dependency;
923 loop {
924 let mut scope = invalidation.scope;
925 cur_dependency = match cur_dependency.next {
926 None => {
927 return SingleInvalidationResult {
928 invalidated_self: true,
929 matched: true,
930 }
931 },
932 Some(ref deps) => {
933 let n = &deps.as_ref().slice()[0];
934 let invalidation_kind = n.invalidation_kind();
935 match invalidation_kind {
936 DependencyInvalidationKind::FullSelector => unreachable!(),
937 DependencyInvalidationKind::Normal(_) => n,
938 DependencyInvalidationKind::Scope(_) => {
940 scope = Some(self.element.opaque());
941 n
942 },
943 DependencyInvalidationKind::Relative(kind) => {
944 self.processor.found_relative_selector_invalidation(
945 self.element,
946 kind,
947 n,
948 );
949 return SingleInvalidationResult {
950 invalidated_self: false,
951 matched: true,
952 };
953 },
954 }
955 },
956 };
957
958 debug!(" > Checking outer dependency {:?}", cur_dependency);
959
960 if !self
964 .processor
965 .check_outer_dependency(cur_dependency, self.element, scope)
966 {
967 return SingleInvalidationResult {
968 invalidated_self: false,
969 matched: false,
970 };
971 }
972
973 let invalidation_kind = cur_dependency.invalidation_kind();
974 if matches!(invalidation_kind,
975 DependencyInvalidationKind::Normal(NormalDependencyInvalidationKind::Element))
976 || (
977 matches!(invalidation_kind,
978 DependencyInvalidationKind::Scope(_))
979 && cur_dependency.selector_offset == 0
980 )
981 {
982 continue;
983 }
984
985 debug!(" > Generating invalidation");
986 break Invalidation::new(cur_dependency, invalidation.host, scope);
987 }
988 },
989 CompoundSelectorMatchingResult::Matched {
990 next_combinator_offset,
991 } => Invalidation {
992 dependency: invalidation.dependency,
993 host: invalidation.host,
994 scope: Some(self.element.opaque()),
995 offset: next_combinator_offset + 1,
996 matched_by_any_previous: false,
997 },
998 };
999
1000 debug_assert_ne!(
1001 next_invalidation.offset, 0,
1002 "Rightmost selectors shouldn't generate more invalidations",
1003 );
1004
1005 let mut invalidated_self = false;
1006 let next_combinator = next_invalidation
1007 .dependency
1008 .selector
1009 .combinator_at_parse_order(next_invalidation.offset - 1);
1010
1011 if matches!(next_combinator, Combinator::PseudoElement)
1012 && self.processor.invalidates_on_pseudo_element()
1013 {
1014 invalidated_self = true;
1037 }
1038
1039 debug!(
1040 " > Invalidation matched, next: {:?}, ({:?})",
1041 next_invalidation, next_combinator
1042 );
1043
1044 let next_invalidation_kind = next_invalidation.kind();
1045
1046 let can_skip_pushing = next_invalidation_kind == invalidation_kind
1106 && invalidation.matched_by_any_previous
1107 && next_invalidation.effective_for_next();
1108
1109 if can_skip_pushing {
1110 debug!(
1111 " > Can avoid push, since the invalidation had \
1112 already been matched before"
1113 );
1114 } else {
1115 match next_invalidation_kind {
1116 InvalidationKind::Descendant(DescendantInvalidationKind::Dom) => {
1117 descendant_invalidations
1118 .dom_descendants
1119 .push(next_invalidation);
1120 },
1121 InvalidationKind::Descendant(DescendantInvalidationKind::Part) => {
1122 descendant_invalidations.parts.push(next_invalidation);
1123 },
1124 InvalidationKind::Descendant(DescendantInvalidationKind::Slotted) => {
1125 descendant_invalidations
1126 .slotted_descendants
1127 .push(next_invalidation);
1128 },
1129 InvalidationKind::Sibling => {
1130 sibling_invalidations.push(next_invalidation);
1131 },
1132 }
1133 }
1134
1135 SingleInvalidationResult {
1136 invalidated_self,
1137 matched: true,
1138 }
1139 }
1140}