diff options
Diffstat (limited to 'servo/components/selectors/visitor.rs')
-rw-r--r-- | servo/components/selectors/visitor.rs | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/servo/components/selectors/visitor.rs b/servo/components/selectors/visitor.rs new file mode 100644 index 0000000000..69d66630e5 --- /dev/null +++ b/servo/components/selectors/visitor.rs @@ -0,0 +1,111 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +//! Visitor traits for selectors. + +#![deny(missing_docs)] + +use crate::attr::NamespaceConstraint; +use crate::parser::{Combinator, Component, Selector, SelectorImpl}; + +/// A trait to visit selector properties. +/// +/// All the `visit_foo` methods return a boolean indicating whether the +/// traversal should continue or not. +pub trait SelectorVisitor: Sized { + /// The selector implementation this visitor wants to visit. + type Impl: SelectorImpl; + + /// Visit an attribute selector that may match (there are other selectors + /// that may never match, like those containing whitespace or the empty + /// string). + fn visit_attribute_selector( + &mut self, + _namespace: &NamespaceConstraint<&<Self::Impl as SelectorImpl>::NamespaceUrl>, + _local_name: &<Self::Impl as SelectorImpl>::LocalName, + _local_name_lower: &<Self::Impl as SelectorImpl>::LocalName, + ) -> bool { + true + } + + /// Visit a simple selector. + fn visit_simple_selector(&mut self, _: &Component<Self::Impl>) -> bool { + true + } + + /// Visit a nested selector list. The caller is responsible to call visit + /// into the internal selectors if / as needed. + /// + /// The default implementation does this. + fn visit_selector_list( + &mut self, + _list_kind: SelectorListKind, + list: &[Selector<Self::Impl>], + ) -> bool { + for nested in list { + if !nested.visit(self) { + return false; + } + } + true + } + + /// Visits a complex selector. + /// + /// Gets the combinator to the right of the selector, or `None` if the + /// selector is the rightmost one. + fn visit_complex_selector(&mut self, _combinator_to_right: Option<Combinator>) -> bool { + true + } +} + +bitflags! { + /// The kinds of components the visitor is visiting the selector list of, if any + #[derive(Clone, Copy, Default)] + pub struct SelectorListKind: u8 { + /// The visitor is inside :not(..) + const NEGATION = 1 << 0; + /// The visitor is inside :is(..) + const IS = 1 << 1; + /// The visitor is inside :where(..) + const WHERE = 1 << 2; + /// The visitor is inside :nth-child(.. of <selector list>) or + /// :nth-last-child(.. of <selector list>) + const NTH_OF = 1 << 3; + } +} + +impl SelectorListKind { + /// Construct a SelectorListKind for the corresponding component. + pub fn from_component<Impl: SelectorImpl>(component: &Component<Impl>) -> Self { + match component { + Component::Negation(_) => SelectorListKind::NEGATION, + Component::Is(_) => SelectorListKind::IS, + Component::Where(_) => SelectorListKind::WHERE, + Component::NthOf(_) => SelectorListKind::NTH_OF, + _ => SelectorListKind::empty(), + } + } + + /// Whether the visitor is inside :not(..) + pub fn in_negation(&self) -> bool { + self.intersects(SelectorListKind::NEGATION) + } + + /// Whether the visitor is inside :is(..) + pub fn in_is(&self) -> bool { + self.intersects(SelectorListKind::IS) + } + + /// Whether the visitor is inside :where(..) + pub fn in_where(&self) -> bool { + self.intersects(SelectorListKind::WHERE) + } + + /// Whether the visitor is inside :nth-child(.. of <selector list>) or + /// :nth-last-child(.. of <selector list>) + pub fn in_nth_of(&self) -> bool { + self.intersects(SelectorListKind::NTH_OF) + } +} |