Skip to main content

style/invalidation/element/
relative_selector.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! Invalidation of element styles relative selectors.
6
7use crate::data::ElementData;
8use crate::dom::{TElement, TNode};
9#[cfg(feature = "gecko")]
10use crate::gecko_bindings::structs::ServoElementSnapshotTable;
11use crate::invalidation::element::element_wrapper::ElementWrapper;
12use crate::invalidation::element::invalidation_map::{
13    AdditionalRelativeSelectorInvalidationMap, Dependency, DependencyInvalidationKind,
14    InvalidationMap, NormalDependencyInvalidationKind, RelativeDependencyInvalidationKind,
15    ScopeDependencyInvalidationKind, TSStateForInvalidation,
16};
17use crate::invalidation::element::invalidator::{
18    note_scope_dependency_force_at_subject, DescendantInvalidationLists, Invalidation,
19    InvalidationProcessor, InvalidationResult, InvalidationVector, SiblingTraversalMap,
20    TreeStyleInvalidator,
21};
22use crate::invalidation::element::restyle_hints::RestyleHint;
23use crate::invalidation::element::state_and_attributes::{
24    check_dependency, dependency_may_be_relevant, invalidated_descendants, invalidated_self,
25    invalidated_sibling, push_invalidation, should_process_descendants,
26};
27#[cfg(feature = "servo")]
28use crate::selector_parser::SnapshotMap as ServoElementSnapshotTable;
29use crate::stylist::{CascadeData, Stylist};
30use dom::ElementState;
31use rustc_hash::FxHashMap;
32use selectors::matching::{
33    early_reject_by_local_name, matches_selector, ElementSelectorFlags,
34    IncludeStartingStyle, MatchingContext, MatchingForInvalidation, MatchingMode,
35    NeedsSelectorFlags, QuirksMode, SelectorCaches, VisitedHandlingMode,
36};
37use selectors::parser::SelectorKey;
38use selectors::OpaqueElement;
39use smallvec::{smallvec, SmallVec};
40use std::ops::DerefMut;
41
42/// Kind of DOM mutation this relative selector invalidation is being carried out in.
43#[derive(Clone, Copy)]
44pub enum DomMutationOperation {
45    /// Insertion operation, can cause side effect, but presumed already happened.
46    Insert,
47    /// Append operation, cannot cause side effect.
48    Append,
49    /// Removal operation, can cause side effect, but presumed already happened. Sibling relationships are destroyed.
50    Remove,
51    /// Invalidating for side effect of a DOM operation, for the previous sibling.
52    SideEffectPrevSibling,
53    /// Invalidating for side effect of a DOM operation, for the next sibling.
54    SideEffectNextSibling,
55}
56
57impl DomMutationOperation {
58    fn accept<E: TElement>(&self, d: &Dependency, e: E) -> bool {
59        match self {
60            Self::Insert | Self::Append | Self::Remove => {
61                !e.relative_selector_search_direction().is_empty()
62            },
63            // `:has(+ .a + .b)` with `.anchor + .a + .remove + .b` - `.a` would be present
64            // in the search path.
65            Self::SideEffectPrevSibling => {
66                !e.relative_selector_search_direction().is_empty()
67                    && d.right_combinator_is_next_sibling()
68            },
69            // If an element is being removed and would cause next-sibling match to happen,
70            // e.g. `:has(+ .a)` with `.anchor + .remove + .a`, `.a` isn't yet searched
71            // for relative selector matching.
72            Self::SideEffectNextSibling => d.dependency_is_relative_with_single_next_sibling(),
73        }
74    }
75
76    fn is_side_effect(&self) -> bool {
77        match self {
78            Self::Insert | Self::Append | Self::Remove => false,
79            Self::SideEffectPrevSibling | Self::SideEffectNextSibling => true,
80        }
81    }
82}
83
84/// Context required to try and optimize away relative dependencies.
85struct OptimizationContext<'a, E: TElement> {
86    sibling_traversal_map: &'a SiblingTraversalMap<E>,
87    quirks_mode: QuirksMode,
88    operation: DomMutationOperation,
89}
90
91impl<'a, E: TElement> OptimizationContext<'a, E> {
92    fn can_be_ignored(
93        &self,
94        is_subtree: bool,
95        element: E,
96        host: Option<OpaqueElement>,
97        dependency: &Dependency,
98        leftmost_collapse_offset: usize,
99    ) -> bool {
100        if is_subtree {
101            // Subtree elements don't have unaffected sibling to look at.
102            return false;
103        }
104        debug_assert!(
105            matches!(
106                dependency.invalidation_kind(),
107                DependencyInvalidationKind::Relative(..)
108            ),
109            "Non-relative selector being evaluated for optimization"
110        );
111        // This optimization predecates on the fact that there may be a sibling that can readily
112        // "take over" this element.
113        let sibling = match self.sibling_traversal_map.prev_sibling_for(&element) {
114            None => {
115                if matches!(self.operation, DomMutationOperation::Append) {
116                    return false;
117                }
118                match self.sibling_traversal_map.next_sibling_for(&element) {
119                    Some(s) => s,
120                    None => return false,
121                }
122            },
123            Some(s) => s,
124        };
125        {
126            // Run through the affected compund.
127            let mut iter = dependency.selector.iter_from(dependency.selector_offset);
128            while let Some(c) = iter.next() {
129                if c.has_indexed_selector_in_subject() {
130                    // We do not calculate indices during invalidation as they're wasteful - as a side effect,
131                    // such selectors always return true, breaking this optimization. Note that we only check
132                    // this compound only because the check to skip compares against this element's sibling.
133                    // i.e. Given `:has(:nth-child(2) .foo)`, we'd try to find `.foo`'s sibling, which
134                    // shares `:nth-child` up the selector.
135                    return false;
136                }
137            }
138        }
139        let dependency_is_rightmost = dependency.selector_offset == 0;
140        if !dependency_is_rightmost {
141            let combinator = dependency
142                .selector
143                .combinator_at_match_order(dependency.selector_offset - 1);
144            if combinator.is_ancestor() {
145                // We can safely ignore these, since we're about to traverse the
146                // rest of the affected tree anyway to find the rightmost invalidated element.
147                return true;
148            }
149            if combinator.is_sibling() && matches!(self.operation, DomMutationOperation::Append) {
150                // If we're at the top of the DOM tree being mutated, we can ignore it if the
151                // operation is append - we know we'll cover all the later siblings and their descendants.
152                return true;
153            }
154        }
155
156        // We have a situation like `:has(.item .item + .item + .item)`, where the first element in the sibling
157        // chain position (i.e. The element matched by the second `.item` from the left) mutates. By the time we
158        // get here, we've collapsed the 4 dependencies for each of `.item` position into one at the rightmost
159        // position. Before we look for a standin, we need to find which `.item` this element matches - Doing
160        // that would generate more work than it saves.
161        if dependency_is_rightmost
162            && leftmost_collapse_offset != dependency.selector_offset
163            && self
164                .sibling_traversal_map
165                .next_sibling_for(&element)
166                .is_some()
167        {
168            return false;
169        }
170
171        let mut caches = SelectorCaches::default();
172        let mut matching_context = MatchingContext::new(
173            MatchingMode::Normal,
174            None,
175            &mut caches,
176            self.quirks_mode,
177            NeedsSelectorFlags::No,
178            MatchingForInvalidation::Yes,
179        );
180        matching_context.current_host = host;
181        let sibling_matches = matches_selector(
182            &dependency.selector,
183            dependency.selector_offset,
184            None,
185            &sibling,
186            &mut matching_context,
187        );
188        if sibling_matches {
189            // Remember that at this point, we know that the combinator to the right of this
190            // compound is a sibling combinator. Effectively, we've found a standin for the
191            // element we're mutating.
192            // e.g. Given `:has(... .a ~ .b ...)`, we're the mutating element matching `... .a`,
193            // if we find a sibling that matches the `... .a`, it can stand in for us.
194            debug_assert!(
195                dependency.next.is_some(),
196                "No relative selector outer dependency?"
197            );
198            return dependency.next.as_ref().map_or(false, |deps| {
199                // ... However, if the standin sibling can be the anchor, we can't skip it, since
200                // that sibling should be invlidated to become the anchor.
201                let next = &deps.as_ref().slice()[0];
202                !matches_selector(
203                    &next.selector,
204                    next.selector_offset,
205                    None,
206                    &sibling,
207                    &mut matching_context,
208                )
209            });
210        }
211        // Ok, there's no standin element - but would this element have matched the upstream
212        // selector anyway? If we don't, either the match exists somewhere far from us
213        // (In which case our mutation doesn't really matter), or it doesn't exist at all,
214        // so we can just skip the invalidation.
215        let (combinator, prev_offset) = {
216            let mut iter = dependency.selector.iter_from(dependency.selector_offset);
217            let mut o = dependency.selector_offset;
218            while iter.next().is_some() {
219                o += 1;
220            }
221            let combinator = iter.next_sequence();
222            o += 1;
223            debug_assert!(
224                combinator.is_some(),
225                "Should at least see a relative combinator"
226            );
227            (combinator.unwrap(), o)
228        };
229        if combinator.is_sibling() && prev_offset >= dependency.selector.len() - 1 {
230            // Hit the relative combinator - we don't have enough information to
231            // see if there's going to be a downstream match.
232            return false;
233        }
234        !matches_selector(
235            &dependency.selector,
236            dependency.selector_offset,
237            None,
238            &element,
239            &mut matching_context,
240        )
241    }
242}
243
244/// Overall invalidator for handling relative selector invalidations.
245pub struct RelativeSelectorInvalidator<'a, 'b, E>
246where
247    E: TElement + 'a,
248{
249    /// Element triggering the invalidation.
250    pub element: E,
251    /// Quirks mode of the current invalidation.
252    pub quirks_mode: QuirksMode,
253    /// Snapshot containing changes to invalidate against.
254    /// Can be None if it's a DOM mutation.
255    pub snapshot_table: Option<&'b ServoElementSnapshotTable>,
256    /// Callback to trigger when the subject element is invalidated.
257    pub invalidated: fn(E, &InvalidationResult),
258    /// The traversal map that should be used to process invalidations.
259    pub sibling_traversal_map: SiblingTraversalMap<E>,
260    /// Marker for 'a lifetime.
261    pub _marker: ::std::marker::PhantomData<&'a ()>,
262}
263
264struct RelativeSelectorInvalidation<'a> {
265    host: Option<OpaqueElement>,
266    kind: RelativeDependencyInvalidationKind,
267    dependency: &'a Dependency,
268}
269
270type ElementDependencies<'a> = SmallVec<[(Option<OpaqueElement>, &'a Dependency); 1]>;
271type Dependencies<'a, E> = SmallVec<[(E, ElementDependencies<'a>); 1]>;
272type AlreadyInvalidated<'a, E> = SmallVec<[AlreadyInvalidatedEntry<'a, E>; 2]>;
273
274struct AlreadyInvalidatedEntry<'a, E>
275where
276    E: TElement + 'a,
277{
278    /// Element where the invalidation will begin.
279    element: E,
280    /// The current shadow host.
281    host: Option<OpaqueElement>,
282    /// Dependency chain for this invalidation.
283    dependency: &'a Dependency,
284    /// The offset, of the leftmost dependencies that this
285    /// invalidation collapsed. See the `update()` function
286    /// for more information.
287    leftmost_collapse_offset: usize,
288}
289
290impl<'a, E> AlreadyInvalidatedEntry<'a, E>
291where
292    E: TElement + 'a,
293{
294    fn new(element: E, host: Option<OpaqueElement>, dependency: &'a Dependency) -> Self {
295        Self {
296            element,
297            host,
298            dependency,
299            leftmost_collapse_offset: dependency.selector_offset,
300        }
301    }
302
303    /// Update this invalidation with a new invalidation that may collapse with it.
304    fn update(&mut self, element: E, host: Option<OpaqueElement>, dependency: &'a Dependency) {
305        // This dependency should invalidate the same way - Collapse the invalidation
306        // to a more general case so we don't do duplicate work.
307        // e.g. For `:has(.item .item + .item + .item)`, since the anchor would be located
308        // in the ancestor chain for any invalidation triggered by any `.item` compound,
309        // 4 entries can collapse into one - but keep track of the leftmost offset.
310        if self.dependency.selector_offset > dependency.selector_offset {
311            *self = Self {
312                element,
313                host,
314                dependency,
315                leftmost_collapse_offset: self.leftmost_collapse_offset,
316            };
317        } else if self.leftmost_collapse_offset < dependency.selector_offset {
318            self.leftmost_collapse_offset = dependency.selector_offset;
319        }
320    }
321}
322
323/// Interface for collecting relative selector dependencies.
324pub struct RelativeSelectorDependencyCollector<'a, E>
325where
326    E: TElement,
327{
328    /// Dependencies that need to run through the normal invalidation that may generate
329    /// a relative selector invalidation.
330    dependencies: FxHashMap<E, ElementDependencies<'a>>,
331    /// Dependencies that created an invalidation right away.
332    invalidations: AlreadyInvalidated<'a, E>,
333    /// The top element in the subtree being invalidated.
334    top: E,
335    /// Optional context that will be used to try and skip invalidations
336    /// by running selector matches.
337    optimization_context: Option<OptimizationContext<'a, E>>,
338}
339
340type Invalidations<'a> = SmallVec<[RelativeSelectorInvalidation<'a>; 1]>;
341type InnerInvalidations<'a, E> = SmallVec<[(E, RelativeSelectorInvalidation<'a>); 1]>;
342
343struct ToInvalidate<'a, E: TElement + 'a> {
344    /// Dependencies to run through normal invalidator.
345    dependencies: Dependencies<'a, E>,
346    /// Dependencies already invalidated.
347    invalidations: Invalidations<'a>,
348}
349
350impl<'a, E: TElement + 'a> Default for ToInvalidate<'a, E> {
351    fn default() -> Self {
352        Self {
353            dependencies: Dependencies::default(),
354            invalidations: Invalidations::default(),
355        }
356    }
357}
358
359fn invalidation_can_collapse(
360    a: &Dependency,
361    b: &Dependency,
362    allow_indexed_selectors: bool,
363) -> bool {
364    // We want to detect identical dependencies that occur at different
365    // compounds but has the identical compound in the same selector,
366    // e.g. :has(.item .item).
367
368    // If they trigger different invalidations, they shouldn't be collapsed.
369    if a.relative_invalidation_kind() != b.relative_invalidation_kind() {
370        return false;
371    }
372
373    // Not in the same selector, trivially skipped.
374    if SelectorKey::new(&a.selector) != SelectorKey::new(&b.selector) {
375        return false;
376    }
377
378    // Check that this is in the same nesting.
379    // TODO(dshin): @scope probably brings more subtleties...
380    let mut a_next = a.next.as_ref();
381    let mut b_next = b.next.as_ref();
382    while let (Some(a_deps), Some(b_deps)) = (a_next, b_next) {
383        // This is a bit subtle - but we don't need to do the checks we do at higher levels.
384        // Cases like `:is(.item .foo) :is(.item .foo)` where `.item` invalidates would
385        // point to different dependencies, pointing to the same outer selector, but
386        // differing in selector offset.
387        let a_nexts = a_deps.as_ref().slice();
388        let b_nexts = b_deps.as_ref().slice();
389        if a_nexts.is_empty()|| b_nexts.is_empty() {
390            // Can happen when we get out to empty @scope() rules.
391            // If they're both empty, we can just do nothing for both.
392            return a_nexts.is_empty() == b_nexts.is_empty();
393        }
394        let a_n = &a_nexts[0];
395        let b_n = &b_nexts[0];
396        if SelectorKey::new(&a_n.selector) != SelectorKey::new(&b_n.selector) {
397            return false;
398        }
399        a_next = a_n.next.as_ref();
400        b_next = b_n.next.as_ref();
401    }
402    if a_next.is_some() || b_next.is_some() {
403        return false;
404    }
405
406    // Ok, now, do the compounds actually match?
407    // This can get expensive quickly, but we're assuming that:
408    //
409    //   * In most cases, authors don't generally duplicate compounds in a selector, so
410    //     this fails quickly
411    //   * In cases where compounds are duplicated, reducing the number of invalidations
412    //     has a payoff that offsets the comparison cost
413    //
414    // Note, `.a.b` != `.b.a` - doesn't affect correctness, though.
415    // TODO(dshin): Caching this may be worth it as well?
416    let mut a_iter = a.selector.iter_from(a.selector_offset);
417    let mut b_iter = b.selector.iter_from(b.selector_offset);
418    loop {
419        let a_component = a_iter.next();
420        let b_component = b_iter.next();
421
422        if a_component != b_component {
423            return false;
424        }
425        let Some(component) = a_component else {
426            return true;
427        };
428        if !allow_indexed_selectors && component.has_indexed_selector_in_subject() {
429            // The element's positioning matters, so can't collapse.
430            return false;
431        }
432    }
433}
434
435impl<'a, E> RelativeSelectorDependencyCollector<'a, E>
436where
437    E: TElement,
438{
439    fn new(top: E, optimization_context: Option<OptimizationContext<'a, E>>) -> Self {
440        Self {
441            dependencies: FxHashMap::default(),
442            invalidations: AlreadyInvalidated::default(),
443            top,
444            optimization_context,
445        }
446    }
447
448    fn insert_invalidation(
449        &mut self,
450        element: E,
451        dependency: &'a Dependency,
452        host: Option<OpaqueElement>,
453    ) {
454        let in_subtree = element != self.top;
455        if let Some(entry) = self.invalidations.iter_mut().find(|entry| {
456            // If we're in the subtree of DOM manipulation - worrying the about positioning of this element
457            // is irrelevant, because the DOM structure is either completely new or about to go away.
458            let both_in_subtree = in_subtree && entry.element != self.top;
459            // If we're considering the same element for invalidation, their evaluation of the indexed selector
460            // is identical by definition.
461            let same_element = element == entry.element;
462            invalidation_can_collapse(
463                dependency,
464                entry.dependency,
465                both_in_subtree || same_element,
466            )
467        }) {
468            entry.update(element, host, dependency)
469        } else {
470            self.invalidations
471                .push(AlreadyInvalidatedEntry::new(element, host, dependency));
472        }
473    }
474
475    /// Add this dependency, if it is unique (i.e. Different outer dependency or same outer dependency
476    /// but requires a different invalidation traversal).
477    pub fn add_dependency(
478        &mut self,
479        dependency: &'a Dependency,
480        element: E,
481        host: Option<OpaqueElement>,
482    ) {
483        match dependency.invalidation_kind() {
484            DependencyInvalidationKind::FullSelector => unreachable!(),
485            DependencyInvalidationKind::Normal(..) | DependencyInvalidationKind::Scope(..) => {
486                self.dependencies
487                    .entry(element)
488                    .and_modify(|v| v.push((host, dependency)))
489                    .or_default()
490                    .push((host, dependency));
491            },
492            DependencyInvalidationKind::Relative(kind) => {
493                debug_assert!(
494                    dependency.next.is_some(),
495                    "Orphaned inner relative selector?"
496                );
497                if element != self.top
498                    && matches!(
499                        kind,
500                        RelativeDependencyInvalidationKind::Parent
501                            | RelativeDependencyInvalidationKind::PrevSibling
502                            | RelativeDependencyInvalidationKind::EarlierSibling
503                    )
504                {
505                    return;
506                }
507                if early_reject_by_local_name(
508                    &dependency.selector,
509                    dependency.selector_offset,
510                    &element,
511                ) {
512                    return;
513                }
514                self.insert_invalidation(element, dependency, host);
515            },
516        };
517    }
518
519    /// Get the dependencies in a list format.
520    fn get(self) -> ToInvalidate<'a, E> {
521        let mut result = ToInvalidate::default();
522        for invalidation in self.invalidations {
523            match invalidation.dependency.invalidation_kind() {
524                DependencyInvalidationKind::FullSelector => unreachable!(),
525                DependencyInvalidationKind::Normal(_) | DependencyInvalidationKind::Scope(_) => {
526                    unreachable!("Inner selector in invalidation?")
527                },
528                DependencyInvalidationKind::Relative(kind) => {
529                    if let Some(context) = self.optimization_context.as_ref() {
530                        if context.can_be_ignored(
531                            invalidation.element != self.top,
532                            invalidation.element,
533                            invalidation.host,
534                            invalidation.dependency,
535                            invalidation.leftmost_collapse_offset,
536                        ) {
537                            continue;
538                        }
539                    }
540                    let dependency = &invalidation.dependency.next.as_ref().unwrap().slice()[0];
541                    result.invalidations.push(RelativeSelectorInvalidation {
542                        kind,
543                        host: invalidation.host,
544                        dependency,
545                    });
546                    // We move the invalidation up to the top of the subtree to avoid unnecessary traveral, but
547                    // this means that we need to take ancestor-earlier sibling invalidations into account, as
548                    // they'd look into earlier siblings of the top of the subtree as well.
549                    if invalidation.element != self.top
550                        && matches!(
551                            kind,
552                            RelativeDependencyInvalidationKind::AncestorEarlierSibling
553                                | RelativeDependencyInvalidationKind::AncestorPrevSibling
554                        )
555                    {
556                        result.invalidations.push(RelativeSelectorInvalidation {
557                            kind: if matches!(
558                                kind,
559                                RelativeDependencyInvalidationKind::AncestorPrevSibling
560                            ) {
561                                RelativeDependencyInvalidationKind::PrevSibling
562                            } else {
563                                RelativeDependencyInvalidationKind::EarlierSibling
564                            },
565                            host: invalidation.host,
566                            dependency,
567                        });
568                    }
569                },
570            };
571        }
572        for (key, element_dependencies) in self.dependencies {
573            // At least for now, we don't try to optimize away dependencies emitted from nested selectors.
574            result.dependencies.push((key, element_dependencies));
575        }
576        result
577    }
578
579    fn collect_all_dependencies_for_element(
580        &mut self,
581        element: E,
582        scope: Option<OpaqueElement>,
583        quirks_mode: QuirksMode,
584        map: &'a InvalidationMap,
585        additional_relative_selector_invalidation_map: &'a AdditionalRelativeSelectorInvalidationMap,
586        operation: DomMutationOperation,
587    ) {
588        element
589            .id()
590            .map(|v| match map.id_to_selector.get(v, quirks_mode) {
591                Some(v) => {
592                    for dependency in v {
593                        if !operation.accept(dependency, element) {
594                            continue;
595                        }
596                        self.add_dependency(dependency, element, scope);
597                    }
598                },
599                None => (),
600            });
601        element.each_class(|v| match map.class_to_selector.get(v, quirks_mode) {
602            Some(v) => {
603                for dependency in v {
604                    if !operation.accept(dependency, element) {
605                        continue;
606                    }
607                    self.add_dependency(dependency, element, scope);
608                }
609            },
610            None => (),
611        });
612        element.each_custom_state(|v| match map.custom_state_affecting_selectors.get(v) {
613            Some(v) => {
614                for dependency in v {
615                    if !operation.accept(dependency, element) {
616                        continue;
617                    }
618                    self.add_dependency(dependency, element, scope);
619                }
620            },
621            None => (),
622        });
623        element.each_attr_name(|v| match map.other_attribute_affecting_selectors.get(v) {
624            Some(v) => {
625                for dependency in v {
626                    if !operation.accept(dependency, element) {
627                        continue;
628                    }
629                    self.add_dependency(dependency, element, scope);
630                }
631            },
632            None => (),
633        });
634        let state = element.state();
635        map.state_affecting_selectors.lookup_with_additional(
636            element,
637            quirks_mode,
638            None,
639            &[],
640            ElementState::empty(),
641            |dependency| {
642                if !dependency.state.intersects(state) {
643                    return true;
644                }
645                if !operation.accept(&dependency.dep, element) {
646                    return true;
647                }
648                self.add_dependency(&dependency.dep, element, scope);
649                true
650            },
651        );
652
653        additional_relative_selector_invalidation_map
654            .ts_state_to_selector
655            .lookup_with_additional(
656                element,
657                quirks_mode,
658                None,
659                &[],
660                ElementState::empty(),
661                |dependency| {
662                    if !operation.accept(&dependency.dep, element) {
663                        return true;
664                    }
665                    // This section contain potential optimization for not running full invalidation -
666                    // consult documentation in `TSStateForInvalidation`.
667                    if dependency.state.may_be_optimized() {
668                        if operation.is_side_effect() {
669                            // Side effect operations act on element not being mutated, so they can't
670                            // change the match outcome of these optimizable pseudoclasses.
671                            return true;
672                        }
673                        debug_assert!(
674                            self.optimization_context.is_some(),
675                            "Optimization context not available for DOM mutation?"
676                        );
677                        if dependency.state.contains(TSStateForInvalidation::EMPTY)
678                            && element.first_element_child().is_some()
679                        {
680                            return true;
681                        }
682
683                        let sibling_traversal_map = self
684                            .optimization_context
685                            .as_ref()
686                            .unwrap()
687                            .sibling_traversal_map;
688                        if dependency
689                            .state
690                            .contains(TSStateForInvalidation::NTH_EDGE_FIRST)
691                            && sibling_traversal_map.prev_sibling_for(&element).is_some()
692                        {
693                            return true;
694                        }
695
696                        if dependency
697                            .state
698                            .contains(TSStateForInvalidation::NTH_EDGE_LAST)
699                            && sibling_traversal_map.next_sibling_for(&element).is_some()
700                        {
701                            return true;
702                        }
703                    }
704                    self.add_dependency(&dependency.dep, element, scope);
705                    true
706                },
707            );
708
709        if let Some(v) = additional_relative_selector_invalidation_map
710            .type_to_selector
711            .get(element.local_name())
712        {
713            for dependency in v {
714                if !operation.accept(dependency, element) {
715                    continue;
716                }
717                self.add_dependency(dependency, element, scope);
718            }
719        }
720
721        for dependency in &additional_relative_selector_invalidation_map.any_to_selector {
722            if !operation.accept(dependency, element) {
723                continue;
724            }
725            self.add_dependency(dependency, element, scope);
726        }
727    }
728
729    fn is_empty(&self) -> bool {
730        self.invalidations.is_empty() && self.dependencies.is_empty()
731    }
732}
733
734impl<'a, 'b, E> RelativeSelectorInvalidator<'a, 'b, E>
735where
736    E: TElement + 'a,
737{
738    /// Gather relative selector dependencies for the given element, and invalidate as necessary.
739    #[inline(never)]
740    pub fn invalidate_relative_selectors_for_this<F>(
741        self,
742        stylist: &'a Stylist,
743        mut gather_dependencies: F,
744    ) where
745        F: FnMut(
746            &E,
747            Option<OpaqueElement>,
748            &'a CascadeData,
749            QuirksMode,
750            &mut RelativeSelectorDependencyCollector<'a, E>,
751        ),
752    {
753        let mut collector = RelativeSelectorDependencyCollector::new(self.element, None);
754        stylist.for_each_cascade_data_with_scope(self.element, |data, scope| {
755            let map = data.relative_invalidation_map_attributes();
756            if !map.used {
757                return;
758            }
759            gather_dependencies(
760                &self.element,
761                scope.map(|e| e.opaque()),
762                data,
763                self.quirks_mode,
764                &mut collector,
765            );
766        });
767        if collector.is_empty() {
768            return;
769        }
770        self.invalidate_from_dependencies(collector.get());
771    }
772
773    /// Gather relative selector dependencies for the given element (And its subtree) that mutated, and invalidate as necessary.
774    #[inline(never)]
775    pub fn invalidate_relative_selectors_for_dom_mutation(
776        self,
777        subtree: bool,
778        stylist: &'a Stylist,
779        inherited_search_path: ElementSelectorFlags,
780        operation: DomMutationOperation,
781    ) {
782        let mut collector = RelativeSelectorDependencyCollector::new(
783            self.element,
784            if operation.is_side_effect() {
785                None
786            } else {
787                Some(OptimizationContext {
788                    sibling_traversal_map: &self.sibling_traversal_map,
789                    quirks_mode: self.quirks_mode,
790                    operation,
791                })
792            },
793        );
794        let mut traverse_subtree = false;
795        self.element.apply_selector_flags(inherited_search_path);
796        stylist.for_each_cascade_data_with_scope(self.element, |data, scope| {
797            let map_attributes = data.relative_invalidation_map_attributes();
798            if !map_attributes.used {
799                return;
800            }
801            let map = data.relative_selector_invalidation_map();
802            traverse_subtree |= map_attributes.needs_ancestors_traversal;
803            collector.collect_all_dependencies_for_element(
804                self.element,
805                scope.map(|e| e.opaque()),
806                self.quirks_mode,
807                map,
808                map_attributes,
809                operation,
810            );
811        });
812
813        if subtree && traverse_subtree {
814            for node in self.element.as_node().dom_descendants() {
815                let descendant = match node.as_element() {
816                    Some(e) => e,
817                    None => continue,
818                };
819                descendant.apply_selector_flags(inherited_search_path);
820                stylist.for_each_cascade_data_with_scope(descendant, |data, scope| {
821                    let map_attributes = data.relative_invalidation_map_attributes();
822                    if !map_attributes.used {
823                        return;
824                    }
825                    let map = data.relative_selector_invalidation_map();
826                    collector.collect_all_dependencies_for_element(
827                        descendant,
828                        scope.map(|e| e.opaque()),
829                        self.quirks_mode,
830                        map,
831                        map_attributes,
832                        operation,
833                    );
834                });
835            }
836        }
837        if collector.is_empty() {
838            return;
839        }
840        self.invalidate_from_dependencies(collector.get());
841    }
842
843    /// Carry out complete invalidation triggered by a relative selector invalidation.
844    fn invalidate_from_dependencies(&self, to_invalidate: ToInvalidate<'a, E>) {
845        for (element, dependencies) in to_invalidate.dependencies {
846            let mut selector_caches = SelectorCaches::default();
847            let mut processor = RelativeSelectorInnerInvalidationProcessor::new(
848                self.quirks_mode,
849                self.snapshot_table,
850                &dependencies,
851                &mut selector_caches,
852                &self.sibling_traversal_map,
853            );
854            TreeStyleInvalidator::new(element, None, &mut processor).invalidate();
855            for (element, invalidation) in processor.take_invalidations() {
856                self.invalidate_upwards(element, &invalidation);
857            }
858        }
859        for invalidation in to_invalidate.invalidations {
860            self.invalidate_upwards(self.element, &invalidation);
861        }
862    }
863
864    fn invalidate_upwards(&self, element: E, invalidation: &RelativeSelectorInvalidation<'a>) {
865        // This contains the main reason for why relative selector invalidation is handled
866        // separately - It travels ancestor and/or earlier sibling direction.
867        match invalidation.kind {
868            RelativeDependencyInvalidationKind::Parent => {
869                element.parent_element().map(|e| {
870                    if !Self::in_search_direction(
871                        &e,
872                        ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR,
873                    ) {
874                        return;
875                    }
876                    self.handle_anchor(e, invalidation.dependency, invalidation.host);
877                });
878            },
879            RelativeDependencyInvalidationKind::Ancestors => {
880                let mut parent = element.parent_element();
881                while let Some(par) = parent {
882                    if !Self::in_search_direction(
883                        &par,
884                        ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR,
885                    ) {
886                        return;
887                    }
888                    self.handle_anchor(par, invalidation.dependency, invalidation.host);
889                    parent = par.parent_element();
890                }
891            },
892            RelativeDependencyInvalidationKind::PrevSibling => {
893                self.sibling_traversal_map
894                    .prev_sibling_for(&element)
895                    .map(|e| {
896                        if !Self::in_search_direction(
897                            &e,
898                            ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING,
899                        ) {
900                            return;
901                        }
902                        self.handle_anchor(e, invalidation.dependency, invalidation.host);
903                    });
904            },
905            RelativeDependencyInvalidationKind::AncestorPrevSibling => {
906                let mut parent = element.parent_element();
907                while let Some(par) = parent {
908                    if !Self::in_search_direction(
909                        &par,
910                        ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR,
911                    ) {
912                        return;
913                    }
914                    par.prev_sibling_element().map(|e| {
915                        if !Self::in_search_direction(
916                            &e,
917                            ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING,
918                        ) {
919                            return;
920                        }
921                        self.handle_anchor(e, invalidation.dependency, invalidation.host);
922                    });
923                    parent = par.parent_element();
924                }
925            },
926            RelativeDependencyInvalidationKind::EarlierSibling => {
927                let mut sibling = self.sibling_traversal_map.prev_sibling_for(&element);
928                while let Some(sib) = sibling {
929                    if !Self::in_search_direction(
930                        &sib,
931                        ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING,
932                    ) {
933                        return;
934                    }
935                    self.handle_anchor(sib, invalidation.dependency, invalidation.host);
936                    sibling = sib.prev_sibling_element();
937                }
938            },
939            RelativeDependencyInvalidationKind::AncestorEarlierSibling => {
940                let mut parent = element.parent_element();
941                while let Some(par) = parent {
942                    if !Self::in_search_direction(
943                        &par,
944                        ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR,
945                    ) {
946                        return;
947                    }
948                    let mut sibling = par.prev_sibling_element();
949                    while let Some(sib) = sibling {
950                        if !Self::in_search_direction(
951                            &sib,
952                            ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING,
953                        ) {
954                            return;
955                        }
956                        self.handle_anchor(sib, invalidation.dependency, invalidation.host);
957                        sibling = sib.prev_sibling_element();
958                    }
959                    parent = par.parent_element();
960                }
961            },
962        }
963    }
964
965    /// Is this element in the direction of the given relative selector search path?
966    fn in_search_direction(element: &E, desired: ElementSelectorFlags) -> bool {
967        element
968            .relative_selector_search_direction()
969            .intersects(desired)
970    }
971
972    /// Handle a potential relative selector anchor.
973    fn handle_anchor(
974        &self,
975        element: E,
976        outer_dependency: &Dependency,
977        host: Option<OpaqueElement>,
978    ) {
979        let is_rightmost = Self::is_subject(outer_dependency);
980        if (is_rightmost
981            && !element.has_selector_flags(ElementSelectorFlags::ANCHORS_RELATIVE_SELECTOR))
982            || (!is_rightmost
983                && !element.has_selector_flags(
984                    ElementSelectorFlags::ANCHORS_RELATIVE_SELECTOR_NON_SUBJECT,
985                ))
986        {
987            // If it was never a relative selector anchor, don't bother.
988            return;
989        }
990        let mut selector_caches = SelectorCaches::default();
991        let matching_context = MatchingContext::<'_, E::Impl>::new_for_visited(
992            MatchingMode::Normal,
993            None,
994            &mut selector_caches,
995            VisitedHandlingMode::AllLinksVisitedAndUnvisited,
996            IncludeStartingStyle::No,
997            self.quirks_mode,
998            NeedsSelectorFlags::No,
999            MatchingForInvalidation::Yes,
1000        );
1001        let mut data = match element.mutate_data() {
1002            Some(data) => data,
1003            None => return,
1004        };
1005        let mut processor = RelativeSelectorOuterInvalidationProcessor {
1006            element,
1007            host,
1008            data: data.deref_mut(),
1009            dependency: &*outer_dependency,
1010            matching_context,
1011            traversal_map: &self.sibling_traversal_map,
1012        };
1013        let result = TreeStyleInvalidator::new(element, None, &mut processor).invalidate();
1014        (self.invalidated)(element, &result);
1015    }
1016
1017    /// Does this relative selector dependency have its relative selector in the subject position?
1018    fn is_subject(outer_dependency: &Dependency) -> bool {
1019        debug_assert!(
1020            matches!(
1021                outer_dependency.invalidation_kind(),
1022                DependencyInvalidationKind::Normal(_) | DependencyInvalidationKind::Scope(_)
1023            ),
1024            "Outer selector of relative selector is relative?"
1025        );
1026
1027        if let Some(x) = outer_dependency.next.as_ref() {
1028            // We only care to ensure that we're the subject in the outermost selector of the current
1029            // selector - Crossing over a scope invalidation would mean moving into a selector inside
1030            // the current scope block
1031            if matches!(
1032                outer_dependency.invalidation_kind(),
1033                DependencyInvalidationKind::Normal(..)
1034            ) {
1035                if !Self::is_subject(&x.as_ref().slice()[0]) {
1036                    // Not subject in outer selector.
1037                    return false;
1038                }
1039            }
1040        }
1041        outer_dependency
1042            .selector
1043            .is_rightmost(outer_dependency.selector_offset)
1044    }
1045}
1046
1047/// Blindly invalidate everything outside of a relative selector.
1048/// Consider `:is(.a :has(.b) .c ~ .d) ~ .e .f`, where .b gets deleted.
1049/// Since the tree mutated, we cannot rely on snapshots.
1050pub struct RelativeSelectorOuterInvalidationProcessor<'a, 'b, E: TElement> {
1051    /// Element being invalidated.
1052    pub element: E,
1053    /// The current shadow host, if any.
1054    pub host: Option<OpaqueElement>,
1055    /// Data for the element being invalidated.
1056    pub data: &'a mut ElementData,
1057    /// Dependency to be processed.
1058    pub dependency: &'b Dependency,
1059    /// Matching context to use for invalidation.
1060    pub matching_context: MatchingContext<'a, E::Impl>,
1061    /// Traversal map for this invalidation.
1062    pub traversal_map: &'a SiblingTraversalMap<E>,
1063}
1064
1065impl<'a, 'b: 'a, E: 'a> InvalidationProcessor<'b, 'a, E>
1066    for RelativeSelectorOuterInvalidationProcessor<'a, 'b, E>
1067where
1068    E: TElement,
1069{
1070    fn invalidates_on_pseudo_element(&self) -> bool {
1071        true
1072    }
1073
1074    fn check_outer_dependency(
1075        &mut self,
1076        _dependency: &Dependency,
1077        _element: E,
1078        _: Option<OpaqueElement>,
1079    ) -> bool {
1080        // At this point, we know a relative selector invalidated, and are ignoring them.
1081        true
1082    }
1083
1084    fn matching_context(&mut self) -> &mut MatchingContext<'a, E::Impl> {
1085        &mut self.matching_context
1086    }
1087
1088    fn sibling_traversal_map(&self) -> &SiblingTraversalMap<E> {
1089        self.traversal_map
1090    }
1091
1092    fn collect_invalidations(
1093        &mut self,
1094        element: E,
1095        _self_invalidations: &mut InvalidationVector<'b>,
1096        descendant_invalidations: &mut DescendantInvalidationLists<'b>,
1097        sibling_invalidations: &mut InvalidationVector<'b>,
1098    ) -> bool {
1099        debug_assert_eq!(element, self.element);
1100        debug_assert!(
1101            self.matching_context.matching_for_invalidation(),
1102            "Not matching for invalidation?"
1103        );
1104
1105        // Ok, this element can potentially an anchor to the given dependency.
1106        // Before we do the potentially-costly ancestor/earlier sibling traversal,
1107        // See if it can actuall be an anchor by trying to match the "rest" of the selector
1108        // outside and to the left of `:has` in question.
1109        // e.g. Element under consideration can only be the anchor to `:has` in
1110        // `.foo .bar ~ .baz:has()`, iff it matches `.foo .bar ~ .baz`.
1111        let invalidated_self = {
1112            let mut invalidated = false;
1113            let mut dependencies_to_invalidate: SmallVec<[&Dependency; 1]> =
1114                smallvec![self.dependency];
1115            while let Some(d) = dependencies_to_invalidate.pop() {
1116                debug_assert!(
1117                    matches!(
1118                        d.invalidation_kind(),
1119                        DependencyInvalidationKind::Normal(_)
1120                            | DependencyInvalidationKind::Scope(_)
1121                    ),
1122                    "Unexpected dependency kind"
1123                );
1124                if !dependency_may_be_relevant(d, &element, false) {
1125                    continue;
1126                }
1127                if !matches_selector(
1128                    &d.selector,
1129                    d.selector_offset,
1130                    None,
1131                    &element,
1132                    self.matching_context(),
1133                ) {
1134                    continue;
1135                }
1136
1137                let invalidation_kind = d.invalidation_kind();
1138
1139                if let DependencyInvalidationKind::Scope(scope_kind) = invalidation_kind {
1140                    if d.selector.is_rightmost(d.selector_offset) {
1141                        if scope_kind == ScopeDependencyInvalidationKind::ScopeEnd {
1142                            let invalidations = note_scope_dependency_force_at_subject(
1143                                d,
1144                                self.matching_context.current_host.clone(),
1145                                self.matching_context.scope_element,
1146                                false,
1147                            );
1148                            descendant_invalidations
1149                                .dom_descendants
1150                                .extend(invalidations);
1151
1152                            invalidated |= true;
1153                        } else if let Some(ref next) = d.next {
1154                            dependencies_to_invalidate.extend(next.as_ref().slice());
1155                        }
1156                        continue;
1157                    }
1158                }
1159
1160                if matches!(
1161                    invalidation_kind,
1162                    DependencyInvalidationKind::Normal(NormalDependencyInvalidationKind::Element)
1163                ) {
1164                    if let Some(ref deps) = d.next {
1165                        // Normal dependencies should only have one next
1166                        dependencies_to_invalidate.push(&deps.as_ref().slice()[0]);
1167                        continue;
1168                    }
1169                    invalidated |= true;
1170                    continue;
1171                }
1172                debug_assert_ne!(d.selector_offset, 0);
1173                debug_assert_ne!(d.selector_offset, d.selector.len());
1174                let invalidation = Invalidation::new(&d, self.host, None);
1175                invalidated |= push_invalidation(
1176                    invalidation,
1177                    d.invalidation_kind(),
1178                    descendant_invalidations,
1179                    sibling_invalidations,
1180                );
1181            }
1182            invalidated
1183        };
1184
1185        if invalidated_self {
1186            self.data.hint.insert(RestyleHint::RESTYLE_SELF);
1187        }
1188        invalidated_self
1189    }
1190
1191    fn should_process_descendants(&mut self, element: E) -> bool {
1192        if element == self.element {
1193            return should_process_descendants(&self.data);
1194        }
1195
1196        match element.borrow_data() {
1197            Some(d) => should_process_descendants(&d),
1198            None => return false,
1199        }
1200    }
1201
1202    fn recursion_limit_exceeded(&mut self, _element: E) {
1203        unreachable!("Unexpected recursion limit");
1204    }
1205
1206    fn invalidated_descendants(&mut self, element: E, child: E) {
1207        invalidated_descendants(element, child)
1208    }
1209
1210    fn invalidated_self(&mut self, element: E) {
1211        debug_assert_ne!(element, self.element);
1212        invalidated_self(element);
1213    }
1214
1215    fn invalidated_sibling(&mut self, element: E, of: E) {
1216        debug_assert_ne!(element, self.element);
1217        invalidated_sibling(element, of);
1218    }
1219}
1220
1221/// Invalidation for the selector(s) inside a relative selector.
1222pub struct RelativeSelectorInnerInvalidationProcessor<'a, 'b, 'c, E>
1223where
1224    E: TElement + 'a,
1225{
1226    /// Matching context to be used.
1227    matching_context: MatchingContext<'b, E::Impl>,
1228    /// Table of snapshots.
1229    snapshot_table: Option<&'c ServoElementSnapshotTable>,
1230    /// Incoming dependencies to be processed.
1231    dependencies: &'c ElementDependencies<'a>,
1232    /// Generated invalidations.
1233    invalidations: InnerInvalidations<'a, E>,
1234    /// Traversal map for this invalidation.
1235    traversal_map: &'b SiblingTraversalMap<E>,
1236}
1237
1238impl<'a, 'b, 'c, E> RelativeSelectorInnerInvalidationProcessor<'a, 'b, 'c, E>
1239where
1240    E: TElement + 'a,
1241{
1242    fn new(
1243        quirks_mode: QuirksMode,
1244        snapshot_table: Option<&'c ServoElementSnapshotTable>,
1245        dependencies: &'c ElementDependencies<'a>,
1246        selector_caches: &'b mut SelectorCaches,
1247        traversal_map: &'b SiblingTraversalMap<E>,
1248    ) -> Self {
1249        let matching_context = MatchingContext::new_for_visited(
1250            MatchingMode::Normal,
1251            None,
1252            selector_caches,
1253            VisitedHandlingMode::AllLinksVisitedAndUnvisited,
1254            IncludeStartingStyle::No,
1255            quirks_mode,
1256            NeedsSelectorFlags::No,
1257            MatchingForInvalidation::Yes,
1258        );
1259        Self {
1260            matching_context,
1261            snapshot_table,
1262            dependencies,
1263            invalidations: InnerInvalidations::default(),
1264            traversal_map,
1265        }
1266    }
1267
1268    fn note_dependency(
1269        &mut self,
1270        element: E,
1271        host: Option<OpaqueElement>,
1272        dependency: &'a Dependency,
1273        descendant_invalidations: &mut DescendantInvalidationLists<'a>,
1274        sibling_invalidations: &mut InvalidationVector<'a>,
1275    ) {
1276        match dependency.invalidation_kind() {
1277            DependencyInvalidationKind::FullSelector => unreachable!(),
1278            DependencyInvalidationKind::Normal(_) | DependencyInvalidationKind::Scope(_) => (),
1279            DependencyInvalidationKind::Relative(kind) => {
1280                self.found_relative_selector_invalidation(element, kind, dependency);
1281                return;
1282            },
1283        }
1284        if matches!(
1285            dependency.normal_invalidation_kind(),
1286            NormalDependencyInvalidationKind::Element
1287        ) {
1288            // Ok, keep heading outwards.
1289            debug_assert!(
1290                dependency.next.is_some(),
1291                "Orphaned inner selector dependency?"
1292            );
1293            if let Some(next) = dependency.next.as_ref() {
1294                self.note_dependency(
1295                    element,
1296                    host,
1297                    &next.as_ref().slice()[0],
1298                    descendant_invalidations,
1299                    sibling_invalidations,
1300                );
1301            }
1302            return;
1303        }
1304        let invalidation = Invalidation::new(&dependency, None, None);
1305        match dependency.normal_invalidation_kind() {
1306            NormalDependencyInvalidationKind::Descendants => {
1307                // Descendant invalidations are simplified due to pseudo-elements not being available within the relative selector.
1308                descendant_invalidations.dom_descendants.push(invalidation)
1309            },
1310            NormalDependencyInvalidationKind::Siblings => sibling_invalidations.push(invalidation),
1311            // Note(dshin, bug 1940212): Nesting can enabling stuffing pseudo-elements into :has, like `::marker { :has(&) }`.
1312            // Ideally, we can just not insert the dependency into the invalidation map, but the necessary selector information
1313            // for this (i.e. `HAS_PSEUDO`) is filtered out in `replace_parent_selector` through
1314            // `SelectorFlags::forbidden_for_nesting`, so just ignoring such dependencies here is the best we can do.
1315            _ => (),
1316        }
1317    }
1318
1319    /// Take the generated invalidations.
1320    fn take_invalidations(self) -> InnerInvalidations<'a, E> {
1321        self.invalidations
1322    }
1323}
1324
1325impl<'a, 'b, 'c, E> InvalidationProcessor<'a, 'b, E>
1326    for RelativeSelectorInnerInvalidationProcessor<'a, 'b, 'c, E>
1327where
1328    E: TElement + 'a,
1329{
1330    fn check_outer_dependency(
1331        &mut self,
1332        dependency: &Dependency,
1333        element: E,
1334        _: Option<OpaqueElement>,
1335    ) -> bool {
1336        if let Some(snapshot_table) = self.snapshot_table {
1337            let wrapper = ElementWrapper::new(element, snapshot_table);
1338            return check_dependency(
1339                dependency,
1340                &element,
1341                &wrapper,
1342                &mut self.matching_context,
1343                None,
1344            );
1345        }
1346        // Just invalidate if we don't have a snapshot.
1347        true
1348    }
1349
1350    fn matching_context(&mut self) -> &mut MatchingContext<'b, E::Impl> {
1351        return &mut self.matching_context;
1352    }
1353
1354    fn collect_invalidations(
1355        &mut self,
1356        element: E,
1357        _self_invalidations: &mut InvalidationVector<'a>,
1358        descendant_invalidations: &mut DescendantInvalidationLists<'a>,
1359        sibling_invalidations: &mut InvalidationVector<'a>,
1360    ) -> bool {
1361        for (scope, dependency) in self.dependencies {
1362            self.note_dependency(
1363                element,
1364                *scope,
1365                dependency,
1366                descendant_invalidations,
1367                sibling_invalidations,
1368            )
1369        }
1370        false
1371    }
1372
1373    fn should_process_descendants(&mut self, _element: E) -> bool {
1374        true
1375    }
1376
1377    fn recursion_limit_exceeded(&mut self, _element: E) {
1378        unreachable!("Unexpected recursion limit");
1379    }
1380
1381    // Don't do anything for normal invalidations.
1382    fn invalidated_self(&mut self, _element: E) {}
1383    fn invalidated_sibling(&mut self, _sibling: E, _of: E) {}
1384    fn invalidated_descendants(&mut self, _element: E, _child: E) {}
1385
1386    fn found_relative_selector_invalidation(
1387        &mut self,
1388        element: E,
1389        kind: RelativeDependencyInvalidationKind,
1390        dep: &'a Dependency,
1391    ) {
1392        debug_assert!(dep.next.is_some(), "Orphaned inners selector?");
1393        if element.relative_selector_search_direction().is_empty() {
1394            return;
1395        }
1396        self.invalidations.push((
1397            element,
1398            RelativeSelectorInvalidation {
1399                host: self.matching_context.current_host,
1400                kind,
1401                dependency: &dep.next.as_ref().unwrap().as_ref().slice()[0],
1402            },
1403        ));
1404    }
1405
1406    fn sibling_traversal_map(&self) -> &SiblingTraversalMap<E> {
1407        &self.traversal_map
1408    }
1409}