tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

matching.rs (56830B)


      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 use crate::attr::{
      6    AttrSelectorOperation, AttrSelectorWithOptionalNamespace, CaseSensitivity, NamespaceConstraint,
      7    ParsedAttrSelectorOperation, ParsedCaseSensitivity,
      8 };
      9 use crate::bloom::{BloomFilter, BLOOM_HASH_MASK};
     10 use crate::kleene_value::KleeneValue;
     11 use crate::parser::{
     12    AncestorHashes, Combinator, Component, LocalName, MatchesFeaturelessHost, NthSelectorData,
     13    RelativeSelectorMatchHint,
     14 };
     15 use crate::parser::{
     16    NonTSPseudoClass, RelativeSelector, Selector, SelectorImpl, SelectorIter, SelectorList,
     17 };
     18 use crate::relative_selector::cache::RelativeSelectorCachedMatch;
     19 use crate::tree::Element;
     20 use bitflags::bitflags;
     21 use debug_unreachable::debug_unreachable;
     22 use log::debug;
     23 use smallvec::SmallVec;
     24 use std::borrow::Borrow;
     25 
     26 pub use crate::context::*;
     27 
     28 // The bloom filter for descendant CSS selectors will have a <1% false
     29 // positive rate until it has this many selectors in it, then it will
     30 // rapidly increase.
     31 pub static RECOMMENDED_SELECTOR_BLOOM_FILTER_SIZE: usize = 4096;
     32 
     33 bitflags! {
     34    /// Set of flags that are set on either the element or its parent (depending
     35    /// on the flag) if the element could potentially match a selector.
     36    #[derive(Clone, Copy)]
     37    pub struct ElementSelectorFlags: usize {
     38        /// When a child is added or removed from the parent, all the children
     39        /// must be restyled, because they may match :nth-last-child,
     40        /// :last-of-type, :nth-last-of-type, or :only-of-type.
     41        const HAS_SLOW_SELECTOR = 1 << 0;
     42 
     43        /// When a child is added or removed from the parent, any later
     44        /// children must be restyled, because they may match :nth-child,
     45        /// :first-of-type, or :nth-of-type.
     46        const HAS_SLOW_SELECTOR_LATER_SIBLINGS = 1 << 1;
     47 
     48        /// HAS_SLOW_SELECTOR* was set by the presence of :nth (But not of).
     49        const HAS_SLOW_SELECTOR_NTH = 1 << 2;
     50 
     51        /// When a DOM mutation occurs on a child that might be matched by
     52        /// :nth-last-child(.. of <selector list>), earlier children must be
     53        /// restyled, and HAS_SLOW_SELECTOR will be set (which normally
     54        /// indicates that all children will be restyled).
     55        ///
     56        /// Similarly, when a DOM mutation occurs on a child that might be
     57        /// matched by :nth-child(.. of <selector list>), later children must be
     58        /// restyled, and HAS_SLOW_SELECTOR_LATER_SIBLINGS will be set.
     59        const HAS_SLOW_SELECTOR_NTH_OF = 1 << 3;
     60 
     61        /// When a child is added or removed from the parent, the first and
     62        /// last children must be restyled, because they may match :first-child,
     63        /// :last-child, or :only-child.
     64        const HAS_EDGE_CHILD_SELECTOR = 1 << 4;
     65 
     66        /// The element has an empty selector, so when a child is appended we
     67        /// might need to restyle the parent completely.
     68        const HAS_EMPTY_SELECTOR = 1 << 5;
     69 
     70        /// The element may anchor a relative selector.
     71        const ANCHORS_RELATIVE_SELECTOR = 1 << 6;
     72 
     73        /// The element may anchor a relative selector that is not the subject
     74        /// of the whole selector.
     75        const ANCHORS_RELATIVE_SELECTOR_NON_SUBJECT = 1 << 7;
     76 
     77        /// The element is reached by a relative selector search in the sibling direction.
     78        const RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING = 1 << 8;
     79 
     80        /// The element is reached by a relative selector search in the ancestor direction.
     81        const RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR = 1 << 9;
     82 
     83        // The element is reached by a relative selector search in both sibling and ancestor directions.
     84        const RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR_SIBLING =
     85            Self::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING.bits() |
     86            Self::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR.bits();
     87    }
     88 }
     89 
     90 impl ElementSelectorFlags {
     91    /// Returns the subset of flags that apply to the element.
     92    pub fn for_self(self) -> ElementSelectorFlags {
     93        self & (ElementSelectorFlags::HAS_EMPTY_SELECTOR
     94            | ElementSelectorFlags::ANCHORS_RELATIVE_SELECTOR
     95            | ElementSelectorFlags::ANCHORS_RELATIVE_SELECTOR_NON_SUBJECT
     96            | ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING
     97            | ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR)
     98    }
     99 
    100    /// Returns the subset of flags that apply to the parent.
    101    pub fn for_parent(self) -> ElementSelectorFlags {
    102        self & (ElementSelectorFlags::HAS_SLOW_SELECTOR
    103            | ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS
    104            | ElementSelectorFlags::HAS_SLOW_SELECTOR_NTH
    105            | ElementSelectorFlags::HAS_SLOW_SELECTOR_NTH_OF
    106            | ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR)
    107    }
    108 }
    109 
    110 /// Holds per-compound-selector data.
    111 struct LocalMatchingContext<'a, 'b: 'a, Impl: SelectorImpl> {
    112    shared: &'a mut MatchingContext<'b, Impl>,
    113    rightmost: SubjectOrPseudoElement,
    114    quirks_data: Option<SelectorIter<'a, Impl>>,
    115 }
    116 
    117 #[inline(always)]
    118 pub fn matches_selector_list<E>(
    119    selector_list: &SelectorList<E::Impl>,
    120    element: &E,
    121    context: &mut MatchingContext<E::Impl>,
    122 ) -> bool
    123 where
    124    E: Element,
    125 {
    126    // This is pretty much any(..) but manually inlined because the compiler
    127    // refuses to do so from querySelector / querySelectorAll.
    128    for selector in selector_list.slice() {
    129        let matches = matches_selector(selector, 0, None, element, context);
    130        if matches {
    131            return true;
    132        }
    133    }
    134 
    135    false
    136 }
    137 
    138 /// Given the ancestor hashes from a selector, see if the current element,
    139 /// represented by the bloom filter, has a chance of matching at all.
    140 #[inline(always)]
    141 pub fn selector_may_match(hashes: &AncestorHashes, bf: &BloomFilter) -> bool {
    142    // Check the first three hashes. Note that we can check for zero before
    143    // masking off the high bits, since if any of the first three hashes is
    144    // zero the fourth will be as well. We also take care to avoid the
    145    // special-case complexity of the fourth hash until we actually reach it,
    146    // because we usually don't.
    147    //
    148    // To be clear: this is all extremely hot.
    149    for i in 0..3 {
    150        let packed = hashes.packed_hashes[i];
    151        if packed == 0 {
    152            // No more hashes left - unable to fast-reject.
    153            return true;
    154        }
    155 
    156        if !bf.might_contain_hash(packed & BLOOM_HASH_MASK) {
    157            // Hooray! We fast-rejected on this hash.
    158            return false;
    159        }
    160    }
    161 
    162    // Now do the slighty-more-complex work of synthesizing the fourth hash,
    163    // and check it against the filter if it exists.
    164    let fourth = hashes.fourth_hash();
    165    fourth == 0 || bf.might_contain_hash(fourth)
    166 }
    167 
    168 /// A result of selector matching, includes 3 failure types,
    169 ///
    170 ///   NotMatchedAndRestartFromClosestLaterSibling
    171 ///   NotMatchedAndRestartFromClosestDescendant
    172 ///   NotMatchedGlobally
    173 ///
    174 /// When NotMatchedGlobally appears, stop selector matching completely since
    175 /// the succeeding selectors never matches.
    176 /// It is raised when
    177 ///   Child combinator cannot find the candidate element.
    178 ///   Descendant combinator cannot find the candidate element.
    179 ///
    180 /// When NotMatchedAndRestartFromClosestDescendant appears, the selector
    181 /// matching does backtracking and restarts from the closest Descendant
    182 /// combinator.
    183 /// It is raised when
    184 ///   NextSibling combinator cannot find the candidate element.
    185 ///   LaterSibling combinator cannot find the candidate element.
    186 ///   Child combinator doesn't match on the found element.
    187 ///
    188 /// When NotMatchedAndRestartFromClosestLaterSibling appears, the selector
    189 /// matching does backtracking and restarts from the closest LaterSibling
    190 /// combinator.
    191 /// It is raised when
    192 ///   NextSibling combinator doesn't match on the found element.
    193 ///
    194 /// For example, when the selector "d1 d2 a" is provided and we cannot *find*
    195 /// an appropriate ancestor element for "d1", this selector matching raises
    196 /// NotMatchedGlobally since even if "d2" is moved to more upper element, the
    197 /// candidates for "d1" becomes less than before and d1 .
    198 ///
    199 /// The next example is siblings. When the selector "b1 + b2 ~ d1 a" is
    200 /// provided and we cannot *find* an appropriate brother element for b1,
    201 /// the selector matching raises NotMatchedAndRestartFromClosestDescendant.
    202 /// The selectors ("b1 + b2 ~") doesn't match and matching restart from "d1".
    203 ///
    204 /// The additional example is child and sibling. When the selector
    205 /// "b1 + c1 > b2 ~ d1 a" is provided and the selector "b1" doesn't match on
    206 /// the element, this "b1" raises NotMatchedAndRestartFromClosestLaterSibling.
    207 /// However since the selector "c1" raises
    208 /// NotMatchedAndRestartFromClosestDescendant. So the selector
    209 /// "b1 + c1 > b2 ~ " doesn't match and restart matching from "d1".
    210 ///
    211 /// There is also the unknown result, which is used during invalidation when
    212 /// specific selector is being tested for before/after comparison. More specifically,
    213 /// selectors that are too expensive to correctly compute during invalidation may
    214 /// return unknown, as the computation will be thrown away and only to be recomputed
    215 /// during styling. For most cases, the unknown result can be treated as matching.
    216 /// This is because a compound of selectors acts like &&, and unknown && matched
    217 /// == matched and unknown && not-matched == not-matched. However, some selectors,
    218 /// like `:is()`, behave like || i.e. `:is(.a, .b)` == a || b. Treating unknown
    219 /// == matching then causes these selectors to always return matching, which undesired
    220 /// for before/after comparison. Coercing to not-matched doesn't work since each
    221 /// inner selector may have compounds: e.g. Toggling `.foo` in `:is(.foo:has(..))`
    222 /// with coersion to not-matched would result in an invalid before/after comparison
    223 /// of not-matched/not-matched.
    224 #[derive(Clone, Copy, Eq, PartialEq)]
    225 enum SelectorMatchingResult {
    226    Matched,
    227    NotMatchedAndRestartFromClosestLaterSibling,
    228    NotMatchedAndRestartFromClosestDescendant,
    229    NotMatchedGlobally,
    230    Unknown,
    231 }
    232 
    233 impl From<SelectorMatchingResult> for KleeneValue {
    234    #[inline]
    235    fn from(value: SelectorMatchingResult) -> Self {
    236        match value {
    237            SelectorMatchingResult::Matched => KleeneValue::True,
    238            SelectorMatchingResult::Unknown => KleeneValue::Unknown,
    239            SelectorMatchingResult::NotMatchedAndRestartFromClosestLaterSibling
    240            | SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant
    241            | SelectorMatchingResult::NotMatchedGlobally => KleeneValue::False,
    242        }
    243    }
    244 }
    245 
    246 /// Matches a selector, fast-rejecting against a bloom filter.
    247 ///
    248 /// We accept an offset to allow consumers to represent and match against
    249 /// partial selectors (indexed from the right). We use this API design, rather
    250 /// than having the callers pass a SelectorIter, because creating a SelectorIter
    251 /// requires dereferencing the selector to get the length, which adds an
    252 /// unnecessary cache miss for cases when we can fast-reject with AncestorHashes
    253 /// (which the caller can store inline with the selector pointer).
    254 #[inline(always)]
    255 pub fn matches_selector<E>(
    256    selector: &Selector<E::Impl>,
    257    offset: usize,
    258    hashes: Option<&AncestorHashes>,
    259    element: &E,
    260    context: &mut MatchingContext<E::Impl>,
    261 ) -> bool
    262 where
    263    E: Element,
    264 {
    265    let result = matches_selector_kleene(selector, offset, hashes, element, context);
    266    if cfg!(debug_assertions) && result == KleeneValue::Unknown {
    267        debug_assert!(
    268            context
    269                .matching_for_invalidation_comparison()
    270                .unwrap_or(false),
    271            "How did we return unknown?"
    272        );
    273    }
    274    result.to_bool(true)
    275 }
    276 
    277 /// Same as matches_selector, but returns the Kleene value as-is.
    278 #[inline(always)]
    279 pub fn matches_selector_kleene<E>(
    280    selector: &Selector<E::Impl>,
    281    offset: usize,
    282    hashes: Option<&AncestorHashes>,
    283    element: &E,
    284    context: &mut MatchingContext<E::Impl>,
    285 ) -> KleeneValue
    286 where
    287    E: Element,
    288 {
    289    // Use the bloom filter to fast-reject.
    290    if let Some(hashes) = hashes {
    291        if let Some(filter) = context.bloom_filter {
    292            if !selector_may_match(hashes, filter) {
    293                return KleeneValue::False;
    294            }
    295        }
    296    }
    297    matches_complex_selector(
    298        selector.iter_from(offset),
    299        element,
    300        context,
    301        if selector.is_rightmost(offset) {
    302            SubjectOrPseudoElement::Yes
    303        } else {
    304            SubjectOrPseudoElement::No
    305        },
    306    )
    307 }
    308 
    309 /// Whether a compound selector matched, and whether it was the rightmost
    310 /// selector inside the complex selector.
    311 pub enum CompoundSelectorMatchingResult {
    312    /// The selector was fully matched.
    313    FullyMatched,
    314    /// The compound selector matched, and the next combinator offset is
    315    /// `next_combinator_offset`.
    316    Matched { next_combinator_offset: usize },
    317    /// The selector didn't match.
    318    NotMatched,
    319 }
    320 
    321 fn complex_selector_early_reject_by_local_name<E: Element>(
    322    list: &SelectorList<E::Impl>,
    323    element: &E,
    324 ) -> bool {
    325    list.slice()
    326        .iter()
    327        .all(|s| early_reject_by_local_name(s, 0, element))
    328 }
    329 
    330 /// Returns true if this compound would not match the given element by due
    331 /// to a local name selector (If one exists).
    332 pub fn early_reject_by_local_name<E: Element>(
    333    selector: &Selector<E::Impl>,
    334    from_offset: usize,
    335    element: &E,
    336 ) -> bool {
    337    let iter = selector.iter_from(from_offset);
    338    for component in iter {
    339        if match component {
    340            Component::LocalName(name) => !matches_local_name(element, name),
    341            Component::Is(list) | Component::Where(list) => {
    342                complex_selector_early_reject_by_local_name(list, element)
    343            },
    344            _ => continue,
    345        } {
    346            return true;
    347        }
    348    }
    349    false
    350 }
    351 
    352 /// Matches a compound selector belonging to `selector`, starting at offset
    353 /// `from_offset`, matching left to right.
    354 ///
    355 /// Requires that `from_offset` points to a `Combinator`.
    356 ///
    357 /// NOTE(emilio): This doesn't allow to match in the leftmost sequence of the
    358 /// complex selector, but it happens to be the case we don't need it.
    359 pub fn matches_compound_selector_from<E>(
    360    selector: &Selector<E::Impl>,
    361    mut from_offset: usize,
    362    context: &mut MatchingContext<E::Impl>,
    363    element: &E,
    364 ) -> CompoundSelectorMatchingResult
    365 where
    366    E: Element,
    367 {
    368    debug_assert!(
    369        !context
    370            .matching_for_invalidation_comparison()
    371            .unwrap_or(false),
    372        "CompoundSelectorMatchingResult doesn't support unknown"
    373    );
    374    if cfg!(debug_assertions) && from_offset != 0 {
    375        selector.combinator_at_parse_order(from_offset - 1); // This asserts.
    376    }
    377 
    378    let mut local_context = LocalMatchingContext {
    379        shared: context,
    380        // We have no info if this is an outer selector. This function is called in
    381        // an invalidation context, which only calls this for non-subject (i.e.
    382        // Non-rightmost) positions.
    383        rightmost: SubjectOrPseudoElement::No,
    384        quirks_data: None,
    385    };
    386 
    387    // Find the end of the selector or the next combinator, then match
    388    // backwards, so that we match in the same order as
    389    // matches_complex_selector, which is usually faster.
    390    let start_offset = from_offset;
    391    for component in selector.iter_raw_parse_order_from(from_offset) {
    392        if matches!(*component, Component::Combinator(..)) {
    393            debug_assert_ne!(from_offset, 0, "Selector started with a combinator?");
    394            break;
    395        }
    396 
    397        from_offset += 1;
    398    }
    399 
    400    debug_assert!(from_offset >= 1);
    401    debug_assert!(from_offset <= selector.len());
    402 
    403    let iter = selector.iter_from(selector.len() - from_offset);
    404    debug_assert!(
    405        iter.clone().next().is_some() || from_offset != selector.len(),
    406        "Got the math wrong: {:?} | {:?} | {} {}",
    407        selector,
    408        selector.iter_raw_match_order().as_slice(),
    409        from_offset,
    410        start_offset
    411    );
    412 
    413    debug_assert!(
    414        !local_context.shared.featureless(),
    415        "Invalidating featureless element somehow?"
    416    );
    417 
    418    for component in iter {
    419        let result = matches_simple_selector(component, element, &mut local_context);
    420        debug_assert!(
    421            result != KleeneValue::Unknown,
    422            "Returned unknown in non invalidation context?"
    423        );
    424        if !result.to_bool(true) {
    425            return CompoundSelectorMatchingResult::NotMatched;
    426        }
    427    }
    428 
    429    if from_offset != selector.len() {
    430        return CompoundSelectorMatchingResult::Matched {
    431            next_combinator_offset: from_offset,
    432        };
    433    }
    434 
    435    CompoundSelectorMatchingResult::FullyMatched
    436 }
    437 
    438 /// Matches a complex selector.
    439 #[inline(always)]
    440 fn matches_complex_selector<E>(
    441    mut iter: SelectorIter<E::Impl>,
    442    element: &E,
    443    context: &mut MatchingContext<E::Impl>,
    444    rightmost: SubjectOrPseudoElement,
    445 ) -> KleeneValue
    446 where
    447    E: Element,
    448 {
    449    // If this is the special pseudo-element mode, consume the ::pseudo-element
    450    // before proceeding, since the caller has already handled that part.
    451    if context.matching_mode() == MatchingMode::ForStatelessPseudoElement && !context.is_nested() {
    452        // Consume the pseudo.
    453        match *iter.next().unwrap() {
    454            Component::PseudoElement(ref pseudo) => {
    455                if let Some(ref f) = context.pseudo_element_matching_fn {
    456                    if !f(pseudo) {
    457                        return KleeneValue::False;
    458                    }
    459                }
    460            },
    461            ref other => {
    462                debug_assert!(
    463                    false,
    464                    "Used MatchingMode::ForStatelessPseudoElement \
    465                     in a non-pseudo selector {:?}",
    466                    other
    467                );
    468                return KleeneValue::False;
    469            },
    470        }
    471 
    472        if !iter.matches_for_stateless_pseudo_element() {
    473            return KleeneValue::False;
    474        }
    475 
    476        // Advance to the non-pseudo-element part of the selector.
    477        let next_sequence = iter.next_sequence().unwrap();
    478        debug_assert_eq!(next_sequence, Combinator::PseudoElement);
    479    }
    480 
    481    matches_complex_selector_internal(
    482        iter,
    483        element,
    484        context,
    485        rightmost,
    486        SubjectOrPseudoElement::Yes,
    487    )
    488    .into()
    489 }
    490 
    491 /// Matches each selector of a list as a complex selector
    492 fn matches_complex_selector_list<E: Element>(
    493    list: &[Selector<E::Impl>],
    494    element: &E,
    495    context: &mut MatchingContext<E::Impl>,
    496    rightmost: SubjectOrPseudoElement,
    497 ) -> KleeneValue {
    498    KleeneValue::any(list.iter(), |selector| {
    499        matches_complex_selector(selector.iter(), element, context, rightmost)
    500    })
    501 }
    502 
    503 fn matches_relative_selector<E: Element>(
    504    relative_selector: &RelativeSelector<E::Impl>,
    505    element: &E,
    506    context: &mut MatchingContext<E::Impl>,
    507    rightmost: SubjectOrPseudoElement,
    508 ) -> bool {
    509    // Overall, we want to mark the path that we've traversed so that when an element
    510    // is invalidated, we early-reject unnecessary relative selector invalidations.
    511    if relative_selector.match_hint.is_descendant_direction() {
    512        if context.needs_selector_flags() {
    513            element.apply_selector_flags(
    514                ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR,
    515            );
    516        }
    517        let mut next_element = element.first_element_child();
    518        while let Some(el) = next_element {
    519            if context.needs_selector_flags() {
    520                el.apply_selector_flags(
    521                    ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR,
    522                );
    523            }
    524            let mut matched = matches_complex_selector(
    525                relative_selector.selector.iter(),
    526                &el,
    527                context,
    528                rightmost,
    529            )
    530            .to_bool(true);
    531            if !matched && relative_selector.match_hint.is_subtree() {
    532                matched = matches_relative_selector_subtree(
    533                    &relative_selector.selector,
    534                    &el,
    535                    context,
    536                    rightmost,
    537                );
    538            }
    539            if matched {
    540                return true;
    541            }
    542            next_element = el.next_sibling_element();
    543        }
    544    } else {
    545        debug_assert!(
    546            matches!(
    547                relative_selector.match_hint,
    548                RelativeSelectorMatchHint::InNextSibling
    549                    | RelativeSelectorMatchHint::InNextSiblingSubtree
    550                    | RelativeSelectorMatchHint::InSibling
    551                    | RelativeSelectorMatchHint::InSiblingSubtree
    552            ),
    553            "Not descendant direction, but also not sibling direction?"
    554        );
    555        if context.needs_selector_flags() {
    556            element.apply_selector_flags(
    557                ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING,
    558            );
    559        }
    560        let sibling_flag = if relative_selector.match_hint.is_subtree() {
    561            ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR_SIBLING
    562        } else {
    563            ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING
    564        };
    565        let mut next_element = element.next_sibling_element();
    566        while let Some(el) = next_element {
    567            if context.needs_selector_flags() {
    568                el.apply_selector_flags(sibling_flag);
    569            }
    570            let matched = if relative_selector.match_hint.is_subtree() {
    571                matches_relative_selector_subtree(
    572                    &relative_selector.selector,
    573                    &el,
    574                    context,
    575                    rightmost,
    576                )
    577            } else {
    578                matches_complex_selector(relative_selector.selector.iter(), &el, context, rightmost)
    579                    .to_bool(true)
    580            };
    581            if matched {
    582                return true;
    583            }
    584            if relative_selector.match_hint.is_next_sibling() {
    585                break;
    586            }
    587            next_element = el.next_sibling_element();
    588        }
    589    }
    590    return false;
    591 }
    592 
    593 fn relative_selector_match_early<E: Element>(
    594    selector: &RelativeSelector<E::Impl>,
    595    element: &E,
    596    context: &mut MatchingContext<E::Impl>,
    597 ) -> Option<bool> {
    598    // See if we can return a cached result.
    599    if let Some(cached) = context
    600        .selector_caches
    601        .relative_selector
    602        .lookup(element.opaque(), selector)
    603    {
    604        return Some(cached.matched());
    605    }
    606    // See if we can fast-reject.
    607    if context
    608        .selector_caches
    609        .relative_selector_filter_map
    610        .fast_reject(element, selector, context.quirks_mode())
    611    {
    612        // Alright, add as unmatched to cache.
    613        context.selector_caches.relative_selector.add(
    614            element.opaque(),
    615            selector,
    616            RelativeSelectorCachedMatch::NotMatched,
    617        );
    618        return Some(false);
    619    }
    620    None
    621 }
    622 
    623 fn match_relative_selectors<E: Element>(
    624    selectors: &[RelativeSelector<E::Impl>],
    625    element: &E,
    626    context: &mut MatchingContext<E::Impl>,
    627    rightmost: SubjectOrPseudoElement,
    628 ) -> KleeneValue {
    629    if context.relative_selector_anchor().is_some() {
    630        // FIXME(emilio): This currently can happen with nesting, and it's not fully
    631        // correct, arguably. But the ideal solution isn't super-clear either. For now,
    632        // cope with it and explicitly reject it at match time. See [1] for discussion.
    633        //
    634        // [1]: https://github.com/w3c/csswg-drafts/issues/9600
    635        return KleeneValue::False;
    636    }
    637    if let Some(may_return_unknown) = context.matching_for_invalidation_comparison() {
    638        // In the context of invalidation, :has is expensive, especially because we
    639        // can't use caching/filtering due to now/then matches. DOM structure also
    640        // may have changed.
    641        return if may_return_unknown {
    642            KleeneValue::Unknown
    643        } else {
    644            KleeneValue::from(!context.in_negation())
    645        };
    646    }
    647    context
    648        .nest_for_relative_selector(element.opaque(), |context| {
    649            do_match_relative_selectors(selectors, element, context, rightmost)
    650        })
    651        .into()
    652 }
    653 
    654 /// Matches a relative selector in a list of relative selectors.
    655 fn do_match_relative_selectors<E: Element>(
    656    selectors: &[RelativeSelector<E::Impl>],
    657    element: &E,
    658    context: &mut MatchingContext<E::Impl>,
    659    rightmost: SubjectOrPseudoElement,
    660 ) -> bool {
    661    // Due to style sharing implications (See style sharing code), we mark the current styling context
    662    // to mark elements considered for :has matching. Additionally, we want to mark the elements themselves,
    663    // since we don't want to indiscriminately invalidate every element as a potential anchor.
    664    if rightmost == SubjectOrPseudoElement::Yes {
    665        if context.needs_selector_flags() {
    666            element.apply_selector_flags(ElementSelectorFlags::ANCHORS_RELATIVE_SELECTOR);
    667        }
    668    } else {
    669        if context.needs_selector_flags() {
    670            element
    671                .apply_selector_flags(ElementSelectorFlags::ANCHORS_RELATIVE_SELECTOR_NON_SUBJECT);
    672        }
    673    }
    674 
    675    for relative_selector in selectors.iter() {
    676        if let Some(result) = relative_selector_match_early(relative_selector, element, context) {
    677            if result {
    678                return true;
    679            }
    680            // Early return indicates no match, continue to next selector.
    681            continue;
    682        }
    683 
    684        let matched = matches_relative_selector(relative_selector, element, context, rightmost);
    685        context.selector_caches.relative_selector.add(
    686            element.opaque(),
    687            relative_selector,
    688            if matched {
    689                RelativeSelectorCachedMatch::Matched
    690            } else {
    691                RelativeSelectorCachedMatch::NotMatched
    692            },
    693        );
    694        if matched {
    695            return true;
    696        }
    697    }
    698 
    699    false
    700 }
    701 
    702 fn matches_relative_selector_subtree<E: Element>(
    703    selector: &Selector<E::Impl>,
    704    element: &E,
    705    context: &mut MatchingContext<E::Impl>,
    706    rightmost: SubjectOrPseudoElement,
    707 ) -> bool {
    708    let mut current = element.first_element_child();
    709 
    710    while let Some(el) = current {
    711        if context.needs_selector_flags() {
    712            el.apply_selector_flags(
    713                ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR,
    714            );
    715        }
    716        if matches_complex_selector(selector.iter(), &el, context, rightmost).to_bool(true) {
    717            return true;
    718        }
    719 
    720        if matches_relative_selector_subtree(selector, &el, context, rightmost) {
    721            return true;
    722        }
    723 
    724        current = el.next_sibling_element();
    725    }
    726 
    727    false
    728 }
    729 
    730 /// Whether the :hover and :active quirk applies.
    731 ///
    732 /// https://quirks.spec.whatwg.org/#the-active-and-hover-quirk
    733 fn hover_and_active_quirk_applies<Impl: SelectorImpl>(
    734    selector_iter: &SelectorIter<Impl>,
    735    context: &MatchingContext<Impl>,
    736    rightmost: SubjectOrPseudoElement,
    737 ) -> bool {
    738    debug_assert_eq!(context.quirks_mode(), QuirksMode::Quirks);
    739 
    740    if context.is_nested() {
    741        return false;
    742    }
    743 
    744    // This compound selector had a pseudo-element to the right that we
    745    // intentionally skipped.
    746    if rightmost == SubjectOrPseudoElement::Yes
    747        && context.matching_mode() == MatchingMode::ForStatelessPseudoElement
    748    {
    749        return false;
    750    }
    751 
    752    selector_iter.clone().all(|simple| match *simple {
    753        Component::NonTSPseudoClass(ref pseudo_class) => pseudo_class.is_active_or_hover(),
    754        _ => false,
    755    })
    756 }
    757 
    758 #[derive(Clone, Copy, PartialEq)]
    759 enum SubjectOrPseudoElement {
    760    Yes,
    761    No,
    762 }
    763 
    764 fn host_for_part<E>(element: &E, context: &MatchingContext<E::Impl>) -> Option<E>
    765 where
    766    E: Element,
    767 {
    768    let scope = context.current_host;
    769    let mut curr = element.containing_shadow_host()?;
    770    if scope == Some(curr.opaque()) {
    771        return Some(curr);
    772    }
    773    loop {
    774        let parent = curr.containing_shadow_host();
    775        if parent.as_ref().map(|h| h.opaque()) == scope {
    776            return Some(curr);
    777        }
    778        curr = parent?;
    779    }
    780 }
    781 
    782 fn assigned_slot<E>(element: &E, context: &MatchingContext<E::Impl>) -> Option<E>
    783 where
    784    E: Element,
    785 {
    786    debug_assert!(element
    787        .assigned_slot()
    788        .map_or(true, |s| s.is_html_slot_element()));
    789    let scope = context.current_host?;
    790    let mut current_slot = element.assigned_slot()?;
    791    while current_slot.containing_shadow_host().unwrap().opaque() != scope {
    792        current_slot = current_slot.assigned_slot()?;
    793    }
    794    Some(current_slot)
    795 }
    796 
    797 struct NextElement<E> {
    798    next_element: Option<E>,
    799    featureless: bool,
    800 }
    801 
    802 impl<E> NextElement<E> {
    803    #[inline(always)]
    804    fn new(next_element: Option<E>, featureless: bool) -> Self {
    805        Self {
    806            next_element,
    807            featureless,
    808        }
    809    }
    810 }
    811 
    812 #[inline(always)]
    813 fn next_element_for_combinator<E>(
    814    element: &E,
    815    combinator: Combinator,
    816    context: &MatchingContext<E::Impl>,
    817 ) -> NextElement<E>
    818 where
    819    E: Element,
    820 {
    821    match combinator {
    822        Combinator::NextSibling | Combinator::LaterSibling => {
    823            NextElement::new(element.prev_sibling_element(), false)
    824        },
    825        Combinator::Child | Combinator::Descendant => {
    826            if let Some(parent) = element.parent_element() {
    827                return NextElement::new(Some(parent), false);
    828            }
    829 
    830            let element = if element.parent_node_is_shadow_root() {
    831                element.containing_shadow_host()
    832            } else {
    833                None
    834            };
    835            NextElement::new(element, true)
    836        },
    837        Combinator::Part => NextElement::new(host_for_part(element, context), false),
    838        Combinator::SlotAssignment => NextElement::new(assigned_slot(element, context), false),
    839        Combinator::PseudoElement => {
    840            NextElement::new(element.pseudo_element_originating_element(), false)
    841        },
    842    }
    843 }
    844 
    845 fn matches_complex_selector_internal<E>(
    846    mut selector_iter: SelectorIter<E::Impl>,
    847    element: &E,
    848    context: &mut MatchingContext<E::Impl>,
    849    mut rightmost: SubjectOrPseudoElement,
    850    mut first_subject_compound: SubjectOrPseudoElement,
    851 ) -> SelectorMatchingResult
    852 where
    853    E: Element,
    854 {
    855    debug!(
    856        "Matching complex selector {:?} for {:?}",
    857        selector_iter, element
    858    );
    859 
    860    let matches_compound_selector =
    861        matches_compound_selector(&mut selector_iter, element, context, rightmost);
    862 
    863    let Some(combinator) = selector_iter.next_sequence() else {
    864        return match matches_compound_selector {
    865            KleeneValue::True => SelectorMatchingResult::Matched,
    866            KleeneValue::Unknown => SelectorMatchingResult::Unknown,
    867            KleeneValue::False => {
    868                SelectorMatchingResult::NotMatchedAndRestartFromClosestLaterSibling
    869            },
    870        };
    871    };
    872 
    873    let is_pseudo_combinator = combinator.is_pseudo_element();
    874    if context.featureless() && !is_pseudo_combinator {
    875        // A featureless element shouldn't match any further combinator.
    876        // TODO(emilio): Maybe we could avoid the compound matching more eagerly.
    877        return SelectorMatchingResult::NotMatchedGlobally;
    878    }
    879 
    880    let is_sibling_combinator = combinator.is_sibling();
    881    if is_sibling_combinator && context.needs_selector_flags() {
    882        // We need the flags even if we don't match.
    883        element.apply_selector_flags(ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS);
    884    }
    885 
    886    if matches_compound_selector == KleeneValue::False {
    887        // We don't short circuit unknown here, since the rest of the selector
    888        // to the left of this compound may still return false.
    889        return SelectorMatchingResult::NotMatchedAndRestartFromClosestLaterSibling;
    890    }
    891 
    892    if !is_pseudo_combinator {
    893        rightmost = SubjectOrPseudoElement::No;
    894        first_subject_compound = SubjectOrPseudoElement::No;
    895    }
    896 
    897    // Stop matching :visited as soon as we find a link, or a combinator for
    898    // something that isn't an ancestor.
    899    let mut visited_handling = if is_sibling_combinator {
    900        VisitedHandlingMode::AllLinksUnvisited
    901    } else {
    902        context.visited_handling()
    903    };
    904 
    905    let candidate_not_found = if is_sibling_combinator {
    906        SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant
    907    } else {
    908        SelectorMatchingResult::NotMatchedGlobally
    909    };
    910 
    911    let mut element = element.clone();
    912    loop {
    913        if element.is_link() {
    914            visited_handling = VisitedHandlingMode::AllLinksUnvisited;
    915        }
    916 
    917        let NextElement {
    918            next_element,
    919            featureless,
    920        } = next_element_for_combinator(&element, combinator, &context);
    921        element = match next_element {
    922            None => return candidate_not_found,
    923            Some(e) => e,
    924        };
    925 
    926        let result = context.with_visited_handling_mode(visited_handling, |context| {
    927            context.with_featureless(featureless, |context| {
    928                matches_complex_selector_internal(
    929                    selector_iter.clone(),
    930                    &element,
    931                    context,
    932                    rightmost,
    933                    first_subject_compound,
    934                )
    935            })
    936        });
    937 
    938        // Return the status immediately if it is one of the global states.
    939        match result {
    940            SelectorMatchingResult::Matched => {
    941                debug_assert!(
    942                    matches_compound_selector.to_bool(true),
    943                    "Compound didn't match?"
    944                );
    945                if !matches_compound_selector.to_bool(false) {
    946                    return SelectorMatchingResult::Unknown;
    947                }
    948                return result;
    949            },
    950            SelectorMatchingResult::Unknown | SelectorMatchingResult::NotMatchedGlobally => {
    951                return result
    952            },
    953            _ => {},
    954        }
    955 
    956        match combinator {
    957            Combinator::Descendant => {
    958                // The Descendant combinator and the status is
    959                // NotMatchedAndRestartFromClosestLaterSibling or
    960                // NotMatchedAndRestartFromClosestDescendant, or the LaterSibling combinator and
    961                // the status is NotMatchedAndRestartFromClosestDescendant, we can continue to
    962                // matching on the next candidate element.
    963            },
    964            Combinator::Child => {
    965                // Upgrade the failure status to NotMatchedAndRestartFromClosestDescendant.
    966                return SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant;
    967            },
    968            Combinator::LaterSibling => {
    969                // If the failure status is NotMatchedAndRestartFromClosestDescendant and combinator is
    970                // LaterSibling, give up this LaterSibling matching and restart from the closest
    971                // descendant combinator.
    972                if matches!(
    973                    result,
    974                    SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant
    975                ) {
    976                    return result;
    977                }
    978            },
    979            Combinator::NextSibling
    980            | Combinator::PseudoElement
    981            | Combinator::Part
    982            | Combinator::SlotAssignment => {
    983                // NOTE(emilio): Conceptually, PseudoElement / Part / SlotAssignment should return
    984                // `candidate_not_found`, but it doesn't matter in practice since they don't have
    985                // sibling / descendant combinators to the right of them. This hopefully saves one
    986                // branch.
    987                return result;
    988            },
    989        }
    990 
    991        if featureless {
    992            // A featureless element didn't match the selector, we can stop matching now rather
    993            // than looking at following elements for our combinator.
    994            return candidate_not_found;
    995        }
    996    }
    997 }
    998 
    999 #[inline]
   1000 fn matches_local_name<E>(element: &E, local_name: &LocalName<E::Impl>) -> bool
   1001 where
   1002    E: Element,
   1003 {
   1004    let name = select_name(element, &local_name.name, &local_name.lower_name).borrow();
   1005    element.has_local_name(name)
   1006 }
   1007 
   1008 fn matches_part<E>(
   1009    element: &E,
   1010    parts: &[<E::Impl as SelectorImpl>::Identifier],
   1011    context: &mut MatchingContext<E::Impl>,
   1012 ) -> bool
   1013 where
   1014    E: Element,
   1015 {
   1016    let mut hosts = SmallVec::<[E; 4]>::new();
   1017 
   1018    let mut host = match element.containing_shadow_host() {
   1019        Some(h) => h,
   1020        None => return false,
   1021    };
   1022 
   1023    let current_host = context.current_host;
   1024    if current_host != Some(host.opaque()) {
   1025        loop {
   1026            let outer_host = host.containing_shadow_host();
   1027            if outer_host.as_ref().map(|h| h.opaque()) == current_host {
   1028                break;
   1029            }
   1030            let outer_host = match outer_host {
   1031                Some(h) => h,
   1032                None => return false,
   1033            };
   1034            // TODO(emilio): if worth it, we could early return if
   1035            // host doesn't have the exportparts attribute.
   1036            hosts.push(host);
   1037            host = outer_host;
   1038        }
   1039    }
   1040 
   1041    // Translate the part into the right scope.
   1042    parts.iter().all(|part| {
   1043        let mut part = part.clone();
   1044        for host in hosts.iter().rev() {
   1045            part = match host.imported_part(&part) {
   1046                Some(p) => p,
   1047                None => return false,
   1048            };
   1049        }
   1050        element.is_part(&part)
   1051    })
   1052 }
   1053 
   1054 fn matches_host<E>(
   1055    element: &E,
   1056    selector: Option<&Selector<E::Impl>>,
   1057    context: &mut MatchingContext<E::Impl>,
   1058    rightmost: SubjectOrPseudoElement,
   1059 ) -> KleeneValue
   1060 where
   1061    E: Element,
   1062 {
   1063    let host = match context.shadow_host() {
   1064        Some(h) => h,
   1065        None => return KleeneValue::False,
   1066    };
   1067    if host != element.opaque() {
   1068        return KleeneValue::False;
   1069    }
   1070    let Some(selector) = selector else {
   1071        return KleeneValue::True;
   1072    };
   1073    context.nest(|context| {
   1074        context.with_featureless(false, |context| {
   1075            matches_complex_selector(selector.iter(), element, context, rightmost)
   1076        })
   1077    })
   1078 }
   1079 
   1080 fn matches_slotted<E>(
   1081    element: &E,
   1082    selector: &Selector<E::Impl>,
   1083    context: &mut MatchingContext<E::Impl>,
   1084    rightmost: SubjectOrPseudoElement,
   1085 ) -> KleeneValue
   1086 where
   1087    E: Element,
   1088 {
   1089    // <slots> are never flattened tree slottables.
   1090    if element.is_html_slot_element() {
   1091        return KleeneValue::False;
   1092    }
   1093    context.nest(|context| matches_complex_selector(selector.iter(), element, context, rightmost))
   1094 }
   1095 
   1096 fn matches_rare_attribute_selector<E>(
   1097    element: &E,
   1098    attr_sel: &AttrSelectorWithOptionalNamespace<E::Impl>,
   1099 ) -> bool
   1100 where
   1101    E: Element,
   1102 {
   1103    let empty_string;
   1104    let namespace = match attr_sel.namespace() {
   1105        Some(ns) => ns,
   1106        None => {
   1107            empty_string = crate::parser::namespace_empty_string::<E::Impl>();
   1108            NamespaceConstraint::Specific(&empty_string)
   1109        },
   1110    };
   1111    element.attr_matches(
   1112        &namespace,
   1113        select_name(element, &attr_sel.local_name, &attr_sel.local_name_lower),
   1114        &match attr_sel.operation {
   1115            ParsedAttrSelectorOperation::Exists => AttrSelectorOperation::Exists,
   1116            ParsedAttrSelectorOperation::WithValue {
   1117                operator,
   1118                case_sensitivity,
   1119                ref value,
   1120            } => AttrSelectorOperation::WithValue {
   1121                operator,
   1122                case_sensitivity: to_unconditional_case_sensitivity(case_sensitivity, element),
   1123                value,
   1124            },
   1125        },
   1126    )
   1127 }
   1128 
   1129 /// There are relatively few selectors in a given compound that may match a featureless element.
   1130 /// Instead of adding a check to every selector that may not match, we handle it here in an out of
   1131 /// line path.
   1132 pub(crate) fn compound_matches_featureless_host<Impl: SelectorImpl>(
   1133    iter: &mut SelectorIter<Impl>,
   1134    scope_matches_featureless_host: bool,
   1135 ) -> MatchesFeaturelessHost {
   1136    let mut matches = MatchesFeaturelessHost::Only;
   1137    for component in iter {
   1138        match component {
   1139            Component::Scope | Component::ImplicitScope if scope_matches_featureless_host => {},
   1140            // :host only matches featureless elements.
   1141            Component::Host(..) => {},
   1142            // Pseudo-elements are allowed to match as well.
   1143            Component::PseudoElement(..) => {},
   1144            // We allow logical pseudo-classes, but we'll fail matching of the inner selectors if
   1145            // necessary.
   1146            Component::Is(ref l) | Component::Where(ref l) => {
   1147                let mut any_yes = false;
   1148                let mut any_no = false;
   1149                for selector in l.slice() {
   1150                    match selector.matches_featureless_host(scope_matches_featureless_host) {
   1151                        MatchesFeaturelessHost::Never => {
   1152                            any_no = true;
   1153                        },
   1154                        MatchesFeaturelessHost::Yes => {
   1155                            any_yes = true;
   1156                            any_no = true;
   1157                        },
   1158                        MatchesFeaturelessHost::Only => {
   1159                            any_yes = true;
   1160                        },
   1161                    }
   1162                }
   1163                if !any_yes {
   1164                    return MatchesFeaturelessHost::Never;
   1165                }
   1166                if any_no {
   1167                    // Potentially downgrade since we might match non-featureless elements too.
   1168                    matches = MatchesFeaturelessHost::Yes;
   1169                }
   1170            },
   1171            Component::Negation(ref l) => {
   1172                // For now preserving behavior, see
   1173                // https://github.com/w3c/csswg-drafts/issues/10179 for existing resolutions that
   1174                // tweak this behavior.
   1175                for selector in l.slice() {
   1176                    if selector.matches_featureless_host(scope_matches_featureless_host)
   1177                        != MatchesFeaturelessHost::Only
   1178                    {
   1179                        return MatchesFeaturelessHost::Never;
   1180                    }
   1181                }
   1182            },
   1183            // Other components don't match the host scope.
   1184            _ => return MatchesFeaturelessHost::Never,
   1185        }
   1186    }
   1187    matches
   1188 }
   1189 
   1190 /// Determines whether the given element matches the given compound selector.
   1191 #[inline]
   1192 fn matches_compound_selector<E>(
   1193    selector_iter: &mut SelectorIter<E::Impl>,
   1194    element: &E,
   1195    context: &mut MatchingContext<E::Impl>,
   1196    rightmost: SubjectOrPseudoElement,
   1197 ) -> KleeneValue
   1198 where
   1199    E: Element,
   1200 {
   1201    if context.featureless()
   1202        && compound_matches_featureless_host(
   1203            &mut selector_iter.clone(),
   1204            /* scope_matches_featureless_host = */ true,
   1205        ) == MatchesFeaturelessHost::Never
   1206    {
   1207        return KleeneValue::False;
   1208    }
   1209    let quirks_data = if context.quirks_mode() == QuirksMode::Quirks {
   1210        Some(selector_iter.clone())
   1211    } else {
   1212        None
   1213    };
   1214    let mut local_context = LocalMatchingContext {
   1215        shared: context,
   1216        rightmost,
   1217        quirks_data,
   1218    };
   1219    KleeneValue::any_false(selector_iter, |simple| {
   1220        matches_simple_selector(simple, element, &mut local_context)
   1221    })
   1222 }
   1223 
   1224 /// Determines whether the given element matches the given single selector.
   1225 fn matches_simple_selector<E>(
   1226    selector: &Component<E::Impl>,
   1227    element: &E,
   1228    context: &mut LocalMatchingContext<E::Impl>,
   1229 ) -> KleeneValue
   1230 where
   1231    E: Element,
   1232 {
   1233    debug_assert!(context.shared.is_nested() || !context.shared.in_negation());
   1234    let rightmost = context.rightmost;
   1235    KleeneValue::from(match *selector {
   1236        Component::ID(ref id) => {
   1237            element.has_id(id, context.shared.classes_and_ids_case_sensitivity())
   1238        },
   1239        Component::Class(ref class) => {
   1240            element.has_class(class, context.shared.classes_and_ids_case_sensitivity())
   1241        },
   1242        Component::LocalName(ref local_name) => matches_local_name(element, local_name),
   1243        Component::AttributeInNoNamespaceExists {
   1244            ref local_name,
   1245            ref local_name_lower,
   1246        } => element.has_attr_in_no_namespace(select_name(element, local_name, local_name_lower)),
   1247        Component::AttributeInNoNamespace {
   1248            ref local_name,
   1249            ref value,
   1250            operator,
   1251            case_sensitivity,
   1252        } => element.attr_matches(
   1253            &NamespaceConstraint::Specific(&crate::parser::namespace_empty_string::<E::Impl>()),
   1254            local_name,
   1255            &AttrSelectorOperation::WithValue {
   1256                operator,
   1257                case_sensitivity: to_unconditional_case_sensitivity(case_sensitivity, element),
   1258                value,
   1259            },
   1260        ),
   1261        Component::AttributeOther(ref attr_sel) => {
   1262            matches_rare_attribute_selector(element, attr_sel)
   1263        },
   1264        Component::Part(ref parts) => matches_part(element, parts, &mut context.shared),
   1265        Component::Slotted(ref selector) => {
   1266            return matches_slotted(element, selector, &mut context.shared, rightmost);
   1267        },
   1268        Component::PseudoElement(ref pseudo) => {
   1269            element.match_pseudo_element(pseudo, context.shared)
   1270        },
   1271        Component::ExplicitUniversalType | Component::ExplicitAnyNamespace => true,
   1272        Component::Namespace(_, ref url) | Component::DefaultNamespace(ref url) => {
   1273            element.has_namespace(&url.borrow())
   1274        },
   1275        Component::ExplicitNoNamespace => {
   1276            let ns = crate::parser::namespace_empty_string::<E::Impl>();
   1277            element.has_namespace(&ns.borrow())
   1278        },
   1279        Component::NonTSPseudoClass(ref pc) => {
   1280            if let Some(ref iter) = context.quirks_data {
   1281                if pc.is_active_or_hover()
   1282                    && !element.is_link()
   1283                    && hover_and_active_quirk_applies(iter, context.shared, context.rightmost)
   1284                {
   1285                    return KleeneValue::False;
   1286                }
   1287            }
   1288            element.match_non_ts_pseudo_class(pc, &mut context.shared)
   1289        },
   1290        Component::Root => element.is_root(),
   1291        Component::Empty => {
   1292            if context.shared.needs_selector_flags() {
   1293                element.apply_selector_flags(ElementSelectorFlags::HAS_EMPTY_SELECTOR);
   1294            }
   1295            element.is_empty()
   1296        },
   1297        Component::Host(ref selector) => {
   1298            return matches_host(element, selector.as_ref(), &mut context.shared, rightmost);
   1299        },
   1300        Component::ParentSelector => match context.shared.scope_element {
   1301            Some(ref scope_element) => element.opaque() == *scope_element,
   1302            None => element.is_root(),
   1303        },
   1304        Component::Scope | Component::ImplicitScope => {
   1305            if let Some(may_return_unknown) = context.shared.matching_for_invalidation_comparison()
   1306            {
   1307                return if may_return_unknown {
   1308                    KleeneValue::Unknown
   1309                } else {
   1310                    KleeneValue::from(!context.shared.in_negation())
   1311                };
   1312            } else {
   1313                match context.shared.scope_element {
   1314                    Some(ref scope_element) => element.opaque() == *scope_element,
   1315                    None => element.is_root(),
   1316                }
   1317            }
   1318        },
   1319        Component::Nth(ref nth_data) => {
   1320            return matches_generic_nth_child(element, context.shared, nth_data, &[], rightmost);
   1321        },
   1322        Component::NthOf(ref nth_of_data) => {
   1323            return context.shared.nest(|context| {
   1324                matches_generic_nth_child(
   1325                    element,
   1326                    context,
   1327                    nth_of_data.nth_data(),
   1328                    nth_of_data.selectors(),
   1329                    rightmost,
   1330                )
   1331            })
   1332        },
   1333        Component::Is(ref list) | Component::Where(ref list) => {
   1334            return context.shared.nest(|context| {
   1335                matches_complex_selector_list(list.slice(), element, context, rightmost)
   1336            })
   1337        },
   1338        Component::Negation(ref list) => {
   1339            return context.shared.nest_for_negation(|context| {
   1340                !matches_complex_selector_list(list.slice(), element, context, rightmost)
   1341            })
   1342        },
   1343        Component::Has(ref relative_selectors) => {
   1344            return match_relative_selectors(
   1345                relative_selectors,
   1346                element,
   1347                context.shared,
   1348                rightmost,
   1349            );
   1350        },
   1351        Component::Combinator(_) => unsafe {
   1352            debug_unreachable!("Shouldn't try to selector-match combinators")
   1353        },
   1354        Component::RelativeSelectorAnchor => {
   1355            let anchor = context.shared.relative_selector_anchor();
   1356            // We may match inner relative selectors, in which case we want to always match.
   1357            anchor.map_or(true, |a| a == element.opaque())
   1358        },
   1359        Component::Invalid(..) => false,
   1360    })
   1361 }
   1362 
   1363 #[inline(always)]
   1364 pub fn select_name<'a, E: Element, T: PartialEq>(
   1365    element: &E,
   1366    local_name: &'a T,
   1367    local_name_lower: &'a T,
   1368 ) -> &'a T {
   1369    if local_name == local_name_lower || element.is_html_element_in_html_document() {
   1370        local_name_lower
   1371    } else {
   1372        local_name
   1373    }
   1374 }
   1375 
   1376 #[inline(always)]
   1377 pub fn to_unconditional_case_sensitivity<'a, E: Element>(
   1378    parsed: ParsedCaseSensitivity,
   1379    element: &E,
   1380 ) -> CaseSensitivity {
   1381    match parsed {
   1382        ParsedCaseSensitivity::CaseSensitive | ParsedCaseSensitivity::ExplicitCaseSensitive => {
   1383            CaseSensitivity::CaseSensitive
   1384        },
   1385        ParsedCaseSensitivity::AsciiCaseInsensitive => CaseSensitivity::AsciiCaseInsensitive,
   1386        ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {
   1387            if element.is_html_element_in_html_document() {
   1388                CaseSensitivity::AsciiCaseInsensitive
   1389            } else {
   1390                CaseSensitivity::CaseSensitive
   1391            }
   1392        },
   1393    }
   1394 }
   1395 
   1396 fn matches_generic_nth_child<E>(
   1397    element: &E,
   1398    context: &mut MatchingContext<E::Impl>,
   1399    nth_data: &NthSelectorData,
   1400    selectors: &[Selector<E::Impl>],
   1401    rightmost: SubjectOrPseudoElement,
   1402 ) -> KleeneValue
   1403 where
   1404    E: Element,
   1405 {
   1406    if element.ignores_nth_child_selectors() {
   1407        return KleeneValue::False;
   1408    }
   1409    let has_selectors = !selectors.is_empty();
   1410    let selectors_match = !has_selectors
   1411        || matches_complex_selector_list(selectors, element, context, rightmost).to_bool(true);
   1412    if let Some(may_return_unknown) = context.matching_for_invalidation_comparison() {
   1413        // Skip expensive indexing math in invalidation.
   1414        return if selectors_match && may_return_unknown {
   1415            KleeneValue::Unknown
   1416        } else {
   1417            KleeneValue::from(selectors_match && !context.in_negation())
   1418        };
   1419    }
   1420 
   1421    let NthSelectorData { ty, an_plus_b, .. } = *nth_data;
   1422    let is_of_type = ty.is_of_type();
   1423    if ty.is_only() {
   1424        debug_assert!(
   1425            !has_selectors,
   1426            ":only-child and :only-of-type cannot have a selector list!"
   1427        );
   1428        return KleeneValue::from(
   1429            matches_generic_nth_child(
   1430                element,
   1431                context,
   1432                &NthSelectorData::first(is_of_type),
   1433                selectors,
   1434                rightmost,
   1435            )
   1436            .to_bool(true)
   1437                && matches_generic_nth_child(
   1438                    element,
   1439                    context,
   1440                    &NthSelectorData::last(is_of_type),
   1441                    selectors,
   1442                    rightmost,
   1443                )
   1444                .to_bool(true),
   1445        );
   1446    }
   1447 
   1448    let is_from_end = ty.is_from_end();
   1449 
   1450    // It's useful to know whether this can only select the first/last element
   1451    // child for optimization purposes, see the `HAS_EDGE_CHILD_SELECTOR` flag.
   1452    let is_edge_child_selector = nth_data.is_simple_edge() && !has_selectors;
   1453 
   1454    if context.needs_selector_flags() {
   1455        let mut flags = if is_edge_child_selector {
   1456            ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR
   1457        } else if is_from_end {
   1458            ElementSelectorFlags::HAS_SLOW_SELECTOR
   1459        } else {
   1460            ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS
   1461        };
   1462        flags |= if has_selectors {
   1463            ElementSelectorFlags::HAS_SLOW_SELECTOR_NTH_OF
   1464        } else {
   1465            ElementSelectorFlags::HAS_SLOW_SELECTOR_NTH
   1466        };
   1467        element.apply_selector_flags(flags);
   1468    }
   1469 
   1470    if !selectors_match {
   1471        return KleeneValue::False;
   1472    }
   1473 
   1474    // :first/last-child are rather trivial to match, don't bother with the
   1475    // cache.
   1476    if is_edge_child_selector {
   1477        return if is_from_end {
   1478            element.next_sibling_element()
   1479        } else {
   1480            element.prev_sibling_element()
   1481        }
   1482        .is_none()
   1483        .into();
   1484    }
   1485 
   1486    // Lookup or compute the index.
   1487    let index = if let Some(i) = context
   1488        .nth_index_cache(is_of_type, is_from_end, selectors)
   1489        .lookup(element.opaque())
   1490    {
   1491        i
   1492    } else {
   1493        let i = nth_child_index(
   1494            element,
   1495            context,
   1496            selectors,
   1497            is_of_type,
   1498            is_from_end,
   1499            /* check_cache = */ true,
   1500            rightmost,
   1501        );
   1502        context
   1503            .nth_index_cache(is_of_type, is_from_end, selectors)
   1504            .insert(element.opaque(), i);
   1505        i
   1506    };
   1507    debug_assert_eq!(
   1508        index,
   1509        nth_child_index(
   1510            element,
   1511            context,
   1512            selectors,
   1513            is_of_type,
   1514            is_from_end,
   1515            /* check_cache = */ false,
   1516            rightmost,
   1517        ),
   1518        "invalid cache"
   1519    );
   1520 
   1521    an_plus_b.matches_index(index).into()
   1522 }
   1523 
   1524 #[inline]
   1525 fn nth_child_index<E>(
   1526    element: &E,
   1527    context: &mut MatchingContext<E::Impl>,
   1528    selectors: &[Selector<E::Impl>],
   1529    is_of_type: bool,
   1530    is_from_end: bool,
   1531    check_cache: bool,
   1532    rightmost: SubjectOrPseudoElement,
   1533 ) -> i32
   1534 where
   1535    E: Element,
   1536 {
   1537    // The traversal mostly processes siblings left to right. So when we walk
   1538    // siblings to the right when computing NthLast/NthLastOfType we're unlikely
   1539    // to get cache hits along the way. As such, we take the hit of walking the
   1540    // siblings to the left checking the cache in the is_from_end case (this
   1541    // matches what Gecko does). The indices-from-the-left is handled during the
   1542    // regular look further below.
   1543    if check_cache
   1544        && is_from_end
   1545        && !context
   1546            .nth_index_cache(is_of_type, is_from_end, selectors)
   1547            .is_empty()
   1548    {
   1549        let mut index: i32 = 1;
   1550        let mut curr = element.clone();
   1551        while let Some(e) = curr.prev_sibling_element() {
   1552            curr = e;
   1553            let matches = if is_of_type {
   1554                element.is_same_type(&curr)
   1555            } else if !selectors.is_empty() {
   1556                matches_complex_selector_list(selectors, &curr, context, rightmost).to_bool(true)
   1557            } else {
   1558                true
   1559            };
   1560            if !matches {
   1561                continue;
   1562            }
   1563            if let Some(i) = context
   1564                .nth_index_cache(is_of_type, is_from_end, selectors)
   1565                .lookup(curr.opaque())
   1566            {
   1567                return i - index;
   1568            }
   1569            index += 1;
   1570        }
   1571    }
   1572 
   1573    let mut index: i32 = 1;
   1574    let mut curr = element.clone();
   1575    let next = |e: E| {
   1576        if is_from_end {
   1577            e.next_sibling_element()
   1578        } else {
   1579            e.prev_sibling_element()
   1580        }
   1581    };
   1582    while let Some(e) = next(curr) {
   1583        curr = e;
   1584        let matches = if is_of_type {
   1585            element.is_same_type(&curr)
   1586        } else if !selectors.is_empty() {
   1587            matches_complex_selector_list(selectors, &curr, context, rightmost).to_bool(true)
   1588        } else {
   1589            true
   1590        };
   1591        if !matches {
   1592            continue;
   1593        }
   1594        // If we're computing indices from the left, check each element in the
   1595        // cache. We handle the indices-from-the-right case at the top of this
   1596        // function.
   1597        if !is_from_end && check_cache {
   1598            if let Some(i) = context
   1599                .nth_index_cache(is_of_type, is_from_end, selectors)
   1600                .lookup(curr.opaque())
   1601            {
   1602                return i + index;
   1603            }
   1604        }
   1605        index += 1;
   1606    }
   1607 
   1608    index
   1609 }