MatchingContext by jryans. draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Tue, 16 May 2017 00:35:22 +0200
changeset 578515 4f4d977d7d70c2267123aa2bd8227e2491ca547e
parent 578514 651b63732c13c34e010fec82e1e296db5e3cfbde
child 578516 d8b8752320f7f462c044f9e8ecdf22673c4e0171
child 578771 60639af227eb18a31465dac80095974b7eab0ebf
push id58943
push userbmo:emilio+bugs@crisal.io
push dateTue, 16 May 2017 04:34:19 +0000
bugs16872
milestone55.0a1
MatchingContext by jryans. Just the patch from https://github.com/servo/servo/pull/16872 rebased. MozReview-Commit-ID: Hw4KTjY4dCD
servo/components/script/dom/element.rs
servo/components/script/layout_wrapper.rs
servo/components/selectors/matching.rs
servo/components/selectors/tree.rs
servo/components/style/gecko/wrapper.rs
servo/components/style/matching.rs
servo/components/style/restyle_hints.rs
servo/components/style/servo/selector_parser.rs
servo/components/style/stylist.rs
--- a/servo/components/script/dom/element.rs
+++ b/servo/components/script/dom/element.rs
@@ -80,17 +80,17 @@ use html5ever::serialize;
 use html5ever::serialize::SerializeOpts;
 use html5ever::serialize::TraversalScope;
 use html5ever::serialize::TraversalScope::{ChildrenOnly, IncludeNode};
 use js::jsapi::{HandleValue, JSAutoCompartment};
 use net_traits::request::CorsSettings;
 use ref_filter_map::ref_filter_map;
 use script_layout_interface::message::ReflowQueryType;
 use script_thread::Runnable;
-use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_selector_list};
+use selectors::matching::{ElementSelectorFlags, MatchingContext, matches_selector_list};
 use selectors::matching::{HAS_EDGE_CHILD_SELECTOR, HAS_SLOW_SELECTOR, HAS_SLOW_SELECTOR_LATER_SIBLINGS};
 use selectors::parser::{AttrSelector, NamespaceConstraint};
 use servo_atoms::Atom;
 use std::ascii::AsciiExt;
 use std::borrow::Cow;
 use std::cell::{Cell, Ref};
 use std::convert::TryFrom;
 use std::default::Default;
@@ -2409,17 +2409,17 @@ impl<'a> ::selectors::Element for Root<E
     }
 
     fn get_namespace(&self) -> &Namespace {
         self.namespace()
     }
 
     fn match_non_ts_pseudo_class<F>(&self,
                                     pseudo_class: &NonTSPseudoClass,
-                                    _: &mut StyleRelations,
+                                    _: &mut MatchingContext,
                                     _: &mut F)
                                     -> bool
         where F: FnMut(&Self, ElementSelectorFlags),
     {
         match *pseudo_class {
             // https://github.com/servo/servo/issues/8718
             NonTSPseudoClass::Link |
             NonTSPseudoClass::AnyLink => self.is_link(),
--- a/servo/components/script/layout_wrapper.rs
+++ b/servo/components/script/layout_wrapper.rs
@@ -45,17 +45,17 @@ use dom::text::Text;
 use gfx_traits::ByteIndex;
 use html5ever::{LocalName, Namespace};
 use msg::constellation_msg::{FrameId, PipelineId};
 use range::Range;
 use script_layout_interface::{HTMLCanvasData, LayoutNodeType, SVGSVGData, TrustedNodeAddress};
 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::{ElementSelectorFlags, StyleRelations};
+use selectors::matching::{ElementSelectorFlags, MatchingContext};
 use selectors::parser::{AttrSelector, NamespaceConstraint};
 use servo_atoms::Atom;
 use servo_url::ServoUrl;
 use std::fmt;
 use std::fmt::Debug;
 use std::hash::{Hash, Hasher};
 use std::marker::PhantomData;
 use std::mem::transmute;
@@ -649,17 +649,17 @@ impl<'le> ::selectors::Element for Servo
 
     #[inline]
     fn get_namespace(&self) -> &Namespace {
         self.element.namespace()
     }
 
     fn match_non_ts_pseudo_class<F>(&self,
                                     pseudo_class: &NonTSPseudoClass,
-                                    _: &mut StyleRelations,
+                                    _: &mut MatchingContext,
                                     _: &mut F)
                                     -> bool
         where F: FnMut(&Self, ElementSelectorFlags),
     {
         match *pseudo_class {
             // https://github.com/servo/servo/issues/8718
             NonTSPseudoClass::Link |
             NonTSPseudoClass::AnyLink => unsafe {
@@ -1147,17 +1147,17 @@ impl<'le> ::selectors::Element for Servo
 
     #[inline]
     fn get_namespace(&self) -> &Namespace {
         self.element.get_namespace()
     }
 
     fn match_non_ts_pseudo_class<F>(&self,
                                     _: &NonTSPseudoClass,
-                                    _: &mut StyleRelations,
+                                    _: &mut MatchingContext,
                                     _: &mut F)
                                     -> bool
         where F: FnMut(&Self, ElementSelectorFlags),
     {
         // NB: This could maybe be implemented
         warn!("ServoThreadSafeLayoutElement::match_non_ts_pseudo_class called");
         false
     }
--- a/servo/components/selectors/matching.rs
+++ b/servo/components/selectors/matching.rs
@@ -12,16 +12,17 @@ use tree::Element;
 // rapidly increase.
 pub static RECOMMENDED_SELECTOR_BLOOM_FILTER_SIZE: usize = 4096;
 
 bitflags! {
     /// Set of flags that determine the different kind of elements affected by
     /// the selector matching process.
     ///
     /// This is used to implement efficient sharing.
+    #[derive(Default)]
     pub flags StyleRelations: usize {
         /// Whether this element is affected by an ID selector.
         const AFFECTED_BY_ID_SELECTOR = 1 << 0,
         /// Whether this element has a style attribute. Computed
         /// externally.
         const AFFECTED_BY_STYLE_ATTRIBUTE = 1 << 1,
         /// Whether this element is affected by presentational hints. This is
         /// computed externally (that is, in Servo).
@@ -63,28 +64,38 @@ impl ElementSelectorFlags {
     }
 
     /// 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)
     }
 }
 
+/// Data associated with the matching process for a element.  This context is
+/// used across many selectors for an element, so it's not appropriate for
+/// transient data that applies to only a single selector.
+#[derive(Default)]
+pub struct MatchingContext {
+    /// Output that records certains relations between elements noticed during
+    /// matching (and also extended after matching).
+    pub relations: StyleRelations,
+}
+
 pub fn matches_selector_list<E>(selector_list: &[Selector<E::Impl>],
                                 element: &E,
                                 parent_bf: Option<&BloomFilter>)
                                 -> bool
     where E: Element
 {
     selector_list.iter().any(|selector| {
         selector.pseudo_element.is_none() &&
         matches_selector(&selector.inner,
                          element,
                          parent_bf,
-                         &mut StyleRelations::empty(),
+                         &mut MatchingContext::default(),
                          &mut |_, _| {})
     })
 }
 
 fn may_match<E>(sel: &SelectorInner<E::Impl>,
                 bf: &BloomFilter)
                 -> bool
     where E: Element,
@@ -103,31 +114,31 @@ fn may_match<E>(sel: &SelectorInner<E::I
 
     true
 }
 
 /// Determines whether the given element matches the given complex selector.
 pub fn matches_selector<E, F>(selector: &SelectorInner<E::Impl>,
                               element: &E,
                               parent_bf: Option<&BloomFilter>,
-                              relations: &mut StyleRelations,
+                              context: &mut MatchingContext,
                               flags_setter: &mut F)
                               -> bool
     where E: Element,
           F: FnMut(&E, ElementSelectorFlags),
 {
     // Use the bloom filter to fast-reject.
     if let Some(filter) = parent_bf {
         if !may_match::<E>(selector, filter) {
             return false;
         }
     }
 
     // Match the selector.
-    matches_complex_selector(&selector.complex, element, relations, flags_setter)
+    matches_complex_selector(&selector.complex, element, context, flags_setter)
 }
 
 /// A result of selector matching, includes 3 failure types,
 ///
 ///   NotMatchedAndRestartFromClosestLaterSibling
 ///   NotMatchedAndRestartFromClosestDescendant
 ///   NotMatchedGlobally
 ///
@@ -173,41 +184,41 @@ enum SelectorMatchingResult {
     NotMatchedAndRestartFromClosestLaterSibling,
     NotMatchedAndRestartFromClosestDescendant,
     NotMatchedGlobally,
 }
 
 /// Matches a complex selector.
 pub fn matches_complex_selector<E, F>(selector: &ComplexSelector<E::Impl>,
                                       element: &E,
-                                      relations: &mut StyleRelations,
+                                      context: &mut MatchingContext,
                                       flags_setter: &mut F)
                                       -> bool
      where E: Element,
            F: FnMut(&E, ElementSelectorFlags),
 {
     match matches_complex_selector_internal(selector.iter(),
                                             element,
-                                            relations,
+                                            context,
                                             flags_setter) {
         SelectorMatchingResult::Matched => true,
         _ => false
     }
 }
 
 fn matches_complex_selector_internal<E, F>(mut selector_iter: SelectorIter<E::Impl>,
                                            element: &E,
-                                           relations: &mut StyleRelations,
+                                           context: &mut MatchingContext,
                                            flags_setter: &mut F)
                                            -> SelectorMatchingResult
      where E: Element,
            F: FnMut(&E, ElementSelectorFlags),
 {
     let matches_all_simple_selectors = selector_iter.all(|simple| {
-        matches_simple_selector(simple, element, relations, flags_setter)
+        matches_simple_selector(simple, element, context, flags_setter)
     });
 
     let combinator = selector_iter.next_sequence();
     let siblings = combinator.map_or(false, |c| c.is_sibling());
     if siblings {
         flags_setter(element, HAS_SLOW_SELECTOR_LATER_SIBLINGS);
     }
 
@@ -228,17 +239,17 @@ fn matches_complex_selector_internal<E, 
 
             loop {
                 let element = match next_element {
                     None => return candidate_not_found,
                     Some(next_element) => next_element,
                 };
                 let result = matches_complex_selector_internal(selector_iter.clone(),
                                                                &element,
-                                                               relations,
+                                                               context,
                                                                flags_setter);
                 match (result, c) {
                     // Return the status immediately.
                     (SelectorMatchingResult::Matched, _) => return result,
                     (SelectorMatchingResult::NotMatchedGlobally, _) => return result,
 
                     // Upgrade the failure status to
                     // NotMatchedAndRestartFromClosestDescendant.
@@ -271,26 +282,26 @@ fn matches_complex_selector_internal<E, 
     }
 }
 
 /// Determines whether the given element matches the given single selector.
 #[inline]
 fn matches_simple_selector<E, F>(
         selector: &Component<E::Impl>,
         element: &E,
-        relations: &mut StyleRelations,
+        context: &mut MatchingContext,
         flags_setter: &mut F)
         -> bool
     where E: Element,
           F: FnMut(&E, ElementSelectorFlags),
 {
     macro_rules! relation_if {
         ($ex:expr, $flag:ident) => {
             if $ex {
-                *relations |= $flag;
+                context.relations |= $flag;
                 true
             } else {
                 false
             }
         }
     }
 
     match *selector {
@@ -336,17 +347,17 @@ fn matches_simple_selector<E, F>(
         }
         Component::AttrIncludesNeverMatch(..) |
         Component::AttrPrefixNeverMatch(..) |
         Component::AttrSubstringNeverMatch(..) |
         Component::AttrSuffixNeverMatch(..) => {
             false
         }
         Component::NonTSPseudoClass(ref pc) => {
-            element.match_non_ts_pseudo_class(pc, relations, flags_setter)
+            element.match_non_ts_pseudo_class(pc, context, flags_setter)
         }
         Component::FirstChild => {
             matches_first_child(element, flags_setter)
         }
         Component::LastChild => {
             matches_last_child(element, flags_setter)
         }
         Component::OnlyChild => {
@@ -380,17 +391,17 @@ fn matches_simple_selector<E, F>(
         Component::LastOfType => {
             matches_generic_nth_child(element, 0, 1, true, true, flags_setter)
         }
         Component::OnlyOfType => {
             matches_generic_nth_child(element, 0, 1, true, false, flags_setter) &&
             matches_generic_nth_child(element, 0, 1, true, true, flags_setter)
         }
         Component::Negation(ref negated) => {
-            !negated.iter().all(|ss| matches_simple_selector(ss, element, relations, flags_setter))
+            !negated.iter().all(|ss| matches_simple_selector(ss, element, context, flags_setter))
         }
     }
 }
 
 #[inline]
 fn matches_generic_nth_child<E, F>(element: &E,
                                    a: i32,
                                    b: i32,
--- a/servo/components/selectors/tree.rs
+++ b/servo/components/selectors/tree.rs
@@ -1,16 +1,16 @@
 /* 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/. */
 
 //! Traits that nodes must implement. Breaks the otherwise-cyclic dependency between layout and
 //! style.
 
-use matching::{ElementSelectorFlags, StyleRelations};
+use matching::{ElementSelectorFlags, MatchingContext};
 use parser::{AttrSelector, SelectorImpl};
 use std::ascii::AsciiExt;
 
 /// The definition of whitespace per CSS Selectors Level 3 ยง 4.
 pub static SELECTOR_WHITESPACE: &'static [char] = &[' ', '\t', '\n', '\r', '\x0C'];
 
 // Attribute matching routines. Consumers with simple implementations can implement
 // MatchAttrGeneric instead.
@@ -136,17 +136,17 @@ pub trait Element: MatchAttr + Sized {
     fn next_sibling_element(&self) -> Option<Self>;
 
     fn is_html_element_in_html_document(&self) -> bool;
     fn get_local_name(&self) -> &<Self::Impl as SelectorImpl>::BorrowedLocalName;
     fn get_namespace(&self) -> &<Self::Impl as SelectorImpl>::BorrowedNamespaceUrl;
 
     fn match_non_ts_pseudo_class<F>(&self,
                                     pc: &<Self::Impl as SelectorImpl>::NonTSPseudoClass,
-                                    relations: &mut StyleRelations,
+                                    context: &mut MatchingContext,
                                     flags_setter: &mut F) -> bool
         where F: FnMut(&Self, ElementSelectorFlags);
 
     fn get_id(&self) -> Option<<Self::Impl as SelectorImpl>::Identifier>;
     fn has_class(&self, name: &<Self::Impl as SelectorImpl>::ClassName) -> bool;
 
     /// Returns whether this element matches `:empty`.
     ///
--- a/servo/components/style/gecko/wrapper.rs
+++ b/servo/components/style/gecko/wrapper.rs
@@ -59,17 +59,17 @@ use logical_geometry::WritingMode;
 use media_queries::Device;
 use properties::{ComputedValues, parse_style_attribute};
 use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock};
 use properties::animated_properties::{AnimationValue, AnimationValueMap, TransitionProperty};
 use properties::style_structs::Font;
 use rule_tree::CascadeLevel as ServoCascadeLevel;
 use selector_parser::ElementExt;
 use selectors::Element;
-use selectors::matching::{ElementSelectorFlags, StyleRelations};
+use selectors::matching::{ElementSelectorFlags, MatchingContext};
 use selectors::parser::{AttrSelector, NamespaceConstraint};
 use shared_lock::Locked;
 use sink::Push;
 use std::cell::RefCell;
 use std::collections::HashMap;
 use std::fmt;
 use std::hash::{Hash, Hasher};
 use std::ptr;
@@ -1120,17 +1120,17 @@ impl<'le> ::selectors::Element for Gecko
     fn get_namespace(&self) -> &WeakNamespace {
         unsafe {
             WeakNamespace::new(Gecko_Namespace(self.0))
         }
     }
 
     fn match_non_ts_pseudo_class<F>(&self,
                                     pseudo_class: &NonTSPseudoClass,
-                                    relations: &mut StyleRelations,
+                                    context: &mut MatchingContext,
                                     flags_setter: &mut F)
                                     -> bool
         where F: FnMut(&Self, ElementSelectorFlags),
     {
         use selectors::matching::*;
         match *pseudo_class {
             NonTSPseudoClass::AnyLink |
             NonTSPseudoClass::Link |
@@ -1214,17 +1214,17 @@ impl<'le> ::selectors::Element for Gecko
             }
             NonTSPseudoClass::MozTableBorderNonzero |
             NonTSPseudoClass::MozBrowserFrame |
             NonTSPseudoClass::MozNativeAnonymous => unsafe {
                 Gecko_MatchesElement(pseudo_class.to_gecko_pseudoclasstype().unwrap(), self.0)
             },
             NonTSPseudoClass::MozAny(ref sels) => {
                 sels.iter().any(|s| {
-                    matches_complex_selector(s, self, relations, flags_setter)
+                    matches_complex_selector(s, self, context, flags_setter)
                 })
             }
             NonTSPseudoClass::MozSystemMetric(ref s) |
             NonTSPseudoClass::MozLocaleDir(ref s) |
             NonTSPseudoClass::MozEmptyExceptChildrenWithLocalname(ref s) |
             NonTSPseudoClass::Dir(ref s) |
             NonTSPseudoClass::Lang(ref s) => {
                 unsafe {
@@ -1371,17 +1371,17 @@ impl<'le> ::selectors::MatchAttr for Gec
         }
     }
 }
 
 impl<'le> ElementExt for GeckoElement<'le> {
     #[inline]
     fn is_link(&self) -> bool {
         self.match_non_ts_pseudo_class(&NonTSPseudoClass::AnyLink,
-                                       &mut StyleRelations::empty(),
+                                       &mut MatchingContext::default(),
                                        &mut |_, _| {})
     }
 
     #[inline]
     fn matches_user_and_author_rules(&self) -> bool {
         self.flags() & (NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE as u32) == 0
     }
 }
--- a/servo/components/style/matching.rs
+++ b/servo/components/style/matching.rs
@@ -19,17 +19,17 @@ use element_state::ElementState;
 use font_metrics::FontMetricsProvider;
 use properties::{CascadeFlags, ComputedValues, SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP, cascade};
 use properties::longhands::display::computed_value as display;
 use restyle_hints::{RESTYLE_CSS_ANIMATIONS, RESTYLE_CSS_TRANSITIONS, RestyleHint};
 use restyle_hints::{RESTYLE_STYLE_ATTRIBUTE, RESTYLE_SMIL};
 use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode};
 use selector_parser::{PseudoElement, RestyleDamage, SelectorImpl};
 use selectors::bloom::BloomFilter;
-use selectors::matching::{ElementSelectorFlags, StyleRelations};
+use selectors::matching::{ElementSelectorFlags, MatchingContext, StyleRelations};
 use selectors::matching::AFFECTED_BY_PSEUDO_ELEMENTS;
 use shared_lock::StylesheetGuards;
 use sink::ForgetfulSink;
 use stylearc::Arc;
 use stylist::ApplicableDeclarationBlock;
 
 /// The way a style should be inherited.
 enum InheritMode {
@@ -890,32 +890,34 @@ pub trait MatchMethods : TElement {
     /// Performs selector matching and property cascading on an element and its
     /// eager pseudos.
     fn match_and_cascade(&self,
                          context: &mut StyleContext<Self>,
                          data: &mut ElementData,
                          sharing: StyleSharingBehavior)
     {
         // Perform selector matching for the primary style.
-        let mut primary_relations = StyleRelations::empty();
-        let _rule_node_changed = self.match_primary(context, data, &mut primary_relations);
+        let mut primary_matching_context = MatchingContext::default();
+        let _rule_node_changed = self.match_primary(context,
+                                                    data,
+                                                    &mut primary_matching_context);
 
         // Cascade properties and compute primary values.
         self.cascade_primary(context, data);
 
         // Match and cascade eager pseudo-elements.
         if !data.styles().is_display_none() {
             let _pseudo_rule_nodes_changed =
                 self.match_pseudos(context, data);
             self.cascade_pseudos(context, data);
         }
 
         // If we have any pseudo elements, indicate so in the primary StyleRelations.
         if !data.styles().pseudos.is_empty() {
-            primary_relations |= AFFECTED_BY_PSEUDO_ELEMENTS;
+            primary_matching_context.relations |= AFFECTED_BY_PSEUDO_ELEMENTS;
         }
 
         // If the style is shareable, add it to the LRU cache.
         if sharing == StyleSharingBehavior::Allow {
             // If we previously tried to match this element against the cache,
             // the revalidation match results will already be cached. Otherwise
             // we'll have None, and compute them later on-demand.
             //
@@ -925,17 +927,17 @@ pub trait MatchMethods : TElement {
                                                     .current_element_info
                                                     .as_mut().unwrap()
                                                     .revalidation_match_results
                                                     .take();
             context.thread_local
                    .style_sharing_candidate_cache
                    .insert_if_possible(self,
                                        data.styles().primary.values(),
-                                       primary_relations,
+                                       primary_matching_context.relations,
                                        revalidation_match_results);
         }
     }
 
     /// Performs the cascade, without matching.
     fn cascade_primary_and_pseudos(&self,
                                    context: &mut StyleContext<Self>,
                                    mut data: &mut ElementData)
@@ -945,17 +947,17 @@ pub trait MatchMethods : TElement {
     }
 
     /// Runs selector matching to (re)compute the primary rule node for this element.
     ///
     /// Returns whether the primary rule node changed.
     fn match_primary(&self,
                      context: &mut StyleContext<Self>,
                      data: &mut ElementData,
-                     relations: &mut StyleRelations)
+                     matching_context: &mut MatchingContext)
                      -> bool
     {
         let implemented_pseudo = self.implemented_pseudo_element();
         if let Some(ref pseudo) = implemented_pseudo {
             if pseudo.is_eager() {
                 // If it's an eager element-backed pseudo, just grab the matched
                 // rules from the parent, and update animations.
                 let parent = self.parent_element().unwrap();
@@ -1017,24 +1019,25 @@ pub trait MatchMethods : TElement {
         };
 
         let pseudo_and_state = match implemented_pseudo {
             Some(ref pseudo) => Some((pseudo, self.get_state())),
             None => None,
         };
 
         // Compute the primary rule node.
-        *relations = stylist.push_applicable_declarations(&selector_matching_target,
-                                                          Some(bloom),
-                                                          style_attribute,
-                                                          smil_override,
-                                                          animation_rules,
-                                                          pseudo_and_state,
-                                                          &mut applicable_declarations,
-                                                          &mut set_selector_flags);
+        stylist.push_applicable_declarations(&selector_matching_target,
+                                             Some(bloom),
+                                             style_attribute,
+                                             smil_override,
+                                             animation_rules,
+                                             pseudo_and_state,
+                                             &mut applicable_declarations,
+                                             matching_context,
+                                             &mut set_selector_flags);
 
         let primary_rule_node =
             compute_rule_node::<Self>(&stylist.rule_tree,
                                       &mut applicable_declarations,
                                       &context.shared.guards);
 
         return data.set_primary_rules(primary_rule_node);
     }
@@ -1079,16 +1082,17 @@ pub trait MatchMethods : TElement {
             // traversing them.
             stylist.push_applicable_declarations(self,
                                                  Some(bloom_filter),
                                                  None,
                                                  None,
                                                  AnimationRules(None, None),
                                                  Some((&pseudo, ElementState::empty())),
                                                  &mut applicable_declarations,
+                                                 &mut MatchingContext::default(),
                                                  &mut set_selector_flags);
 
             if !applicable_declarations.is_empty() {
                 let new_rules =
                     compute_rule_node::<Self>(rule_tree,
                                               &mut applicable_declarations,
                                               &guards);
                 if pseudos.has(&pseudo) {
--- a/servo/components/style/restyle_hints.rs
+++ b/servo/components/style/restyle_hints.rs
@@ -11,17 +11,17 @@ use dom::TElement;
 use element_state::*;
 use fnv::FnvHashMap;
 #[cfg(feature = "gecko")]
 use gecko_bindings::structs::nsRestyleHint;
 #[cfg(feature = "servo")]
 use heapsize::HeapSizeOf;
 use selector_parser::{AttrValue, NonTSPseudoClass, PseudoElement, SelectorImpl, Snapshot, SnapshotMap};
 use selectors::{Element, MatchAttr};
-use selectors::matching::{ElementSelectorFlags, StyleRelations};
+use selectors::matching::{ElementSelectorFlags, MatchingContext};
 use selectors::matching::matches_selector;
 use selectors::parser::{AttrSelector, Combinator, Component, Selector};
 use selectors::parser::{SelectorInner, SelectorMethods};
 use selectors::visitor::SelectorVisitor;
 use smallvec::SmallVec;
 use std::borrow::Borrow;
 use std::cell::Cell;
 use std::clone::Clone;
@@ -343,29 +343,29 @@ fn dir_selector_to_state(s: &[u16]) -> E
     }
 }
 
 impl<'a, E> Element for ElementWrapper<'a, E>
     where E: TElement,
 {
     fn match_non_ts_pseudo_class<F>(&self,
                                     pseudo_class: &NonTSPseudoClass,
-                                    relations: &mut StyleRelations,
+                                    context: &mut MatchingContext,
                                     _setter: &mut F)
                                     -> bool
         where F: FnMut(&Self, ElementSelectorFlags),
     {
         // :moz-any is quite special, because we need to keep matching as a
         // snapshot.
         #[cfg(feature = "gecko")]
         {
             use selectors::matching::matches_complex_selector;
             if let NonTSPseudoClass::MozAny(ref selectors) = *pseudo_class {
                 return selectors.iter().any(|s| {
-                    matches_complex_selector(s, self, relations, _setter)
+                    matches_complex_selector(s, self, context, _setter)
                 })
             }
         }
 
         // :dir needs special handling.  It's implemented in terms of state
         // flags, but which state flag it maps to depends on the argument to
         // :dir.  That means we can't just add its state flags to the
         // NonTSPseudoClass, because if we added all of them there, and tested
@@ -388,24 +388,24 @@ impl<'a, E> Element for ElementWrapper<'
                 };
                 return state.contains(selector_flag);
             }
         }
 
         let flag = pseudo_class.state_flag();
         if flag.is_empty() {
             return self.element.match_non_ts_pseudo_class(pseudo_class,
-                                                          relations,
+                                                          context,
                                                           &mut |_, _| {})
         }
         match self.snapshot().and_then(|s| s.state()) {
             Some(snapshot_state) => snapshot_state.intersects(flag),
             None => {
                 self.element.match_non_ts_pseudo_class(pseudo_class,
-                                                       relations,
+                                                       context,
                                                        &mut |_, _| {})
             }
         }
     }
 
     fn parent_element(&self) -> Option<Self> {
         self.element.parent_element()
             .map(|e| ElementWrapper::new(e, self.snapshot_map))
@@ -852,21 +852,21 @@ impl DependencySet {
                 return true;
             }
 
             // 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_selector(&dep.selector, &snapshot_el, None,
-                                 &mut StyleRelations::empty(),
+                                 &mut MatchingContext::default(),
                                  &mut |_, _| {});
             let matches_now =
                 matches_selector(&dep.selector, el, None,
-                                 &mut StyleRelations::empty(),
+                                 &mut MatchingContext::default(),
                                  &mut |_, _| {});
             if matched_then != matches_now {
                 hint.insert(dep.hint);
             }
 
             !hint.is_all()
         });
 
--- a/servo/components/style/servo/selector_parser.rs
+++ b/servo/components/style/servo/selector_parser.rs
@@ -10,17 +10,17 @@ use {Atom, Prefix, Namespace, LocalName}
 use attr::{AttrIdentifier, AttrValue};
 use cssparser::{Parser as CssParser, ToCss, serialize_identifier};
 use dom::{OpaqueNode, TElement, TNode};
 use element_state::ElementState;
 use fnv::FnvHashMap;
 use restyle_hints::ElementSnapshot;
 use selector_parser::{ElementExt, PseudoElementCascadeType, SelectorParser};
 use selectors::{Element, MatchAttrGeneric};
-use selectors::matching::StyleRelations;
+use selectors::matching::MatchingContext;
 use selectors::parser::{AttrSelector, SelectorMethods};
 use selectors::visitor::SelectorVisitor;
 use std::borrow::Cow;
 use std::fmt;
 use std::fmt::Debug;
 use std::mem;
 use std::ops::{Deref, DerefMut};
 
@@ -575,17 +575,17 @@ impl MatchAttrGeneric for ServoElementSn
             NamespaceConstraint::Any => self.get_attr_ignore_ns(local_name),
         }.map_or(false, |v| test(v))
     }
 }
 
 impl<E: Element<Impl=SelectorImpl> + Debug> ElementExt for E {
     fn is_link(&self) -> bool {
         self.match_non_ts_pseudo_class(&NonTSPseudoClass::AnyLink,
-                                       &mut StyleRelations::empty(),
+                                       &mut MatchingContext::default(),
                                        &mut |_, _| {})
     }
 
     #[inline]
     fn matches_user_and_author_rules(&self) -> bool {
         true
     }
 }
--- a/servo/components/style/stylist.rs
+++ b/servo/components/style/stylist.rs
@@ -22,17 +22,17 @@ use properties::{self, CascadeFlags, Com
 use properties::INHERIT_ALL;
 use properties::PropertyDeclarationBlock;
 use restyle_hints::{RestyleHint, DependencySet};
 use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
 use selector_parser::{SelectorImpl, PseudoElement, SnapshotMap};
 use selectors::Element;
 use selectors::bloom::BloomFilter;
 use selectors::matching::{AFFECTED_BY_STYLE_ATTRIBUTE, AFFECTED_BY_PRESENTATIONAL_HINTS};
-use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_selector};
+use selectors::matching::{ElementSelectorFlags, matches_selector, MatchingContext};
 use selectors::parser::{AttrSelector, Combinator, Component, Selector, SelectorInner, SelectorIter};
 use selectors::parser::{SelectorMethods, LocalName as LocalNameSelector};
 use selectors::visitor::SelectorVisitor;
 use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
 use sink::Push;
 use smallvec::VecLike;
 use std::borrow::Borrow;
 use std::collections::HashMap;
@@ -672,25 +672,25 @@ impl Stylist {
             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); }
                 }
             }
         };
 
-
         let mut declarations = vec![];
         self.push_applicable_declarations(element,
                                           None,
                                           None,
                                           None,
                                           AnimationRules(None, None),
                                           Some((pseudo, pseudo_state)),
                                           &mut declarations,
+                                          &mut MatchingContext::default(),
                                           &mut set_selector_flags);
         if declarations.is_empty() {
             return None
         }
 
         let rule_node =
             self.rule_tree.insert_ordered_rules_with_important(
                 declarations.into_iter().map(|a| (a.source, a.level)),
@@ -799,29 +799,29 @@ impl Stylist {
         // mode info in the `SharedLayoutContext`.
         self.quirks_mode = quirks_mode;
     }
 
     /// Returns the applicable CSS declarations for the given element.
     ///
     /// This corresponds to `ElementRuleCollector` in WebKit.
     ///
-    /// The returned `StyleRelations` indicate hints about which kind of rules
-    /// have matched.
+    /// The `StyleRelations` recorded in `MatchingContext` indicate hints about
+    /// which kind of rules have matched.
     pub fn push_applicable_declarations<E, V, F>(
                                         &self,
                                         element: &E,
                                         parent_bf: Option<&BloomFilter>,
                                         style_attribute: Option<&Arc<Locked<PropertyDeclarationBlock>>>,
                                         smil_override: Option<&Arc<Locked<PropertyDeclarationBlock>>>,
                                         animation_rules: AnimationRules,
                                         pseudo_element: Option<(&PseudoElement, ElementState)>,
                                         applicable_declarations: &mut V,
+                                        context: &mut MatchingContext,
                                         flags_setter: &mut F)
-                                        -> StyleRelations
         where E: TElement,
               V: Push<ApplicableDeclarationBlock> + VecLike<ApplicableDeclarationBlock>,
               F: FnMut(&E, ElementSelectorFlags),
     {
         debug_assert!(!self.is_device_dirty);
         // Gecko definitely has pseudo-elements with style attributes, like
         // ::-moz-color-swatch.
         debug_assert!(cfg!(feature = "gecko") ||
@@ -829,118 +829,114 @@ impl Stylist {
                       "Style attributes do not apply to pseudo-elements");
         debug_assert!(pseudo_element.as_ref().map_or(true, |p| !p.0.is_precomputed()));
 
         let map = match pseudo_element {
             Some((ref pseudo, _)) => self.pseudos_map.get(pseudo).unwrap(),
             None => &self.element_map,
         };
 
-        let mut relations = StyleRelations::empty();
-
         debug!("Determining if style is shareable: pseudo: {}",
                pseudo_element.is_some());
 
         // Step 1: Normal user-agent rules.
         map.user_agent.get_all_matching_rules(element,
                                               pseudo_element,
                                               parent_bf,
                                               applicable_declarations,
-                                              &mut relations,
+                                              context,
                                               flags_setter,
                                               CascadeLevel::UANormal);
-        debug!("UA normal: {:?}", relations);
+        debug!("UA normal: {:?}", context.relations);
 
         if pseudo_element.is_none() {
             // Step 2: Presentational hints.
             let length_before_preshints = applicable_declarations.len();
             element.synthesize_presentational_hints_for_legacy_attributes(applicable_declarations);
             if applicable_declarations.len() != length_before_preshints {
                 if cfg!(debug_assertions) {
                     for declaration in &applicable_declarations[length_before_preshints..] {
                         assert_eq!(declaration.level, CascadeLevel::PresHints);
                     }
                 }
                 // Never share style for elements with preshints
-                relations |= AFFECTED_BY_PRESENTATIONAL_HINTS;
+                context.relations |= AFFECTED_BY_PRESENTATIONAL_HINTS;
             }
-            debug!("preshints: {:?}", relations);
+            debug!("preshints: {:?}", context.relations);
         }
 
         if element.matches_user_and_author_rules() {
             // Step 3: User and author normal rules.
             map.user.get_all_matching_rules(element,
                                             pseudo_element,
                                             parent_bf,
                                             applicable_declarations,
-                                            &mut relations,
+                                            context,
                                             flags_setter,
                                             CascadeLevel::UserNormal);
-            debug!("user normal: {:?}", relations);
+            debug!("user normal: {:?}", context.relations);
             map.author.get_all_matching_rules(element,
                                               pseudo_element,
                                               parent_bf,
                                               applicable_declarations,
-                                              &mut relations,
+                                              context,
                                               flags_setter,
                                               CascadeLevel::AuthorNormal);
-            debug!("author normal: {:?}", relations);
+            debug!("author normal: {:?}", context.relations);
 
             // Step 4: Normal style attributes.
             if let Some(sa) = style_attribute {
-                relations |= AFFECTED_BY_STYLE_ATTRIBUTE;
+                context.relations |= AFFECTED_BY_STYLE_ATTRIBUTE;
                 Push::push(
                     applicable_declarations,
                     ApplicableDeclarationBlock::from_declarations(sa.clone(),
                                                                   CascadeLevel::StyleAttributeNormal));
             }
 
-            debug!("style attr: {:?}", relations);
+            debug!("style attr: {:?}", context.relations);
 
             // Step 5: SMIL override.
             // Declarations from SVG SMIL animation elements.
             if let Some(so) = smil_override {
                 Push::push(
                     applicable_declarations,
                     ApplicableDeclarationBlock::from_declarations(so.clone(),
                                                                   CascadeLevel::SMILOverride));
             }
-            debug!("SMIL: {:?}", relations);
+            debug!("SMIL: {:?}", context.relations);
 
             // Step 6: Animations.
             // The animations sheet (CSS animations, script-generated animations,
             // and CSS transitions that are no longer tied to CSS markup)
             if let Some(anim) = animation_rules.0 {
                 Push::push(
                     applicable_declarations,
                     ApplicableDeclarationBlock::from_declarations(anim,
                                                                   CascadeLevel::Animations));
             }
-            debug!("animation: {:?}", relations);
+            debug!("animation: {:?}", context.relations);
         } else {
             debug!("skipping non-agent rules");
         }
 
         //
         // Steps 7-10 correspond to !important rules, and are handled during
         // rule tree insertion.
         //
 
         // Step 11: Transitions.
         // The transitions sheet (CSS transitions that are tied to CSS markup)
         if let Some(anim) = animation_rules.1 {
             Push::push(
                 applicable_declarations,
                 ApplicableDeclarationBlock::from_declarations(anim, CascadeLevel::Transitions));
         }
-        debug!("transition: {:?}", relations);
+        debug!("transition: {:?}", context.relations);
 
-        debug!("push_applicable_declarations: shareable: {:?}", relations);
-
-        relations
+        debug!("push_applicable_declarations: shareable: {:?}", context.relations);
     }
 
     /// Return whether the device is dirty, that is, whether the screen size or
     /// media type have changed (for now).
     #[inline]
     pub fn is_device_dirty(&self) -> bool {
         self.is_device_dirty
     }
@@ -962,30 +958,27 @@ impl Stylist {
     pub fn match_revalidation_selectors<E, F>(&self,
                                               element: &E,
                                               bloom: &BloomFilter,
                                               flags_setter: &mut F)
                                               -> BitVec
         where E: TElement,
               F: FnMut(&E, ElementSelectorFlags),
     {
-        use selectors::matching::StyleRelations;
-        use selectors::matching::matches_selector;
-
         // Note that, by the time we're revalidating, we're guaranteed that the
         // candidate and the entry have the same id, classes, and local name.
         // This means we're guaranteed to get the same rulehash buckets for all
         // the lookups, which means that the bitvecs are comparable. We verify
         // this in the caller by asserting that the bitvecs are same-length.
         let mut results = BitVec::new();
         self.selectors_for_cache_revalidation.lookup(*element, &mut |selector| {
             results.push(matches_selector(selector,
                                           element,
                                           Some(bloom),
-                                          &mut StyleRelations::empty(),
+                                          &mut MatchingContext::default(),
                                           flags_setter));
             true
         });
 
         results
     }
 
     /// Given an element, and a snapshot table that represents a previous state
@@ -1258,17 +1251,17 @@ impl SelectorMap<Rule> {
     ///
     /// Extract matching rules as per element's ID, classes, tag name, etc..
     /// Sort the Rules at the end to maintain cascading order.
     pub fn get_all_matching_rules<E, V, F>(&self,
                                            element: &E,
                                            pseudo_element: Option<(&PseudoElement, ElementState)>,
                                            parent_bf: Option<&BloomFilter>,
                                            matching_rules_list: &mut V,
-                                           relations: &mut StyleRelations,
+                                           context: &mut MatchingContext,
                                            flags_setter: &mut F,
                                            cascade_level: CascadeLevel)
         where E: Element<Impl=SelectorImpl>,
               V: VecLike<ApplicableDeclarationBlock>,
               F: FnMut(&E, ElementSelectorFlags),
     {
         if self.is_empty() {
             return
@@ -1278,49 +1271,49 @@ impl SelectorMap<Rule> {
         let init_len = matching_rules_list.len();
         if let Some(id) = element.get_id() {
             SelectorMap::get_matching_rules_from_hash(element,
                                                       pseudo_element,
                                                       parent_bf,
                                                       &self.id_hash,
                                                       &id,
                                                       matching_rules_list,
-                                                      relations,
+                                                      context,
                                                       flags_setter,
                                                       cascade_level)
         }
 
         element.each_class(|class| {
             SelectorMap::get_matching_rules_from_hash(element,
                                                       pseudo_element,
                                                       parent_bf,
                                                       &self.class_hash,
                                                       class,
                                                       matching_rules_list,
-                                                      relations,
+                                                      context,
                                                       flags_setter,
                                                       cascade_level);
         });
 
         SelectorMap::get_matching_rules_from_hash(element,
                                                   pseudo_element,
                                                   parent_bf,
                                                   &self.local_name_hash,
                                                   element.get_local_name(),
                                                   matching_rules_list,
-                                                  relations,
+                                                  context,
                                                   flags_setter,
                                                   cascade_level);
 
         SelectorMap::get_matching_rules(element,
                                         pseudo_element,
                                         parent_bf,
                                         &self.other,
                                         matching_rules_list,
-                                        relations,
+                                        context,
                                         flags_setter,
                                         cascade_level);
 
         // Sort only the rules we just added.
         sort_by_key(&mut matching_rules_list[init_len..],
                     |block| (block.specificity, block.source_order));
     }
 
@@ -1349,44 +1342,44 @@ impl SelectorMap<Rule> {
 
     fn get_matching_rules_from_hash<E, Str, BorrowedStr: ?Sized, Vector, F>(
         element: &E,
         pseudo_element: Option<(&PseudoElement, ElementState)>,
         parent_bf: Option<&BloomFilter>,
         hash: &FnvHashMap<Str, Vec<Rule>>,
         key: &BorrowedStr,
         matching_rules: &mut Vector,
-        relations: &mut StyleRelations,
+        context: &mut MatchingContext,
         flags_setter: &mut F,
         cascade_level: CascadeLevel)
         where E: Element<Impl=SelectorImpl>,
               Str: Borrow<BorrowedStr> + Eq + Hash,
               BorrowedStr: Eq + Hash,
               Vector: VecLike<ApplicableDeclarationBlock>,
               F: FnMut(&E, ElementSelectorFlags),
     {
         if let Some(rules) = hash.get(key) {
             SelectorMap::get_matching_rules(element,
                                             pseudo_element,
                                             parent_bf,
                                             rules,
                                             matching_rules,
-                                            relations,
+                                            context,
                                             flags_setter,
                                             cascade_level)
         }
     }
 
     /// Adds rules in `rules` that match `element` to the `matching_rules` list.
     fn get_matching_rules<E, V, F>(element: &E,
                                    pseudo_element: Option<(&PseudoElement, ElementState)>,
                                    parent_bf: Option<&BloomFilter>,
                                    rules: &[Rule],
                                    matching_rules: &mut V,
-                                   relations: &mut StyleRelations,
+                                   context: &mut MatchingContext,
                                    flags_setter: &mut F,
                                    cascade_level: CascadeLevel)
         where E: Element<Impl=SelectorImpl>,
               V: VecLike<ApplicableDeclarationBlock>,
               F: FnMut(&E, ElementSelectorFlags),
     {
         for rule in rules.iter() {
             debug_assert_eq!(rule.selector.pseudo_element.is_some(),
@@ -1408,17 +1401,17 @@ impl SelectorMap<Rule> {
                 if !state.is_empty() && !pseudo_state.contains(state) {
                     continue;
                 }
             }
 
             if matches_selector(&rule.selector.inner,
                                 element,
                                 parent_bf,
-                                relations,
+                                context,
                                 flags_setter) {
                 matching_rules.push(
                     rule.to_applicable_declaration_block(cascade_level));
             }
         }
     }
 }