mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
style: Document Gecko's selector parser.
This commit is contained in:
parent
2778354455
commit
bcac8265c9
1 changed files with 54 additions and 5 deletions
|
@ -2,6 +2,8 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
//! Gecko-specific bits for selector-parsing.
|
||||||
|
|
||||||
use cssparser::ToCss;
|
use cssparser::ToCss;
|
||||||
use element_state::ElementState;
|
use element_state::ElementState;
|
||||||
use selector_parser::{SelectorParser, PseudoElementCascadeType};
|
use selector_parser::{SelectorParser, PseudoElementCascadeType};
|
||||||
|
@ -11,11 +13,16 @@ use std::borrow::Cow;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
|
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
|
||||||
|
|
||||||
/// NOTE: The boolean field represents whether this element is an anonymous box.
|
/// A representation of a CSS pseudo-element.
|
||||||
///
|
///
|
||||||
/// This is just for convenience, instead of recomputing it. Also, note that
|
/// In Gecko, we represent pseudo-elements as plain `Atom`s.
|
||||||
/// Atom is always a static atom, so if space is a concern, we can use the
|
///
|
||||||
/// raw pointer and use the lower bit to represent it without space overhead.
|
/// The boolean field represents whether this element is an anonymous box. This
|
||||||
|
/// is just for convenience, instead of recomputing it.
|
||||||
|
///
|
||||||
|
/// Also, note that the `Atom` member is always a static atom, so if space is a
|
||||||
|
/// concern, we can use the raw pointer and use the lower bit to represent it
|
||||||
|
/// without space overhead.
|
||||||
///
|
///
|
||||||
/// FIXME(emilio): we know all these atoms are static. Patches are starting to
|
/// FIXME(emilio): we know all these atoms are static. Patches are starting to
|
||||||
/// pile up, but a further potential optimisation is generating bindings without
|
/// pile up, but a further potential optimisation is generating bindings without
|
||||||
|
@ -32,16 +39,22 @@ use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
|
||||||
pub struct PseudoElement(Atom, bool);
|
pub struct PseudoElement(Atom, bool);
|
||||||
|
|
||||||
impl PseudoElement {
|
impl PseudoElement {
|
||||||
|
/// Get the pseudo-element as an atom.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_atom(&self) -> &Atom {
|
pub fn as_atom(&self) -> &Atom {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether this pseudo-element is an anonymous box.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_anon_box(&self) -> bool {
|
fn is_anon_box(&self) -> bool {
|
||||||
self.1
|
self.1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Construct a pseudo-element from an `Atom`, receiving whether it is also
|
||||||
|
/// an anonymous box, and don't check it on release builds.
|
||||||
|
///
|
||||||
|
/// On debug builds we assert it's the result we expect.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_atom_unchecked(atom: Atom, is_anon_box: bool) -> Self {
|
pub fn from_atom_unchecked(atom: Atom, is_anon_box: bool) -> Self {
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
|
@ -73,6 +86,13 @@ impl PseudoElement {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs an atom from a string of text, and whether we're in a
|
||||||
|
/// user-agent stylesheet.
|
||||||
|
///
|
||||||
|
/// If we're not in a user-agent stylesheet, we will never parse anonymous
|
||||||
|
/// box pseudo-elements.
|
||||||
|
///
|
||||||
|
/// Returns `None` if the pseudo-element is not recognised.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_slice(s: &str, in_ua_stylesheet: bool) -> Option<Self> {
|
fn from_slice(s: &str, in_ua_stylesheet: bool) -> Option<Self> {
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
|
@ -102,20 +122,36 @@ impl ToCss for PseudoElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Our representation of a non tree-structural pseudo-class.
|
||||||
|
///
|
||||||
|
/// FIXME(emilio): Find a way to autogenerate this.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum NonTSPseudoClass {
|
pub enum NonTSPseudoClass {
|
||||||
|
/// :any-link
|
||||||
AnyLink,
|
AnyLink,
|
||||||
|
/// :link
|
||||||
Link,
|
Link,
|
||||||
|
/// :visited
|
||||||
Visited,
|
Visited,
|
||||||
|
/// :active
|
||||||
Active,
|
Active,
|
||||||
|
/// :focus
|
||||||
Focus,
|
Focus,
|
||||||
|
/// :fullscreen
|
||||||
Fullscreen,
|
Fullscreen,
|
||||||
|
/// :hover
|
||||||
Hover,
|
Hover,
|
||||||
|
/// :enabled
|
||||||
Enabled,
|
Enabled,
|
||||||
|
/// :disabled
|
||||||
Disabled,
|
Disabled,
|
||||||
|
/// :checked
|
||||||
Checked,
|
Checked,
|
||||||
|
/// :indeterminate
|
||||||
Indeterminate,
|
Indeterminate,
|
||||||
|
/// :read-write
|
||||||
ReadWrite,
|
ReadWrite,
|
||||||
|
/// :read-only
|
||||||
ReadOnly,
|
ReadOnly,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,6 +177,7 @@ impl ToCss for NonTSPseudoClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NonTSPseudoClass {
|
impl NonTSPseudoClass {
|
||||||
|
/// Get the state flag associated with a pseudo-class, if any.
|
||||||
pub fn state_flag(&self) -> ElementState {
|
pub fn state_flag(&self) -> ElementState {
|
||||||
use element_state::*;
|
use element_state::*;
|
||||||
use self::NonTSPseudoClass::*;
|
use self::NonTSPseudoClass::*;
|
||||||
|
@ -162,6 +199,7 @@ impl NonTSPseudoClass {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The dummy struct we use to implement our selector parsing.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct SelectorImpl;
|
pub struct SelectorImpl;
|
||||||
|
|
||||||
|
@ -231,6 +269,13 @@ impl<'a> ::selectors::Parser for SelectorParser<'a> {
|
||||||
|
|
||||||
impl SelectorImpl {
|
impl SelectorImpl {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
/// Returns the kind of cascade type that a given pseudo is going to use.
|
||||||
|
///
|
||||||
|
/// In Gecko we only compute ::before and ::after eagerly. We save the rules
|
||||||
|
/// for anonymous boxes separately, so we resolve them as precomputed
|
||||||
|
/// pseudos.
|
||||||
|
///
|
||||||
|
/// We resolve the others lazily, see `Servo_ResolvePseudoStyle`.
|
||||||
pub fn pseudo_element_cascade_type(pseudo: &PseudoElement) -> PseudoElementCascadeType {
|
pub fn pseudo_element_cascade_type(pseudo: &PseudoElement) -> PseudoElementCascadeType {
|
||||||
if Self::pseudo_is_before_or_after(pseudo) {
|
if Self::pseudo_is_before_or_after(pseudo) {
|
||||||
return PseudoElementCascadeType::Eager
|
return PseudoElementCascadeType::Eager
|
||||||
|
@ -244,8 +289,9 @@ impl SelectorImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
/// Executes a function for each pseudo-element.
|
||||||
pub fn each_pseudo_element<F>(mut fun: F)
|
pub fn each_pseudo_element<F>(mut fun: F)
|
||||||
where F: FnMut(PseudoElement)
|
where F: FnMut(PseudoElement),
|
||||||
{
|
{
|
||||||
macro_rules! pseudo_element {
|
macro_rules! pseudo_element {
|
||||||
($pseudo_str_with_colon:expr, $atom:expr, $is_anon_box:expr) => {{
|
($pseudo_str_with_colon:expr, $atom:expr, $is_anon_box:expr) => {{
|
||||||
|
@ -257,12 +303,15 @@ impl SelectorImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
/// Returns whether the given pseudo-element is `::before` or `::after`.
|
||||||
pub fn pseudo_is_before_or_after(pseudo: &PseudoElement) -> bool {
|
pub fn pseudo_is_before_or_after(pseudo: &PseudoElement) -> bool {
|
||||||
*pseudo.as_atom() == atom!(":before") ||
|
*pseudo.as_atom() == atom!(":before") ||
|
||||||
*pseudo.as_atom() == atom!(":after")
|
*pseudo.as_atom() == atom!(":after")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
/// Returns the relevant state flag for a given non-tree-structural
|
||||||
|
/// pseudo-class.
|
||||||
pub fn pseudo_class_state_flag(pc: &NonTSPseudoClass) -> ElementState {
|
pub fn pseudo_class_state_flag(pc: &NonTSPseudoClass) -> ElementState {
|
||||||
pc.state_flag()
|
pc.state_flag()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue