/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! Gecko-specific bits for selector-parsing.
usecrate::computed_value_flags::ComputedValueFlags; usecrate::invalidation::element::document_state::InvalidationMatchingData; usecrate::properties::ComputedValues; usecrate::selector_parser::{Direction, HorizontalDirection, SelectorParser}; usecrate::str::starts_with_ignore_ascii_case; usecrate::string_cache::{Atom, Namespace, WeakAtom, WeakNamespace}; usecrate::values::{AtomIdent, AtomString}; use cssparser::{BasicParseError, BasicParseErrorKind, Parser}; use cssparser::{CowRcStr, SourceLocation, ToCss, Token}; use dom::{DocumentState, ElementState}; use selectors::parser::SelectorParseErrorKind; use std::fmt; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss as ToCss_}; use thin_vec::ThinVec;
/// The type used to store the language argument to the `:lang` pseudo-class. #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToCss, ToShmem)] #[css(comma)] pubstruct Lang(#[css(iterable)] pub ThinVec<AtomIdent>);
/// The type used to store the state argument to the `:state` pseudo-class. #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToCss, ToShmem)] pubstruct CustomState(pub AtomIdent);
macro_rules! pseudo_class_name {
([$(($css:expr, $name:ident, $state:tt, $flags:tt),)*]) => { /// Our representation of a non tree-structural pseudo-class. #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToShmem)] pubenum NonTSPseudoClass {
$( #[doc = $css]
$name,
)* /// The `:lang` pseudo-class.
Lang(Lang), /// The `:dir` pseudo-class.
Dir(Direction), /// The :state` pseudo-class.
CustomState(CustomState), /// The non-standard `:-moz-locale-dir` pseudo-class.
MozLocaleDir(Direction),
}
}
}
apply_non_ts_list!(pseudo_class_name);
impl NonTSPseudoClass { /// Parses the name and returns a non-ts-pseudo-class if succeeds. /// None otherwise. It doesn't check whether the pseudo-class is enabled /// in a particular state. pubfn parse_non_functional(name: &str) -> Option<Self> {
macro_rules! pseudo_class_parse {
([$(($css:expr, $name:ident, $state:tt, $flags:tt),)*]) => {
match_ignore_ascii_case! { &name,
$($css => Some(NonTSPseudoClass::$name),)* "-moz-full-screen" => Some(NonTSPseudoClass::Fullscreen), "-moz-read-only" => Some(NonTSPseudoClass::ReadOnly), "-moz-read-write" => Some(NonTSPseudoClass::ReadWrite), "-moz-focusring" => Some(NonTSPseudoClass::FocusVisible), "-moz-ui-valid" => Some(NonTSPseudoClass::UserValid), "-moz-ui-invalid" => Some(NonTSPseudoClass::UserInvalid), "-webkit-autofill" => Some(NonTSPseudoClass::Autofill),
_ => None,
}
}
}
apply_non_ts_list!(pseudo_class_parse)
}
/// Returns true if this pseudo-class has any of the given flags set. fn has_any_flag(&self, flags: NonTSPseudoClassFlag) -> bool {
macro_rules! check_flag {
(_) => { false
};
($flags:ident) => {
NonTSPseudoClassFlag::$flags.intersects(flags)
};
}
macro_rules! pseudo_class_check_is_enabled_in {
([$(($css:expr, $name:ident, $state:tt, $flags:tt),)*]) => { match *self {
$(NonTSPseudoClass::$name => check_flag!($flags),)*
NonTSPseudoClass::MozLocaleDir(_) => check_flag!(PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME),
NonTSPseudoClass::CustomState(_) |
NonTSPseudoClass::Lang(_) |
NonTSPseudoClass::Dir(_) => false,
}
}
}
apply_non_ts_list!(pseudo_class_check_is_enabled_in)
}
/// Returns whether the pseudo-class is enabled in content sheets. #[inline] fn is_enabled_in_content(&self) -> bool { if matches!(*self, Self::CustomState(_)) { return static_prefs::pref!("dom.element.customstateset.enabled");
} if matches!(*self, Self::HasSlotted) { return static_prefs::pref!("layout.css.has-slotted-selector.enabled");
}
!self.has_any_flag(NonTSPseudoClassFlag::PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME)
}
/// Get the state flag associated with a pseudo-class, if any. pubfn state_flag(&self) -> ElementState {
macro_rules! flag {
(_) => {
ElementState::empty()
};
($state:ident) => {
ElementState::$state
};
}
macro_rules! pseudo_class_state {
([$(($css:expr, $name:ident, $state:tt, $flags:tt),)*]) => { match *self {
$(NonTSPseudoClass::$name => flag!($state),)*
NonTSPseudoClass::Dir(ref dir) => dir.element_state(),
NonTSPseudoClass::MozLocaleDir(..) |
NonTSPseudoClass::CustomState(..) |
NonTSPseudoClass::Lang(..) => ElementState::empty(),
}
}
}
apply_non_ts_list!(pseudo_class_state)
}
/// Get the document state flag associated with a pseudo-class, if any. pubfn document_state_flag(&self) -> DocumentState { match *self {
NonTSPseudoClass::MozLocaleDir(ref dir) => match dir.as_horizontal_direction() {
Some(HorizontalDirection::Ltr) => DocumentState::LTR_LOCALE,
Some(HorizontalDirection::Rtl) => DocumentState::RTL_LOCALE,
None => DocumentState::empty(),
},
NonTSPseudoClass::MozWindowInactive => DocumentState::WINDOW_INACTIVE,
_ => DocumentState::empty(),
}
}
/// Returns true if the given pseudoclass should trigger style sharing cache /// revalidation. pubfn needs_cache_revalidation(&self) -> bool { self.state_flag().is_empty() &&
!matches!(
*self, // :dir() depends on state only, but may have an empty state_flag for invalid // arguments.
NonTSPseudoClass::Dir(_) | // We prevent style sharing for NAC.
NonTSPseudoClass::MozNativeAnonymous | // :-moz-placeholder is parsed but never matches.
NonTSPseudoClass::MozPlaceholder | // :-moz-is-html, :-moz-locale-dir and :-moz-window-inactive // depend only on the state of the document, which is invariant across all // elements involved in a given style cache.
NonTSPseudoClass::MozIsHTML |
NonTSPseudoClass::MozLocaleDir(_) |
NonTSPseudoClass::MozWindowInactive
)
}
}
impl ::selectors::parser::NonTSPseudoClass for NonTSPseudoClass { typeImpl = SelectorImpl;
/// The dummy struct we use to implement our selector parsing. #[derive(Clone, Debug, Eq, PartialEq)] pubstruct SelectorImpl;
/// A set of extra data to carry along with the matching context, either for /// selector-matching or invalidation. #[derive(Default)] pubstruct ExtraMatchingData<'a> { /// The invalidation data to invalidate doc-state pseudo-classes correctly. pub invalidation_data: InvalidationMatchingData,
/// The invalidation bits from matching container queries. These are here /// just for convenience mostly. pub cascade_input_flags: ComputedValueFlags,
/// The style of the originating element in order to evaluate @container /// size queries affecting pseudo-elements. pub originating_element_style: Option<&'a ComputedValues>,
}
impl ::selectors::SelectorImpl for SelectorImpl { type ExtraMatchingData<'a> = ExtraMatchingData<'a>; type AttrValue = AtomString; type Identifier = AtomIdent; type LocalName = AtomIdent; type NamespacePrefix = AtomIdent; type NamespaceUrl = Namespace; type BorrowedNamespaceUrl = WeakNamespace; type BorrowedLocalName = WeakAtom;
type PseudoElement = PseudoElement; type NonTSPseudoClass = NonTSPseudoClass;
impl SelectorImpl { /// A helper to traverse each eagerly cascaded pseudo-element, executing /// `fun` on it. #[inline] pubfn each_eagerly_cascaded_pseudo_element<F>(mut fun: F) where
F: FnMut(PseudoElement),
{ for pseudo in &EAGER_PSEUDOS {
fun(pseudo.clone())
}
}
}
// Selector and component sizes are important for matching performance.
size_of_test!(selectors::parser::Selector<SelectorImpl>, 8);
size_of_test!(selectors::parser::Component<SelectorImpl>, 24);
size_of_test!(PseudoElement, 16);
size_of_test!(NonTSPseudoClass, 16);
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.2 Sekunden
(vorverarbeitet am 2026-06-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.