tor-browser

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

visitor.rs (4884B)


      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 //! Visitor traits for selectors.
      6 
      7 #![deny(missing_docs)]
      8 
      9 use crate::attr::NamespaceConstraint;
     10 use crate::parser::{Combinator, Component, RelativeSelector, Selector, SelectorImpl};
     11 use bitflags::bitflags;
     12 
     13 /// A trait to visit selector properties.
     14 ///
     15 /// All the `visit_foo` methods return a boolean indicating whether the
     16 /// traversal should continue or not.
     17 pub trait SelectorVisitor: Sized {
     18    /// The selector implementation this visitor wants to visit.
     19    type Impl: SelectorImpl;
     20 
     21    /// Visit an attribute selector that may match (there are other selectors
     22    /// that may never match, like those containing whitespace or the empty
     23    /// string).
     24    fn visit_attribute_selector(
     25        &mut self,
     26        _namespace: &NamespaceConstraint<&<Self::Impl as SelectorImpl>::NamespaceUrl>,
     27        _local_name: &<Self::Impl as SelectorImpl>::LocalName,
     28        _local_name_lower: &<Self::Impl as SelectorImpl>::LocalName,
     29    ) -> bool {
     30        true
     31    }
     32 
     33    /// Visit a simple selector.
     34    fn visit_simple_selector(&mut self, _: &Component<Self::Impl>) -> bool {
     35        true
     36    }
     37 
     38    /// Visit a nested relative selector list. The caller is responsible to call visit
     39    /// into the internal selectors if / as needed.
     40    ///
     41    /// The default implementation skips it altogether.
     42    fn visit_relative_selector_list(&mut self, _list: &[RelativeSelector<Self::Impl>]) -> bool {
     43        true
     44    }
     45 
     46    /// Visit a nested selector list. The caller is responsible to call visit
     47    /// into the internal selectors if / as needed.
     48    ///
     49    /// The default implementation does this.
     50    fn visit_selector_list(
     51        &mut self,
     52        _list_kind: SelectorListKind,
     53        list: &[Selector<Self::Impl>],
     54    ) -> bool {
     55        for nested in list {
     56            if !nested.visit(self) {
     57                return false;
     58            }
     59        }
     60        true
     61    }
     62 
     63    /// Visits a complex selector.
     64    ///
     65    /// Gets the combinator to the right of the selector, or `None` if the
     66    /// selector is the rightmost one.
     67    fn visit_complex_selector(&mut self, _combinator_to_right: Option<Combinator>) -> bool {
     68        true
     69    }
     70 }
     71 
     72 bitflags! {
     73    /// The kinds of components the visitor is visiting the selector list of, if any
     74    #[derive(Clone, Copy, Default)]
     75    pub struct SelectorListKind: u8 {
     76        /// The visitor is inside :not(..)
     77        const NEGATION = 1 << 0;
     78        /// The visitor is inside :is(..)
     79        const IS = 1 << 1;
     80        /// The visitor is inside :where(..)
     81        const WHERE = 1 << 2;
     82        /// The visitor is inside :nth-child(.. of <selector list>) or
     83        /// :nth-last-child(.. of <selector list>)
     84        const NTH_OF = 1 << 3;
     85        /// The visitor is inside :has(..)
     86        const HAS = 1 << 4;
     87    }
     88 }
     89 
     90 impl SelectorListKind {
     91    /// Construct a SelectorListKind for the corresponding component.
     92    pub fn from_component<Impl: SelectorImpl>(component: &Component<Impl>) -> Self {
     93        match component {
     94            Component::Negation(_) => SelectorListKind::NEGATION,
     95            Component::Is(_) => SelectorListKind::IS,
     96            Component::Where(_) => SelectorListKind::WHERE,
     97            Component::NthOf(_) => SelectorListKind::NTH_OF,
     98            _ => SelectorListKind::empty(),
     99        }
    100    }
    101 
    102    /// Whether the visitor is inside :not(..)
    103    pub fn in_negation(&self) -> bool {
    104        self.intersects(SelectorListKind::NEGATION)
    105    }
    106 
    107    /// Whether the visitor is inside :is(..)
    108    pub fn in_is(&self) -> bool {
    109        self.intersects(SelectorListKind::IS)
    110    }
    111 
    112    /// Whether the visitor is inside :where(..)
    113    pub fn in_where(&self) -> bool {
    114        self.intersects(SelectorListKind::WHERE)
    115    }
    116 
    117    /// Whether the visitor is inside :nth-child(.. of <selector list>) or
    118    /// :nth-last-child(.. of <selector list>)
    119    pub fn in_nth_of(&self) -> bool {
    120        self.intersects(SelectorListKind::NTH_OF)
    121    }
    122 
    123    /// Whether the visitor is inside :has(..)
    124    pub fn in_has(&self) -> bool {
    125        self.intersects(SelectorListKind::HAS)
    126    }
    127 
    128    /// Whether this nested selector is relevant for nth-of dependencies.
    129    pub fn relevant_to_nth_of_dependencies(&self) -> bool {
    130        // Order of nesting for `:has` and `:nth-child(.. of ..)` doesn't matter, because:
    131        // * `:has(:nth-child(.. of ..))`: The location of the anchoring element is
    132        //   independent from where `:nth-child(.. of ..)` is applied.
    133        // * `:nth-child(.. of :has(..))`: Invalidations inside `:has` must first use the
    134        //   `:has` machinary to find the anchor, then carry out the remaining invalidation.
    135        self.in_nth_of() && !self.in_has()
    136    }
    137 }