From dd503dfacb46c63702e4a4b49b85ca30df62a8df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Mon, 8 Feb 2016 02:53:22 +0100 Subject: [PATCH 1/6] Refactor style to be completely backend-independent This commit refactors the style crate to be completely independent of the actual implementation and pseudo-elements supported. This also adds a gecko backend which introduces parsing for the anonymous box pseudo-elements[1], although there's still no way of querying them. https://mxr.mozilla.org/mozilla-central/source/layout/style/nsCSSAnonBoxList.h --- components/layout/Cargo.toml | 2 +- components/layout/context.rs | 6 +- components/layout/data.rs | 2 +- components/layout/layout_thread.rs | 10 +- components/layout/traversal.rs | 4 +- components/layout/wrapper.rs | 45 ++-- components/script/Cargo.toml | 2 +- components/script/dom/document.rs | 2 +- components/script/dom/htmllinkelement.rs | 3 +- components/script/dom/htmlmetaelement.rs | 3 +- components/script/dom/htmlstyleelement.rs | 3 +- components/script/layout_interface.rs | 2 +- components/servo/Cargo.lock | 14 +- components/style/Cargo.toml | 2 +- components/style/context.rs | 14 +- components/style/data.rs | 18 +- components/style/dom.rs | 16 +- components/style/lib.rs | 1 + components/style/matching.rs | 118 +++++---- components/style/restyle_hints.rs | 45 ++-- components/style/selector_impl.rs | 64 ++++- components/style/selector_matching.rs | 120 ++++----- components/style/servo.rs | 15 ++ components/style/stylesheets.rs | 126 +++++---- components/style/traversal.rs | 25 +- components/style_traits/Cargo.toml | 2 +- components/util/Cargo.toml | 2 +- ports/cef/Cargo.lock | 12 +- ports/geckolib/Cargo.lock | 14 +- ports/geckolib/Cargo.toml | 8 +- ports/geckolib/data.rs | 4 +- ports/geckolib/glue.rs | 5 +- ports/geckolib/lib.rs | 12 + ports/geckolib/selector_impl.rs | 307 ++++++++++++++++++++++ ports/geckolib/traversal.rs | 8 +- ports/geckolib/wrapper.rs | 18 +- ports/gonk/Cargo.lock | 12 +- tests/unit/style/Cargo.toml | 2 +- tests/unit/style/media_queries.rs | 3 +- tests/unit/style/stylesheets.rs | 3 +- tests/unit/style/viewport.rs | 3 +- 41 files changed, 767 insertions(+), 310 deletions(-) create mode 100644 components/style/servo.rs create mode 100644 ports/geckolib/selector_impl.rs diff --git a/components/layout/Cargo.toml b/components/layout/Cargo.toml index c926475ae41..8ee2de344b7 100644 --- a/components/layout/Cargo.toml +++ b/components/layout/Cargo.toml @@ -64,7 +64,7 @@ heapsize_plugin = "0.1.2" libc = "0.2" log = "0.3" rustc-serialize = "0.3" -selectors = {version = "0.4.2", features = ["heap_size"]} +selectors = {version = "0.5", features = ["heap_size"]} serde = "0.6" serde_json = "0.5" serde_macros = "0.6" diff --git a/components/layout/context.rs b/components/layout/context.rs index 7eb01a68846..953c98797f5 100644 --- a/components/layout/context.rs +++ b/components/layout/context.rs @@ -25,8 +25,10 @@ use std::hash::BuildHasherDefault; use std::rc::Rc; use std::sync::mpsc::Sender; use std::sync::{Arc, Mutex}; -use style::context::{LocalStyleContext, SharedStyleContext, StyleContext}; +use style::context::{LocalStyleContext, StyleContext}; use style::matching::{ApplicableDeclarationsCache, StyleSharingCandidateCache}; +use style::selector_impl::ServoSelectorImpl; +use style::servo::SharedStyleContext; use url::Url; use util::opts; @@ -104,7 +106,7 @@ pub struct LayoutContext<'a> { cached_local_layout_context: Rc, } -impl<'a> StyleContext<'a> for LayoutContext<'a> { +impl<'a> StyleContext<'a, ServoSelectorImpl> for LayoutContext<'a> { fn shared_context(&self) -> &'a SharedStyleContext { &self.shared.style_context } diff --git a/components/layout/data.rs b/components/layout/data.rs index 459743cd689..b11e4ebfd05 100644 --- a/components/layout/data.rs +++ b/components/layout/data.rs @@ -4,7 +4,7 @@ use construct::ConstructionResult; use incremental::RestyleDamage; -use style::data::PrivateStyleData; +use style::servo::PrivateStyleData; /// Data that layout associates with a node. pub struct PrivateLayoutData { diff --git a/components/layout/layout_thread.rs b/components/layout/layout_thread.rs index aaa6a1e98c0..a540039c51b 100644 --- a/components/layout/layout_thread.rs +++ b/components/layout/layout_thread.rs @@ -62,13 +62,15 @@ use std::sync::mpsc::{channel, Sender, Receiver}; use std::sync::{Arc, Mutex, MutexGuard, RwLock}; use style::animation::Animation; use style::computed_values::{filter, mix_blend_mode}; -use style::context::{SharedStyleContext, StylistWrapper, ReflowGoal}; +use style::context::{ReflowGoal, StylistWrapper}; use style::dom::{TDocument, TElement, TNode}; use style::error_reporting::ParseErrorReporter; use style::media_queries::{Device, MediaType}; use style::parallel::WorkQueueData; -use style::selector_matching::{Stylist, USER_OR_USER_AGENT_STYLESHEETS}; -use style::stylesheets::{CSSRuleIteratorExt, Stylesheet}; +use style::selector_impl::ServoSelectorImpl; +use style::selector_matching::USER_OR_USER_AGENT_STYLESHEETS; +use style::servo::{SharedStyleContext, Stylesheet, Stylist}; +use style::stylesheets::CSSRuleIteratorExt; use traversal::RecalcStyleAndConstructFlows; use url::Url; use util::geometry::MAX_RECT; @@ -477,7 +479,7 @@ impl LayoutThread { style_context: SharedStyleContext { viewport_size: self.viewport_size.clone(), screen_size_changed: screen_size_changed, - stylist: StylistWrapper(&*rw_data.stylist), + stylist: StylistWrapper::(&*rw_data.stylist), generation: self.generation, goal: goal, new_animations_sender: Mutex::new(self.new_animations_sender.clone()), diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index 69e85c39303..d5febecc483 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -16,6 +16,7 @@ use incremental::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, RestyleDam use std::mem; use style::context::{StyleContext, ReflowGoal}; use style::matching::MatchMethods; +use style::selector_impl::ServoSelectorImpl; use style::traversal::{DomTraversalContext, STYLE_BLOOM}; use style::traversal::{put_thread_local_bloom_filter, recalc_style_at}; use util::opts; @@ -27,7 +28,8 @@ pub struct RecalcStyleAndConstructFlows<'lc> { root: OpaqueNode, } -impl<'lc, 'ln, N: LayoutNode<'ln>> DomTraversalContext<'ln, N> for RecalcStyleAndConstructFlows<'lc> { +impl<'lc, 'ln, N: LayoutNode<'ln>> DomTraversalContext<'ln, N> for RecalcStyleAndConstructFlows<'lc> + where N::ConcreteElement: ::selectors::Element { type SharedContext = SharedLayoutContext; #[allow(unsafe_code)] fn new<'a>(shared: &'a Self::SharedContext, root: OpaqueNode) -> Self { diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 1c8f1ee1d8e..faacdbf44f0 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -64,13 +64,13 @@ use std::sync::Arc; use string_cache::{Atom, Namespace}; use style::computed_values::content::ContentItem; use style::computed_values::{content, display}; -use style::data::PrivateStyleData; use style::dom::{TDocument, TElement, TNode, UnsafeNode}; use style::element_state::*; use style::properties::ComputedValues; use style::properties::{PropertyDeclaration, PropertyDeclarationBlock}; use style::restyle_hints::ElementSnapshot; -use style::selector_impl::{NonTSPseudoClass, ServoSelectorImpl}; +use style::selector_impl::{NonTSPseudoClass, PseudoElement, ServoSelectorImpl}; +use style::servo::PrivateStyleData; use url::Url; use util::str::{is_whitespace, search_index}; @@ -664,16 +664,20 @@ pub trait ThreadSafeLayoutNode<'ln> : Clone + Copy + Sized { #[inline] fn get_before_pseudo(&self) -> Option { - self.borrow_layout_data().unwrap().style_data.before_style.as_ref().map(|style| { - self.with_pseudo(PseudoElementType::Before(style.get_box().display)) - }) + self.borrow_layout_data().unwrap() + .style_data.per_pseudo + .get(&PseudoElement::Before).unwrap_or(&None).as_ref().map(|style| { + self.with_pseudo(PseudoElementType::Before(style.get_box().display)) + }) } #[inline] fn get_after_pseudo(&self) -> Option { - self.borrow_layout_data().unwrap().style_data.after_style.as_ref().map(|style| { - self.with_pseudo(PseudoElementType::After(style.get_box().display)) - }) + self.borrow_layout_data().unwrap() + .style_data.per_pseudo + .get(&PseudoElement::After).unwrap_or(&None).as_ref().map(|style| { + self.with_pseudo(PseudoElementType::After(style.get_box().display)) + }) } /// Borrows the layout data immutably. Fails on a conflicting borrow. @@ -696,8 +700,8 @@ pub trait ThreadSafeLayoutNode<'ln> : Clone + Copy + Sized { fn style(&self) -> Ref> { Ref::map(self.borrow_layout_data().unwrap(), |data| { let style = match self.get_pseudo_element_type() { - PseudoElementType::Before(_) => &data.style_data.before_style, - PseudoElementType::After(_) => &data.style_data.after_style, + PseudoElementType::Before(_) => data.style_data.per_pseudo.get(&PseudoElement::Before).unwrap(), + PseudoElementType::After(_) => data.style_data.per_pseudo.get(&PseudoElement::After).unwrap(), PseudoElementType::Normal => &data.style_data.style, }; style.as_ref().unwrap() @@ -711,9 +715,19 @@ pub trait ThreadSafeLayoutNode<'ln> : Clone + Copy + Sized { let mut data = self.mutate_layout_data().unwrap(); let style = match self.get_pseudo_element_type() { - PseudoElementType::Before(_) => &mut data.style_data.before_style, - PseudoElementType::After (_) => &mut data.style_data.after_style, - PseudoElementType::Normal => &mut data.style_data.style, + PseudoElementType::Before(_) => { + match data.style_data.per_pseudo.get_mut(&PseudoElement::Before) { + None => return, + Some(style) => style, + } + } + PseudoElementType::After(_) => { + match data.style_data.per_pseudo.get_mut(&PseudoElement::After) { + None => return, + Some(style) => style, + } + } + PseudoElementType::Normal => &mut data.style_data.style, }; *style = None; @@ -934,10 +948,11 @@ impl<'ln> ThreadSafeLayoutNode<'ln> for ServoThreadSafeLayoutNode<'ln> { let data = &self.borrow_layout_data().unwrap().style_data; let style = if self.pseudo.is_before() { - &data.before_style + data.per_pseudo.get(&PseudoElement::Before).unwrap() } else { - &data.after_style + data.per_pseudo.get(&PseudoElement::After).unwrap() }; + return match style.as_ref().unwrap().get_box().content { content::T::Content(ref value) if !value.is_empty() => { TextContent::GeneratedContent((*value).clone()) diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index ef93986c204..1f3b7874d22 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -81,7 +81,7 @@ num = "0.1.24" rand = "0.3" ref_slice = "0.1.0" rustc-serialize = "0.3" -selectors = {version = "0.4.2", features = ["heap_size"]} +selectors = {version = "0.5", features = ["heap_size"]} serde = "0.6" smallvec = "0.1" string_cache = {version = "0.2.9", features = ["heap_size", "unstable"]} diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 99a61d2f981..a3af57b0814 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -105,7 +105,7 @@ use std::sync::Arc; use string_cache::{Atom, QualName}; use style::context::ReflowGoal; use style::restyle_hints::ElementSnapshot; -use style::stylesheets::Stylesheet; +use style::servo::Stylesheet; use time; use url::{Host, Url}; use util::str::{DOMString, split_html_space_chars, str_join}; diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index 38bb2287ac3..683b8cc6a84 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -36,7 +36,8 @@ use std::mem; use std::sync::{Arc, Mutex}; use string_cache::Atom; use style::media_queries::{MediaQueryList, parse_media_query_list}; -use style::stylesheets::{Origin, Stylesheet}; +use style::servo::Stylesheet; +use style::stylesheets::Origin; use url::Url; use util::str::{DOMString, HTML_SPACE_CHARACTERS}; diff --git a/components/script/dom/htmlmetaelement.rs b/components/script/dom/htmlmetaelement.rs index fdba6dc7c3c..779c5c79e07 100644 --- a/components/script/dom/htmlmetaelement.rs +++ b/components/script/dom/htmlmetaelement.rs @@ -15,7 +15,8 @@ use dom::virtualmethods::VirtualMethods; use std::ascii::AsciiExt; use std::sync::Arc; use string_cache::Atom; -use style::stylesheets::{CSSRule, Origin, Stylesheet}; +use style::servo::Stylesheet; +use style::stylesheets::{CSSRule, Origin}; use style::viewport::ViewportRule; use util::str::{DOMString, HTML_SPACE_CHARACTERS}; diff --git a/components/script/dom/htmlstyleelement.rs b/components/script/dom/htmlstyleelement.rs index 4b423b920b7..067561d4181 100644 --- a/components/script/dom/htmlstyleelement.rs +++ b/components/script/dom/htmlstyleelement.rs @@ -17,7 +17,8 @@ use layout_interface::{LayoutChan, Msg}; use std::sync::Arc; use string_cache::Atom; use style::media_queries::parse_media_query_list; -use style::stylesheets::{Origin, Stylesheet}; +use style::servo::Stylesheet; +use style::stylesheets::Origin; use util::str::DOMString; #[dom_struct] diff --git a/components/script/layout_interface.rs b/components/script/layout_interface.rs index c759b358e79..831c04a9516 100644 --- a/components/script/layout_interface.rs +++ b/components/script/layout_interface.rs @@ -24,7 +24,7 @@ use std::sync::mpsc::{Receiver, Sender, channel}; use string_cache::Atom; use style::context::ReflowGoal; use style::selector_impl::PseudoElement; -use style::stylesheets::Stylesheet; +use style::servo::Stylesheet; use url::Url; use util::ipc::OptionalOpaqueIpcSender; diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 4f62b6d95e4..b1dfc4d674b 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -1003,7 +1003,7 @@ dependencies = [ "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "script 0.0.1", "script_traits 0.0.1", - "selectors 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "selectors 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1590,7 +1590,7 @@ dependencies = [ "ref_slice 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "script_traits 0.0.1", - "selectors 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "selectors 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1641,7 +1641,7 @@ dependencies = [ [[package]] name = "selectors" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1850,7 +1850,7 @@ dependencies = [ "num 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "plugins 0.0.1", "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "selectors 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "selectors 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1870,7 +1870,7 @@ dependencies = [ "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", "plugins 0.0.1", - "selectors 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "selectors 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "style 0.0.1", "style_traits 0.0.1", @@ -1891,7 +1891,7 @@ dependencies = [ "num 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "plugins 0.0.1", "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "selectors 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "selectors 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2049,7 +2049,7 @@ dependencies = [ "plugins 0.0.1", "rand 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "selectors 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "selectors 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/components/style/Cargo.toml b/components/style/Cargo.toml index 5ab2db3199b..9e681f94b03 100644 --- a/components/style/Cargo.toml +++ b/components/style/Cargo.toml @@ -32,7 +32,7 @@ log = "0.3" matches = "0.1" num = "0.1.24" rustc-serialize = "0.3" -selectors = {version = "0.4.2", features = ["heap_size", "unstable"]} +selectors = {version = "0.5", features = ["heap_size", "unstable"]} serde = "0.6" serde_macros = "0.6" smallvec = "0.1" diff --git a/components/style/context.rs b/components/style/context.rs index f6b3cf86631..6e4edfd1b52 100644 --- a/components/style/context.rs +++ b/components/style/context.rs @@ -8,19 +8,20 @@ use dom::OpaqueNode; use error_reporting::ParseErrorReporter; use euclid::Size2D; use matching::{ApplicableDeclarationsCache, StyleSharingCandidateCache}; +use selector_impl::SelectorImplExt; use selector_matching::Stylist; use std::cell::RefCell; use std::collections::HashMap; use std::sync::mpsc::Sender; use std::sync::{Arc, Mutex, RwLock}; -pub struct StylistWrapper(pub *const Stylist); +pub struct StylistWrapper(pub *const Stylist); // FIXME(#6569) This implementation is unsound. #[allow(unsafe_code)] -unsafe impl Sync for StylistWrapper {} +unsafe impl Sync for StylistWrapper {} -pub struct SharedStyleContext { +pub struct SharedStyleContext { /// The current viewport size. pub viewport_size: Size2D, @@ -30,7 +31,7 @@ pub struct SharedStyleContext { /// The CSS selector stylist. /// /// FIXME(#2604): Make this no longer an unsafe pointer once we have fast `RWArc`s. - pub stylist: StylistWrapper, + pub stylist: StylistWrapper, /// Starts at zero, and increased by one every time a layout completes. /// This can be used to easily check for invalid stale data. @@ -58,8 +59,9 @@ pub struct LocalStyleContext { pub style_sharing_candidate_cache: RefCell, } -pub trait StyleContext<'a> { - fn shared_context(&self) -> &'a SharedStyleContext; +pub trait StyleContext<'a, Impl: SelectorImplExt> { + + fn shared_context(&self) -> &'a SharedStyleContext; fn local_context(&self) -> &LocalStyleContext; } diff --git a/components/style/data.rs b/components/style/data.rs index bfd1cd6113a..244e97e362d 100644 --- a/components/style/data.rs +++ b/components/style/data.rs @@ -3,29 +3,27 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use properties::ComputedValues; +use selectors::parser::SelectorImpl; +use std::collections::HashMap; use std::sync::Arc; use std::sync::atomic::AtomicIsize; -pub struct PrivateStyleData { +pub struct PrivateStyleData { /// The results of CSS styling for this node. pub style: Option>, - /// The results of CSS styling for this node's `before` pseudo-element, if any. - pub before_style: Option>, - - /// The results of CSS styling for this node's `after` pseudo-element, if any. - pub after_style: Option>, + /// The results of CSS styling for each pseudo-element (if any). + pub per_pseudo: HashMap>>, /// Information needed during parallel traversals. pub parallel: DomParallelInfo, } -impl PrivateStyleData { - pub fn new() -> PrivateStyleData { +impl PrivateStyleData { + pub fn new() -> PrivateStyleData { PrivateStyleData { style: None, - before_style: None, - after_style: None, + per_pseudo: HashMap::new(), parallel: DomParallelInfo::new(), } } diff --git a/components/style/dom.rs b/components/style/dom.rs index 9b0ce59167d..f4df206d32f 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -8,7 +8,8 @@ use data::PrivateStyleData; use element_state::ElementState; use properties::{ComputedValues, PropertyDeclaration, PropertyDeclarationBlock}; use restyle_hints::{ElementSnapshot, RESTYLE_DESCENDANTS, RESTYLE_LATER_SIBLINGS, RESTYLE_SELF, RestyleHint}; -use selector_impl::ServoSelectorImpl; +use selector_impl::ElementExt; +use selectors::Element; use selectors::matching::DeclarationBlock; use smallvec::VecLike; use std::cell::{Ref, RefMut}; @@ -136,15 +137,18 @@ pub trait TNode<'ln> : Sized + Copy + Clone { /// Borrows the PrivateStyleData without checks. #[inline(always)] - unsafe fn borrow_data_unchecked(&self) -> Option<*const PrivateStyleData>; + unsafe fn borrow_data_unchecked(&self) + -> Option<*const PrivateStyleData<::Impl>>; /// Borrows the PrivateStyleData immutably. Fails on a conflicting borrow. #[inline(always)] - fn borrow_data(&self) -> Option>; + fn borrow_data(&self) + -> Option::Impl>>>; /// Borrows the PrivateStyleData mutably. Fails on a conflicting borrow. #[inline(always)] - fn mutate_data(&self) -> Option>; + fn mutate_data(&self) + -> Option::Impl>>>; /// Get the description of how to account for recent style changes. fn restyle_damage(self) -> Self::ConcreteRestyleDamage; @@ -165,7 +169,7 @@ pub trait TNode<'ln> : Sized + Copy + Clone { /// Returns the style results for the given node. If CSS selector matching /// has not yet been performed, fails. - fn style(&self) -> Ref> { + fn style(&'ln self) -> Ref> { Ref::map(self.borrow_data().unwrap(), |data| data.style.as_ref().unwrap()) } @@ -186,7 +190,7 @@ pub trait TDocument<'ld> : Sized + Copy + Clone { fn drain_modified_elements(&self) -> Vec<(Self::ConcreteElement, ElementSnapshot)>; } -pub trait TElement<'le> : Sized + Copy + Clone + ::selectors::Element { +pub trait TElement<'le> : Sized + Copy + Clone + ElementExt { type ConcreteNode: TNode<'le, ConcreteElement = Self, ConcreteDocument = Self::ConcreteDocument>; type ConcreteDocument: TDocument<'le, ConcreteNode = Self::ConcreteNode, ConcreteElement = Self>; diff --git a/components/style/lib.rs b/components/style/lib.rs index 6dbb7250ffc..2305b0271cb 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -62,6 +62,7 @@ pub mod restyle_hints; pub mod selector_impl; pub mod selector_matching; pub mod sequential; +pub mod servo; pub mod stylesheets; pub mod traversal; #[macro_use] diff --git a/components/style/matching.rs b/components/style/matching.rs index 0e7ee4b6453..f4c5cd191cd 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -9,13 +9,14 @@ use context::SharedStyleContext; use data::PrivateStyleData; use dom::{TElement, TNode, TRestyleDamage}; use properties::{ComputedValues, PropertyDeclaration, cascade}; -use selector_impl::{NonTSPseudoClass, PseudoElement}; +use selector_impl::SelectorImplExt; use selector_matching::{DeclarationBlock, Stylist}; use selectors::Element; use selectors::bloom::BloomFilter; use selectors::matching::{CommonStyleAffectingAttributeMode, CommonStyleAffectingAttributes}; use selectors::matching::{common_style_affecting_attributes, rare_style_affecting_attributes}; use smallvec::SmallVec; +use std::collections::HashMap; use std::hash::{Hash, Hasher}; use std::slice::Iter; use std::sync::mpsc::Sender; @@ -51,23 +52,27 @@ fn create_common_style_affecting_attributes_from_element<'le, E: TElement<'le>>( flags } -pub struct ApplicableDeclarations { +pub struct ApplicableDeclarations { pub normal: SmallVec<[DeclarationBlock; 16]>, - pub before: Vec, - pub after: Vec, + pub per_pseudo: HashMap>, /// Whether the `normal` declarations are shareable with other nodes. pub normal_shareable: bool, } -impl ApplicableDeclarations { - pub fn new() -> ApplicableDeclarations { - ApplicableDeclarations { +impl ApplicableDeclarations { + pub fn new() -> ApplicableDeclarations { + let mut applicable_declarations = ApplicableDeclarations { normal: SmallVec::new(), - before: Vec::new(), - after: Vec::new(), + per_pseudo: HashMap::new(), normal_shareable: false, - } + }; + + Impl::each_eagerly_cascaded_pseudo_element(|pseudo| { + applicable_declarations.per_pseudo.insert(pseudo, vec![]); + }); + + applicable_declarations } } @@ -246,7 +251,7 @@ impl StyleSharingCandidate { local_name: element.get_local_name().clone(), class: element.get_attr(&ns!(), &atom!("class")) .map(|string| string.to_owned()), - link: element.match_non_ts_pseudo_class(NonTSPseudoClass::AnyLink), + link: element.is_link(), namespace: (*element.get_namespace()).clone(), common_style_affecting_attributes: create_common_style_affecting_attributes_from_element::<'le, E>(&element) @@ -314,7 +319,7 @@ impl StyleSharingCandidate { } } - if element.match_non_ts_pseudo_class(NonTSPseudoClass::AnyLink) != self.link { + if element.is_link() != self.link { return false } @@ -359,9 +364,10 @@ pub enum StyleSharingResult { StyleWasShared(usize, ConcreteRestyleDamage), } -trait PrivateMatchMethods<'ln>: TNode<'ln> { +trait PrivateMatchMethods<'ln>: TNode<'ln> + where ::Impl: SelectorImplExt { fn cascade_node_pseudo_element(&self, - context: &SharedStyleContext, + context: &SharedStyleContext<::Impl>, parent_style: Option<&Arc>, applicable_declarations: &[DeclarationBlock], style: &mut Option>, @@ -434,7 +440,7 @@ trait PrivateMatchMethods<'ln>: TNode<'ln> { } fn update_animations_for_cascade(&self, - context: &SharedStyleContext, + context: &SharedStyleContext<::Impl>, style: &mut Option>) -> bool { let style = match *style { @@ -478,7 +484,8 @@ trait PrivateMatchMethods<'ln>: TNode<'ln> { } } -impl<'ln, N: TNode<'ln>> PrivateMatchMethods<'ln> for N {} +impl<'ln, N: TNode<'ln>> PrivateMatchMethods<'ln> for N + where ::Impl: SelectorImplExt {} trait PrivateElementMatchMethods<'le>: TElement<'le> { fn share_style_with_candidate_if_possible(&self, @@ -490,7 +497,7 @@ trait PrivateElementMatchMethods<'le>: TElement<'le> { Some(_) | None => return None, }; - let parent_data: Option<&PrivateStyleData> = unsafe { + let parent_data: Option<&PrivateStyleData<_>> = unsafe { parent_node.borrow_data_unchecked().map(|d| &*d) }; @@ -512,11 +519,12 @@ trait PrivateElementMatchMethods<'le>: TElement<'le> { impl<'le, E: TElement<'le>> PrivateElementMatchMethods<'le> for E {} -pub trait ElementMatchMethods<'le> : TElement<'le> { +pub trait ElementMatchMethods<'le> : TElement<'le> + where Self::Impl: SelectorImplExt { fn match_element(&self, - stylist: &Stylist, + stylist: &Stylist, parent_bf: Option<&BloomFilter>, - applicable_declarations: &mut ApplicableDeclarations) + applicable_declarations: &mut ApplicableDeclarations) -> bool { let style_attribute = self.style_attribute().as_ref(); @@ -526,20 +534,16 @@ pub trait ElementMatchMethods<'le> : TElement<'le> { style_attribute, None, &mut applicable_declarations.normal); - stylist.push_applicable_declarations(self, - parent_bf, - None, - Some(PseudoElement::Before), - &mut applicable_declarations.before); - stylist.push_applicable_declarations(self, - parent_bf, - None, - Some(PseudoElement::After), - &mut applicable_declarations.after); + Self::Impl::each_eagerly_cascaded_pseudo_element(|pseudo| { + stylist.push_applicable_declarations(self, + parent_bf, + None, + Some(pseudo.clone()), + applicable_declarations.per_pseudo.entry(pseudo).or_insert(vec![])); + }); applicable_declarations.normal_shareable && - applicable_declarations.before.is_empty() && - applicable_declarations.after.is_empty() + applicable_declarations.per_pseudo.values().all(|v| v.is_empty()) } /// Attempts to share a style with another node. This method is unsafe because it depends on @@ -580,7 +584,8 @@ pub trait ElementMatchMethods<'le> : TElement<'le> { } } -impl<'le, E: TElement<'le>> ElementMatchMethods<'le> for E {} +impl<'le, E: TElement<'le>> ElementMatchMethods<'le> for E + where E::Impl: SelectorImplExt {} pub trait MatchMethods<'ln> : TNode<'ln> { // The below two functions are copy+paste because I can't figure out how to @@ -632,11 +637,12 @@ pub trait MatchMethods<'ln> : TNode<'ln> { } unsafe fn cascade_node(&self, - context: &SharedStyleContext, + context: &SharedStyleContext<::Impl>, parent: Option, - applicable_declarations: &ApplicableDeclarations, + applicable_declarations: &ApplicableDeclarations<::Impl>, applicable_declarations_cache: &mut ApplicableDeclarationsCache, - new_animations_sender: &Mutex>) { + new_animations_sender: &Mutex>) + where ::Impl: SelectorImplExt { // Get our parent's style. This must be unsafe so that we don't touch the parent's // borrow flags. // @@ -673,28 +679,24 @@ pub trait MatchMethods<'ln> : TNode<'ln> { new_animations_sender, applicable_declarations.normal_shareable, true); - if !applicable_declarations.before.is_empty() { - damage = damage | self.cascade_node_pseudo_element( - context, - Some(data.style.as_ref().unwrap()), - &*applicable_declarations.before, - &mut data.before_style, - applicable_declarations_cache, - new_animations_sender, - false, - false); - } - if !applicable_declarations.after.is_empty() { - damage = damage | self.cascade_node_pseudo_element( - context, - Some(data.style.as_ref().unwrap()), - &*applicable_declarations.after, - &mut data.after_style, - applicable_declarations_cache, - new_animations_sender, - false, - false); - } + + ::Impl::each_eagerly_cascaded_pseudo_element(|pseudo| { + let applicable_declarations_for_this_pseudo = + applicable_declarations.per_pseudo.get(&pseudo).unwrap(); + + + if !applicable_declarations_for_this_pseudo.is_empty() { + damage = damage | self.cascade_node_pseudo_element( + context, + Some(data.style.as_ref().unwrap()), + &*applicable_declarations_for_this_pseudo, + data.per_pseudo.entry(pseudo).or_insert(None), + applicable_declarations_cache, + new_animations_sender, + false, + false); + } + }); } // This method needs to borrow the data as mutable, so make sure data_ref goes out of diff --git a/components/style/restyle_hints.rs b/components/style/restyle_hints.rs index 1eaccff91e0..7d5a93ab157 100644 --- a/components/style/restyle_hints.rs +++ b/components/style/restyle_hints.rs @@ -4,10 +4,10 @@ use attr::{AttrIdentifier, AttrValue}; use element_state::*; -use selector_impl::{NonTSPseudoClass, ServoSelectorImpl}; +use selector_impl::SelectorImplExt; use selectors::Element; use selectors::matching::matches_compound_selector; -use selectors::parser::{AttrSelector, Combinator, CompoundSelector, NamespaceConstraint, SimpleSelector}; +use selectors::parser::{AttrSelector, Combinator, CompoundSelector, NamespaceConstraint, SelectorImpl, SimpleSelector}; use std::clone::Clone; use std::sync::Arc; use string_cache::{Atom, Namespace}; @@ -78,12 +78,16 @@ impl ElementSnapshot { static EMPTY_SNAPSHOT: ElementSnapshot = ElementSnapshot { state: None, attrs: None }; -struct ElementWrapper<'a, E> where E: Element { +struct ElementWrapper<'a, E> + where E: Element, + E::Impl: SelectorImplExt { element: E, snapshot: &'a ElementSnapshot, } -impl<'a, E> ElementWrapper<'a, E> where E: Element { +impl<'a, E> ElementWrapper<'a, E> + where E: Element, + E::Impl: SelectorImplExt { pub fn new(el: E) -> ElementWrapper<'a, E> { ElementWrapper { element: el, snapshot: &EMPTY_SNAPSHOT } } @@ -93,16 +97,19 @@ impl<'a, E> ElementWrapper<'a, E> where E: Element { } } -impl<'a, E> Element for ElementWrapper<'a, E> where E: Element { +impl<'a, E> Element for ElementWrapper<'a, E> + where E: Element, + E::Impl: SelectorImplExt { type Impl = E::Impl; - fn match_non_ts_pseudo_class(&self, pseudo_class: NonTSPseudoClass) -> bool { - let flag = pseudo_class.state_flag(); + fn match_non_ts_pseudo_class(&self, + pseudo_class: ::NonTSPseudoClass) -> bool { + let flag = Self::Impl::pseudo_class_state_flag(&pseudo_class); if flag == ElementState::empty() { self.element.match_non_ts_pseudo_class(pseudo_class) } else { match self.snapshot.state { - Some(s) => s.contains(pseudo_class.state_flag()), + Some(s) => s.contains(flag), None => self.element.match_non_ts_pseudo_class(pseudo_class) } } @@ -177,14 +184,14 @@ impl<'a, E> Element for ElementWrapper<'a, E> where E: Element) -> ElementState { +fn selector_to_state(sel: &SimpleSelector) -> ElementState { match *sel { - SimpleSelector::NonTSPseudoClass(ref pc) => pc.state_flag(), + SimpleSelector::NonTSPseudoClass(ref pc) => Impl::pseudo_class_state_flag(pc), _ => ElementState::empty(), } } -fn is_attr_selector(sel: &SimpleSelector) -> bool { +fn is_attr_selector(sel: &SimpleSelector) -> bool { match *sel { SimpleSelector::ID(_) | SimpleSelector::Class(_) | @@ -249,25 +256,25 @@ impl Sensitivities { // maximum effect that a given state or attribute change may have on the style of // elements in the document. #[derive(Debug)] -struct Dependency { - selector: Arc>, +struct Dependency { + selector: Arc>, combinator: Option, sensitivities: Sensitivities, } #[derive(Debug)] -pub struct DependencySet { - deps: Vec, +pub struct DependencySet { + deps: Vec>, } -impl DependencySet { - pub fn new() -> DependencySet { +impl DependencySet { + pub fn new() -> DependencySet { DependencySet { deps: Vec::new() } } pub fn compute_hint(&self, el: &E, snapshot: &ElementSnapshot, current_state: ElementState) -> RestyleHint - where E: Element + Clone { + where E: Element + Clone { let state_changes = snapshot.state.map_or(ElementState::empty(), |old_state| current_state ^ old_state); let attrs_changed = snapshot.attrs.is_some(); let mut hint = RestyleHint::empty(); @@ -287,7 +294,7 @@ impl DependencySet { hint } - pub fn note_selector(&mut self, selector: Arc>) { + pub fn note_selector(&mut self, selector: Arc>) { let mut cur = selector; let mut combinator: Option = None; loop { diff --git a/components/style/selector_impl.rs b/components/style/selector_impl.rs index 74f2bcde91b..1aa2469b6f5 100644 --- a/components/style/selector_impl.rs +++ b/components/style/selector_impl.rs @@ -2,15 +2,33 @@ * 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 selector_matching::{USER_OR_USER_AGENT_STYLESHEETS, QUIRKS_MODE_STYLESHEET}; +use selectors::Element; use selectors::parser::{ParserContext, SelectorImpl}; +use stylesheets::Stylesheet; -#[derive(Clone, Debug, PartialEq, HeapSizeOf)] +pub trait ElementExt: Element { + fn is_link(&self) -> bool; +} + +pub trait SelectorImplExt : SelectorImpl + Sized { + fn each_eagerly_cascaded_pseudo_element(mut fun: F) + where F: FnMut(::PseudoElement); + + fn pseudo_class_state_flag(pc: &Self::NonTSPseudoClass) -> ElementState; + + fn get_user_or_user_agent_stylesheets() -> &'static [Stylesheet]; + + fn get_quirks_mode_stylesheet() -> &'static Stylesheet; +} + +#[derive(Clone, Debug, PartialEq, Eq, HeapSizeOf, Hash)] pub enum PseudoElement { Before, After, } -#[derive(Clone, Debug, PartialEq, HeapSizeOf)] +#[derive(Clone, Debug, PartialEq, Eq, HeapSizeOf, Hash)] pub enum NonTSPseudoClass { AnyLink, Link, @@ -82,10 +100,42 @@ impl SelectorImpl for ServoSelectorImpl { fn parse_pseudo_element(_context: &ParserContext, name: &str) -> Result { use self::PseudoElement::*; - match_ignore_ascii_case! { name, - "before" => Ok(Before), - "after" => Ok(After), - _ => Err(()) - } + let pseudo_element = match_ignore_ascii_case! { name, + "before" => Before, + "after" => After, + _ => return Err(()) + }; + + Ok(pseudo_element) + } +} + +impl> ElementExt for E { + fn is_link(&self) -> bool { + self.match_non_ts_pseudo_class(NonTSPseudoClass::AnyLink) + } +} + +impl SelectorImplExt for ServoSelectorImpl { + #[inline] + fn each_eagerly_cascaded_pseudo_element(mut fun: F) + where F: FnMut(PseudoElement) { + fun(PseudoElement::Before); + fun(PseudoElement::After); + } + + #[inline] + fn pseudo_class_state_flag(pc: &NonTSPseudoClass) -> ElementState { + pc.state_flag() + } + + #[inline] + fn get_user_or_user_agent_stylesheets() -> &'static [Stylesheet] { + &*USER_OR_USER_AGENT_STYLESHEETS + } + + #[inline] + fn get_quirks_mode_stylesheet() -> &'static Stylesheet { + &*QUIRKS_MODE_STYLESHEET } } diff --git a/components/style/selector_matching.rs b/components/style/selector_matching.rs index 6fe34195b90..5fa0d3ab1f3 100644 --- a/components/style/selector_matching.rs +++ b/components/style/selector_matching.rs @@ -11,12 +11,14 @@ use error_reporting::{ParseErrorReporter, StdoutErrorReporter}; use media_queries::{Device, MediaType}; use properties::{PropertyDeclaration, PropertyDeclarationBlock}; use restyle_hints::{ElementSnapshot, RestyleHint, DependencySet}; -use selector_impl::{PseudoElement, ServoSelectorImpl}; +use selector_impl::{SelectorImplExt, ServoSelectorImpl}; use selectors::Element; use selectors::bloom::BloomFilter; use selectors::matching::DeclarationBlock as GenericDeclarationBlock; use selectors::matching::{Rule, SelectorMap}; +use selectors::parser::SelectorImpl; use smallvec::VecLike; +use std::collections::HashMap; use std::process; use std::sync::Arc; use style_traits::viewport::ViewportConstraints; @@ -30,7 +32,7 @@ use viewport::{MaybeNew, ViewportRuleCascade}; pub type DeclarationBlock = GenericDeclarationBlock>; lazy_static! { - pub static ref USER_OR_USER_AGENT_STYLESHEETS: Vec = { + 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?) @@ -61,7 +63,7 @@ lazy_static! { } lazy_static! { - pub static ref QUIRKS_MODE_STYLESHEET: Stylesheet = { + pub static ref QUIRKS_MODE_STYLESHEET: Stylesheet = { match read_resource_file(&["quirks-mode.css"]) { Ok(res) => { Stylesheet::from_bytes( @@ -80,7 +82,7 @@ lazy_static! { }; } -pub struct Stylist { +pub struct Stylist { // Device that the stylist is currently evaluating against. pub device: Device, @@ -95,50 +97,55 @@ pub struct Stylist { // The current selector maps, after evaluating media // rules against the current device. - element_map: PerPseudoElementSelectorMap, - before_map: PerPseudoElementSelectorMap, - after_map: PerPseudoElementSelectorMap, + element_map: PerPseudoElementSelectorMap, + pseudos_map: HashMap>, rules_source_order: usize, // Selector dependencies used to compute restyle hints. - state_deps: DependencySet, + state_deps: DependencySet, } -impl Stylist { +impl Stylist { #[inline] - pub fn new(device: Device) -> Stylist { - Stylist { + pub fn new(device: Device) -> Stylist { + let mut stylist = Stylist { viewport_constraints: None, device: device, is_device_dirty: true, quirks_mode: false, element_map: PerPseudoElementSelectorMap::new(), - before_map: PerPseudoElementSelectorMap::new(), - after_map: PerPseudoElementSelectorMap::new(), + pseudos_map: HashMap::new(), rules_source_order: 0, state_deps: DependencySet::new(), - } + }; + + Impl::each_eagerly_cascaded_pseudo_element(|pseudo| { + stylist.pseudos_map.insert(pseudo, PerPseudoElementSelectorMap::new()); + }); + // FIXME: Add iso-8859-9.css when the document’s encoding is ISO-8859-8. + + stylist } - pub fn update(&mut self, doc_stylesheets: &[Arc], - stylesheets_changed: bool) -> bool { + pub fn update(&mut self, doc_stylesheets: &[Arc>], + stylesheets_changed: bool) -> bool + where Impl: 'static { if !(self.is_device_dirty || stylesheets_changed) { return false; } self.element_map = PerPseudoElementSelectorMap::new(); - self.before_map = PerPseudoElementSelectorMap::new(); - self.after_map = PerPseudoElementSelectorMap::new(); + self.pseudos_map = HashMap::new(); self.rules_source_order = 0; self.state_deps.clear(); - for ref stylesheet in USER_OR_USER_AGENT_STYLESHEETS.iter() { + for ref stylesheet in Impl::get_user_or_user_agent_stylesheets().iter() { self.add_stylesheet(&stylesheet); } if self.quirks_mode { - self.add_stylesheet(&QUIRKS_MODE_STYLESHEET); + self.add_stylesheet(&Impl::get_quirks_mode_stylesheet()); } for ref stylesheet in doc_stylesheets.iter() { @@ -149,28 +156,12 @@ impl Stylist { true } - fn add_stylesheet(&mut self, stylesheet: &Stylesheet) { + fn add_stylesheet(&mut self, stylesheet: &Stylesheet) { let device = &self.device; if !stylesheet.is_effective_for_device(device) { return; } - let (mut element_map, mut before_map, mut after_map) = match stylesheet.origin { - Origin::UserAgent => ( - &mut self.element_map.user_agent, - &mut self.before_map.user_agent, - &mut self.after_map.user_agent, - ), - Origin::Author => ( - &mut self.element_map.author, - &mut self.before_map.author, - &mut self.after_map.author, - ), - Origin::User => ( - &mut self.element_map.user, - &mut self.before_map.user, - &mut self.after_map.user, - ), - }; + let mut rules_source_order = self.rules_source_order; // Take apart the StyleRule into individual Rules and insert @@ -179,11 +170,14 @@ impl Stylist { ($style_rule: ident, $priority: ident) => { if $style_rule.declarations.$priority.len() > 0 { for selector in &$style_rule.selectors { - let map = match selector.pseudo_element { - None => &mut element_map, - Some(PseudoElement::Before) => &mut before_map, - Some(PseudoElement::After) => &mut after_map, + let map = if let Some(ref pseudo) = selector.pseudo_element { + self.pseudos_map.entry(pseudo.clone()) + .or_insert_with(PerPseudoElementSelectorMap::new) + .borrow_for_origin(&stylesheet.origin) + } else { + self.element_map.borrow_for_origin(&stylesheet.origin) }; + map.$priority.insert(Rule { selector: selector.compound_selectors.clone(), declarations: DeclarationBlock { @@ -216,11 +210,11 @@ impl Stylist { // more expensive than getting it directly from the caller. current_state: ElementState) -> RestyleHint - where E: Element + Clone { + where E: Element + Clone { self.state_deps.compute_hint(element, snapshot, current_state) } - pub fn set_device(&mut self, mut device: Device, stylesheets: &[Arc]) { + pub fn set_device(&mut self, mut device: Device, stylesheets: &[Arc>]) { let cascaded_rule = stylesheets.iter() .flat_map(|s| s.effective_rules(&self.device).viewport()) .cascade(); @@ -256,19 +250,18 @@ impl Stylist { element: &E, parent_bf: Option<&BloomFilter>, style_attribute: Option<&PropertyDeclarationBlock>, - pseudo_element: Option, + pseudo_element: Option, applicable_declarations: &mut V) -> bool - where E: Element + TElement<'le>, + where E: Element + TElement<'le>, V: VecLike { assert!(!self.is_device_dirty); assert!(style_attribute.is_none() || pseudo_element.is_none(), "Style attributes do not apply to pseudo-elements"); let map = match pseudo_element { + Some(ref pseudo) => self.pseudos_map.get(pseudo).unwrap(), None => &self.element_map, - Some(PseudoElement::Before) => &self.before_map, - Some(PseudoElement::After) => &self.after_map, }; let mut shareable = true; @@ -336,14 +329,14 @@ impl Stylist { } } -struct PerOriginSelectorMap { - normal: SelectorMap, ServoSelectorImpl>, - important: SelectorMap, ServoSelectorImpl>, +struct PerOriginSelectorMap { + normal: SelectorMap, Impl>, + important: SelectorMap, Impl>, } -impl PerOriginSelectorMap { +impl PerOriginSelectorMap { #[inline] - fn new() -> PerOriginSelectorMap { + fn new() -> PerOriginSelectorMap { PerOriginSelectorMap { normal: SelectorMap::new(), important: SelectorMap::new(), @@ -351,19 +344,28 @@ impl PerOriginSelectorMap { } } -struct PerPseudoElementSelectorMap { - user_agent: PerOriginSelectorMap, - author: PerOriginSelectorMap, - user: PerOriginSelectorMap, +struct PerPseudoElementSelectorMap { + user_agent: PerOriginSelectorMap, + author: PerOriginSelectorMap, + user: PerOriginSelectorMap, } -impl PerPseudoElementSelectorMap { +impl PerPseudoElementSelectorMap { #[inline] - fn new() -> PerPseudoElementSelectorMap { + fn new() -> PerPseudoElementSelectorMap { PerPseudoElementSelectorMap { user_agent: PerOriginSelectorMap::new(), author: PerOriginSelectorMap::new(), user: PerOriginSelectorMap::new(), } } + + #[inline] + fn borrow_for_origin(&mut self, origin: &Origin) -> &mut PerOriginSelectorMap { + match *origin { + Origin::UserAgent => &mut self.user_agent, + Origin::Author => &mut self.author, + Origin::User => &mut self.user, + } + } } diff --git a/components/style/servo.rs b/components/style/servo.rs new file mode 100644 index 00000000000..56aef8f6210 --- /dev/null +++ b/components/style/servo.rs @@ -0,0 +1,15 @@ +/* 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 context; +use data; +use selector_impl::ServoSelectorImpl; +use selector_matching; +use stylesheets; + +/// Concrete types for servo Style implementation +pub type Stylesheet = stylesheets::Stylesheet; +pub type PrivateStyleData = data::PrivateStyleData; +pub type Stylist = selector_matching::Stylist; +pub type StylistWrapper = context::StylistWrapper; +pub type SharedStyleContext = context::SharedStyleContext; diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs index bc4008040c2..1e5d641ff02 100644 --- a/components/style/stylesheets.rs +++ b/components/style/stylesheets.rs @@ -10,12 +10,12 @@ use font_face::{FontFaceRule, parse_font_face_block}; use media_queries::{Device, MediaQueryList, parse_media_query_list}; use parser::{ParserContext, log_css_error}; use properties::{PropertyDeclarationBlock, parse_property_declaration_list}; -use selector_impl::ServoSelectorImpl; -use selectors::parser::{Selector, parse_selector_list}; +use selectors::parser::{Selector, SelectorImpl, parse_selector_list}; use smallvec::SmallVec; use std::ascii::AsciiExt; use std::cell::Cell; use std::iter::Iterator; +use std::marker::PhantomData; use std::slice; use string_cache::{Atom, Namespace}; use url::Url; @@ -39,10 +39,10 @@ pub enum Origin { #[derive(Debug, HeapSizeOf, PartialEq)] -pub struct Stylesheet { +pub struct Stylesheet { /// List of rules in the order they were found (important for /// cascading order) - pub rules: Vec, + pub rules: Vec>, /// List of media associated with the Stylesheet, if any. pub media: Option, pub origin: Origin, @@ -50,22 +50,22 @@ pub struct Stylesheet { #[derive(Debug, HeapSizeOf, PartialEq)] -pub enum CSSRule { +pub enum CSSRule { Charset(String), Namespace(Option, Namespace), - Style(StyleRule), - Media(MediaRule), + Style(StyleRule), + Media(MediaRule), FontFace(FontFaceRule), Viewport(ViewportRule), } #[derive(Debug, HeapSizeOf, PartialEq)] -pub struct MediaRule { +pub struct MediaRule { pub media_queries: MediaQueryList, - pub rules: Vec, + pub rules: Vec>, } -impl MediaRule { +impl MediaRule { #[inline] pub fn evaluate(&self, device: &Device) -> bool { self.media_queries.evaluate(device) @@ -73,17 +73,17 @@ impl MediaRule { } #[derive(Debug, HeapSizeOf, PartialEq)] -pub struct StyleRule { - pub selectors: Vec>, +pub struct StyleRule { + pub selectors: Vec>, pub declarations: PropertyDeclarationBlock, } -impl Stylesheet { +impl Stylesheet { pub fn from_bytes_iter>>( input: I, base_url: Url, protocol_encoding_label: Option<&str>, environment_encoding: Option, origin: Origin, - error_reporter: Box) -> Stylesheet { + error_reporter: Box) -> Stylesheet { let mut bytes = vec![]; // TODO: incremental decoding and tokenization/parsing for chunk in input { @@ -98,7 +98,7 @@ impl Stylesheet { protocol_encoding_label: Option<&str>, environment_encoding: Option, origin: Origin, error_reporter: Box) - -> Stylesheet { + -> Stylesheet { // TODO: bytes.as_slice could be bytes.container_as_bytes() let (string, _) = decode_stylesheet_bytes( bytes, protocol_encoding_label, environment_encoding); @@ -106,10 +106,11 @@ impl Stylesheet { } pub fn from_str(css: &str, base_url: Url, origin: Origin, - error_reporter: Box) -> Stylesheet { + error_reporter: Box) -> Stylesheet { let rule_parser = TopLevelRuleParser { context: ParserContext::new(origin, &base_url, error_reporter.clone()), state: Cell::new(State::Start), + _impl: PhantomData, }; let mut input = Parser::new(css); let mut iter = RuleListParser::new_for_stylesheet(&mut input, rule_parser); @@ -158,7 +159,7 @@ impl Stylesheet { /// Return an iterator over all the rules within the style-sheet. #[inline] - pub fn rules(&self) -> Rules { + pub fn rules(&self) -> Rules { Rules::new(self.rules.iter(), None) } @@ -169,7 +170,7 @@ impl Stylesheet { /// nested rules will be skipped. Use `rules` if all rules need to be /// examined. #[inline] - pub fn effective_rules<'a>(&'a self, device: &'a Device) -> Rules<'a> { + pub fn effective_rules<'a>(&'a self, device: &'a Device) -> Rules<'a, Impl> { Rules::new(self.rules.iter(), Some(device)) } } @@ -178,25 +179,25 @@ impl Stylesheet { /// /// The iteration order is pre-order. Specifically, this implies that a /// conditional group rule will come before its nested rules. -pub struct Rules<'a> { +pub struct Rules<'a, Impl: SelectorImpl + 'a> { // 2 because normal case is likely to be just one level of nesting (@media) - stack: SmallVec<[slice::Iter<'a, CSSRule>; 2]>, + stack: SmallVec<[slice::Iter<'a, CSSRule>; 2]>, device: Option<&'a Device> } -impl<'a> Rules<'a> { - fn new(iter: slice::Iter<'a, CSSRule>, device: Option<&'a Device>) -> Rules<'a> { - let mut stack: SmallVec<[slice::Iter<'a, CSSRule>; 2]> = SmallVec::new(); +impl<'a, Impl: SelectorImpl + 'a> Rules<'a, Impl> { + fn new(iter: slice::Iter<'a, CSSRule>, device: Option<&'a Device>) -> Rules<'a, Impl> { + let mut stack: SmallVec<[slice::Iter<'a, CSSRule>; 2]> = SmallVec::new(); stack.push(iter); Rules { stack: stack, device: device } } } -impl<'a> Iterator for Rules<'a> { - type Item = &'a CSSRule; +impl<'a, Impl: SelectorImpl + 'a> Iterator for Rules<'a, Impl> { + type Item = &'a CSSRule; - fn next(&mut self) -> Option<&'a CSSRule> { + fn next(&mut self) -> Option<&'a CSSRule> { while !self.stack.is_empty() { let top = self.stack.len() - 1; while let Some(rule) = self.stack[top].next() { @@ -231,6 +232,7 @@ impl<'a> Iterator for Rules<'a> { pub mod rule_filter { //! Specific `CSSRule` variant iterators. + use selectors::parser::SelectorImpl; use std::marker::PhantomData; use super::super::font_face::FontFaceRule; use super::super::viewport::ViewportRule; @@ -245,7 +247,8 @@ pub mod rule_filter { _lifetime: PhantomData<&'a ()> } - impl<'a, I> $variant<'a, I> where I: Iterator { + impl<'a, I, Impl: SelectorImpl + 'a> $variant<'a, I> + where I: Iterator> { pub fn new(iter: I) -> $variant<'a, I> { $variant { iter: iter, @@ -254,7 +257,8 @@ pub mod rule_filter { } } - impl<'a, I> Iterator for $variant<'a, I> where I: Iterator { + impl<'a, I, Impl: SelectorImpl + 'a> Iterator for $variant<'a, I> + where I: Iterator> { type Item = &'a $value; fn next(&mut self) -> Option<&'a $value> { @@ -275,14 +279,14 @@ pub mod rule_filter { } } + rule_filter!(Media -> MediaRule); + rule_filter!(Style -> StyleRule); rule_filter!(FontFace -> FontFaceRule); - rule_filter!(Media -> MediaRule); - rule_filter!(Style -> StyleRule); rule_filter!(Viewport -> ViewportRule); } /// Extension methods for `CSSRule` iterators. -pub trait CSSRuleIteratorExt<'a>: Iterator + Sized { +pub trait CSSRuleIteratorExt<'a, Impl: SelectorImpl + 'a>: Iterator> + Sized { /// Yield only @font-face rules. fn font_face(self) -> rule_filter::FontFace<'a, Self>; @@ -296,7 +300,7 @@ pub trait CSSRuleIteratorExt<'a>: Iterator + Sized { fn viewport(self) -> rule_filter::Viewport<'a, Self>; } -impl<'a, I> CSSRuleIteratorExt<'a> for I where I: Iterator { +impl<'a, I, Impl: SelectorImpl + 'a> CSSRuleIteratorExt<'a, Impl> for I where I: Iterator> { #[inline] fn font_face(self) -> rule_filter::FontFace<'a, I> { rule_filter::FontFace::new(self) @@ -318,8 +322,12 @@ impl<'a, I> CSSRuleIteratorExt<'a> for I where I: Iterator { } } -fn parse_nested_rules(context: &ParserContext, input: &mut Parser) -> Vec { - let mut iter = RuleListParser::new_for_nested_rule(input, NestedRuleParser { context: context }); +fn parse_nested_rules(context: &ParserContext, input: &mut Parser) -> Vec> { + let mut iter = RuleListParser::new_for_nested_rule(input, + NestedRuleParser { + context: context, + _impl: PhantomData + }); let mut rules = Vec::new(); while let Some(result) = iter.next() { match result { @@ -335,9 +343,10 @@ fn parse_nested_rules(context: &ParserContext, input: &mut Parser) -> Vec { +struct TopLevelRuleParser<'a, Impl: SelectorImpl> { context: ParserContext<'a>, state: Cell, + _impl: PhantomData } #[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)] @@ -356,12 +365,12 @@ enum AtRulePrelude { } -impl<'a> AtRuleParser for TopLevelRuleParser<'a> { +impl<'a, Impl: SelectorImpl> AtRuleParser for TopLevelRuleParser<'a, Impl> { type Prelude = AtRulePrelude; - type AtRule = CSSRule; + type AtRule = CSSRule; fn parse_prelude(&self, name: &str, input: &mut Parser) - -> Result, ()> { + -> Result>, ()> { match_ignore_ascii_case! { name, "charset" => { if self.state.get() <= State::Start { @@ -397,45 +406,46 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> { } self.state.set(State::Body); - AtRuleParser::parse_prelude(&NestedRuleParser { context: &self.context }, name, input) + AtRuleParser::parse_prelude(&NestedRuleParser { context: &self.context, _impl: PhantomData }, name, input) } #[inline] - fn parse_block(&self, prelude: AtRulePrelude, input: &mut Parser) -> Result { - AtRuleParser::parse_block(&NestedRuleParser { context: &self.context }, prelude, input) + fn parse_block(&self, prelude: AtRulePrelude, input: &mut Parser) -> Result, ()> { + AtRuleParser::parse_block(&NestedRuleParser { context: &self.context, _impl: PhantomData }, prelude, input) } } -impl<'a> QualifiedRuleParser for TopLevelRuleParser<'a> { - type Prelude = Vec>; - type QualifiedRule = CSSRule; +impl<'a, Impl: SelectorImpl> QualifiedRuleParser for TopLevelRuleParser<'a, Impl> { + type Prelude = Vec>; + type QualifiedRule = CSSRule; #[inline] - fn parse_prelude(&self, input: &mut Parser) -> Result>, ()> { + fn parse_prelude(&self, input: &mut Parser) -> Result>, ()> { self.state.set(State::Body); - QualifiedRuleParser::parse_prelude(&NestedRuleParser { context: &self.context }, input) + QualifiedRuleParser::parse_prelude(&NestedRuleParser { context: &self.context, _impl: PhantomData }, input) } #[inline] - fn parse_block(&self, prelude: Vec>, input: &mut Parser) -> Result { - QualifiedRuleParser::parse_block(&NestedRuleParser { context: &self.context }, + fn parse_block(&self, prelude: Vec>, input: &mut Parser) -> Result, ()> { + QualifiedRuleParser::parse_block(&NestedRuleParser { context: &self.context, _impl: PhantomData }, prelude, input) } } -struct NestedRuleParser<'a, 'b: 'a> { +struct NestedRuleParser<'a, 'b: 'a, Impl: SelectorImpl> { context: &'a ParserContext<'b>, + _impl: PhantomData, } -impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> { +impl<'a, 'b, Impl: SelectorImpl> AtRuleParser for NestedRuleParser<'a, 'b, Impl> { type Prelude = AtRulePrelude; - type AtRule = CSSRule; + type AtRule = CSSRule; fn parse_prelude(&self, name: &str, input: &mut Parser) - -> Result, ()> { + -> Result>, ()> { match_ignore_ascii_case! { name, "media" => { let media_queries = parse_media_query_list(input); @@ -455,7 +465,7 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> { } } - fn parse_block(&self, prelude: AtRulePrelude, input: &mut Parser) -> Result { + fn parse_block(&self, prelude: AtRulePrelude, input: &mut Parser) -> Result, ()> { match prelude { AtRulePrelude::FontFace => { parse_font_face_block(self.context, input).map(CSSRule::FontFace) @@ -474,15 +484,15 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> { } -impl<'a, 'b> QualifiedRuleParser for NestedRuleParser<'a, 'b> { - type Prelude = Vec>; - type QualifiedRule = CSSRule; +impl<'a, 'b, Impl: SelectorImpl> QualifiedRuleParser for NestedRuleParser<'a, 'b, Impl> { + type Prelude = Vec>; + type QualifiedRule = CSSRule; - fn parse_prelude(&self, input: &mut Parser) -> Result>, ()> { + fn parse_prelude(&self, input: &mut Parser) -> Result>, ()> { parse_selector_list(&self.context.selector_context, input) } - fn parse_block(&self, prelude: Vec>, input: &mut Parser) -> Result { + fn parse_block(&self, prelude: Vec>, input: &mut Parser) -> Result, ()> { Ok(CSSRule::Style(StyleRule { selectors: prelude, declarations: parse_property_declaration_list(self.context, input) diff --git a/components/style/traversal.rs b/components/style/traversal.rs index 781c99f619e..78f7cc46308 100644 --- a/components/style/traversal.rs +++ b/components/style/traversal.rs @@ -5,6 +5,8 @@ use context::{SharedStyleContext, StyleContext}; use dom::{OpaqueNode, TNode, TRestyleDamage, UnsafeNode}; use matching::{ApplicableDeclarations, ElementMatchMethods, MatchMethods, StyleSharingResult}; +use selector_impl::SelectorImplExt; +use selectors::Element; use selectors::bloom::BloomFilter; use std::cell::RefCell; use util::opts; @@ -41,11 +43,11 @@ thread_local!( /// /// If one does not exist, a new one will be made for you. If it is out of date, /// it will be cleared and reused. -fn take_thread_local_bloom_filter<'ln, N>(parent_node: Option, - root: OpaqueNode, - context: &SharedStyleContext) - -> Box - where N: TNode<'ln> { +fn take_thread_local_bloom_filter<'ln, N, Impl: SelectorImplExt>(parent_node: Option, + root: OpaqueNode, + context: &SharedStyleContext) + -> Box + where N: TNode<'ln> { STYLE_BLOOM.with(|style_bloom| { match (parent_node, style_bloom.borrow_mut().take()) { // Root node. Needs new bloom filter. @@ -77,9 +79,9 @@ fn take_thread_local_bloom_filter<'ln, N>(parent_node: Option, }) } -pub fn put_thread_local_bloom_filter(bf: Box, - unsafe_node: &UnsafeNode, - context: &SharedStyleContext) { +pub fn put_thread_local_bloom_filter(bf: Box, + unsafe_node: &UnsafeNode, + context: &SharedStyleContext) { STYLE_BLOOM.with(move |style_bloom| { assert!(style_bloom.borrow().is_none(), "Putting into a never-taken thread-local bloom filter"); @@ -117,7 +119,12 @@ pub trait DomTraversalContext<'ln, N: TNode<'ln>> { /// layout computation. This computes the styles applied to each node. #[inline] #[allow(unsafe_code)] -pub fn recalc_style_at<'a, 'ln, N: TNode<'ln>, C: StyleContext<'a>> (context: &'a C, root: OpaqueNode, node: N) { +pub fn recalc_style_at<'a, 'ln, N, C>(context: &'a C, + root: OpaqueNode, + node: N) + where N: TNode<'ln>, + C: StyleContext<'a, ::Impl>, + ::Impl: SelectorImplExt + 'a { // Initialize layout data. // // FIXME(pcwalton): Stop allocating here. Ideally this should just be done by the HTML diff --git a/components/style_traits/Cargo.toml b/components/style_traits/Cargo.toml index 45c5b5c9eaa..17dc272d4ca 100644 --- a/components/style_traits/Cargo.toml +++ b/components/style_traits/Cargo.toml @@ -22,7 +22,7 @@ lazy_static = "0.1.10" log = "0.3" num = "0.1.24" rustc-serialize = "0.3" -selectors = {version = "0.4.2", features = ["heap_size"]} +selectors = {version = "0.5", features = ["heap_size"]} serde = "0.6" serde_macros = "0.6" url = {version = "0.5.5", features = ["heap_size"]} diff --git a/components/util/Cargo.toml b/components/util/Cargo.toml index 34409a5fe9a..b6f8fd15640 100644 --- a/components/util/Cargo.toml +++ b/components/util/Cargo.toml @@ -41,7 +41,7 @@ num = "0.1.24" num_cpus = "0.2.2" rand = "0.3" rustc-serialize = "0.3" -selectors = {version = "0.4.2", features = ["heap_size"]} +selectors = {version = "0.5", features = ["heap_size"]} serde = "0.6" serde_macros = "0.6" smallvec = "0.1" diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index 34fe0033e48..b533ddcfce4 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -934,7 +934,7 @@ dependencies = [ "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "script 0.0.1", "script_traits 0.0.1", - "selectors 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "selectors 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1477,7 +1477,7 @@ dependencies = [ "ref_slice 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "script_traits 0.0.1", - "selectors 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "selectors 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1519,7 +1519,7 @@ dependencies = [ [[package]] name = "selectors" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1763,7 +1763,7 @@ dependencies = [ "num 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "plugins 0.0.1", "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "selectors 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "selectors 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1787,7 +1787,7 @@ dependencies = [ "num 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "plugins 0.0.1", "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "selectors 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "selectors 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1945,7 +1945,7 @@ dependencies = [ "plugins 0.0.1", "rand 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "selectors 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "selectors 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ports/geckolib/Cargo.lock b/ports/geckolib/Cargo.lock index c5d7da0b52a..b22092e02b2 100644 --- a/ports/geckolib/Cargo.lock +++ b/ports/geckolib/Cargo.lock @@ -6,10 +6,14 @@ dependencies = [ "bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "heapsize 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "heapsize_plugin 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "selectors 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "plugins 0.0.1", + "selectors 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "style 0.0.1", @@ -312,7 +316,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "selectors" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -389,7 +393,7 @@ dependencies = [ "num 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "plugins 0.0.1", "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "selectors 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "selectors 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -413,7 +417,7 @@ dependencies = [ "num 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "plugins 0.0.1", "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "selectors 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "selectors 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -492,7 +496,7 @@ dependencies = [ "plugins 0.0.1", "rand 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "selectors 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "selectors 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ports/geckolib/Cargo.toml b/ports/geckolib/Cargo.toml index 6f70ef7fc99..4e9cf774ea2 100644 --- a/ports/geckolib/Cargo.toml +++ b/ports/geckolib/Cargo.toml @@ -13,14 +13,20 @@ app_units = {version = "0.2.1", features = ["plugins"]} bitflags = "0.3" cssparser = {version = "0.5.3", features = ["heap_size", "serde-serialization"]} euclid = {version = "0.6.2", features = ["plugins"]} +heapsize = "0.3.0" +heapsize_plugin = "0.1.2" +lazy_static = "0.1" libc = "0.2" log = "0.3" num_cpus = "0.2.2" -selectors = {version = "0.4.2", features = ["heap_size"]} +selectors = {version = "0.5", features = ["heap_size"]} smallvec = "0.1" string_cache = {version = "0.2.9", features = ["heap_size"]} url = {version = "0.5.5", features = ["heap_size"]} +[dependencies.plugins] +path = "../../components/plugins" + [dependencies.util] path = "../../components/util" diff --git a/ports/geckolib/data.rs b/ports/geckolib/data.rs index 3e78c6c87ae..38351d70e2a 100644 --- a/ports/geckolib/data.rs +++ b/ports/geckolib/data.rs @@ -6,17 +6,15 @@ use bindings::ServoStyleSetData; use euclid::Size2D; use euclid::size::TypedSize2D; use num_cpus; +use selector_impl::{Stylist, Stylesheet, SharedStyleContext}; use std::cmp; use std::collections::HashMap; use std::sync::mpsc::{channel, Receiver, Sender}; use std::sync::{Arc, RwLock}; use style::animation::Animation; -use style::context::SharedStyleContext; use style::dom::OpaqueNode; use style::media_queries::{Device, MediaType}; use style::parallel::WorkQueueData; -use style::selector_matching::Stylist; -use style::stylesheets::Stylesheet; use util::geometry::ViewportPx; use util::thread_state; use util::workqueue::WorkQueue; diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 9ad4c99577a..d536a65bcb0 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -9,15 +9,16 @@ use bindings::RawGeckoDocument; use bindings::{ServoArcStyleSheet, ServoNodeData, ServoStyleSetData, uint8_t, uint32_t}; use data::PerDocumentStyleData; use euclid::Size2D; +use selector_impl::{SharedStyleContext, Stylesheet}; use std::mem::{forget, transmute}; use std::slice; use std::str::from_utf8_unchecked; use std::sync::{Arc, Mutex}; -use style::context::{ReflowGoal, SharedStyleContext, StylistWrapper}; +use style::context::{ReflowGoal, StylistWrapper}; use style::dom::{TDocument, TNode}; use style::error_reporting::StdoutErrorReporter; use style::parallel; -use style::stylesheets::{Origin, Stylesheet}; +use style::stylesheets::Origin; use traversal::RecalcStyleOnly; use url::Url; use util::arc_ptr_eq; diff --git a/ports/geckolib/lib.rs b/ports/geckolib/lib.rs index e47d757b127..dfb9bb06ea3 100644 --- a/ports/geckolib/lib.rs +++ b/ports/geckolib/lib.rs @@ -5,13 +5,24 @@ #![feature(as_unsafe_cell)] #![feature(box_syntax)] #![feature(ptr_as_ref)] +#![feature(custom_derive)] +#![feature(plugin)] + +#![plugin(heapsize_plugin)] +#![plugin(plugins)] extern crate app_units; #[macro_use] extern crate bitflags; +#[macro_use] extern crate cssparser; extern crate euclid; +extern crate heapsize; +#[macro_use] +extern crate lazy_static; extern crate libc; +#[macro_use] +extern crate log; extern crate num_cpus; extern crate selectors; extern crate smallvec; @@ -26,5 +37,6 @@ mod bindings; mod data; #[allow(non_snake_case)] pub mod glue; +mod selector_impl; mod traversal; mod wrapper; diff --git a/ports/geckolib/selector_impl.rs b/ports/geckolib/selector_impl.rs new file mode 100644 index 00000000000..2b2b3a3eb2b --- /dev/null +++ b/ports/geckolib/selector_impl.rs @@ -0,0 +1,307 @@ +/* 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 selectors::parser::{ParserContext, SelectorImpl}; +use std::process; +use style; +use style::element_state::ElementState; +use style::error_reporting::StdoutErrorReporter; +use style::selector_impl::SelectorImplExt; +use style::stylesheets::Origin; +use url::Url; +use util::resource_files::read_resource_file; + +pub type Stylist = style::selector_matching::Stylist; +pub type Stylesheet = style::stylesheets::Stylesheet; +pub type SharedStyleContext = style::context::SharedStyleContext; +pub type PrivateStyleData = style::data::PrivateStyleData; + +pub struct GeckoSelectorImpl; + +// TODO: Replace this with Gecko's stylesheets +lazy_static! { + 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:///{:?}", filename)).unwrap(), + None, + None, + Origin::UserAgent, + box StdoutErrorReporter); + stylesheets.push(ua_stylesheet); + } + Err(..) => { + error!("Failed to load UA stylesheet {}!", filename); + process::exit(1); + } + } + } + + stylesheets + }; +} + +lazy_static! { + static ref QUIRKS_MODE_STYLESHEET: Stylesheet = { + match read_resource_file(&["quirks-mode.css"]) { + Ok(res) => { + Stylesheet::from_bytes( + &res, + url!("chrome:///quirks-mode.css"), + None, + None, + Origin::UserAgent, + box StdoutErrorReporter) + }, + Err(..) => { + error!("Stylist failed to load 'quirks-mode.css'!"); + process::exit(1); + } + } + }; +} + + +#[derive(Clone, Debug, PartialEq, Eq, HeapSizeOf, Hash)] +pub enum PseudoElement { + Before, + After, + FirstLine, + // TODO: Probably a few more are missing here + + // https://mxr.mozilla.org/mozilla-central/source/layout/style/nsCSSAnonBoxList.h + MozNonElement, + MozAnonymousBlock, + MozAnonymousPositionedBlock, + MozMathMLAnonymousBlock, + MozXULAnonymousBlock, + + MozHorizontalFramesetBorder, + MozVerticalFramesetBorder, + MozLineFrame, + MozButtonContent, + MozButtonLabel, + MozCellContent, + MozDropdownList, + MozFieldsetContent, + MozFramesetBlank, + MozDisplayComboboxControlFrame, + + MozHTMLCanvasContent, + MozInlineTable, + MozTable, + MozTableCell, + MozTableColumnGroup, + MozTableColumn, + MozTableOuter, + MozTableRowGroup, + MozTableRow, + + MozCanvas, + MozPageBreak, + MozPage, + MozPageContent, + MozPageSequence, + MozScrolledContent, + MozScrolledCanvas, + MozScrolledPageSequence, + MozColumnContent, + MozViewport, + MozViewportScroll, + MozAnonymousFlexItem, + MozAnonymousGridItem, + + MozRuby, + MozRubyBase, + MozRubyBaseContainer, + MozRubyText, + MozRubyTextContainer, + + MozTreeColumn, + MozTreeRow, + MozTreeSeparator, + MozTreeCell, + MozTreeIndentation, + MozTreeLine, + MozTreeTwisty, + MozTreeImage, + MozTreeCellText, + MozTreeCheckbox, + MozTreeProgressMeter, + MozTreeDropFeedback, + + MozSVGMarkerAnonChild, + MozSVGOuterSVGAnonChild, + MozSVGForeignContent, + MozSVGText, +} + +#[derive(Clone, Debug, PartialEq, Eq, HeapSizeOf, Hash)] +pub enum NonTSPseudoClass { + AnyLink, + Link, + Visited, + Active, + Focus, + Hover, + Enabled, + Disabled, + Checked, + Indeterminate, +} + +impl NonTSPseudoClass { + pub fn state_flag(&self) -> ElementState { + use self::NonTSPseudoClass::*; + use style::element_state::*; + 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, + + AnyLink | + Link | + Visited => ElementState::empty(), + } + } +} + +impl SelectorImpl for GeckoSelectorImpl { + 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, + _ => 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, + "first-line" => FirstLine, + + "-moz-non-element" => MozNonElement, + + "-moz-anonymous-block" => MozAnonymousBlock, + "-moz-anonymous-positioned-block" => MozAnonymousPositionedBlock, + "-moz-mathml-anonymous-block" => MozMathMLAnonymousBlock, + "-moz-xul-anonymous-block" => MozXULAnonymousBlock, + + "-moz-hframeset-border" => MozHorizontalFramesetBorder, + "-moz-vframeset-border" => MozVerticalFramesetBorder, + + "-moz-line-frame" => MozLineFrame, + + "-moz-button-content" => MozButtonContent, + "-moz-buttonlabel" => MozButtonLabel, + "-moz-cell-content" => MozCellContent, + "-moz-dropdown-list" => MozDropdownList, + "-moz-fieldset-content" => MozFieldsetContent, + "-moz-frameset-blank" => MozFramesetBlank, + "-moz-display-comboboxcontrol-frame" => MozDisplayComboboxControlFrame, + "-moz-html-canvas-content" => MozHTMLCanvasContent, + + "-moz-inline-table" => MozInlineTable, + "-moz-table" => MozTable, + "-moz-table-cell" => MozTableCell, + "-moz-table-column-group" => MozTableColumnGroup, + "-moz-table-column" => MozTableColumn, + "-moz-table-outer" => MozTableOuter, + "-moz-table-row-group" => MozTableRowGroup, + "-moz-table-row" => MozTableRow, + + "-moz-canvas" => MozCanvas, + "-moz-pagebreak" => MozPageBreak, + "-moz-page" => MozPage, + "-moz-pagecontent" => MozPageContent, + "-moz-page-sequence" => MozPageSequence, + "-moz-scrolled-content" => MozScrolledContent, + "-moz-scrolled-canvas" => MozScrolledCanvas, + "-moz-scrolled-page-sequence" => MozScrolledPageSequence, + "-moz-column-content" => MozColumnContent, + "-moz-viewport" => MozViewport, + "-moz-viewport-scroll" => MozViewportScroll, + "-moz-anonymous-flex-item" => MozAnonymousFlexItem, + "-moz-anonymous-grid-item" => MozAnonymousGridItem, + "-moz-ruby" => MozRuby, + "-moz-ruby-base" => MozRubyBase, + "-moz-ruby-base-container" => MozRubyBaseContainer, + "-moz-ruby-text" => MozRubyText, + "-moz-ruby-text-container" => MozRubyTextContainer, + "-moz-tree-column" => MozTreeColumn, + "-moz-tree-row" => MozTreeRow, + "-moz-tree-separator" => MozTreeSeparator, + "-moz-tree-cell" => MozTreeCell, + "-moz-tree-indentation" => MozTreeIndentation, + "-moz-tree-line" => MozTreeLine, + "-moz-tree-twisty" => MozTreeTwisty, + "-moz-tree-image" => MozTreeImage, + "-moz-tree-cell-text" => MozTreeCellText, + "-moz-tree-checkbox" => MozTreeCheckbox, + "-moz-tree-progressmeter" => MozTreeProgressMeter, + "-moz-tree-drop-feedback" => MozTreeDropFeedback, + "-moz-svg-marker-anon-child" => MozSVGMarkerAnonChild, + "-moz-svg-outer-svg-anon-child" => MozSVGOuterSVGAnonChild, + "-moz-svg-foreign-content" => MozSVGForeignContent, + "-moz-svg-text" => MozSVGText, + + _ => return Err(()) + }; + + Ok(pseudo_element) + } +} + +impl SelectorImplExt for GeckoSelectorImpl { + #[inline] + fn each_eagerly_cascaded_pseudo_element(mut fun: F) + where F: FnMut(PseudoElement) { + fun(PseudoElement::Before); + fun(PseudoElement::After); + // TODO: probably a lot more are missing here + } + + #[inline] + fn pseudo_class_state_flag(pc: &NonTSPseudoClass) -> ElementState { + pc.state_flag() + } + + // FIXME: Don't use Servo's UA stylesheets, use Gecko's instead + #[inline] + fn get_user_or_user_agent_stylesheets() -> &'static [Stylesheet] { + &*USER_OR_USER_AGENT_STYLESHEETS + } + + #[inline] + fn get_quirks_mode_stylesheet() -> &'static Stylesheet { + &*QUIRKS_MODE_STYLESHEET + } +} diff --git a/ports/geckolib/traversal.rs b/ports/geckolib/traversal.rs index 217035f5a52..7c824f3e5b5 100644 --- a/ports/geckolib/traversal.rs +++ b/ports/geckolib/traversal.rs @@ -2,10 +2,11 @@ * 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 selector_impl::{GeckoSelectorImpl, SharedStyleContext}; use std::cell::RefCell; use std::mem; use std::rc::Rc; -use style::context::{LocalStyleContext, SharedStyleContext, StyleContext}; +use style::context::{LocalStyleContext, StyleContext}; use style::dom::{OpaqueNode, TNode}; use style::matching::{ApplicableDeclarationsCache, StyleSharingCandidateCache}; use style::traversal::{DomTraversalContext, recalc_style_at}; @@ -48,7 +49,7 @@ impl<'a> StandaloneStyleContext<'a> { } } -impl<'a> StyleContext<'a> for StandaloneStyleContext<'a> { +impl<'a> StyleContext<'a, GeckoSelectorImpl> for StandaloneStyleContext<'a> { fn shared_context(&self) -> &'a SharedStyleContext { &self.shared } @@ -63,7 +64,8 @@ pub struct RecalcStyleOnly<'lc> { root: OpaqueNode, } -impl<'lc, 'ln, N: TNode<'ln>> DomTraversalContext<'ln, N> for RecalcStyleOnly<'lc> { +impl<'lc, 'ln, N: TNode<'ln>> DomTraversalContext<'ln, N> for RecalcStyleOnly<'lc> + where N::ConcreteElement: ::selectors::Element { type SharedContext = SharedStyleContext; #[allow(unsafe_code)] fn new<'a>(shared: &'a Self::SharedContext, root: OpaqueNode) -> Self { diff --git a/ports/geckolib/wrapper.rs b/ports/geckolib/wrapper.rs index 03c436f7d28..eb5de635090 100644 --- a/ports/geckolib/wrapper.rs +++ b/ports/geckolib/wrapper.rs @@ -19,6 +19,8 @@ use bindings::{Gecko_LocalName, Gecko_Namespace, Gecko_NodeIsElement, Gecko_SetN use bindings::{RawGeckoDocument, RawGeckoElement, RawGeckoNode}; use bindings::{ServoNodeData}; use libc::uintptr_t; +use selector_impl::{GeckoSelectorImpl, NonTSPseudoClass, PrivateStyleData}; +use selectors::Element; use selectors::matching::DeclarationBlock; use selectors::parser::{AttrSelector, NamespaceConstraint}; use smallvec::VecLike; @@ -29,7 +31,6 @@ use std::slice; use std::str::from_utf8_unchecked; use std::sync::Arc; use string_cache::{Atom, Namespace}; -use style::data::PrivateStyleData; use style::dom::{OpaqueNode, TDocument, TElement, TNode, TRestyleDamage, UnsafeNode}; use style::element_state::ElementState; #[allow(unused_imports)] // Used in commented-out code. @@ -38,7 +39,7 @@ use style::properties::{ComputedValues, PropertyDeclaration, PropertyDeclaration #[allow(unused_imports)] // Used in commented-out code. use style::properties::{parse_style_attribute}; use style::restyle_hints::ElementSnapshot; -use style::selector_impl::{NonTSPseudoClass, ServoSelectorImpl}; +use style::selector_impl::ElementExt; #[allow(unused_imports)] // Used in commented-out code. use url::Url; @@ -357,7 +358,7 @@ impl<'le> TElement<'le> for GeckoElement<'le> { } impl<'le> ::selectors::Element for GeckoElement<'le> { - type Impl = ServoSelectorImpl; + type Impl = GeckoSelectorImpl; fn parent_element(&self) -> Option { unsafe { @@ -427,11 +428,6 @@ impl<'le> ::selectors::Element for GeckoElement<'le> { NonTSPseudoClass::Link => unsafe { Gecko_IsLink(self.element) != 0 }, NonTSPseudoClass::AnyLink => unsafe { Gecko_IsUnvisitedLink(self.element) != 0 }, NonTSPseudoClass::Visited => unsafe { Gecko_IsVisitedLink(self.element) != 0 }, - - NonTSPseudoClass::ServoNonZeroBorder => { - unimplemented!() - }, - NonTSPseudoClass::Active | NonTSPseudoClass::Focus | NonTSPseudoClass::Hover | @@ -489,6 +485,12 @@ impl<'le> ::selectors::Element for GeckoElement<'le> { } } +impl<'le> ElementExt for GeckoElement<'le> { + fn is_link(&self) -> bool { + self.match_non_ts_pseudo_class(NonTSPseudoClass::AnyLink) + } +} + unsafe fn reinterpret_string<'a>(ptr: *const ::libc::c_char, length: u32) -> Option<&'a str> { (ptr as *const u8).as_ref().map(|p| from_utf8_unchecked(slice::from_raw_parts(p, length as usize))) } diff --git a/ports/gonk/Cargo.lock b/ports/gonk/Cargo.lock index d21024d2764..c410acbe2fe 100644 --- a/ports/gonk/Cargo.lock +++ b/ports/gonk/Cargo.lock @@ -916,7 +916,7 @@ dependencies = [ "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "script 0.0.1", "script_traits 0.0.1", - "selectors 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "selectors 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1459,7 +1459,7 @@ dependencies = [ "ref_slice 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "script_traits 0.0.1", - "selectors 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "selectors 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1501,7 +1501,7 @@ dependencies = [ [[package]] name = "selectors" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1743,7 +1743,7 @@ dependencies = [ "num 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "plugins 0.0.1", "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "selectors 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "selectors 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1767,7 +1767,7 @@ dependencies = [ "num 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "plugins 0.0.1", "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "selectors 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "selectors 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1925,7 +1925,7 @@ dependencies = [ "plugins 0.0.1", "rand 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "selectors 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "selectors 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_macros 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/tests/unit/style/Cargo.toml b/tests/unit/style/Cargo.toml index 637f3fe112d..43a2fafaa55 100644 --- a/tests/unit/style/Cargo.toml +++ b/tests/unit/style/Cargo.toml @@ -27,6 +27,6 @@ path = "../../../components/util" app_units = {version = "0.2.1", features = ["plugins"]} cssparser = {version = "0.5.3", features = ["heap_size"]} euclid = {version = "0.6.2", features = ["plugins"]} -selectors = {version = "0.4.2", features = ["heap_size"]} +selectors = {version = "0.5", features = ["heap_size"]} string_cache = {version = "0.2.9", features = ["heap_size"]} url = {version = "0.5.5", features = ["heap_size"]} diff --git a/tests/unit/style/media_queries.rs b/tests/unit/style/media_queries.rs index 34a8a54197f..c194fa4ee92 100644 --- a/tests/unit/style/media_queries.rs +++ b/tests/unit/style/media_queries.rs @@ -8,7 +8,8 @@ use euclid::size::Size2D; use std::borrow::ToOwned; use style::error_reporting::ParseErrorReporter; use style::media_queries::*; -use style::stylesheets::{Origin, Stylesheet, CSSRuleIteratorExt}; +use style::servo::Stylesheet; +use style::stylesheets::{Origin, CSSRuleIteratorExt}; use style::values::specified; pub struct CSSErrorReporterTest; diff --git a/tests/unit/style/stylesheets.rs b/tests/unit/style/stylesheets.rs index 997a0c8af6f..46e1f89aaff 100644 --- a/tests/unit/style/stylesheets.rs +++ b/tests/unit/style/stylesheets.rs @@ -10,8 +10,9 @@ use std::sync::Arc; use std::sync::Mutex; use string_cache::Atom; use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, DeclaredValue, longhands}; -use style::stylesheets::{CSSRule, StyleRule, Origin, Stylesheet}; +use style::stylesheets::{CSSRule, StyleRule, Origin}; use style::error_reporting::ParseErrorReporter; +use style::servo::Stylesheet; #[test] fn test_parse_stylesheet() { diff --git a/tests/unit/style/viewport.rs b/tests/unit/style/viewport.rs index c3fb4dd59f1..15707faec75 100644 --- a/tests/unit/style/viewport.rs +++ b/tests/unit/style/viewport.rs @@ -9,7 +9,8 @@ use media_queries::CSSErrorReporterTest; use style::error_reporting::ParseErrorReporter; use style::media_queries::{Device, MediaType}; use style::parser::ParserContext; -use style::stylesheets::{Origin, Stylesheet, CSSRuleIteratorExt}; +use style::servo::Stylesheet; +use style::stylesheets::{Origin, CSSRuleIteratorExt}; use style::values::specified::Length::{self, ViewportPercentage}; use style::values::specified::LengthOrPercentageOrAuto::{self, Auto}; use style::values::specified::ViewportPercentageLength::Vw; From eddec5cc06123ca98cd9ecdfc393a14bd7ed779b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 11 Feb 2016 03:05:06 +0100 Subject: [PATCH 2/6] style: Use fnv hashing for pseudo-elements --- components/style/data.rs | 5 +++-- components/style/matching.rs | 6 +++--- components/style/selector_matching.rs | 7 ++++--- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/components/style/data.rs b/components/style/data.rs index 244e97e362d..e2e806cee26 100644 --- a/components/style/data.rs +++ b/components/style/data.rs @@ -5,6 +5,7 @@ use properties::ComputedValues; use selectors::parser::SelectorImpl; use std::collections::HashMap; +use std::hash::BuildHasherDefault; use std::sync::Arc; use std::sync::atomic::AtomicIsize; @@ -13,7 +14,7 @@ pub struct PrivateStyleData { pub style: Option>, /// The results of CSS styling for each pseudo-element (if any). - pub per_pseudo: HashMap>>, + pub per_pseudo: HashMap>, BuildHasherDefault<::fnv::FnvHasher>>, /// Information needed during parallel traversals. pub parallel: DomParallelInfo, @@ -23,7 +24,7 @@ impl PrivateStyleData { pub fn new() -> PrivateStyleData { PrivateStyleData { style: None, - per_pseudo: HashMap::new(), + per_pseudo: HashMap::with_hasher(Default::default()), parallel: DomParallelInfo::new(), } } diff --git a/components/style/matching.rs b/components/style/matching.rs index f4c5cd191cd..b33d9fcd6da 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -17,7 +17,7 @@ use selectors::matching::{CommonStyleAffectingAttributeMode, CommonStyleAffectin use selectors::matching::{common_style_affecting_attributes, rare_style_affecting_attributes}; use smallvec::SmallVec; use std::collections::HashMap; -use std::hash::{Hash, Hasher}; +use std::hash::{BuildHasherDefault, Hash, Hasher}; use std::slice::Iter; use std::sync::mpsc::Sender; use std::sync::{Arc, Mutex}; @@ -54,7 +54,7 @@ fn create_common_style_affecting_attributes_from_element<'le, E: TElement<'le>>( pub struct ApplicableDeclarations { pub normal: SmallVec<[DeclarationBlock; 16]>, - pub per_pseudo: HashMap>, + pub per_pseudo: HashMap, BuildHasherDefault<::fnv::FnvHasher>>, /// Whether the `normal` declarations are shareable with other nodes. pub normal_shareable: bool, @@ -64,7 +64,7 @@ impl ApplicableDeclarations { pub fn new() -> ApplicableDeclarations { let mut applicable_declarations = ApplicableDeclarations { normal: SmallVec::new(), - per_pseudo: HashMap::new(), + per_pseudo: HashMap::with_hasher(Default::default()), normal_shareable: false, }; diff --git a/components/style/selector_matching.rs b/components/style/selector_matching.rs index 5fa0d3ab1f3..be3ae5453fa 100644 --- a/components/style/selector_matching.rs +++ b/components/style/selector_matching.rs @@ -19,6 +19,7 @@ use selectors::matching::{Rule, SelectorMap}; use selectors::parser::SelectorImpl; use smallvec::VecLike; use std::collections::HashMap; +use std::hash::BuildHasherDefault; use std::process; use std::sync::Arc; use style_traits::viewport::ViewportConstraints; @@ -98,7 +99,7 @@ pub struct Stylist { // The current selector maps, after evaluating media // rules against the current device. element_map: PerPseudoElementSelectorMap, - pseudos_map: HashMap>, + pseudos_map: HashMap, BuildHasherDefault<::fnv::FnvHasher>>, rules_source_order: usize, // Selector dependencies used to compute restyle hints. @@ -115,7 +116,7 @@ impl Stylist { quirks_mode: false, element_map: PerPseudoElementSelectorMap::new(), - pseudos_map: HashMap::new(), + pseudos_map: HashMap::with_hasher(Default::default()), rules_source_order: 0, state_deps: DependencySet::new(), }; @@ -136,7 +137,7 @@ impl Stylist { return false; } self.element_map = PerPseudoElementSelectorMap::new(); - self.pseudos_map = HashMap::new(); + self.pseudos_map = HashMap::with_hasher(Default::default()); self.rules_source_order = 0; self.state_deps.clear(); From dad1738ba720797c79e6ff509fa0902b466775fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 11 Feb 2016 03:37:34 +0100 Subject: [PATCH 3/6] geckolib: Fix :link and :any-link pseudo-element matching The logic was switched between them. --- ports/geckolib/wrapper.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/geckolib/wrapper.rs b/ports/geckolib/wrapper.rs index eb5de635090..c650d9c6dee 100644 --- a/ports/geckolib/wrapper.rs +++ b/ports/geckolib/wrapper.rs @@ -425,8 +425,8 @@ impl<'le> ::selectors::Element for GeckoElement<'le> { fn match_non_ts_pseudo_class(&self, pseudo_class: NonTSPseudoClass) -> bool { match pseudo_class { // https://github.com/servo/servo/issues/8718 - NonTSPseudoClass::Link => unsafe { Gecko_IsLink(self.element) != 0 }, - NonTSPseudoClass::AnyLink => unsafe { Gecko_IsUnvisitedLink(self.element) != 0 }, + NonTSPseudoClass::AnyLink => unsafe { Gecko_IsLink(self.element) != 0 }, + NonTSPseudoClass::Link => unsafe { Gecko_IsUnvisitedLink(self.element) != 0 }, NonTSPseudoClass::Visited => unsafe { Gecko_IsVisitedLink(self.element) != 0 }, NonTSPseudoClass::Active | NonTSPseudoClass::Focus | From a604d605edf1813cc129409babb819d26db90824 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Fri, 12 Feb 2016 01:51:36 +0100 Subject: [PATCH 4/6] style: Prevent a crash when push_applicable_declarations is called with a non eagerly-cascaded pseudo-element This actually didn't happen, but this should be done sooner than later. --- components/style/selector_matching.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/components/style/selector_matching.rs b/components/style/selector_matching.rs index be3ae5453fa..a6c93cebcbc 100644 --- a/components/style/selector_matching.rs +++ b/components/style/selector_matching.rs @@ -261,7 +261,12 @@ impl Stylist { "Style attributes do not apply to pseudo-elements"); let map = match pseudo_element { - Some(ref pseudo) => self.pseudos_map.get(pseudo).unwrap(), + Some(ref pseudo) => match self.pseudos_map.get(pseudo) { + Some(map) => map, + // TODO(ecoal95): get non eagerly-cascaded pseudo-element rules here. + // Actually assume there are no rules applicable. + None => return true, + }, None => &self.element_map, }; From 61e04df2664725624f706327cd417fe24aff6e2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Fri, 12 Feb 2016 02:11:44 +0100 Subject: [PATCH 5/6] style: Refactor the per_pseudo map from StyleData to avoid having an option value type. This make the layout code way clearer. --- components/layout/incremental.rs | 13 +++++----- components/layout/wrapper.rs | 44 +++++++++++++++----------------- components/style/animation.rs | 2 +- components/style/data.rs | 2 +- components/style/dom.rs | 2 +- components/style/matching.rs | 39 ++++++++++++++++------------ ports/geckolib/wrapper.rs | 2 +- 7 files changed, 52 insertions(+), 52 deletions(-) diff --git a/components/layout/incremental.rs b/components/layout/incremental.rs index 6865d037651..9bf4aff2e14 100644 --- a/components/layout/incremental.rs +++ b/components/layout/incremental.rs @@ -49,7 +49,7 @@ bitflags! { } impl TRestyleDamage for RestyleDamage { - fn compute(old: &Option>, new: &ComputedValues) -> RestyleDamage { compute_damage(old, new) } + fn compute(old: Option<&Arc>, new: &ComputedValues) -> RestyleDamage { compute_damage(old, new) } /// Returns a bitmask that represents a flow that needs to be rebuilt and reflowed. /// @@ -143,12 +143,11 @@ macro_rules! add_if_not_equal( }) ); -pub fn compute_damage(old: &Option>, new: &ComputedValues) -> RestyleDamage { - let old: &ComputedValues = - match old.as_ref() { - None => return RestyleDamage::rebuild_and_reflow(), - Some(cv) => &**cv, - }; +pub fn compute_damage(old: Option<&Arc>, new: &ComputedValues) -> RestyleDamage { + let old: &ComputedValues = match old { + None => return RestyleDamage::rebuild_and_reflow(), + Some(cv) => &**cv, + }; let mut damage = RestyleDamage::empty(); diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index faacdbf44f0..3174bed38a4 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -666,7 +666,8 @@ pub trait ThreadSafeLayoutNode<'ln> : Clone + Copy + Sized { fn get_before_pseudo(&self) -> Option { self.borrow_layout_data().unwrap() .style_data.per_pseudo - .get(&PseudoElement::Before).unwrap_or(&None).as_ref().map(|style| { + .get(&PseudoElement::Before) + .map(|style| { self.with_pseudo(PseudoElementType::Before(style.get_box().display)) }) } @@ -675,7 +676,8 @@ pub trait ThreadSafeLayoutNode<'ln> : Clone + Copy + Sized { fn get_after_pseudo(&self) -> Option { self.borrow_layout_data().unwrap() .style_data.per_pseudo - .get(&PseudoElement::After).unwrap_or(&None).as_ref().map(|style| { + .get(&PseudoElement::After) + .map(|style| { self.with_pseudo(PseudoElementType::After(style.get_box().display)) }) } @@ -700,11 +702,11 @@ pub trait ThreadSafeLayoutNode<'ln> : Clone + Copy + Sized { fn style(&self) -> Ref> { Ref::map(self.borrow_layout_data().unwrap(), |data| { let style = match self.get_pseudo_element_type() { - PseudoElementType::Before(_) => data.style_data.per_pseudo.get(&PseudoElement::Before).unwrap(), - PseudoElementType::After(_) => data.style_data.per_pseudo.get(&PseudoElement::After).unwrap(), - PseudoElementType::Normal => &data.style_data.style, + PseudoElementType::Before(_) => data.style_data.per_pseudo.get(&PseudoElement::Before), + PseudoElementType::After(_) => data.style_data.per_pseudo.get(&PseudoElement::After), + PseudoElementType::Normal => data.style_data.style.as_ref(), }; - style.as_ref().unwrap() + style.unwrap() }) } @@ -713,24 +715,18 @@ pub trait ThreadSafeLayoutNode<'ln> : Clone + Copy + Sized { /// Unlike the version on TNode, this handles pseudo-elements. fn unstyle(self) { let mut data = self.mutate_layout_data().unwrap(); - let style = - match self.get_pseudo_element_type() { - PseudoElementType::Before(_) => { - match data.style_data.per_pseudo.get_mut(&PseudoElement::Before) { - None => return, - Some(style) => style, - } - } - PseudoElementType::After(_) => { - match data.style_data.per_pseudo.get_mut(&PseudoElement::After) { - None => return, - Some(style) => style, - } - } - PseudoElementType::Normal => &mut data.style_data.style, - }; - *style = None; + match self.get_pseudo_element_type() { + PseudoElementType::Before(_) => { + data.style_data.per_pseudo.remove(&PseudoElement::Before); + } + PseudoElementType::After(_) => { + data.style_data.per_pseudo.remove(&PseudoElement::After); + } + PseudoElementType::Normal => { + data.style_data.style = None; + } + }; } fn is_ignorable_whitespace(&self) -> bool; @@ -953,7 +949,7 @@ impl<'ln> ThreadSafeLayoutNode<'ln> for ServoThreadSafeLayoutNode<'ln> { data.per_pseudo.get(&PseudoElement::After).unwrap() }; - return match style.as_ref().unwrap().get_box().content { + return match style.as_ref().get_box().content { content::T::Content(ref value) if !value.is_empty() => { TextContent::GeneratedContent((*value).clone()) } diff --git a/components/style/animation.rs b/components/style/animation.rs index 10f96b19b1c..2dece839686 100644 --- a/components/style/animation.rs +++ b/components/style/animation.rs @@ -979,7 +979,7 @@ pub fn update_style_for_animation(animati let mut new_style = (*style).clone(); animation.property_animation.update(&mut *Arc::make_mut(&mut new_style), progress); if let Some(damage) = damage { - *damage = *damage | ConcreteRestyleDamage::compute(&Some((*style).clone()), &new_style); + *damage = *damage | ConcreteRestyleDamage::compute(Some(style), &new_style); } *style = new_style diff --git a/components/style/data.rs b/components/style/data.rs index e2e806cee26..ffe12908cba 100644 --- a/components/style/data.rs +++ b/components/style/data.rs @@ -14,7 +14,7 @@ pub struct PrivateStyleData { pub style: Option>, /// The results of CSS styling for each pseudo-element (if any). - pub per_pseudo: HashMap>, BuildHasherDefault<::fnv::FnvHasher>>, + pub per_pseudo: HashMap, BuildHasherDefault<::fnv::FnvHasher>>, /// Information needed during parallel traversals. pub parallel: DomParallelInfo, diff --git a/components/style/dom.rs b/components/style/dom.rs index f4df206d32f..dfffe1eb131 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -44,7 +44,7 @@ impl OpaqueNode { } pub trait TRestyleDamage : BitOr + Copy { - fn compute(old: &Option>, new: &ComputedValues) -> Self; + fn compute(old: Option<&Arc>, new: &ComputedValues) -> Self; fn rebuild_and_reflow() -> Self; } diff --git a/components/style/matching.rs b/components/style/matching.rs index b33d9fcd6da..74ae2971940 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -370,16 +370,16 @@ trait PrivateMatchMethods<'ln>: TNode<'ln> context: &SharedStyleContext<::Impl>, parent_style: Option<&Arc>, applicable_declarations: &[DeclarationBlock], - style: &mut Option>, + mut style: Option<&mut Arc>, applicable_declarations_cache: &mut ApplicableDeclarationsCache, new_animations_sender: &Mutex>, shareable: bool, animate_properties: bool) - -> Self::ConcreteRestyleDamage { + -> (Self::ConcreteRestyleDamage, Arc) { let mut cacheable = true; if animate_properties { - cacheable = !self.update_animations_for_cascade(context, style) && cacheable; + cacheable = !self.update_animations_for_cascade(context, &mut style) && cacheable; } let mut this_style; @@ -414,7 +414,7 @@ trait PrivateMatchMethods<'ln>: TNode<'ln> // Trigger transitions if necessary. This will reset `this_style` back to its old value if // it did trigger a transition. if animate_properties { - if let Some(ref style) = *style { + if let Some(ref style) = style { let animations_started = animation::start_transitions_if_applicable(new_animations_sender, self.opaque(), @@ -426,7 +426,7 @@ trait PrivateMatchMethods<'ln>: TNode<'ln> // Calculate style difference. let this_style = Arc::new(this_style); - let damage = Self::ConcreteRestyleDamage::compute(style, &*this_style); + let damage = Self::ConcreteRestyleDamage::compute(style.map(|s| &*s), &*this_style); // Cache the resolved style if it was cacheable. if cacheable { @@ -434,14 +434,13 @@ trait PrivateMatchMethods<'ln>: TNode<'ln> this_style.clone()); } - // Write in the final style and return the damage done to our caller. - *style = Some(this_style); - damage + // Return the final style and the damage done to our caller. + (damage, this_style) } fn update_animations_for_cascade(&self, context: &SharedStyleContext<::Impl>, - style: &mut Option>) + style: &mut Option<&mut Arc>) -> bool { let style = match *style { None => return false, @@ -572,7 +571,7 @@ pub trait ElementMatchMethods<'le> : TElement<'le> let node = self.as_node(); let style = &mut node.mutate_data().unwrap().style; let damage = <>::ConcreteNode as TNode<'le>> - ::ConcreteRestyleDamage::compute(style, &*shared_style); + ::ConcreteRestyleDamage::compute((*style).as_ref(), &*shared_style); *style = Some(shared_style); return StyleSharingResult::StyleWasShared(i, damage) } @@ -666,38 +665,44 @@ pub trait MatchMethods<'ln> : TNode<'ln> { let cloned_parent_style = parent_style.unwrap().clone(); data.style = Some(cloned_parent_style); } else { - let mut damage; - { + let damage = { let mut data_ref = self.mutate_data().unwrap(); let mut data = &mut *data_ref; - damage = self.cascade_node_pseudo_element( + let (mut damage, final_style) = self.cascade_node_pseudo_element( context, parent_style, &applicable_declarations.normal, - &mut data.style, + data.style.as_mut(), applicable_declarations_cache, new_animations_sender, applicable_declarations.normal_shareable, true); + data.style = Some(final_style); + ::Impl::each_eagerly_cascaded_pseudo_element(|pseudo| { let applicable_declarations_for_this_pseudo = applicable_declarations.per_pseudo.get(&pseudo).unwrap(); if !applicable_declarations_for_this_pseudo.is_empty() { - damage = damage | self.cascade_node_pseudo_element( + let (new_damage, style) = self.cascade_node_pseudo_element( context, Some(data.style.as_ref().unwrap()), &*applicable_declarations_for_this_pseudo, - data.per_pseudo.entry(pseudo).or_insert(None), + data.per_pseudo.get_mut(&pseudo), applicable_declarations_cache, new_animations_sender, false, false); + data.per_pseudo.insert(pseudo, style); + + damage = damage | new_damage; } }); - } + + damage + }; // This method needs to borrow the data as mutable, so make sure data_ref goes out of // scope first. diff --git a/ports/geckolib/wrapper.rs b/ports/geckolib/wrapper.rs index c650d9c6dee..00f54f175b6 100644 --- a/ports/geckolib/wrapper.rs +++ b/ports/geckolib/wrapper.rs @@ -78,7 +78,7 @@ impl<'ln> GeckoNode<'ln> { #[derive(Clone, Copy)] pub struct DummyRestyleDamage; impl TRestyleDamage for DummyRestyleDamage { - fn compute(_: &Option>, _: &ComputedValues) -> Self { DummyRestyleDamage } + fn compute(_: Option<&Arc>, _: &ComputedValues) -> Self { DummyRestyleDamage } fn rebuild_and_reflow() -> Self { DummyRestyleDamage } } impl BitOr for DummyRestyleDamage { From 04d2db5747ce85b5ee7f9cbc9f6d13e523c68a76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Sat, 13 Feb 2016 13:31:38 +0100 Subject: [PATCH 6/6] layout: Stop parameterizing on N for RecalcStyleAndConstructFlows This is unfortunate, but making that useful would require parameterizing `SharedLayoutContext` and `LayoutContext` depending on the `SelectorImpl` (which is a **huge** work right now). Probably the easier way to do it, and probably the one that keeps the layout code more legible, and since there won't be multiple implementations at the same compilation unit, would be "defining" a default implementation for layout via feature flags. That should allow us to remove the components/style/servo.rs file. --- components/layout/traversal.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index d5febecc483..35269529352 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -16,20 +16,18 @@ use incremental::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, RestyleDam use std::mem; use style::context::{StyleContext, ReflowGoal}; use style::matching::MatchMethods; -use style::selector_impl::ServoSelectorImpl; use style::traversal::{DomTraversalContext, STYLE_BLOOM}; use style::traversal::{put_thread_local_bloom_filter, recalc_style_at}; use util::opts; use util::tid::tid; -use wrapper::{LayoutNode, ThreadSafeLayoutNode}; +use wrapper::{LayoutNode, ServoLayoutNode, ThreadSafeLayoutNode}; pub struct RecalcStyleAndConstructFlows<'lc> { context: LayoutContext<'lc>, root: OpaqueNode, } -impl<'lc, 'ln, N: LayoutNode<'ln>> DomTraversalContext<'ln, N> for RecalcStyleAndConstructFlows<'lc> - where N::ConcreteElement: ::selectors::Element { +impl<'lc, 'ln> DomTraversalContext<'ln, ServoLayoutNode<'ln>> for RecalcStyleAndConstructFlows<'lc> { type SharedContext = SharedLayoutContext; #[allow(unsafe_code)] fn new<'a>(shared: &'a Self::SharedContext, root: OpaqueNode) -> Self { @@ -69,8 +67,8 @@ impl<'lc, 'ln, N: LayoutNode<'ln>> DomTraversalContext<'ln, N> for RecalcStyleAn } } - fn process_preorder(&self, node: N) { recalc_style_at(&self.context, self.root, node); } - fn process_postorder(&self, node: N) { construct_flows_at(&self.context, self.root, node); } + fn process_preorder(&self, node: ServoLayoutNode<'ln>) { recalc_style_at(&self.context, self.root, node); } + fn process_postorder(&self, node: ServoLayoutNode<'ln>) { construct_flows_at(&self.context, self.root, node); } } /// A bottom-up, parallelizable traversal.