/* 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/. */
#![deny(missing_docs)]
//! Servo's selector parser.
usecrate::attr::{AttrIdentifier, AttrValue}; usecrate::computed_value_flags::ComputedValueFlags; usecrate::derives::*; usecrate::dom::{OpaqueNode, TElement, TNode}; usecrate::invalidation::element::document_state::InvalidationMatchingData; usecrate::invalidation::element::element_wrapper::ElementSnapshot; usecrate::properties::longhands::display::computed_value::T as Display; usecrate::properties::{ComputedValues, PropertyFlags}; usecrate::selector_parser::AttrValue as SelectorAttrValue; usecrate::selector_parser::{PseudoElementCascadeType, SelectorParser}; usecrate::values::{AtomIdent, AtomString}; usecrate::{Atom, CaseSensitivityExt, LocalName, Namespace, Prefix}; use cssparser::{
match_ignore_ascii_case, serialize_identifier, CowRcStr, Parser as CssParser, SourceLocation,
ToCss,
}; use dom::{DocumentState, ElementState}; use rustc_hash::FxHashMap; use selectors::attr::{AttrSelectorOperation, CaseSensitivity, NamespaceConstraint}; use selectors::parser::SelectorParseErrorKind; use selectors::visitor::SelectorVisitor; use std::fmt; use std::mem; use std::ops::{Deref, DerefMut}; use style_traits::{ParseError, StyleParseErrorKind};
/// A pseudo-element, both public and private. /// /// NB: If you add to this list, be sure to update `each_simple_pseudo_element` too. #[derive(
Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, ToShmem,
)] #[allow(missing_docs)] #[repr(usize)] pubenum PseudoElement { // Eager pseudos. Keep these first so that eager_index() works.
After = 0,
Before,
Selection, // If/when :first-letter is added, update is_first_letter accordingly.
// If/when :first-line is added, update is_first_line accordingly.
// If/when ::first-letter or ::first-line are added, adjust our // property_restriction implementation to do property filtering for them. // Also, make sure the UA sheet has the !important rules some of the // APPLIES_TO_PLACEHOLDER properties expect!
FirstLetter,
// Implemented pseudos. These pseudo elements are representing the // elements within an UA shadow DOM, and matching the elements with // their appropriate styles.
ColorSwatch,
FileSelectorButton,
Placeholder,
SliderFill,
SliderThumb,
SliderTrack,
// Private, Servo-specific implemented pseudos. Only matchable in UA sheet.
ServoTextControlInnerContainer,
ServoTextControlInnerEditor,
/// The number of eager pseudo-elements. Keep this in sync with cascade_type. pubconst EAGER_PSEUDO_COUNT: usize = 4;
impl PseudoElement { /// Gets the canonical index of this eagerly-cascaded pseudo-element. #[inline] pubfn eager_index(&self) -> usize {
debug_assert!(self.is_eager()); self.clone() as usize
}
/// An index for this pseudo-element to be indexed in an enumerated array. #[inline] pubfn index(&self) -> usize { self.clone() as usize
}
/// An array of `None`, one per pseudo-element. pubfn pseudo_none_array<T>() -> [Option<T>; PSEUDO_COUNT] {
Default::default()
}
/// Creates a pseudo-element from an eager index. #[inline] pubfn from_eager_index(i: usize) -> Self {
assert!(i < EAGER_PSEUDO_COUNT); let result: PseudoElement = unsafe { mem::transmute(i) };
debug_assert!(result.is_eager());
result
}
/// Whether the current pseudo element is ::before or ::after. #[inline] pubfn is_before_or_after(&self) -> bool { self.is_before() || self.is_after()
}
/// Whether this is an unknown ::-webkit- pseudo-element. #[inline] pubfn is_unknown_webkit_pseudo_element(&self) -> bool { false
}
/// Whether this pseudo-element is the ::marker pseudo. #[inline] pubfn is_marker(&self) -> bool {
*self == PseudoElement::Marker
}
/// Whether this pseudo-element is the ::selection pseudo. #[inline] pubfn is_selection(&self) -> bool {
*self == PseudoElement::Selection
}
/// Whether this pseudo-element is the ::before pseudo. #[inline] pubfn is_before(&self) -> bool {
*self == PseudoElement::Before
}
/// Whether this pseudo-element is the ::after pseudo. #[inline] pubfn is_after(&self) -> bool {
*self == PseudoElement::After
}
/// Whether the current pseudo element is :first-letter #[inline] pubfn is_first_letter(&self) -> bool {
*self == PseudoElement::FirstLetter
}
/// Whether the current pseudo element is :first-line #[inline] pubfn is_first_line(&self) -> bool { false
}
/// Whether this pseudo-element is representing the color swatch /// inside an `<input>` element. #[inline] pubfn is_color_swatch(&self) -> bool {
*self == PseudoElement::ColorSwatch
}
/// Whether this pseudo-element is eagerly-cascaded. #[inline] pubfn is_eager(&self) -> bool { self.cascade_type() == PseudoElementCascadeType::Eager
}
/// Whether this pseudo-element is lazily-cascaded. #[inline] pubfn is_lazy(&self) -> bool { self.cascade_type() == PseudoElementCascadeType::Lazy
}
/// Whether this pseudo-element is for an anonymous box. pubfn is_anon_box(&self) -> bool { self.is_precomputed()
}
/// Whether this pseudo-element is precomputed. #[inline] pubfn is_precomputed(&self) -> bool { self.cascade_type() == PseudoElementCascadeType::Precomputed
}
/// Returns which kind of cascade type has this pseudo. /// /// See the documentation for `PseudoElementCascadeType` for how we choose /// which cascade type to use. /// /// Note: Keep eager pseudos in sync with `EAGER_PSEUDO_COUNT` and /// `EMPTY_PSEUDO_ARRAY` in `style/data.rs` #[inline] pubfn cascade_type(&self) -> PseudoElementCascadeType { match *self {
PseudoElement::After
| PseudoElement::Before
| PseudoElement::FirstLetter
| PseudoElement::Selection => PseudoElementCascadeType::Eager,
PseudoElement::Backdrop
| PseudoElement::ColorSwatch
| PseudoElement::FileSelectorButton
| PseudoElement::Marker
| PseudoElement::Placeholder
| PseudoElement::DetailsContent
| PseudoElement::SliderFill
| PseudoElement::SliderThumb
| PseudoElement::SliderTrack
| PseudoElement::ServoTextControlInnerContainer
| PseudoElement::ServoTextControlInnerEditor => PseudoElementCascadeType::Lazy,
PseudoElement::ServoAnonymousBox
| PseudoElement::ServoAnonymousTable
| PseudoElement::ServoAnonymousTableCell
| PseudoElement::ServoAnonymousTableRow
| PseudoElement::ServoTableGrid
| PseudoElement::ServoTableWrapper => PseudoElementCascadeType::Precomputed,
}
}
/// Covert non-canonical pseudo-element to canonical one, and keep a /// canonical one as it is. pubfn canonical(&self) -> PseudoElement { self.clone()
}
/// Stub, only Gecko needs this pubfn pseudo_info(&self) {
()
}
/// Property flag that properties must have to apply to this pseudo-element. #[inline] pubfn property_restriction(&self) -> Option<PropertyFlags> {
Some(matchself {
PseudoElement::FirstLetter => PropertyFlags::APPLIES_TO_FIRST_LETTER,
PseudoElement::Marker if static_prefs::pref!("layout.css.marker.restricted") => {
PropertyFlags::APPLIES_TO_MARKER
},
PseudoElement::Placeholder => PropertyFlags::APPLIES_TO_PLACEHOLDER,
_ => return None,
})
}
/// Whether this pseudo-element should actually exist if it has /// the given styles. pubfn should_exist(&self, style: &ComputedValues) -> bool { let display = style.get_box().clone_display(); if display == Display::None { returnfalse;
} ifself.is_before_or_after() && style.ineffective_content_property() { returnfalse;
}
true
}
/// Whether this pseudo-element is the ::highlight pseudo. pubfn is_highlight(&self) -> bool { false
}
/// Whether this pseudo-element is the ::target-text pseudo. #[inline] pubfn is_target_text(&self) -> bool { false
}
/// Whether this is a highlight pseudo-element that is styled lazily during /// painting rather than during the restyle traversal. These pseudos need /// explicit repaint triggering when their styles change. #[inline] pubfn is_lazy_painted_highlight_pseudo(&self) -> bool { self.is_selection() || self.is_highlight() || self.is_target_text()
}
/// Whether this pseudo-element is "element-backed", which means that it inherits from its regular /// flat tree parent, which might not be the originating element. #[inline] pubfn is_element_backed(&self) -> bool { use selectors::parser::PseudoElement; self.parses_as_element_backed()
|| matches!( self, Self::Placeholder
| Self::ColorSwatch
| Self::FileSelectorButton
| Self::SliderFill
| Self::SliderThumb
| Self::SliderTrack
| Self::ServoTextControlInnerContainer
| Self::ServoTextControlInnerEditor,
)
}
}
/// The type used for storing `:lang` arguments. pubtype Lang = Box<str>;
/// The type used to store the state argument to the `:state` pseudo-class. #[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToCss, ToShmem)] pubstruct CustomState(pub AtomIdent);
impl NonTSPseudoClass { /// Gets a given state flag for this pseudo-class. This is used to do /// selector matching, and it's set from the DOM. pubfn state_flag(&self) -> ElementState { match *self { Self::Active => ElementState::ACTIVE, Self::AnyLink => ElementState::VISITED_OR_UNVISITED, Self::Autofill => ElementState::AUTOFILL, Self::Checked => ElementState::CHECKED, Self::Default => ElementState::DEFAULT, Self::Defined => ElementState::DEFINED, Self::Disabled => ElementState::DISABLED, Self::Enabled => ElementState::ENABLED, Self::Focus => ElementState::FOCUS, Self::FocusVisible => ElementState::FOCUSRING, Self::FocusWithin => ElementState::FOCUS_WITHIN, Self::Fullscreen => ElementState::FULLSCREEN, Self::Hover => ElementState::HOVER, Self::InRange => ElementState::INRANGE, Self::Indeterminate => ElementState::INDETERMINATE, Self::Invalid => ElementState::INVALID, Self::Link => ElementState::UNVISITED, Self::Modal => ElementState::MODAL, Self::MozMeterOptimum => ElementState::OPTIMUM, Self::MozMeterSubOptimum => ElementState::SUB_OPTIMUM, Self::MozMeterSubSubOptimum => ElementState::SUB_SUB_OPTIMUM, Self::Open => ElementState::OPEN, Self::Optional => ElementState::OPTIONAL_, Self::OutOfRange => ElementState::OUTOFRANGE, Self::PlaceholderShown => ElementState::PLACEHOLDER_SHOWN, Self::PopoverOpen => ElementState::POPOVER_OPEN, Self::ReadOnly => ElementState::READONLY, Self::ReadWrite => ElementState::READWRITE, Self::Required => ElementState::REQUIRED, Self::Target => ElementState::URLTARGET, Self::UserInvalid => ElementState::USER_INVALID, Self::UserValid => ElementState::USER_VALID, Self::Valid => ElementState::VALID, Self::Visited => ElementState::VISITED, Self::CustomState(_) | Self::Lang(_) | Self::ServoNonZeroBorder => {
ElementState::empty()
},
}
}
/// Get the document state flag associated with a pseudo-class, if any. pubfn document_state_flag(&self) -> DocumentState {
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()
}
}
/// The abstract struct we implement the selector parser implementation on top /// of. #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "servo", derive(MallocSizeOf))] pubstruct SelectorImpl;
/// A set of extra data to carry along with the matching context, either for /// selector-matching or invalidation. #[derive(Debug, 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 PseudoElement = PseudoElement; type NonTSPseudoClass = NonTSPseudoClass;
type ExtraMatchingData<'a> = ExtraMatchingData<'a>; type AttrValue = AtomString; type Identifier = AtomIdent; type LocalName = LocalName; type NamespacePrefix = Prefix; type NamespaceUrl = Namespace; type BorrowedLocalName = web_atoms::LocalName; type BorrowedNamespaceUrl = web_atoms::Namespace;
}
impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> { typeImpl = SelectorImpl; type Error = StyleParseErrorKind<'i>;
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 i in0..EAGER_PSEUDO_COUNT {
fun(PseudoElement::from_eager_index(i));
}
}
}
/// A map from elements to snapshots for the Servo style back-end. #[derive(Debug)] pubstruct SnapshotMap(FxHashMap<OpaqueNode, ServoElementSnapshot>);
impl SnapshotMap { /// Create a new empty `SnapshotMap`. pubfn new() -> Self {
SnapshotMap(FxHashMap::default())
}
/// Get a snapshot given an element. pubfn get<T: TElement>(&self, el: &T) -> Option<&ServoElementSnapshot> { self.0.get(&el.as_node().opaque())
}
}
impl Deref for SnapshotMap { type Target = FxHashMap<OpaqueNode, ServoElementSnapshot>;
/// Servo's version of an element snapshot. #[derive(Debug, Default, MallocSizeOf)] pubstruct ServoElementSnapshot { /// The stored state of the element. pub state: Option<ElementState>, /// The set of stored attributes and its values. pub attrs: Option<Vec<(AttrIdentifier, AttrValue)>>, /// The set of changed attributes and its values. pub changed_attrs: Vec<LocalName>, /// Whether the class attribute changed or not. pub class_changed: bool, /// Whether the id attribute changed or not. pub id_changed: bool, /// Whether other attributes other than id or class changed or not. pub other_attributes_changed: bool,
}
impl ServoElementSnapshot { /// Create an empty element snapshot. pubfn new() -> Self { Self::default()
}
/// Returns whether the id attribute changed or not. pubfn id_changed(&self) -> bool { self.id_changed
}
/// Returns whether the class attribute changed or not. pubfn class_changed(&self) -> bool { self.class_changed
}
/// Returns whether other attributes other than id or class changed or not. pubfn other_attr_changed(&self) -> bool { self.other_attributes_changed
}
/// Executes the callback once for each attribute that changed. #[inline] pubfn each_attr_changed<F>(&self, mut callback: F) where
F: FnMut(&LocalName),
{ for name in &self.changed_attrs {
callback(name)
}
}
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.