From b2a7e4437391abd92486d5bef879fadadabab162 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 19 Jul 2016 16:17:02 +0200 Subject: [PATCH] Move ServoSelectorImpl to a dedicated module. --- components/layout_thread/lib.rs | 2 +- components/style/lib.rs | 1 + components/style/selector_impl.rs | 197 ++---------------- components/style/selector_matching.rs | 61 +----- components/style/servo.rs | 2 +- components/style/servo_selector_impl.rs | 253 ++++++++++++++++++++++++ docs/components/style.md | 2 +- 7 files changed, 269 insertions(+), 249 deletions(-) create mode 100644 components/style/servo_selector_impl.rs diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index e670d214e03..0c24ee44ee5 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -107,8 +107,8 @@ use style::media_queries::{Device, MediaType}; use style::parallel::WorkQueueData; use style::properties::ComputedValues; use style::refcell::RefCell; -use style::selector_matching::USER_OR_USER_AGENT_STYLESHEETS; use style::servo::{Animation, LocalStyleContextCreationInfo, SharedStyleContext, Stylesheet, Stylist}; +use style::servo_selector_impl::USER_OR_USER_AGENT_STYLESHEETS; use style::stylesheets::CSSRuleIteratorExt; use style::workqueue::WorkQueue; use url::Url; diff --git a/components/style/lib.rs b/components/style/lib.rs index 6e8cedab4cf..5a3395f9d36 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -97,6 +97,7 @@ pub mod selector_impl; pub mod selector_matching; pub mod sequential; pub mod servo; +pub mod servo_selector_impl; pub mod sink; pub mod str; pub mod stylesheets; diff --git a/components/style/selector_impl.rs b/components/style/selector_impl.rs index cd47d0dc7f5..0cd76e3f5b6 100644 --- a/components/style/selector_impl.rs +++ b/components/style/selector_impl.rs @@ -5,13 +5,21 @@ //! The pseudo-classes and pseudo-elements supported by the style system. use element_state::ElementState; -use properties::{self, ServoComputedValues}; -use selector_matching::{USER_OR_USER_AGENT_STYLESHEETS, QUIRKS_MODE_STYLESHEET}; +use properties; use selectors::Element; -use selectors::parser::{ParserContext, SelectorImpl}; +use selectors::parser::SelectorImpl; use std::fmt::Debug; use stylesheets::Stylesheet; +#[cfg(feature = "servo")] +pub use servo_selector_impl::ServoSelectorImpl; + +#[cfg(feature = "servo")] +pub use servo_selector_impl::{ServoSelectorImpl as TheSelectorImpl, PseudoElement, NonTSPseudoClass}; + +#[cfg(feature = "gecko")] +pub use gecko_selector_impl::{GeckoSelectorImpl as TheSelectorImpl, PseudoElement, NonTSPseudoClass}; + /// This function determines if a pseudo-element is eagerly cascaded or not. /// /// Eagerly cascaded pseudo-elements are "normal" pseudo-elements (i.e. @@ -101,186 +109,3 @@ pub trait SelectorImplExt : SelectorImpl + Clone + Debug + Sized + 'static { fn get_quirks_mode_stylesheet() -> Option<&'static Stylesheet>; } - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "servo", derive(HeapSizeOf))] -pub enum PseudoElement { - Before, - After, - Selection, - DetailsSummary, - DetailsContent, -} - -impl PseudoElement { - #[inline] - pub fn is_before_or_after(&self) -> bool { - match *self { - PseudoElement::Before | - PseudoElement::After => true, - _ => false, - } - } - - #[inline] - pub fn cascade_type(&self) -> PseudoElementCascadeType { - match *self { - PseudoElement::Before | - PseudoElement::After | - PseudoElement::Selection => PseudoElementCascadeType::Eager, - PseudoElement::DetailsSummary => PseudoElementCascadeType::Lazy, - PseudoElement::DetailsContent => PseudoElementCascadeType::Precomputed, - } - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "servo", derive(HeapSizeOf))] -pub enum NonTSPseudoClass { - AnyLink, - Link, - Visited, - Active, - Focus, - Hover, - Enabled, - Disabled, - Checked, - Indeterminate, - ServoNonZeroBorder, - ReadWrite, - ReadOnly, - PlaceholderShown, -} - -impl NonTSPseudoClass { - pub fn state_flag(&self) -> ElementState { - use element_state::*; - use self::NonTSPseudoClass::*; - match *self { - Active => IN_ACTIVE_STATE, - Focus => IN_FOCUS_STATE, - Hover => IN_HOVER_STATE, - Enabled => IN_ENABLED_STATE, - Disabled => IN_DISABLED_STATE, - Checked => IN_CHECKED_STATE, - Indeterminate => IN_INDETERMINATE_STATE, - ReadOnly | ReadWrite => IN_READ_WRITE_STATE, - PlaceholderShown => IN_PLACEHOLDER_SHOWN_STATE, - - AnyLink | - Link | - Visited | - ServoNonZeroBorder => ElementState::empty(), - } - } -} - -#[derive(Clone, Debug, PartialEq)] -#[cfg_attr(feature = "servo", derive(HeapSizeOf))] -pub struct ServoSelectorImpl; - -impl SelectorImpl for ServoSelectorImpl { - type AttrString = String; - type PseudoElement = PseudoElement; - type NonTSPseudoClass = NonTSPseudoClass; - - fn parse_non_ts_pseudo_class(context: &ParserContext, - name: &str) -> Result { - use self::NonTSPseudoClass::*; - let pseudo_class = match_ignore_ascii_case! { name, - "any-link" => AnyLink, - "link" => Link, - "visited" => Visited, - "active" => Active, - "focus" => Focus, - "hover" => Hover, - "enabled" => Enabled, - "disabled" => Disabled, - "checked" => Checked, - "indeterminate" => Indeterminate, - "read-write" => ReadWrite, - "read-only" => ReadOnly, - "placeholder-shown" => PlaceholderShown, - "-servo-nonzero-border" => { - if !context.in_user_agent_stylesheet { - return Err(()); - } - ServoNonZeroBorder - }, - _ => return Err(()) - }; - - Ok(pseudo_class) - } - - fn parse_pseudo_element(context: &ParserContext, - name: &str) -> Result { - use self::PseudoElement::*; - let pseudo_element = match_ignore_ascii_case! { name, - "before" => Before, - "after" => After, - "selection" => Selection, - "-servo-details-summary" => { - if !context.in_user_agent_stylesheet { - return Err(()) - } - DetailsSummary - }, - "-servo-details-content" => { - if !context.in_user_agent_stylesheet { - return Err(()) - } - DetailsContent - }, - _ => return Err(()) - }; - - Ok(pseudo_element) - } -} - -impl SelectorImplExt for ServoSelectorImpl { - type ComputedValues = ServoComputedValues; - - #[inline] - fn pseudo_element_cascade_type(pseudo: &PseudoElement) -> PseudoElementCascadeType { - pseudo.cascade_type() - } - - #[inline] - fn each_pseudo_element(mut fun: F) - where F: FnMut(PseudoElement) { - fun(PseudoElement::Before); - fun(PseudoElement::After); - fun(PseudoElement::DetailsContent); - fun(PseudoElement::DetailsSummary); - fun(PseudoElement::Selection); - } - - #[inline] - fn pseudo_class_state_flag(pc: &NonTSPseudoClass) -> ElementState { - pc.state_flag() - } - - #[inline] - fn pseudo_is_before_or_after(pseudo: &PseudoElement) -> bool { - pseudo.is_before_or_after() - } - - #[inline] - fn get_user_or_user_agent_stylesheets() -> &'static [Stylesheet] { - &*USER_OR_USER_AGENT_STYLESHEETS - } - - #[inline] - fn get_quirks_mode_stylesheet() -> Option<&'static Stylesheet> { - Some(&*QUIRKS_MODE_STYLESHEET) - } -} - -impl> ElementExt for E { - fn is_link(&self) -> bool { - self.match_non_ts_pseudo_class(NonTSPseudoClass::AnyLink) - } -} diff --git a/components/style/selector_matching.rs b/components/style/selector_matching.rs index b632d783e1e..14f37cbcda8 100644 --- a/components/style/selector_matching.rs +++ b/components/style/selector_matching.rs @@ -9,10 +9,9 @@ use element_state::*; use error_reporting::StdoutErrorReporter; use keyframes::KeyframesAnimation; use media_queries::{Device, MediaType}; -use parser::ParserContextExtraData; use properties::{self, PropertyDeclaration, PropertyDeclarationBlock}; use restyle_hints::{ElementSnapshot, RestyleHint, DependencySet}; -use selector_impl::{SelectorImplExt, ServoSelectorImpl}; +use selector_impl::SelectorImplExt; use selectors::bloom::BloomFilter; use selectors::matching::DeclarationBlock as GenericDeclarationBlock; use selectors::matching::{Rule, SelectorMap}; @@ -22,73 +21,15 @@ use sink::Push; use smallvec::VecLike; use std::collections::HashMap; use std::hash::BuildHasherDefault; -use std::process; use std::sync::Arc; use string_cache::Atom; use style_traits::viewport::ViewportConstraints; use stylesheets::{CSSRule, CSSRuleIteratorExt, Origin, Stylesheet}; -use url::Url; -use util::opts; -use util::resource_files::read_resource_file; use viewport::{MaybeNew, ViewportRuleCascade}; pub type DeclarationBlock = GenericDeclarationBlock>; -lazy_static! { - pub static ref USER_OR_USER_AGENT_STYLESHEETS: Vec> = { - let mut stylesheets = vec!(); - // FIXME: presentational-hints.css should be at author origin with zero specificity. - // (Does it make a difference?) - for &filename in &["user-agent.css", "servo.css", "presentational-hints.css"] { - match read_resource_file(filename) { - Ok(res) => { - let ua_stylesheet = Stylesheet::from_bytes( - &res, - Url::parse(&format!("chrome://resources/{:?}", filename)).unwrap(), - None, - None, - Origin::UserAgent, - Box::new(StdoutErrorReporter), - ParserContextExtraData::default()); - stylesheets.push(ua_stylesheet); - } - Err(..) => { - error!("Failed to load UA stylesheet {}!", filename); - process::exit(1); - } - } - } - for &(ref contents, ref url) in &opts::get().user_stylesheets { - stylesheets.push(Stylesheet::from_bytes( - &contents, url.clone(), None, None, Origin::User, Box::new(StdoutErrorReporter), - ParserContextExtraData::default())); - } - stylesheets - }; -} - -lazy_static! { - pub static ref QUIRKS_MODE_STYLESHEET: Stylesheet = { - match read_resource_file("quirks-mode.css") { - Ok(res) => { - Stylesheet::from_bytes( - &res, - Url::parse("chrome://resources/quirks-mode.css").unwrap(), - None, - None, - Origin::UserAgent, - Box::new(StdoutErrorReporter), - ParserContextExtraData::default()) - }, - Err(..) => { - error!("Stylist failed to load 'quirks-mode.css'!"); - process::exit(1); - } - } - }; -} - /// This structure holds all the selectors and device characteristics /// for a given document. The selectors are converted into `Rule`s /// (defined in rust-selectors), and introduced in a `SelectorMap` diff --git a/components/style/servo.rs b/components/style/servo.rs index d5605a62832..8af957e48da 100644 --- a/components/style/servo.rs +++ b/components/style/servo.rs @@ -7,8 +7,8 @@ use animation; use context; use data; use properties::ServoComputedValues; -use selector_impl::ServoSelectorImpl; use selector_matching; +use servo_selector_impl::ServoSelectorImpl; use stylesheets; pub type Stylesheet = stylesheets::Stylesheet; diff --git a/components/style/servo_selector_impl.rs b/components/style/servo_selector_impl.rs new file mode 100644 index 00000000000..517f135b84e --- /dev/null +++ b/components/style/servo_selector_impl.rs @@ -0,0 +1,253 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ + +use element_state::ElementState; +use error_reporting::StdoutErrorReporter; +use parser::ParserContextExtraData; +use properties::ServoComputedValues; +use selector_impl::{SelectorImplExt, ElementExt, PseudoElementCascadeType}; +use selectors::Element; +use selectors::parser::{ParserContext, SelectorImpl}; +use std::process; +use stylesheets::{Stylesheet, Origin}; +use url::Url; +use util::opts; +use util::resource_files::read_resource_file; + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub enum PseudoElement { + Before, + After, + Selection, + DetailsSummary, + DetailsContent, +} + +impl PseudoElement { + #[inline] + pub fn is_before_or_after(&self) -> bool { + match *self { + PseudoElement::Before | + PseudoElement::After => true, + _ => false, + } + } + + #[inline] + pub fn cascade_type(&self) -> PseudoElementCascadeType { + match *self { + PseudoElement::Before | + PseudoElement::After | + PseudoElement::Selection => PseudoElementCascadeType::Eager, + PseudoElement::DetailsSummary => PseudoElementCascadeType::Lazy, + PseudoElement::DetailsContent => PseudoElementCascadeType::Precomputed, + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub enum NonTSPseudoClass { + AnyLink, + Link, + Visited, + Active, + Focus, + Hover, + Enabled, + Disabled, + Checked, + Indeterminate, + ServoNonZeroBorder, + ReadWrite, + ReadOnly, + PlaceholderShown, +} + +impl NonTSPseudoClass { + pub fn state_flag(&self) -> ElementState { + use element_state::*; + use self::NonTSPseudoClass::*; + match *self { + Active => IN_ACTIVE_STATE, + Focus => IN_FOCUS_STATE, + Hover => IN_HOVER_STATE, + Enabled => IN_ENABLED_STATE, + Disabled => IN_DISABLED_STATE, + Checked => IN_CHECKED_STATE, + Indeterminate => IN_INDETERMINATE_STATE, + ReadOnly | ReadWrite => IN_READ_WRITE_STATE, + PlaceholderShown => IN_PLACEHOLDER_SHOWN_STATE, + + AnyLink | + Link | + Visited | + ServoNonZeroBorder => ElementState::empty(), + } + } +} + +#[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct ServoSelectorImpl; + +impl SelectorImpl for ServoSelectorImpl { + type AttrString = String; + type PseudoElement = PseudoElement; + type NonTSPseudoClass = NonTSPseudoClass; + + fn parse_non_ts_pseudo_class(context: &ParserContext, + name: &str) -> Result { + use self::NonTSPseudoClass::*; + let pseudo_class = match_ignore_ascii_case! { name, + "any-link" => AnyLink, + "link" => Link, + "visited" => Visited, + "active" => Active, + "focus" => Focus, + "hover" => Hover, + "enabled" => Enabled, + "disabled" => Disabled, + "checked" => Checked, + "indeterminate" => Indeterminate, + "read-write" => ReadWrite, + "read-only" => ReadOnly, + "placeholder-shown" => PlaceholderShown, + "-servo-nonzero-border" => { + if !context.in_user_agent_stylesheet { + return Err(()); + } + ServoNonZeroBorder + }, + _ => return Err(()) + }; + + Ok(pseudo_class) + } + + fn parse_pseudo_element(context: &ParserContext, + name: &str) -> Result { + use self::PseudoElement::*; + let pseudo_element = match_ignore_ascii_case! { name, + "before" => Before, + "after" => After, + "selection" => Selection, + "-servo-details-summary" => { + if !context.in_user_agent_stylesheet { + return Err(()) + } + DetailsSummary + }, + "-servo-details-content" => { + if !context.in_user_agent_stylesheet { + return Err(()) + } + DetailsContent + }, + _ => return Err(()) + }; + + Ok(pseudo_element) + } +} + +impl SelectorImplExt for ServoSelectorImpl { + type ComputedValues = ServoComputedValues; + + #[inline] + fn pseudo_element_cascade_type(pseudo: &PseudoElement) -> PseudoElementCascadeType { + pseudo.cascade_type() + } + + #[inline] + fn each_pseudo_element(mut fun: F) + where F: FnMut(PseudoElement) { + fun(PseudoElement::Before); + fun(PseudoElement::After); + fun(PseudoElement::DetailsContent); + fun(PseudoElement::DetailsSummary); + fun(PseudoElement::Selection); + } + + #[inline] + fn pseudo_class_state_flag(pc: &NonTSPseudoClass) -> ElementState { + pc.state_flag() + } + + #[inline] + fn pseudo_is_before_or_after(pseudo: &PseudoElement) -> bool { + pseudo.is_before_or_after() + } + + #[inline] + fn get_user_or_user_agent_stylesheets() -> &'static [Stylesheet] { + &*USER_OR_USER_AGENT_STYLESHEETS + } + + #[inline] + fn get_quirks_mode_stylesheet() -> Option<&'static Stylesheet> { + Some(&*QUIRKS_MODE_STYLESHEET) + } +} + +impl> ElementExt for E { + fn is_link(&self) -> bool { + self.match_non_ts_pseudo_class(NonTSPseudoClass::AnyLink) + } +} + +lazy_static! { + pub static ref USER_OR_USER_AGENT_STYLESHEETS: Vec> = { + let mut stylesheets = vec!(); + // FIXME: presentational-hints.css should be at author origin with zero specificity. + // (Does it make a difference?) + for &filename in &["user-agent.css", "servo.css", "presentational-hints.css"] { + match read_resource_file(filename) { + Ok(res) => { + let ua_stylesheet = Stylesheet::from_bytes( + &res, + Url::parse(&format!("chrome://resources/{:?}", filename)).unwrap(), + None, + None, + Origin::UserAgent, + Box::new(StdoutErrorReporter), + ParserContextExtraData::default()); + stylesheets.push(ua_stylesheet); + } + Err(..) => { + error!("Failed to load UA stylesheet {}!", filename); + process::exit(1); + } + } + } + for &(ref contents, ref url) in &opts::get().user_stylesheets { + stylesheets.push(Stylesheet::from_bytes( + &contents, url.clone(), None, None, Origin::User, Box::new(StdoutErrorReporter), + ParserContextExtraData::default())); + } + stylesheets + }; +} + +lazy_static! { + pub static ref QUIRKS_MODE_STYLESHEET: Stylesheet = { + match read_resource_file("quirks-mode.css") { + Ok(res) => { + Stylesheet::from_bytes( + &res, + Url::parse("chrome://resources/quirks-mode.css").unwrap(), + None, + None, + Origin::UserAgent, + Box::new(StdoutErrorReporter), + ParserContextExtraData::default()) + }, + Err(..) => { + error!("Stylist failed to load 'quirks-mode.css'!"); + process::exit(1); + } + } + }; +} diff --git a/docs/components/style.md b/docs/components/style.md index a3d657e53e0..0bf82713de1 100644 --- a/docs/components/style.md +++ b/docs/components/style.md @@ -139,7 +139,7 @@ that you didn't find it here so it can be added :) [stylo]: https://public.etherpad-mozilla.org/p/stylo [selector-impl]: http://doc.servo.org/selectors/parser/trait.SelectorImpl.html [selector-impl-ext]: http://doc.servo.org/style/selector_impl/trait.SelectorImplExt.html -[servo-selector-impl]: http://doc.servo.org/style/selector_impl/struct.ServoSelectorImpl.html +[servo-selector-impl]: http://doc.servo.org/style/servo_selector_impl/struct.ServoSelectorImpl.html [tree-structural-pseudo-classes]: https://www.w3.org/TR/selectors4/#structural-pseudos [style-dom-traits]: http://doc.servo.org/style/dom/index.html [layout-wrapper]: http://doc.servo.org/layout/wrapper/index.html