From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- servo/components/selectors/visitor.rs | 136 ++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 servo/components/selectors/visitor.rs (limited to 'servo/components/selectors/visitor.rs') diff --git a/servo/components/selectors/visitor.rs b/servo/components/selectors/visitor.rs new file mode 100644 index 0000000000..d5befbc68b --- /dev/null +++ b/servo/components/selectors/visitor.rs @@ -0,0 +1,136 @@ +/* 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, RelativeSelector, 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<&::NamespaceUrl>, + _local_name: &::LocalName, + _local_name_lower: &::LocalName, + ) -> bool { + true + } + + /// Visit a simple selector. + fn visit_simple_selector(&mut self, _: &Component) -> bool { + true + } + + /// Visit a nested relative selector list. The caller is responsible to call visit + /// into the internal selectors if / as needed. + /// + /// The default implementation skips it altogether. + fn visit_relative_selector_list(&mut self, _list: &[RelativeSelector]) -> 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], + ) -> 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) -> 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 ) or + /// :nth-last-child(.. of ) + const NTH_OF = 1 << 3; + /// The visitor is inside :has(..) + const HAS = 1 << 4; + } +} + +impl SelectorListKind { + /// Construct a SelectorListKind for the corresponding component. + pub fn from_component(component: &Component) -> 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 ) or + /// :nth-last-child(.. of ) + pub fn in_nth_of(&self) -> bool { + self.intersects(SelectorListKind::NTH_OF) + } + + /// Whether the visitor is inside :has(..) + pub fn in_has(&self) -> bool { + self.intersects(SelectorListKind::HAS) + } + + /// Whether this nested selector is relevant for nth-of dependencies. + pub fn relevant_to_nth_of_dependencies(&self) -> bool { + // Order of nesting for `:has` and `:nth-child(.. of ..)` doesn't matter, because: + // * `:has(:nth-child(.. of ..))`: The location of the anchoring element is + // independent from where `:nth-child(.. of ..)` is applied. + // * `:nth-child(.. of :has(..))`: Invalidations inside `:has` must first use the + // `:has` machinary to find the anchor, then carry out the remaining invalidation. + self.in_nth_of() && !self.in_has() + } +} -- cgit v1.2.3