/* 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::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::{serialize_identifier, CowRcStr, Parser as CssParser, SourceLocation, ToCss}; use dom::{DocumentState, ElementState}; use fxhash::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, ::first-line, or ::placeholder 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!
impl ::selectors::parser::PseudoElement for PseudoElement { typeImpl = SelectorImpl;
}
/// The number of eager pseudo-elements. Keep this in sync with cascade_type. pubconst EAGER_PSEUDO_COUNT: usize = 3;
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 { false
}
/// 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 { false
}
/// Whether the current pseudo element is :first-line #[inline] pubfn is_first_line(&self) -> bool { false
}
/// Whether this pseudo-element is the ::-moz-color-swatch pseudo. #[inline] pubfn is_color_swatch(&self) -> bool { false
}
/// 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. /// /// For more info on cascade types, see docs/components/style.md /// /// Note: Keep this in sync with EAGER_PSEUDO_COUNT. #[inline] pubfn cascade_type(&self) -> PseudoElementCascadeType { match *self {
PseudoElement::After | PseudoElement::Before | PseudoElement::Selection => {
PseudoElementCascadeType::Eager
},
PseudoElement::Backdrop | PseudoElement::DetailsSummary => PseudoElementCascadeType::Lazy,
PseudoElement::DetailsContent |
PseudoElement::ServoAnonymousBox |
PseudoElement::ServoAnonymousTable |
PseudoElement::ServoAnonymousTableCell |
PseudoElement::ServoAnonymousTableRow |
PseudoElement::ServoLegacyText |
PseudoElement::ServoLegacyInputText |
PseudoElement::ServoLegacyTableWrapper |
PseudoElement::ServoLegacyAnonymousTableWrapper |
PseudoElement::ServoLegacyAnonymousTable |
PseudoElement::ServoLegacyAnonymousBlock |
PseudoElement::ServoLegacyInlineBlockWrapper |
PseudoElement::ServoLegacyInlineAbsolute |
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> {
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
}
}
/// 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::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 = markup5ever::LocalName; type BorrowedNamespaceUrl = markup5ever::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.