From 9e860df9df02492f0b67b86262abc3bbdc2d8b6f Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Sat, 4 Feb 2017 13:11:02 -0800 Subject: [PATCH] Bug 1336646 - Apply selector flags during traversal. r=emilio --- Cargo.lock | 18 +-- components/layout/query.rs | 4 +- components/script/dom/bindings/trace.rs | 2 + components/script/dom/element.rs | 55 ++++--- components/script/dom/node.rs | 6 +- components/script/layout_wrapper.rs | 18 ++- .../script_layout_interface/wrapper_traits.rs | 11 +- components/selectors/Cargo.toml | 2 +- components/selectors/matching.rs | 146 +++++++----------- components/selectors/tree.rs | 13 -- components/style/context.rs | 44 +++++- components/style/dom.rs | 14 ++ components/style/gecko/wrapper.rs | 34 ++++ components/style/matching.rs | 26 +++- components/style/restyle_hints.rs | 8 +- components/style/stylist.rs | 78 ++++++---- tests/unit/script/size_of.rs | 8 +- 17 files changed, 295 insertions(+), 192 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d4fc618a95b..de3c8529c3a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -934,7 +934,7 @@ dependencies = [ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "selectors 0.17.0", + "selectors 0.18.0", "servo_url 0.0.1", "style 0.0.1", "style_traits 0.0.1", @@ -1355,7 +1355,7 @@ dependencies = [ "rayon 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "script_layout_interface 0.0.1", "script_traits 0.0.1", - "selectors 0.17.0", + "selectors 0.18.0", "serde 0.8.20 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1401,7 +1401,7 @@ dependencies = [ "script 0.0.1", "script_layout_interface 0.0.1", "script_traits 0.0.1", - "selectors 0.17.0", + "selectors 0.18.0", "serde_derive 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", "servo_config 0.0.1", @@ -2292,7 +2292,7 @@ dependencies = [ "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "script_layout_interface 0.0.1", "script_traits 0.0.1", - "selectors 0.17.0", + "selectors 0.18.0", "serde 0.8.20 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", "servo_atoms 0.0.1", @@ -2336,7 +2336,7 @@ dependencies = [ "profile_traits 0.0.1", "range 0.0.1", "script_traits 0.0.1", - "selectors 0.17.0", + "selectors 0.18.0", "servo_url 0.0.1", "style 0.0.1", ] @@ -2386,7 +2386,7 @@ dependencies = [ [[package]] name = "selectors" -version = "0.17.0" +version = "0.18.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2766,7 +2766,7 @@ dependencies = [ "rayon 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "selectors 0.17.0", + "selectors 0.18.0", "serde 0.8.20 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", "servo_atoms 0.0.1", @@ -2792,7 +2792,7 @@ dependencies = [ "parking_lot 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "selectors 0.17.0", + "selectors 0.18.0", "servo_atoms 0.0.1", "servo_config 0.0.1", "servo_url 0.0.1", @@ -2829,7 +2829,7 @@ dependencies = [ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "selectors 0.17.0", + "selectors 0.18.0", "servo_url 0.0.1", "style 0.0.1", "style_traits 0.0.1", diff --git a/components/layout/query.rs b/components/layout/query.rs index c54372221f9..5c78a1bc75d 100644 --- a/components/layout/query.rs +++ b/components/layout/query.rs @@ -716,14 +716,14 @@ pub fn process_resolved_style_request<'a, N>(context: &LayoutContext, // has a mechanism to give us that within a defined scope (after which point // it's cleared to maintained style system invariants). let mut tlc = ThreadLocalStyleContext::new(&context.style_context); - let context = StyleContext { + let mut context = StyleContext { shared: &context.style_context, thread_local: &mut tlc, }; let mut result = None; let ensure = |el: N::ConcreteElement| el.as_node().initialize_data(); let clear = |el: N::ConcreteElement| el.as_node().clear_data(); - resolve_style(&context, element, &ensure, &clear, |_: &_| { + resolve_style(&mut context, element, &ensure, &clear, |_: &_| { let s = process_resolved_style_request_internal(node, pseudo, property, layout_root); result = Some(s); }); diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 6e0ce0d47dc..763ccb9b22b 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -76,6 +76,7 @@ use script_layout_interface::reporter::CSSErrorReporter; use script_layout_interface::rpc::LayoutRPC; use script_traits::{DocumentActivity, TimerEventId, TimerSource, TouchpadPressurePhase}; use script_traits::{UntrustedNodeAddress, WindowSizeData, WindowSizeType}; +use selectors::matching::ElementSelectorFlags; use serde::{Deserialize, Serialize}; use servo_atoms::Atom; use servo_url::ServoUrl; @@ -347,6 +348,7 @@ unsafe_no_jsmanaged_fields!(TimeProfilerChan); unsafe_no_jsmanaged_fields!(MemProfilerChan); unsafe_no_jsmanaged_fields!(PseudoElement); unsafe_no_jsmanaged_fields!(Length); +unsafe_no_jsmanaged_fields!(ElementSelectorFlags); unsafe_no_jsmanaged_fields!(ElementState); unsafe_no_jsmanaged_fields!(DOMString); unsafe_no_jsmanaged_fields!(Mime); diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 9fae93d10cd..cf770674e74 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -83,7 +83,7 @@ use parking_lot::RwLock; use ref_filter_map::ref_filter_map; use script_layout_interface::message::ReflowQueryType; use script_thread::Runnable; -use selectors::matching::{ElementFlags, MatchingReason, matches}; +use selectors::matching::{ElementSelectorFlags, matches}; use selectors::matching::{HAS_EDGE_CHILD_SELECTOR, HAS_SLOW_SELECTOR, HAS_SLOW_SELECTOR_LATER_SIBLINGS}; use selectors::parser::{AttrSelector, NamespaceConstraint}; use servo_atoms::Atom; @@ -95,7 +95,6 @@ use std::default::Default; use std::fmt; use std::rc::Rc; use std::sync::Arc; -use std::sync::atomic::{AtomicUsize, Ordering}; use style::attr::{AttrValue, LengthOrPercentageOrAuto}; use style::context::{QuirksMode, ReflowGoal}; use style::element_state::*; @@ -109,6 +108,7 @@ use style::rule_tree::CascadeLevel; use style::selector_parser::{NonTSPseudoClass, RestyleDamage, SelectorImpl, SelectorParser}; use style::sink::Push; use style::stylist::ApplicableDeclarationBlock; +use style::thread_state; use style::values::CSSFloat; use style::values::specified::{self, CSSColor, CSSRGBA}; use stylesheet_loader::StylesheetOwner; @@ -131,7 +131,12 @@ pub struct Element { attr_list: MutNullableJS, class_list: MutNullableJS, state: Cell, - atomic_flags: AtomicElementFlags, + /// These flags are set by the style system to indicate the that certain + /// operations may require restyling this element or its descendants. The + /// flags are not atomic, so the style system takes care of only set them + /// when it has exclusive access to the element. + #[ignore_heap_size_of = "bitflags defined in rust-selectors"] + selector_flags: Cell, } impl fmt::Debug for Element { @@ -219,7 +224,7 @@ impl Element { attr_list: Default::default(), class_list: Default::default(), state: Cell::new(state), - atomic_flags: AtomicElementFlags::new(), + selector_flags: Cell::new(ElementSelectorFlags::empty()), } } @@ -351,7 +356,8 @@ pub trait LayoutElementHelpers { fn get_checked_state_for_layout(&self) -> bool; fn get_indeterminate_state_for_layout(&self) -> bool; fn get_state_for_layout(&self) -> ElementState; - fn insert_atomic_flags(&self, flags: ElementFlags); + fn insert_selector_flags(&self, flags: ElementSelectorFlags); + fn has_selector_flags(&self, flags: ElementSelectorFlags) -> bool; } impl LayoutElementHelpers for LayoutJS { @@ -720,9 +726,19 @@ impl LayoutElementHelpers for LayoutJS { #[inline] #[allow(unsafe_code)] - fn insert_atomic_flags(&self, flags: ElementFlags) { + fn insert_selector_flags(&self, flags: ElementSelectorFlags) { + debug_assert!(thread_state::get() == thread_state::LAYOUT); unsafe { - (*self.unsafe_get()).atomic_flags.insert(flags); + let f = &(*self.unsafe_get()).selector_flags; + f.set(f.get() | flags); + } + } + + #[inline] + #[allow(unsafe_code)] + fn has_selector_flags(&self, flags: ElementSelectorFlags) -> bool { + unsafe { + (*self.unsafe_get()).selector_flags.get().contains(flags) } } } @@ -1973,7 +1989,7 @@ impl ElementMethods for Element { match SelectorParser::parse_author_origin_no_namespace(&selectors) { Err(()) => Err(Error::Syntax), Ok(selectors) => { - Ok(matches(&selectors.0, &Root::from_ref(self), None, MatchingReason::Other)) + Ok(matches(&selectors.0, &Root::from_ref(self), None)) } } } @@ -1991,7 +2007,8 @@ impl ElementMethods for Element { let root = self.upcast::(); for element in root.inclusive_ancestors() { if let Some(element) = Root::downcast::(element) { - if matches(&selectors.0, &element, None, MatchingReason::Other) { + if matches(&selectors.0, &element, None) + { return Ok(Some(element)); } } @@ -2231,7 +2248,7 @@ impl VirtualMethods for Element { s.children_changed(mutation); } - let flags = self.atomic_flags.get(); + let flags = self.selector_flags.get(); if flags.intersects(HAS_SLOW_SELECTOR) { // All children of this node need to be restyled when any child changes. self.upcast::().dirty(NodeDamage::OtherNodeDamage); @@ -2744,24 +2761,6 @@ impl<'a> AttributeMutation<'a> { } } -/// Thread-safe wrapper for ElementFlags set during selector matching -#[derive(JSTraceable, HeapSizeOf)] -struct AtomicElementFlags(AtomicUsize); - -impl AtomicElementFlags { - fn new() -> Self { - AtomicElementFlags(AtomicUsize::new(0)) - } - - fn get(&self) -> ElementFlags { - ElementFlags::from_bits_truncate(self.0.load(Ordering::Relaxed) as u8) - } - - fn insert(&self, flags: ElementFlags) { - self.0.fetch_or(flags.bits() as usize, Ordering::Relaxed); - } -} - /// A holder for an element's "tag name", which will be lazily /// resolved and cached. Should be reset when the document /// owner changes. diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 37b5764c174..df335be75a6 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -67,7 +67,7 @@ use script_layout_interface::{LayoutElementType, LayoutNodeType, TrustedNodeAddr use script_layout_interface::message::Msg; use script_traits::DocumentActivity; use script_traits::UntrustedNodeAddress; -use selectors::matching::{MatchingReason, matches}; +use selectors::matching::matches; use selectors::parser::SelectorList; use servo_url::ServoUrl; use std::borrow::ToOwned; @@ -322,7 +322,7 @@ impl<'a> Iterator for QuerySelectorIterator { // (instead of passing `None`)? Probably. self.iterator.by_ref().filter_map(|node| { if let Some(element) = Root::downcast(node) { - if matches(selectors, &element, None, MatchingReason::Other) { + if matches(selectors, &element, None) { return Some(Root::upcast(element)); } } @@ -685,7 +685,7 @@ impl Node { // Step 3. Ok(selectors) => { Ok(self.traverse_preorder().filter_map(Root::downcast).find(|element| { - matches(&selectors.0, element, None, MatchingReason::Other) + matches(&selectors.0, element, None) })) } } diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs index fcaba5905a7..a5baec25745 100644 --- a/components/script/layout_wrapper.rs +++ b/components/script/layout_wrapper.rs @@ -49,7 +49,7 @@ use script_layout_interface::{HTMLCanvasData, LayoutNodeType, SVGSVGData, Truste use script_layout_interface::{OpaqueStyleAndLayoutData, PartialPersistentLayoutData}; use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, GetLayoutData, LayoutNode}; use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode}; -use selectors::matching::ElementFlags; +use selectors::matching::ElementSelectorFlags; use selectors::parser::{AttrSelector, NamespaceConstraint}; use servo_atoms::Atom; use servo_url::ServoUrl; @@ -437,6 +437,14 @@ impl<'le> TElement for ServoLayoutElement<'le> { fn skip_root_and_item_based_display_fixup(&self) -> bool { false } + + unsafe fn set_selector_flags(&self, flags: ElementSelectorFlags) { + self.element.insert_selector_flags(flags); + } + + fn has_selector_flags(&self, flags: ElementSelectorFlags) -> bool { + self.element.has_selector_flags(flags) + } } impl<'le> PartialEq for ServoLayoutElement<'le> { @@ -665,10 +673,6 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> { self.element.html_element_in_html_document_for_layout() } } - - fn insert_flags(&self, flags: ElementFlags) { - self.element.insert_atomic_flags(flags); - } } #[derive(Copy, Clone, Debug)] @@ -1009,6 +1013,10 @@ impl<'le> ThreadSafeLayoutElement for ServoThreadSafeLayoutElement<'le> { self.as_node().type_id() } + unsafe fn unsafe_get(self) -> ServoLayoutElement<'le> { + self.element + } + fn get_attr<'a>(&'a self, namespace: &Namespace, name: &LocalName) -> Option<&'a str> { self.element.get_attr(namespace, name) } diff --git a/components/script_layout_interface/wrapper_traits.rs b/components/script_layout_interface/wrapper_traits.rs index 08e120d3fe8..59ad5c4128a 100644 --- a/components/script_layout_interface/wrapper_traits.rs +++ b/components/script_layout_interface/wrapper_traits.rs @@ -313,6 +313,15 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug + /// Returns `None` if this is a pseudo-element; otherwise, returns `Some`. fn type_id(&self) -> Option; + /// Returns access to the underlying TElement. This is breaks the abstraction + /// barrier of ThreadSafeLayout wrapper layer, and can lead to races if not used + /// carefully. + /// + /// We need this so that the functions defined on this trait can call + /// lazily_compute_pseudo_element_style, which operates on TElement. + unsafe fn unsafe_get(self) -> + <::ConcreteNode as TNode>::ConcreteElement; + #[inline] fn get_attr(&self, namespace: &Namespace, name: &LocalName) -> Option<&str>; @@ -413,7 +422,7 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug + let new_style = context.stylist .lazily_compute_pseudo_element_style( - self, + unsafe { &self.unsafe_get() }, &style_pseudo, &data.styles().primary.values, &context.default_computed_values); diff --git a/components/selectors/Cargo.toml b/components/selectors/Cargo.toml index b34c6648a15..03c8ced7e72 100644 --- a/components/selectors/Cargo.toml +++ b/components/selectors/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "selectors" -version = "0.17.0" +version = "0.18.0" # Not yet published authors = ["Simon Sapin ", "Alan Jeffrey "] documentation = "https://docs.rs/selectors/" diff --git a/components/selectors/matching.rs b/components/selectors/matching.rs index e4c13bf83fb..efe1d76007e 100644 --- a/components/selectors/matching.rs +++ b/components/selectors/matching.rs @@ -7,27 +7,6 @@ use parser::{SimpleSelector, Selector, SelectorImpl}; use std::borrow::Borrow; use tree::Element; -/// The reason why we're doing selector matching. -/// -/// If this is for styling, this will include the flags in the parent element. -/// -/// This is done because Servo doesn't need those flags at all when it's not -/// styling (e.g., when you're doing document.querySelector). For example, a -/// slow selector in an API like querySelector doesn't imply that the parent -/// could match it. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum MatchingReason { - ForStyling, - Other, -} - -impl MatchingReason { - #[inline] - fn for_styling(&self) -> bool { - *self == MatchingReason::ForStyling - } -} - // The bloom filter for descendant CSS selectors will have a <1% false // positive rate until it has this many selectors in it, then it will // rapidly increase. @@ -84,23 +63,20 @@ bitflags! { } bitflags! { - /// Set of flags that are set on the parent depending on whether a child - /// could potentially match a selector. - /// - /// These setters, in the case of Servo, must be atomic, due to the parallel - /// traversal. - pub flags ElementFlags: u8 { - /// When a child is added or removed from this element, all the children + /// Set of flags that are set on either the element or its parent (depending + /// on the flag) if the element could potentially match a selector. + pub flags ElementSelectorFlags: u8 { + /// When a child is added or removed from the parent, all the children /// must be restyled, because they may match :nth-last-child, /// :last-of-type, :nth-last-of-type, or :only-of-type. const HAS_SLOW_SELECTOR = 1 << 0, - /// When a child is added or removed from this element, any later + /// When a child is added or removed from the parent, any later /// children must be restyled, because they may match :nth-child, /// :first-of-type, or :nth-of-type. const HAS_SLOW_SELECTOR_LATER_SIBLINGS = 1 << 1, - /// When a child is added or removed from this element, the first and + /// When a child is added or removed from the parent, the first and /// last children must be restyled, because they may match :first-child, /// :last-child, or :only-child. const HAS_EDGE_CHILD_SELECTOR = 1 << 2, @@ -111,16 +87,28 @@ bitflags! { } } +impl ElementSelectorFlags { + /// Returns the subset of flags that apply to the element. + pub fn for_self(self) -> ElementSelectorFlags { + self & (HAS_EMPTY_SELECTOR) + } + + /// Returns the subset of flags that apply to the parent. + pub fn for_parent(self) -> ElementSelectorFlags { + self & (HAS_SLOW_SELECTOR | HAS_SLOW_SELECTOR_LATER_SIBLINGS | HAS_EDGE_CHILD_SELECTOR) + } +} + pub fn matches(selector_list: &[Selector], element: &E, - parent_bf: Option<&BloomFilter>, - reason: MatchingReason) + parent_bf: Option<&BloomFilter>) -> bool where E: Element { selector_list.iter().any(|selector| { selector.pseudo_element.is_none() && - matches_complex_selector(&*selector.complex_selector, element, parent_bf, &mut StyleRelations::empty(), reason) + matches_complex_selector(&*selector.complex_selector, element, parent_bf, + &mut StyleRelations::empty(), &mut ElementSelectorFlags::empty()) }) } @@ -134,11 +122,11 @@ pub fn matches_complex_selector(selector: &ComplexSelector, element: &E, parent_bf: Option<&BloomFilter>, relations: &mut StyleRelations, - reason: MatchingReason) + flags: &mut ElementSelectorFlags) -> bool where E: Element { - match matches_complex_selector_internal(selector, element, parent_bf, relations, reason) { + match matches_complex_selector_internal(selector, element, parent_bf, relations, flags) { SelectorMatchingResult::Matched => { match selector.next { Some((_, Combinator::NextSibling)) | @@ -209,12 +197,12 @@ fn can_fast_reject(mut selector: &ComplexSelector, element: &E, parent_bf: Option<&BloomFilter>, relations: &mut StyleRelations, - reason: MatchingReason) + flags: &mut ElementSelectorFlags) -> Option where E: Element { if !selector.compound_selector.iter().all(|simple_selector| { - matches_simple_selector(simple_selector, element, parent_bf, relations, reason) }) { + matches_simple_selector(simple_selector, element, parent_bf, relations, flags) }) { return Some(SelectorMatchingResult::NotMatchedAndRestartFromClosestLaterSibling); } @@ -271,11 +259,11 @@ fn matches_complex_selector_internal(selector: &ComplexSelector, element: &E, parent_bf: Option<&BloomFilter>, relations: &mut StyleRelations, - reason: MatchingReason) + flags: &mut ElementSelectorFlags) -> SelectorMatchingResult where E: Element { - if let Some(result) = can_fast_reject(selector, element, parent_bf, relations, reason) { + if let Some(result) = can_fast_reject(selector, element, parent_bf, relations, flags) { return result; } @@ -302,7 +290,7 @@ fn matches_complex_selector_internal(selector: &ComplexSelector, &element, parent_bf, relations, - reason); + flags); match (result, combinator) { // Return the status immediately. (SelectorMatchingResult::Matched, _) => return result, @@ -346,7 +334,7 @@ fn matches_simple_selector( element: &E, parent_bf: Option<&BloomFilter>, relations: &mut StyleRelations, - reason: MatchingReason) + flags: &mut ElementSelectorFlags) -> bool where E: Element { @@ -429,14 +417,14 @@ fn matches_simple_selector( AFFECTED_BY_STATE) } SimpleSelector::FirstChild => { - relation_if!(matches_first_child(element, reason), AFFECTED_BY_CHILD_INDEX) + relation_if!(matches_first_child(element, flags), AFFECTED_BY_CHILD_INDEX) } SimpleSelector::LastChild => { - relation_if!(matches_last_child(element, reason), AFFECTED_BY_CHILD_INDEX) + relation_if!(matches_last_child(element, flags), AFFECTED_BY_CHILD_INDEX) } SimpleSelector::OnlyChild => { - relation_if!(matches_first_child(element, reason) && - matches_last_child(element, reason), AFFECTED_BY_CHILD_INDEX) + relation_if!(matches_first_child(element, flags) && + matches_last_child(element, flags), AFFECTED_BY_CHILD_INDEX) } SimpleSelector::Root => { // We never share styles with an element with no parent, so no point @@ -444,43 +432,41 @@ fn matches_simple_selector( element.is_root() } SimpleSelector::Empty => { - if reason.for_styling() { - element.insert_flags(HAS_EMPTY_SELECTOR); - } + flags.insert(HAS_EMPTY_SELECTOR); relation_if!(element.is_empty(), AFFECTED_BY_EMPTY) } SimpleSelector::NthChild(a, b) => { - relation_if!(matches_generic_nth_child(element, a, b, false, false, reason), + relation_if!(matches_generic_nth_child(element, a, b, false, false, flags), AFFECTED_BY_CHILD_INDEX) } SimpleSelector::NthLastChild(a, b) => { - relation_if!(matches_generic_nth_child(element, a, b, false, true, reason), + relation_if!(matches_generic_nth_child(element, a, b, false, true, flags), AFFECTED_BY_CHILD_INDEX) } SimpleSelector::NthOfType(a, b) => { - relation_if!(matches_generic_nth_child(element, a, b, true, false, reason), + relation_if!(matches_generic_nth_child(element, a, b, true, false, flags), AFFECTED_BY_CHILD_INDEX) } SimpleSelector::NthLastOfType(a, b) => { - relation_if!(matches_generic_nth_child(element, a, b, true, true, reason), + relation_if!(matches_generic_nth_child(element, a, b, true, true, flags), AFFECTED_BY_CHILD_INDEX) } SimpleSelector::FirstOfType => { - relation_if!(matches_generic_nth_child(element, 0, 1, true, false, reason), + relation_if!(matches_generic_nth_child(element, 0, 1, true, false, flags), AFFECTED_BY_CHILD_INDEX) } SimpleSelector::LastOfType => { - relation_if!(matches_generic_nth_child(element, 0, 1, true, true, reason), + relation_if!(matches_generic_nth_child(element, 0, 1, true, true, flags), AFFECTED_BY_CHILD_INDEX) } SimpleSelector::OnlyOfType => { - relation_if!(matches_generic_nth_child(element, 0, 1, true, false, reason) && - matches_generic_nth_child(element, 0, 1, true, true, reason), + relation_if!(matches_generic_nth_child(element, 0, 1, true, false, flags) && + matches_generic_nth_child(element, 0, 1, true, true, flags), AFFECTED_BY_CHILD_INDEX) } SimpleSelector::Negation(ref negated) => { !negated.iter().all(|s| { - matches_complex_selector(s, element, parent_bf, relations, reason) + matches_complex_selector(s, element, parent_bf, relations, flags) }) } } @@ -492,22 +478,15 @@ fn matches_generic_nth_child(element: &E, b: i32, is_of_type: bool, is_from_end: bool, - reason: MatchingReason) -> bool + flags: &mut ElementSelectorFlags) + -> bool where E: Element { - // Selectors Level 4 changed from Level 3: - // This can match without a parent element: - // https://drafts.csswg.org/selectors-4/#child-index - - if reason.for_styling() { - if let Some(parent) = element.parent_element() { - parent.insert_flags(if is_from_end { - HAS_SLOW_SELECTOR - } else { - HAS_SLOW_SELECTOR_LATER_SIBLINGS - }); - } - } + flags.insert(if is_from_end { + HAS_SLOW_SELECTOR + } else { + HAS_SLOW_SELECTOR_LATER_SIBLINGS + }); let mut index = 1; let mut next_sibling = if is_from_end { @@ -546,28 +525,15 @@ fn matches_generic_nth_child(element: &E, } #[inline] -fn matches_first_child(element: &E, reason: MatchingReason) -> bool where E: Element { - // Selectors Level 4 changed from Level 3: - // This can match without a parent element: - // https://drafts.csswg.org/selectors-4/#child-index - if reason.for_styling() { - if let Some(parent) = element.parent_element() { - parent.insert_flags(HAS_EDGE_CHILD_SELECTOR); - } - } +fn matches_first_child(element: &E, flags: &mut ElementSelectorFlags) + -> bool where E: Element { + flags.insert(HAS_EDGE_CHILD_SELECTOR); element.prev_sibling_element().is_none() } #[inline] -fn matches_last_child(element: &E, reason: MatchingReason) -> bool where E: Element { - // Selectors Level 4 changed from Level 3: - // This can match without a parent element: - // https://drafts.csswg.org/selectors-4/#child-index - if reason.for_styling() { - if let Some(parent) = element.parent_element() { - parent.insert_flags(HAS_EDGE_CHILD_SELECTOR); - } - } - +fn matches_last_child(element: &E, flags: &mut ElementSelectorFlags) + -> bool where E: Element { + flags.insert(HAS_EDGE_CHILD_SELECTOR); element.next_sibling_element().is_none() } diff --git a/components/selectors/tree.rs b/components/selectors/tree.rs index 850b58a6b2c..a76e1d577c8 100644 --- a/components/selectors/tree.rs +++ b/components/selectors/tree.rs @@ -5,7 +5,6 @@ //! Traits that nodes must implement. Breaks the otherwise-cyclic dependency between layout and //! style. -use matching::ElementFlags; use parser::{AttrSelector, SelectorImpl}; use std::ascii::AsciiExt; @@ -162,16 +161,4 @@ pub trait Element: MatchAttr + Sized { // in the future when we have associated types and/or a more convenient // JS GC story... --pcwalton fn each_class(&self, callback: F) where F: FnMut(&::ClassName); - - /// Add flags to the element. See the `ElementFlags` docs for details. - /// - /// This may be called while the element *or one of its children* is being - /// matched. Therefore the implementation must be thread-safe if children - /// may be matched in parallel. - fn insert_flags(&self, _flags: ElementFlags) {} - - /// Clears the relevant ElementFlags. This is *not* called from - /// rust-selectors, but provided as part of the Element interface since it - /// makes sense. - fn clear_flags(&self) {} } diff --git a/components/style/context.rs b/components/style/context.rs index ec66f01b2b5..d4b0d9c9c2d 100644 --- a/components/style/context.rs +++ b/components/style/context.rs @@ -9,12 +9,13 @@ use animation::Animation; use app_units::Au; use bloom::StyleBloom; use data::ElementData; -use dom::{OpaqueNode, TNode, TElement}; +use dom::{OpaqueNode, TNode, TElement, SendElement}; use error_reporting::ParseErrorReporter; use euclid::Size2D; use matching::StyleSharingCandidateCache; use parking_lot::RwLock; use properties::ComputedValues; +use selectors::matching::ElementSelectorFlags; use servo_config::opts; use std::collections::HashMap; use std::env; @@ -23,6 +24,7 @@ use std::ops::Add; use std::sync::{Arc, Mutex}; use std::sync::mpsc::Sender; use stylist::Stylist; +use thread_state; use timer::Timer; /// This structure is used to create a local style context from a shared one. @@ -165,6 +167,34 @@ impl TraversalStatistics { } } +/// A task to be run in sequential mode on the parent (non-worker) thread. This +/// is used by the style system to queue up work which is not safe to do during +/// the parallel traversal. +pub enum SequentialTask { + /// Sets selector flags. This is used when we need to set flags on an + /// element that we don't have exclusive access to (i.e. the parent). + SetSelectorFlags(SendElement, ElementSelectorFlags), +} + +impl SequentialTask { + /// Executes this task. + pub fn execute(self) { + use self::SequentialTask::*; + debug_assert!(thread_state::get() == thread_state::LAYOUT); + match self { + SetSelectorFlags(el, flags) => { + unsafe { el.set_selector_flags(flags) }; + } + } + } + + /// Creates a task to set the selector flags on an element. + pub fn set_selector_flags(el: E, flags: ElementSelectorFlags) -> Self { + use self::SequentialTask::*; + SetSelectorFlags(unsafe { SendElement::new(el) }, flags) + } +} + /// A thread-local style context. /// /// This context contains data that needs to be used during restyling, but is @@ -178,6 +208,10 @@ pub struct ThreadLocalStyleContext { /// A channel on which new animations that have been triggered by style /// recalculation can be sent. pub new_animations_sender: Sender, + /// A set of tasks to be run (on the parent thread) in sequential mode after + /// the rest of the styling is complete. This is useful for infrequently-needed + /// non-threadsafe operations. + pub tasks: Vec>, /// Statistics about the traversal. pub statistics: TraversalStatistics, /// Information related to the current element, non-None during processing. @@ -191,6 +225,7 @@ impl ThreadLocalStyleContext { style_sharing_candidate_cache: StyleSharingCandidateCache::new(), bloom_filter: StyleBloom::new(), new_animations_sender: shared.local_context_creation_data.lock().unwrap().new_animations_sender.clone(), + tasks: Vec::new(), statistics: TraversalStatistics::default(), current_element_info: None, } @@ -222,10 +257,15 @@ impl ThreadLocalStyleContext { } } -#[cfg(debug_assertions)] impl Drop for ThreadLocalStyleContext { fn drop(&mut self) { debug_assert!(self.current_element_info.is_none()); + + // Execute any enqueued sequential tasks. + debug_assert!(thread_state::get() == thread_state::LAYOUT); + for task in self.tasks.drain(..) { + task.execute(); + } } } diff --git a/components/style/dom.rs b/components/style/dom.rs index 8a023e764c3..f6bcf76f68e 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -14,6 +14,7 @@ use element_state::ElementState; use parking_lot::RwLock; use properties::{ComputedValues, PropertyDeclarationBlock}; use selector_parser::{ElementExt, PreExistingComputedValues, PseudoElement}; +use selectors::matching::ElementSelectorFlags; use sink::Push; use std::fmt; use std::fmt::Debug; @@ -321,6 +322,19 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre /// blockification on this element. (This function exists so that Gecko /// native anonymous content can opt out of this style fixup.) fn skip_root_and_item_based_display_fixup(&self) -> bool; + + /// Sets selector flags, which indicate what kinds of selectors may have + /// matched on this element and therefore what kind of work may need to + /// be performed when DOM state changes. + /// + /// This is unsafe, like all the flag-setting methods, because it's only safe + /// to call with exclusive access to the element. When setting flags on the + /// parent during parallel traversal, we use SequentialTask to queue up the + /// set to run after the threads join. + unsafe fn set_selector_flags(&self, flags: ElementSelectorFlags); + + /// Returns true if the element has all the specified selector flags. + fn has_selector_flags(&self, flags: ElementSelectorFlags) -> bool; } /// TNode and TElement aren't Send because we want to be careful and explicit diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 1468e31f487..92b41122b3b 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -46,6 +46,7 @@ use properties::PropertyDeclarationBlock; use rule_tree::CascadeLevel as ServoCascadeLevel; use selector_parser::{ElementExt, Snapshot}; use selectors::Element; +use selectors::matching::ElementSelectorFlags; use selectors::parser::{AttrSelector, NamespaceConstraint}; use servo_url::ServoUrl; use sink::Push; @@ -379,6 +380,29 @@ lazy_static! { }; } +/// Converts flags from the layout used by rust-selectors to the layout used +/// by Gecko. We could align these and then do this without conditionals, but +/// it's probably not worth the trouble. +fn selector_flags_to_node_flags(flags: ElementSelectorFlags) -> u32 { + use gecko_bindings::structs::*; + use selectors::matching::*; + let mut gecko_flags = 0u32; + if flags.contains(HAS_SLOW_SELECTOR) { + gecko_flags |= NODE_HAS_SLOW_SELECTOR as u32; + } + if flags.contains(HAS_SLOW_SELECTOR_LATER_SIBLINGS) { + gecko_flags |= NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS as u32; + } + if flags.contains(HAS_EDGE_CHILD_SELECTOR) { + gecko_flags |= NODE_HAS_EDGE_CHILD_SELECTOR as u32; + } + if flags.contains(HAS_EMPTY_SELECTOR) { + gecko_flags |= NODE_HAS_EMPTY_SELECTOR as u32; + } + + gecko_flags +} + impl<'le> TElement for GeckoElement<'le> { type ConcreteNode = GeckoNode<'le>; @@ -476,6 +500,16 @@ impl<'le> TElement for GeckoElement<'le> { // are NAC handles both cases. self.flags() & (NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE as u32) != 0 } + + unsafe fn set_selector_flags(&self, flags: ElementSelectorFlags) { + debug_assert!(!flags.is_empty()); + self.set_flags(selector_flags_to_node_flags(flags)); + } + + fn has_selector_flags(&self, flags: ElementSelectorFlags) -> bool { + let node_flags = selector_flags_to_node_flags(flags); + (self.flags() & node_flags) == node_flags + } } impl<'le> PartialEq for GeckoElement<'le> { diff --git a/components/style/matching.rs b/components/style/matching.rs index 0a26255e82d..652feba7264 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -12,7 +12,7 @@ use animation::{self, Animation, PropertyAnimation}; use atomic_refcell::AtomicRefMut; use cache::LRUCache; use cascade_info::CascadeInfo; -use context::{SharedStyleContext, StyleContext}; +use context::{SequentialTask, SharedStyleContext, StyleContext}; use data::{ComputedStyle, ElementData, ElementStyles, PseudoRuleNodes, PseudoStyles}; use dom::{SendElement, TElement, TNode}; use properties::{CascadeFlags, ComputedValues, SHAREABLE, SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP, cascade}; @@ -22,7 +22,8 @@ use rule_tree::{CascadeLevel, StrongRuleNode}; use selector_parser::{PseudoElement, RestyleDamage, SelectorImpl}; use selectors::MatchAttr; use selectors::bloom::BloomFilter; -use selectors::matching::{AFFECTED_BY_PSEUDO_ELEMENTS, AFFECTED_BY_STYLE_ATTRIBUTE, MatchingReason, StyleRelations}; +use selectors::matching::{AFFECTED_BY_PSEUDO_ELEMENTS, AFFECTED_BY_STYLE_ATTRIBUTE}; +use selectors::matching::{ElementSelectorFlags, StyleRelations}; use servo_config::opts; use sink::ForgetfulSink; use std::collections::HashMap; @@ -586,6 +587,7 @@ pub trait MatchMethods : TElement { let stylist = &context.shared.stylist; let style_attribute = self.style_attribute(); let animation_rules = self.get_animation_rules(None); + let mut flags = ElementSelectorFlags::empty(); // Compute the primary rule node. let mut primary_relations = @@ -595,7 +597,7 @@ pub trait MatchMethods : TElement { animation_rules, None, &mut applicable_declarations, - MatchingReason::ForStyling); + &mut flags); let primary_rule_node = compute_rule_node(context, &mut applicable_declarations); // Compute the pseudo rule nodes. @@ -608,7 +610,7 @@ pub trait MatchMethods : TElement { None, pseudo_animation_rules, Some(&pseudo), &mut applicable_declarations, - MatchingReason::ForStyling); + &mut flags); if !applicable_declarations.is_empty() { let rule_node = compute_rule_node(context, &mut applicable_declarations); @@ -621,6 +623,22 @@ pub trait MatchMethods : TElement { primary_relations |= AFFECTED_BY_PSEUDO_ELEMENTS; } + // Apply the selector flags. + let self_flags = flags.for_self(); + if !self_flags.is_empty() { + unsafe { self.set_selector_flags(self_flags); } + } + let parent_flags = flags.for_parent(); + if !parent_flags.is_empty() { + if let Some(p) = self.parent_element() { + // Avoid the overhead of the SequentialTask if the flags are already set. + if !p.has_selector_flags(parent_flags) { + let task = SequentialTask::set_selector_flags(p, parent_flags); + context.thread_local.tasks.push(task); + } + } + } + MatchResults { primary: primary_rule_node, relations: primary_relations, diff --git a/components/style/restyle_hints.rs b/components/style/restyle_hints.rs index 785a18c1d1f..b83c939ddc3 100644 --- a/components/style/restyle_hints.rs +++ b/components/style/restyle_hints.rs @@ -15,7 +15,7 @@ use gecko_bindings::structs::nsRestyleHint; use heapsize::HeapSizeOf; use selector_parser::{AttrValue, NonTSPseudoClass, Snapshot, SelectorImpl}; use selectors::{Element, MatchAttr}; -use selectors::matching::{MatchingReason, StyleRelations}; +use selectors::matching::{ElementSelectorFlags, StyleRelations}; use selectors::matching::matches_complex_selector; use selectors::parser::{AttrSelector, Combinator, ComplexSelector, SimpleSelector}; use std::clone::Clone; @@ -524,14 +524,16 @@ impl DependencySet { (attrs_changed && dep.sensitivities.attrs), "Testing a known ineffective dependency?"); if (attrs_changed || state_changes.intersects(dep.sensitivities.states)) && !hint.intersects(dep.hint) { + // We can ignore the selector flags, since they would have already been set during + // original matching for any element that might change its matching behavior here. let matched_then = matches_complex_selector(&dep.selector, snapshot, None, &mut StyleRelations::empty(), - MatchingReason::Other); + &mut ElementSelectorFlags::empty()); let matches_now = matches_complex_selector(&dep.selector, element, None, &mut StyleRelations::empty(), - MatchingReason::Other); + &mut ElementSelectorFlags::empty()); if matched_then != matches_now { hint.insert(dep.hint); } diff --git a/components/style/stylist.rs b/components/style/stylist.rs index 313d2dae76e..279e8f0ac86 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -18,12 +18,12 @@ use properties::{self, CascadeFlags, ComputedValues, INHERIT_ALL}; use properties::PropertyDeclarationBlock; use restyle_hints::{RestyleHint, DependencySet}; use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource}; -use selector_parser::{ElementExt, SelectorImpl, PseudoElement, Snapshot}; +use selector_parser::{SelectorImpl, PseudoElement, Snapshot}; use selectors::Element; use selectors::bloom::BloomFilter; use selectors::matching::{AFFECTED_BY_ANIMATIONS, AFFECTED_BY_TRANSITIONS}; use selectors::matching::{AFFECTED_BY_STYLE_ATTRIBUTE, AFFECTED_BY_PRESENTATIONAL_HINTS}; -use selectors::matching::{MatchingReason, StyleRelations, matches_complex_selector}; +use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_complex_selector}; use selectors::parser::{Selector, SimpleSelector, LocalName as LocalNameSelector, ComplexSelector}; use sink::Push; use smallvec::VecLike; @@ -34,6 +34,7 @@ use std::hash::Hash; use std::sync::Arc; use style_traits::viewport::ViewportConstraints; use stylesheets::{CssRule, Origin, StyleRule, Stylesheet, UserAgentStylesheets}; +use thread_state; use viewport::{self, MaybeNew, ViewportRule}; pub use ::fnv::FnvHashMap; @@ -368,7 +369,7 @@ impl Stylist { parent: &Arc, default: &Arc) -> Option - where E: ElementExt + + where E: TElement + fmt::Debug + PresentationalHintsSynthetizer { @@ -379,13 +380,14 @@ impl Stylist { let mut declarations = vec![]; + let mut flags = ElementSelectorFlags::empty(); self.push_applicable_declarations(element, None, None, AnimationRules(None, None), Some(pseudo), &mut declarations, - MatchingReason::ForStyling); + &mut flags); let rule_node = self.rule_tree.insert_ordered_rules( @@ -400,6 +402,28 @@ impl Stylist { Box::new(StdoutErrorReporter), CascadeFlags::empty()); + // Apply the selector flags. We should be in sequential mode already, + // so we can directly apply the parent flags. + if cfg!(feature = "servo") { + // Servo calls this function from the worker, but only for internal + // pseudos, so we should never generate selector flags here. + debug_assert!(flags.is_empty()); + } else { + // Gecko calls this from sequential mode, so we can directly apply + // the flags. + debug_assert!(thread_state::get() == thread_state::LAYOUT); + let self_flags = flags.for_self(); + if !self_flags.is_empty() { + unsafe { element.set_selector_flags(self_flags); } + } + let parent_flags = flags.for_parent(); + if !parent_flags.is_empty() { + if let Some(p) = element.parent_element() { + unsafe { p.set_selector_flags(parent_flags); } + } + } + } + Some(ComputedStyle::new(rule_node, Arc::new(computed))) } @@ -495,8 +519,8 @@ impl Stylist { animation_rules: AnimationRules, pseudo_element: Option<&PseudoElement>, applicable_declarations: &mut V, - reason: MatchingReason) -> StyleRelations - where E: ElementExt + + flags: &mut ElementSelectorFlags) -> StyleRelations + where E: TElement + fmt::Debug + PresentationalHintsSynthetizer, V: Push + VecLike @@ -521,7 +545,7 @@ impl Stylist { parent_bf, applicable_declarations, &mut relations, - reason, + flags, CascadeLevel::UANormal); debug!("UA normal: {:?}", relations); @@ -545,14 +569,14 @@ impl Stylist { parent_bf, applicable_declarations, &mut relations, - reason, + flags, CascadeLevel::UserNormal); debug!("user normal: {:?}", relations); map.author.get_all_matching_rules(element, parent_bf, applicable_declarations, &mut relations, - reason, + flags, CascadeLevel::AuthorNormal); debug!("author normal: {:?}", relations); @@ -586,7 +610,7 @@ impl Stylist { parent_bf, applicable_declarations, &mut relations, - reason, + flags, CascadeLevel::AuthorImportant); debug!("author important: {:?}", relations); @@ -609,7 +633,7 @@ impl Stylist { parent_bf, applicable_declarations, &mut relations, - reason, + flags, CascadeLevel::UserImportant); debug!("user important: {:?}", relations); @@ -622,7 +646,7 @@ impl Stylist { parent_bf, applicable_declarations, &mut relations, - reason, + flags, CascadeLevel::UAImportant); debug!("UA important: {:?}", relations); @@ -663,7 +687,7 @@ impl Stylist { pub fn match_same_not_common_style_affecting_attributes_rules(&self, element: &E, candidate: &E) -> bool - where E: ElementExt, + where E: TElement, { use selectors::matching::StyleRelations; use selectors::matching::matches_complex_selector; @@ -678,11 +702,11 @@ impl Stylist { let element_matches = matches_complex_selector(&selector.complex_selector, element, None, &mut StyleRelations::empty(), - MatchingReason::Other); + &mut ElementSelectorFlags::empty()); let candidate_matches = matches_complex_selector(&selector.complex_selector, candidate, None, &mut StyleRelations::empty(), - MatchingReason::Other); + &mut ElementSelectorFlags::empty()); if element_matches != candidate_matches { return false; @@ -704,7 +728,7 @@ impl Stylist { pub fn match_same_sibling_affecting_rules(&self, element: &E, candidate: &E) -> bool - where E: ElementExt, + where E: TElement, { use selectors::matching::StyleRelations; use selectors::matching::matches_complex_selector; @@ -717,12 +741,12 @@ impl Stylist { let element_matches = matches_complex_selector(&selector.complex_selector, element, None, &mut StyleRelations::empty(), - MatchingReason::Other); + &mut ElementSelectorFlags::empty()); let candidate_matches = matches_complex_selector(&selector.complex_selector, candidate, None, &mut StyleRelations::empty(), - MatchingReason::Other); + &mut ElementSelectorFlags::empty()); if element_matches != candidate_matches { debug!("match_same_sibling_affecting_rules: Failure due to {:?}", @@ -860,7 +884,7 @@ impl SelectorMap { parent_bf: Option<&BloomFilter>, matching_rules_list: &mut V, relations: &mut StyleRelations, - reason: MatchingReason, + flags: &mut ElementSelectorFlags, cascade_level: CascadeLevel) where E: Element, V: VecLike @@ -878,7 +902,7 @@ impl SelectorMap { &id, matching_rules_list, relations, - reason, + flags, cascade_level) } @@ -889,7 +913,7 @@ impl SelectorMap { class, matching_rules_list, relations, - reason, + flags, cascade_level); }); @@ -904,7 +928,7 @@ impl SelectorMap { element.get_local_name(), matching_rules_list, relations, - reason, + flags, cascade_level); SelectorMap::get_matching_rules(element, @@ -912,7 +936,7 @@ impl SelectorMap { &self.other_rules, matching_rules_list, relations, - reason, + flags, cascade_level); // Sort only the rules we just added. @@ -963,7 +987,7 @@ impl SelectorMap { key: &BorrowedStr, matching_rules: &mut Vector, relations: &mut StyleRelations, - reason: MatchingReason, + flags: &mut ElementSelectorFlags, cascade_level: CascadeLevel) where E: Element, Str: Borrow + Eq + Hash, @@ -976,7 +1000,7 @@ impl SelectorMap { rules, matching_rules, relations, - reason, + flags, cascade_level) } } @@ -987,7 +1011,7 @@ impl SelectorMap { rules: &[Rule], matching_rules: &mut V, relations: &mut StyleRelations, - reason: MatchingReason, + flags: &mut ElementSelectorFlags, cascade_level: CascadeLevel) where E: Element, V: VecLike @@ -1002,7 +1026,7 @@ impl SelectorMap { }; if any_declaration_for_importance && matches_complex_selector(&*rule.selector, element, parent_bf, - relations, reason) { + relations, flags) { matching_rules.push( rule.to_applicable_declaration_block(cascade_level)); } diff --git a/tests/unit/script/size_of.rs b/tests/unit/script/size_of.rs index a328bcbf6f5..30bc822fdbf 100644 --- a/tests/unit/script/size_of.rs +++ b/tests/unit/script/size_of.rs @@ -31,10 +31,10 @@ macro_rules! sizeof_checker ( // Update the sizes here sizeof_checker!(size_event_target, EventTarget, 40); sizeof_checker!(size_node, Node, 152); -sizeof_checker!(size_element, Element, 320); -sizeof_checker!(size_htmlelement, HTMLElement, 336); -sizeof_checker!(size_div, HTMLDivElement, 336); -sizeof_checker!(size_span, HTMLSpanElement, 336); +sizeof_checker!(size_element, Element, 312); +sizeof_checker!(size_htmlelement, HTMLElement, 328); +sizeof_checker!(size_div, HTMLDivElement, 328); +sizeof_checker!(size_span, HTMLSpanElement, 328); sizeof_checker!(size_text, Text, 184); sizeof_checker!(size_characterdata, CharacterData, 184); sizeof_checker!(size_servothreadsafelayoutnode, ServoThreadSafeLayoutNode, 16);