servo: Merge #14320 - Update to selectors 0.15 (from servo:selectorsup); r=nox
authorSimon Sapin <simon.sapin@exyr.org>
Tue, 22 Nov 2016 10:44:03 -0600
changeset 340202 27e41c7f2ad2e260827f665a265efe806cedd32b
parent 340201 635fc4362a296ed178bef1bf5b85422bfe83ace2
child 340203 28425cffb7bf7c6eac9e0ffef121144efdbd2ffc
push id31307
push usergszorc@mozilla.com
push dateSat, 04 Feb 2017 00:59:06 +0000
treeherdermozilla-central@94079d43835f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnox
servo: Merge #14320 - Update to selectors 0.15 (from servo:selectorsup); r=nox <!-- Please describe your changes on the following line: --> --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [x] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: f37fc5ea5ef3335ebc0a754dce93872dd5fd85a1
servo/components/layout/Cargo.toml
servo/components/layout/animation.rs
servo/components/layout_thread/Cargo.toml
servo/components/script/Cargo.toml
servo/components/script/dom/element.rs
servo/components/script/dom/node.rs
servo/components/script/layout_wrapper.rs
servo/components/script_layout_interface/Cargo.toml
servo/components/script_layout_interface/wrapper_traits.rs
servo/components/style/Cargo.toml
servo/components/style/gecko/selector_parser.rs
servo/components/style/gecko/snapshot.rs
servo/components/style/gecko/wrapper.rs
servo/components/style/matching.rs
servo/components/style/parser.rs
servo/components/style/restyle_hints.rs
servo/components/style/selector_parser.rs
servo/components/style/servo/selector_parser.rs
servo/components/style/stylesheets.rs
servo/components/style/stylist.rs
servo/docs/components/style.md
servo/ports/cef/Cargo.lock
servo/ports/geckolib/Cargo.lock
servo/ports/geckolib/Cargo.toml
servo/ports/geckolib/glue.rs
servo/ports/servo/Cargo.lock
servo/tests/unit/style/Cargo.toml
servo/tests/unit/style/parsing/selectors.rs
servo/tests/unit/style/stylesheets.rs
servo/tests/unit/style/stylist.rs
servo/tests/unit/stylo/Cargo.toml
--- a/servo/components/layout/Cargo.toml
+++ b/servo/components/layout/Cargo.toml
@@ -29,17 +29,17 @@ net_traits = {path = "../net_traits"}
 ordered-float = "0.2.2"
 parking_lot = "0.3.3"
 plugins = {path = "../plugins"}
 profile_traits = {path = "../profile_traits"}
 range = {path = "../range"}
 rayon = "0.5"
 script_layout_interface = {path = "../script_layout_interface"}
 script_traits = {path = "../script_traits"}
-selectors = "0.14"
+selectors = "0.15"
 serde = "0.8"
 serde_derive = "0.8"
 serde_json = "0.8"
 servo_atoms = {path = "../atoms"}
 servo_url = {path = "../url"}
 smallvec = "0.1"
 style = {path = "../style"}
 style_traits = {path = "../style_traits"}
--- a/servo/components/layout/animation.rs
+++ b/servo/components/layout/animation.rs
@@ -123,18 +123,18 @@ pub fn update_animation_state(constellat
     };
 
     constellation_chan.send(ConstellationMsg::ChangeRunningAnimationsState(pipeline_id, animation_state))
                       .unwrap();
 }
 
 /// Recalculates style for a set of animations. This does *not* run with the DOM
 /// lock held.
-// NB: This is specific for ServoSelectorImpl, since the layout context and the
-// flows are ServoSelectorImpl specific too. If that goes away at some point,
+// NB: This is specific for SelectorImpl, since the layout context and the
+// flows are SelectorImpl specific too. If that goes away at some point,
 // this should be made generic.
 pub fn recalc_style_for_animations(context: &SharedLayoutContext,
                                    flow: &mut Flow,
                                    animations: &HashMap<OpaqueNode,
                                                         Vec<Animation>>) {
     let mut damage = RestyleDamage::empty();
     flow.mutate_fragments(&mut |fragment| {
         if let Some(ref animations) = animations.get(&fragment.node) {
--- a/servo/components/layout_thread/Cargo.toml
+++ b/servo/components/layout_thread/Cargo.toml
@@ -26,17 +26,17 @@ msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
 parking_lot = {version = "0.3.3", features = ["nightly"]}
 plugins = {path = "../plugins"}
 profile_traits = {path = "../profile_traits"}
 rayon = "0.5"
 script = {path = "../script"}
 script_layout_interface = {path = "../script_layout_interface"}
 script_traits = {path = "../script_traits"}
-selectors = "0.14"
+selectors = "0.15"
 serde_derive = "0.8"
 serde_json = "0.8"
 servo_url = {path = "../url"}
 style = {path = "../style"}
 util = {path = "../util"}
 
 [dependencies.webrender_traits]
 git = "https://github.com/servo/webrender"
--- a/servo/components/script/Cargo.toml
+++ b/servo/components/script/Cargo.toml
@@ -61,17 +61,17 @@ plugins = {path = "../plugins"}
 profile_traits = {path = "../profile_traits"}
 rand = "0.3"
 range = {path = "../range"}
 ref_slice = "1.0"
 regex = "0.1.43"
 rustc-serialize = "0.3"
 script_layout_interface = {path = "../script_layout_interface"}
 script_traits = {path = "../script_traits"}
-selectors = "0.14"
+selectors = "0.15"
 serde = "0.8"
 servo_atoms = {path = "../atoms"}
 servo_url = {path = "../url", features = ["servo"] }
 smallvec = "0.1"
 style = {path = "../style"}
 style_traits = {path = "../style_traits"}
 time = "0.1.12"
 url = {version = "1.2", features = ["heap_size", "query_encoding"]}
--- a/servo/components/script/dom/element.rs
+++ b/servo/components/script/dom/element.rs
@@ -68,17 +68,17 @@ use html5ever::serialize;
 use html5ever::serialize::SerializeOpts;
 use html5ever::serialize::TraversalScope;
 use html5ever::serialize::TraversalScope::{ChildrenOnly, IncludeNode};
 use html5ever::tree_builder::{LimitedQuirks, NoQuirks, Quirks};
 use html5ever_atoms::{Prefix, LocalName, Namespace, QualName};
 use parking_lot::RwLock;
 use selectors::matching::{ElementFlags, MatchingReason, matches};
 use selectors::matching::{HAS_EDGE_CHILD_SELECTOR, HAS_SLOW_SELECTOR, HAS_SLOW_SELECTOR_LATER_SIBLINGS};
-use selectors::parser::{AttrSelector, NamespaceConstraint, parse_author_origin_selector_list_from_str};
+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;
 use std::fmt;
 use std::sync::Arc;
@@ -87,17 +87,17 @@ use style::attr::{AttrValue, LengthOrPer
 use style::dom::TRestyleDamage;
 use style::element_state::*;
 use style::matching::{common_style_affecting_attributes, rare_style_affecting_attributes};
 use style::parser::ParserContextExtraData;
 use style::properties::{DeclaredValue, Importance};
 use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, parse_style_attribute};
 use style::properties::longhands::{background_image, border_spacing, font_family, font_size, overflow_x};
 use style::restyle_hints::RESTYLE_SELF;
-use style::selector_parser::{NonTSPseudoClass, RestyleDamage, ServoSelectorImpl};
+use style::selector_parser::{NonTSPseudoClass, RestyleDamage, SelectorImpl, SelectorParser};
 use style::sink::Push;
 use style::stylist::ApplicableDeclarationBlock;
 use style::values::CSSFloat;
 use style::values::specified::{self, CSSColor, CSSRGBA, LengthOrPercentage};
 
 // TODO: Update focus state when the top-level browsing context gains or loses system focus,
 // and when the element enters or leaves a browsing context container.
 // https://html.spec.whatwg.org/multipage/#selector-focus
@@ -1880,38 +1880,38 @@ impl ElementMethods for Element {
 
     // https://dom.spec.whatwg.org/#dom-childnode-remove
     fn Remove(&self) {
         self.upcast::<Node>().remove_self();
     }
 
     // https://dom.spec.whatwg.org/#dom-element-matches
     fn Matches(&self, selectors: DOMString) -> Fallible<bool> {
-        match parse_author_origin_selector_list_from_str(&selectors) {
+        match SelectorParser::parse_author_origin_no_namespace(&selectors) {
             Err(()) => Err(Error::Syntax),
-            Ok(ref selectors) => {
-                Ok(matches(selectors, &Root::from_ref(self), None, MatchingReason::Other))
+            Ok(selectors) => {
+                Ok(matches(&selectors.0, &Root::from_ref(self), None, MatchingReason::Other))
             }
         }
     }
 
     // https://dom.spec.whatwg.org/#dom-element-webkitmatchesselector
     fn WebkitMatchesSelector(&self, selectors: DOMString) -> Fallible<bool> {
         self.Matches(selectors)
     }
 
     // https://dom.spec.whatwg.org/#dom-element-closest
     fn Closest(&self, selectors: DOMString) -> Fallible<Option<Root<Element>>> {
-        match parse_author_origin_selector_list_from_str(&selectors) {
+        match SelectorParser::parse_author_origin_no_namespace(&selectors) {
             Err(()) => Err(Error::Syntax),
-            Ok(ref selectors) => {
+            Ok(selectors) => {
                 let root = self.upcast::<Node>();
                 for element in root.inclusive_ancestors() {
                     if let Some(element) = Root::downcast::<Element>(element) {
-                        if matches(selectors, &element, None, MatchingReason::Other) {
+                        if matches(&selectors.0, &element, None, MatchingReason::Other) {
                             return Ok(Some(element));
                         }
                     }
                 }
                 Ok(None)
             }
         }
     }
@@ -2136,19 +2136,19 @@ impl VirtualMethods for Element {
 
         if document_from_node(self).is_html_document() != old_doc.is_html_document() {
             self.tag_name.clear();
         }
     }
 }
 
 impl<'a> ::selectors::MatchAttrGeneric for Root<Element> {
-    type Impl = ServoSelectorImpl;
+    type Impl = SelectorImpl;
 
-    fn match_attr<F>(&self, attr: &AttrSelector<ServoSelectorImpl>, test: F) -> bool
+    fn match_attr<F>(&self, attr: &AttrSelector<SelectorImpl>, test: F) -> bool
         where F: Fn(&str) -> bool
     {
         use ::selectors::Element;
         let local_name = {
             if self.is_html_element_in_html_document() {
                 &attr.lower_name
             } else {
                 &attr.name
--- a/servo/components/script/dom/node.rs
+++ b/servo/components/script/dom/node.rs
@@ -66,29 +66,28 @@ use js::jsapi::{JSContext, JSObject, JSR
 use libc::{self, c_void, uintptr_t};
 use msg::constellation_msg::PipelineId;
 use ref_slice::ref_slice;
 use script_layout_interface::{HTMLCanvasData, OpaqueStyleAndLayoutData, SVGSVGData};
 use script_layout_interface::{LayoutElementType, LayoutNodeType, TrustedNodeAddress};
 use script_layout_interface::message::Msg;
 use script_traits::UntrustedNodeAddress;
 use selectors::matching::{MatchingReason, matches};
-use selectors::parser::Selector;
-use selectors::parser::parse_author_origin_selector_list_from_str;
+use selectors::parser::SelectorList;
 use servo_url::ServoUrl;
 use std::borrow::ToOwned;
 use std::cell::{Cell, UnsafeCell};
 use std::cmp::max;
 use std::default::Default;
 use std::iter;
 use std::mem;
 use std::ops::Range;
 use std::sync::Arc;
 use style::dom::OpaqueNode;
-use style::selector_parser::ServoSelectorImpl;
+use style::selector_parser::{SelectorImpl, SelectorParser};
 use style::stylesheets::Stylesheet;
 use style::thread_state;
 use uuid::Uuid;
 
 //
 // The basic Node structure
 //
 
@@ -300,35 +299,35 @@ impl Node {
     }
 
     pub fn to_untrusted_node_address(&self) -> UntrustedNodeAddress {
         UntrustedNodeAddress(self.reflector().get_jsobject().get() as *const c_void)
     }
 }
 
 pub struct QuerySelectorIterator {
-    selectors: Vec<Selector<ServoSelectorImpl>>,
+    selectors: SelectorList<SelectorImpl>,
     iterator: TreeIterator,
 }
 
 impl<'a> QuerySelectorIterator {
-     fn new(iter: TreeIterator, selectors: Vec<Selector<ServoSelectorImpl>>)
+     fn new(iter: TreeIterator, selectors: SelectorList<SelectorImpl>)
                   -> QuerySelectorIterator {
         QuerySelectorIterator {
             selectors: selectors,
             iterator: iter,
         }
     }
 }
 
 impl<'a> Iterator for QuerySelectorIterator {
     type Item = Root<Node>;
 
     fn next(&mut self) -> Option<Root<Node>> {
-        let selectors = &self.selectors;
+        let selectors = &self.selectors.0;
         // TODO(cgaebel): Is it worth it to build a bloom filter here
         // (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) {
                     return Some(Root::upcast(element));
                 }
             }
@@ -685,36 +684,36 @@ impl Node {
         let node = try!(doc.node_from_nodes_and_strings(nodes));
         // Step 2.
         self.AppendChild(&node).map(|_| ())
     }
 
     // https://dom.spec.whatwg.org/#dom-parentnode-queryselector
     pub fn query_selector(&self, selectors: DOMString) -> Fallible<Option<Root<Element>>> {
         // Step 1.
-        match parse_author_origin_selector_list_from_str(&selectors) {
+        match SelectorParser::parse_author_origin_no_namespace(&selectors) {
             // Step 2.
             Err(()) => Err(Error::Syntax),
             // Step 3.
-            Ok(ref selectors) => {
+            Ok(selectors) => {
                 Ok(self.traverse_preorder().filter_map(Root::downcast).find(|element| {
-                    matches(selectors, element, None, MatchingReason::Other)
+                    matches(&selectors.0, element, None, MatchingReason::Other)
                 }))
             }
         }
     }
 
     /// https://dom.spec.whatwg.org/#scope-match-a-selectors-string
     /// Get an iterator over all nodes which match a set of selectors
     /// Be careful not to do anything which may manipulate the DOM tree
     /// whilst iterating, otherwise the iterator may be invalidated.
     pub fn query_selector_iter(&self, selectors: DOMString)
                                   -> Fallible<QuerySelectorIterator> {
         // Step 1.
-        match parse_author_origin_selector_list_from_str(&selectors) {
+        match SelectorParser::parse_author_origin_no_namespace(&selectors) {
             // Step 2.
             Err(()) => Err(Error::Syntax),
             // Step 3.
             Ok(selectors) => {
                 let mut descendants = self.traverse_preorder();
                 // Skip the root of the tree.
                 assert!(&*descendants.next().unwrap() == self);
                 Ok(QuerySelectorIterator::new(descendants, selectors))
--- a/servo/components/script/layout_wrapper.rs
+++ b/servo/components/script/layout_wrapper.rs
@@ -61,17 +61,17 @@ use style::atomic_refcell::{AtomicRef, A
 use style::attr::AttrValue;
 use style::computed_values::display;
 use style::context::SharedStyleContext;
 use style::data::ElementData;
 use style::dom::{LayoutIterator, NodeInfo, OpaqueNode, PresentationalHintsSynthetizer, TElement, TNode};
 use style::dom::UnsafeNode;
 use style::element_state::*;
 use style::properties::{ComputedValues, PropertyDeclarationBlock};
-use style::selector_parser::{NonTSPseudoClass, PseudoElement, RestyleDamage, ServoSelectorImpl};
+use style::selector_parser::{NonTSPseudoClass, PseudoElement, RestyleDamage, SelectorImpl};
 use style::sink::Push;
 use style::str::is_whitespace;
 use style::stylist::ApplicableDeclarationBlock;
 
 #[derive(Copy, Clone)]
 pub struct ServoLayoutNode<'a> {
     /// The wrapped node.
     node: LayoutJS<Node>,
@@ -555,19 +555,19 @@ impl<'le> ServoLayoutElement<'le> {
     }
 }
 
 fn as_element<'le>(node: LayoutJS<Node>) -> Option<ServoLayoutElement<'le>> {
     node.downcast().map(ServoLayoutElement::from_layout_js)
 }
 
 impl<'le> ::selectors::MatchAttrGeneric for ServoLayoutElement<'le> {
-    type Impl = ServoSelectorImpl;
+    type Impl = SelectorImpl;
 
-    fn match_attr<F>(&self, attr: &AttrSelector<ServoSelectorImpl>, test: F) -> bool
+    fn match_attr<F>(&self, attr: &AttrSelector<SelectorImpl>, test: F) -> bool
     where F: Fn(&str) -> bool {
         use ::selectors::Element;
         let name = if self.is_html_element_in_html_document() {
             &attr.lower_name
         } else {
             &attr.name
         };
         match attr.namespace {
@@ -1092,19 +1092,19 @@ impl<'le> ThreadSafeLayoutElement for Se
 /// pseudo-elements (like `::-servo-details-content`).
 ///
 /// Probably a few more of this functions can be implemented (like `has_class`,
 /// `each_class`, etc), but they have no use right now.
 ///
 /// Note that the element implementation is needed only for selector matching,
 /// not for inheritance (styles are inherited appropiately).
 impl<'le> ::selectors::MatchAttrGeneric for ServoThreadSafeLayoutElement<'le> {
-    type Impl = ServoSelectorImpl;
+    type Impl = SelectorImpl;
 
-    fn match_attr<F>(&self, attr: &AttrSelector<ServoSelectorImpl>, test: F) -> bool
+    fn match_attr<F>(&self, attr: &AttrSelector<SelectorImpl>, test: F) -> bool
         where F: Fn(&str) -> bool {
         match attr.namespace {
             NamespaceConstraint::Specific(ref ns) => {
                 self.get_attr(&ns.url, &attr.name).map_or(false, |attr| test(attr))
             },
             NamespaceConstraint::Any => {
                 unsafe {
                     (*self.element.element.unsafe_get()).get_attr_vals_for_layout(&attr.name).iter()
--- a/servo/components/script_layout_interface/Cargo.toml
+++ b/servo/components/script_layout_interface/Cargo.toml
@@ -23,12 +23,12 @@ ipc-channel = "0.5"
 libc = "0.2"
 log = "0.3.5"
 msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
 plugins = {path = "../plugins"}
 profile_traits = {path = "../profile_traits"}
 range = {path = "../range"}
 script_traits = {path = "../script_traits"}
-selectors = "0.14"
+selectors = "0.15"
 servo_atoms = {path = "../atoms"}
 servo_url = {path = "../url"}
 style = {path = "../style"}
--- a/servo/components/script_layout_interface/wrapper_traits.rs
+++ b/servo/components/script_layout_interface/wrapper_traits.rs
@@ -17,17 +17,17 @@ use std::fmt::Debug;
 use std::sync::Arc;
 use style::atomic_refcell::AtomicRefCell;
 use style::computed_values::display;
 use style::context::SharedStyleContext;
 use style::data::ElementData;
 use style::dom::{LayoutIterator, NodeInfo, PresentationalHintsSynthetizer, TNode};
 use style::dom::OpaqueNode;
 use style::properties::ServoComputedValues;
-use style::selector_parser::{PseudoElement, PseudoElementCascadeType, RestyleDamage, ServoSelectorImpl};
+use style::selector_parser::{PseudoElement, PseudoElementCascadeType, RestyleDamage, SelectorImpl};
 
 #[derive(Copy, PartialEq, Clone, Debug)]
 pub enum PseudoElementType<T> {
     Normal,
     Before(T),
     After(T),
     DetailsSummary(T),
     DetailsContent(T),
@@ -142,17 +142,17 @@ impl<ConcreteNode> Iterator for TreeIter
 }
 
 
 /// A thread-safe version of `LayoutNode`, used during flow construction. This type of layout
 /// node does not allow any parents or siblings of nodes to be accessed, to avoid races.
 pub trait ThreadSafeLayoutNode: Clone + Copy + GetLayoutData + NodeInfo + PartialEq + Sized {
     type ConcreteThreadSafeLayoutElement:
         ThreadSafeLayoutElement<ConcreteThreadSafeLayoutNode = Self>
-        + ::selectors::Element<Impl=ServoSelectorImpl>;
+        + ::selectors::Element<Impl=SelectorImpl>;
     type ChildrenIterator: Iterator<Item = Self> + Sized;
 
     /// Converts self into an `OpaqueNode`.
     fn opaque(&self) -> OpaqueNode;
 
     /// Returns the type ID of this node.
     /// Returns `None` if this is a pseudo-element; otherwise, returns `Some`.
     fn type_id(&self) -> Option<LayoutNodeType>;
@@ -266,17 +266,17 @@ pub trait ThreadSafeLayoutNode: Clone + 
 // It can be used to violate thread-safety, so don't use it elsewhere in layout!
 #[allow(unsafe_code)]
 pub trait DangerousThreadSafeLayoutNode: ThreadSafeLayoutNode {
     unsafe fn dangerous_first_child(&self) -> Option<Self>;
     unsafe fn dangerous_next_sibling(&self) -> Option<Self>;
 }
 
 pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug +
-                                   ::selectors::Element<Impl=ServoSelectorImpl> +
+                                   ::selectors::Element<Impl=SelectorImpl> +
                                    GetLayoutData +
                                    PresentationalHintsSynthetizer {
     type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<ConcreteThreadSafeLayoutElement = Self>;
 
     fn as_node(&self) -> Self::ConcreteThreadSafeLayoutNode;
 
     /// Creates a new `ThreadSafeLayoutElement` for the same `LayoutElement`
     /// with a different pseudo-element type.
--- a/servo/components/style/Cargo.toml
+++ b/servo/components/style/Cargo.toml
@@ -39,17 +39,17 @@ num-integer = "0.1.32"
 num-traits = "0.1.32"
 ordered-float = "0.2.2"
 owning_ref = "0.2.2"
 parking_lot = "0.3.3"
 quickersort = "2.0.0"
 rand = "0.3"
 rayon = "0.5"
 rustc-serialize = "0.3"
-selectors = "0.14"
+selectors = "0.15"
 serde = {version = "0.8", optional = true}
 serde_derive = {version = "0.8", optional = true}
 servo_atoms = {path = "../atoms", optional = true}
 smallvec = "0.1"
 style_traits = {path = "../style_traits"}
 servo_url = {path = "../url"}
 time = "0.1"
 unicode-segmentation = "0.1.2"
--- a/servo/components/style/gecko/selector_parser.rs
+++ b/servo/components/style/gecko/selector_parser.rs
@@ -1,23 +1,21 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use cssparser::ToCss;
 use element_state::ElementState;
+use selector_parser::{SelectorParser, PseudoElementCascadeType};
 use selector_parser::{attr_equals_selector_is_shareable, attr_exists_selector_is_shareable};
-use selector_parser::PseudoElementCascadeType;
-use selectors::parser::{AttrSelector, ParserContext, SelectorImpl};
+use selectors::parser::AttrSelector;
+use std::borrow::Cow;
 use std::fmt;
 use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
 
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct GeckoSelectorImpl;
-
 /// NOTE: The boolean field represents whether this element is an anonymous box.
 ///
 /// This is just for convenience, instead of recomputing it. Also, note that
 /// Atom is always a static atom, so if space is a concern, we can use the
 /// raw pointer and use the lower bit to represent it without space overhead.
 ///
 /// FIXME(emilio): we know all these atoms are static. Patches are starting to
 /// pile up, but a further potential optimisation is generating bindings without
@@ -156,17 +154,20 @@ impl NonTSPseudoClass {
 
             AnyLink |
             Link |
             Visited => ElementState::empty(),
         }
     }
 }
 
-impl SelectorImpl for GeckoSelectorImpl {
+#[derive(Clone, Debug, PartialEq)]
+pub struct SelectorImpl;
+
+impl ::selectors::SelectorImpl for SelectorImpl {
     type AttrValue = Atom;
     type Identifier = Atom;
     type ClassName = Atom;
     type LocalName = Atom;
     type NamespacePrefix = Atom;
     type NamespaceUrl = Namespace;
     type BorrowedNamespaceUrl = WeakNamespace;
     type BorrowedLocalName = WeakAtom;
@@ -177,21 +178,24 @@ impl SelectorImpl for GeckoSelectorImpl 
     fn attr_exists_selector_is_shareable(attr_selector: &AttrSelector<Self>) -> bool {
         attr_exists_selector_is_shareable(attr_selector)
     }
 
     fn attr_equals_selector_is_shareable(attr_selector: &AttrSelector<Self>,
                                          value: &Self::AttrValue) -> bool {
         attr_equals_selector_is_shareable(attr_selector, value)
     }
+}
 
-    fn parse_non_ts_pseudo_class(_context: &ParserContext<Self>,
-                                 name: &str) -> Result<NonTSPseudoClass, ()> {
+impl<'a> ::selectors::Parser for SelectorParser<'a> {
+    type Impl = SelectorImpl;
+
+    fn parse_non_ts_pseudo_class(&self, name: Cow<str>) -> Result<NonTSPseudoClass, ()> {
         use self::NonTSPseudoClass::*;
-        let pseudo_class = match_ignore_ascii_case! { name,
+        let pseudo_class = match_ignore_ascii_case! { &name,
             "any-link" => AnyLink,
             "link" => Link,
             "visited" => Visited,
             "active" => Active,
             "focus" => Focus,
             "hover" => Hover,
             "enabled" => Enabled,
             "disabled" => Disabled,
@@ -200,26 +204,33 @@ impl SelectorImpl for GeckoSelectorImpl 
             "read-write" => ReadWrite,
             "read-only" => ReadOnly,
             _ => return Err(())
         };
 
         Ok(pseudo_class)
     }
 
-    fn parse_pseudo_element(context: &ParserContext<Self>,
-                            name: &str) -> Result<PseudoElement, ()> {
-        match PseudoElement::from_slice(name, context.in_user_agent_stylesheet) {
+    fn parse_pseudo_element(&self, name: Cow<str>) -> Result<PseudoElement, ()> {
+        match PseudoElement::from_slice(&name, self.in_user_agent_stylesheet()) {
             Some(pseudo) => Ok(pseudo),
             None => Err(()),
         }
     }
+
+    fn default_namespace(&self) -> Option<Namespace> {
+        self.namespaces.default.clone()
+    }
+
+    fn namespace_for_prefix(&self, prefix: &Atom) -> Option<Namespace> {
+        self.namespaces.prefixes.get(prefix).cloned()
+    }
 }
 
-impl GeckoSelectorImpl {
+impl SelectorImpl {
     #[inline]
     pub fn pseudo_element_cascade_type(pseudo: &PseudoElement) -> PseudoElementCascadeType {
         if Self::pseudo_is_before_or_after(pseudo) {
             return PseudoElementCascadeType::Eager
         }
 
         if pseudo.is_anon_box() {
             return PseudoElementCascadeType::Precomputed
--- a/servo/components/style/gecko/snapshot.rs
+++ b/servo/components/style/gecko/snapshot.rs
@@ -4,17 +4,17 @@
 
 use element_state::ElementState;
 use gecko::snapshot_helpers;
 use gecko::wrapper::AttrSelectorHelpers;
 use gecko_bindings::bindings;
 use gecko_bindings::structs::ServoElementSnapshot;
 use gecko_bindings::structs::ServoElementSnapshotFlags as Flags;
 use restyle_hints::ElementSnapshot;
-use selector_parser::TheSelectorImpl;
+use selector_parser::SelectorImpl;
 use selectors::parser::AttrSelector;
 use string_cache::Atom;
 
 // NB: This is sound, in some sense, because during computation of restyle hints
 // the snapshot is kept alive by the modified elements table.
 #[derive(Debug)]
 pub struct GeckoElementSnapshot(*mut ServoElementSnapshot);
 
@@ -31,78 +31,78 @@ impl GeckoElementSnapshot {
 
     #[inline]
     fn has_any(&self, flags: Flags) -> bool {
         unsafe { ((*self.0).mContains as u8 & flags as u8) != 0 }
     }
 }
 
 impl ::selectors::MatchAttr for GeckoElementSnapshot {
-    type Impl = TheSelectorImpl;
+    type Impl = SelectorImpl;
 
-    fn match_attr_has(&self, attr: &AttrSelector<TheSelectorImpl>) -> bool {
+    fn match_attr_has(&self, attr: &AttrSelector<SelectorImpl>) -> bool {
         unsafe {
             bindings::Gecko_SnapshotHasAttr(self.0,
                                             attr.ns_or_null(),
                                             attr.select_name(self.is_html_element_in_html_document()))
         }
     }
 
-    fn match_attr_equals(&self, attr: &AttrSelector<TheSelectorImpl>, value: &Atom) -> bool {
+    fn match_attr_equals(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
         unsafe {
             bindings::Gecko_SnapshotAttrEquals(self.0,
                                                attr.ns_or_null(),
                                                attr.select_name(self.is_html_element_in_html_document()),
                                                value.as_ptr(),
                                                /* ignoreCase = */ false)
         }
     }
 
-    fn match_attr_equals_ignore_ascii_case(&self, attr: &AttrSelector<TheSelectorImpl>, value: &Atom) -> bool {
+    fn match_attr_equals_ignore_ascii_case(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
         unsafe {
             bindings::Gecko_SnapshotAttrEquals(self.0,
                                                attr.ns_or_null(),
                                                attr.select_name(self.is_html_element_in_html_document()),
                                                value.as_ptr(),
                                                /* ignoreCase = */ true)
         }
     }
-    fn match_attr_includes(&self, attr: &AttrSelector<TheSelectorImpl>, value: &Atom) -> bool {
+    fn match_attr_includes(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
         unsafe {
             bindings::Gecko_SnapshotAttrIncludes(self.0,
                                                  attr.ns_or_null(),
                                                  attr.select_name(self.is_html_element_in_html_document()),
                                                  value.as_ptr())
         }
     }
-    fn match_attr_dash(&self, attr: &AttrSelector<TheSelectorImpl>, value: &Atom) -> bool {
+    fn match_attr_dash(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
         unsafe {
             bindings::Gecko_SnapshotAttrDashEquals(self.0,
                                                    attr.ns_or_null(),
                                                    attr.select_name(self.is_html_element_in_html_document()),
                                                    value.as_ptr())
         }
     }
-    fn match_attr_prefix(&self, attr: &AttrSelector<TheSelectorImpl>, value: &Atom) -> bool {
+    fn match_attr_prefix(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
         unsafe {
             bindings::Gecko_SnapshotAttrHasPrefix(self.0,
                                                   attr.ns_or_null(),
                                                   attr.select_name(self.is_html_element_in_html_document()),
                                                   value.as_ptr())
         }
     }
-    fn match_attr_substring(&self, attr: &AttrSelector<TheSelectorImpl>, value: &Atom) -> bool {
+    fn match_attr_substring(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
         unsafe {
             bindings::Gecko_SnapshotAttrHasSubstring(self.0,
                                                      attr.ns_or_null(),
                                                      attr.select_name(self.is_html_element_in_html_document()),
                                                      value.as_ptr())
         }
     }
-    fn match_attr_suffix(&self, attr: &AttrSelector<TheSelectorImpl>, value: &Atom) -> bool {
+    fn match_attr_suffix(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
         unsafe {
             bindings::Gecko_SnapshotAttrHasSuffix(self.0,
                                                   attr.ns_or_null(),
                                                   attr.select_name(self.is_html_element_in_html_document()),
                                                   value.as_ptr())
         }
     }
 }
--- a/servo/components/style/gecko/wrapper.rs
+++ b/servo/components/style/gecko/wrapper.rs
@@ -7,17 +7,17 @@
 
 use atomic_refcell::{AtomicRef, AtomicRefCell};
 use data::ElementData;
 use dom::{LayoutIterator, NodeInfo, TElement, TNode, UnsafeNode};
 use dom::{OpaqueNode, PresentationalHintsSynthetizer};
 use element_state::ElementState;
 use error_reporting::StdoutErrorReporter;
 use gecko::restyle_damage::GeckoRestyleDamage;
-use gecko::selector_parser::{GeckoSelectorImpl, NonTSPseudoClass, PseudoElement};
+use gecko::selector_parser::{SelectorImpl, NonTSPseudoClass, PseudoElement};
 use gecko::snapshot_helpers;
 use gecko_bindings::bindings;
 use gecko_bindings::bindings::{Gecko_DropStyleChildrenIterator, Gecko_MaybeCreateStyleChildrenIterator};
 use gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetLastChild, Gecko_GetNextStyleChild};
 use gecko_bindings::bindings::{Gecko_GetServoDeclarationBlock, Gecko_IsHTMLElementInHTMLDocument};
 use gecko_bindings::bindings::{Gecko_IsLink, Gecko_IsRootElement};
 use gecko_bindings::bindings::{Gecko_IsUnvisitedLink, Gecko_IsVisitedLink, Gecko_Namespace};
 use gecko_bindings::bindings::{RawGeckoElement, RawGeckoNode};
@@ -527,17 +527,17 @@ impl<'le> ::selectors::Element for Gecko
     }
 }
 
 pub trait AttrSelectorHelpers {
     fn ns_or_null(&self) -> *mut nsIAtom;
     fn select_name(&self, is_html_element_in_html_document: bool) -> *mut nsIAtom;
 }
 
-impl AttrSelectorHelpers for AttrSelector<GeckoSelectorImpl> {
+impl AttrSelectorHelpers for AttrSelector<SelectorImpl> {
     fn ns_or_null(&self) -> *mut nsIAtom {
         match self.namespace {
             NamespaceConstraint::Any => ptr::null_mut(),
             NamespaceConstraint::Specific(ref ns) => ns.url.0.as_ptr(),
         }
     }
 
     fn select_name(&self, is_html_element_in_html_document: bool) -> *mut nsIAtom {
@@ -545,17 +545,17 @@ impl AttrSelectorHelpers for AttrSelecto
             self.lower_name.as_ptr()
         } else {
             self.name.as_ptr()
         }
     }
 }
 
 impl<'le> ::selectors::MatchAttr for GeckoElement<'le> {
-    type Impl = GeckoSelectorImpl;
+    type Impl = SelectorImpl;
 
     fn match_attr_has(&self, attr: &AttrSelector<Self::Impl>) -> bool {
         unsafe {
             bindings::Gecko_HasAttr(self.0,
                                     attr.ns_or_null(),
                                     attr.select_name(self.is_html_element_in_html_document()))
         }
     }
--- a/servo/components/style/matching.rs
+++ b/servo/components/style/matching.rs
@@ -12,17 +12,17 @@ use atomic_refcell::AtomicRefMut;
 use cache::LRUCache;
 use cascade_info::CascadeInfo;
 use context::{SharedStyleContext, StyleContext};
 use data::{ElementData, ElementStyles, PseudoStyles};
 use dom::{TElement, TNode, TRestyleDamage, UnsafeNode};
 use properties::{CascadeFlags, ComputedValues, SHAREABLE, cascade};
 use properties::longhands::display::computed_value as display;
 use rule_tree::StrongRuleNode;
-use selector_parser::{PseudoElement, RestyleDamage, TheSelectorImpl};
+use selector_parser::{PseudoElement, RestyleDamage, SelectorImpl};
 use selectors::MatchAttr;
 use selectors::bloom::BloomFilter;
 use selectors::matching::{AFFECTED_BY_PSEUDO_ELEMENTS, MatchingReason, StyleRelations};
 use sink::ForgetfulSink;
 use std::collections::HashMap;
 use std::hash::BuildHasherDefault;
 use std::mem;
 use std::slice::IterMut;
@@ -530,17 +530,17 @@ pub trait MatchMethods : TElement {
                                                  style_attribute,
                                                  None,
                                                  &mut applicable_declarations,
                                                  MatchingReason::ForStyling);
         let primary_rule_node = compute_rule_node(context, &mut applicable_declarations);
 
         // Compute the pseudo rule nodes.
         let mut per_pseudo: PseudoRuleNodes = HashMap::with_hasher(Default::default());
-        TheSelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| {
+        SelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| {
             debug_assert!(applicable_declarations.is_empty());
             stylist.push_applicable_declarations(self, parent_bf, None,
                                                  Some(&pseudo.clone()),
                                                  &mut applicable_declarations,
                                                  MatchingReason::ForStyling);
 
             if !applicable_declarations.is_empty() {
                 let rule_node = compute_rule_node(context, &mut applicable_declarations);
--- a/servo/components/style/parser.rs
+++ b/servo/components/style/parser.rs
@@ -3,18 +3,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! The context within which CSS code is parsed.
 
 use cssparser::{Parser, SourcePosition};
 use error_reporting::ParseErrorReporter;
 #[cfg(feature = "gecko")]
 use gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI};
-use selector_parser::TheSelectorImpl;
-use selectors::parser::ParserContext as SelectorParserContext;
 use servo_url::ServoUrl;
 use stylesheets::Origin;
 
 #[cfg(not(feature = "gecko"))]
 pub struct ParserContextExtraData;
 
 #[cfg(feature = "gecko")]
 pub struct ParserContextExtraData {
@@ -33,32 +31,28 @@ impl ParserContextExtraData {
     pub fn default() -> ParserContextExtraData {
         ParserContextExtraData { base: None, referrer: None, principal: None }
     }
 }
 
 pub struct ParserContext<'a> {
     pub stylesheet_origin: Origin,
     pub base_url: &'a ServoUrl,
-    pub selector_context: SelectorParserContext<TheSelectorImpl>,
     pub error_reporter: Box<ParseErrorReporter + Send>,
     pub extra_data: ParserContextExtraData,
 }
 
 impl<'a> ParserContext<'a> {
     pub fn new_with_extra_data(stylesheet_origin: Origin, base_url: &'a ServoUrl,
                                error_reporter: Box<ParseErrorReporter + Send>,
                                extra_data: ParserContextExtraData)
                                -> ParserContext<'a> {
-        let mut selector_context = SelectorParserContext::new();
-        selector_context.in_user_agent_stylesheet = stylesheet_origin == Origin::UserAgent;
         ParserContext {
             stylesheet_origin: stylesheet_origin,
             base_url: base_url,
-            selector_context: selector_context,
             error_reporter: error_reporter,
             extra_data: extra_data,
         }
     }
 
     pub fn new(stylesheet_origin: Origin, base_url: &'a ServoUrl, error_reporter: Box<ParseErrorReporter + Send>)
                -> ParserContext<'a> {
         let extra_data = ParserContextExtraData::default();
--- a/servo/components/style/restyle_hints.rs
+++ b/servo/components/style/restyle_hints.rs
@@ -3,21 +3,21 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Restyle hints: an optimization to avoid unnecessarily matching selectors.
 
 use Atom;
 use element_state::*;
 #[cfg(feature = "servo")]
 use heapsize::HeapSizeOf;
-use selector_parser::{AttrValue, ElementExt, NonTSPseudoClass, Snapshot, TheSelectorImpl};
+use selector_parser::{AttrValue, ElementExt, NonTSPseudoClass, Snapshot, SelectorImpl};
 use selectors::{Element, MatchAttr};
 use selectors::matching::{MatchingReason, StyleRelations};
 use selectors::matching::matches_complex_selector;
-use selectors::parser::{AttrSelector, Combinator, ComplexSelector, SelectorImpl, SimpleSelector};
+use selectors::parser::{AttrSelector, Combinator, ComplexSelector, SimpleSelector};
 use std::clone::Clone;
 use std::sync::Arc;
 
 /// When the ElementState of an element (like IN_HOVER_STATE) changes, certain
 /// pseudo-classes (like :hover) may require us to restyle that element, its
 /// siblings, and/or its descendants. Similarly, when various attributes of an
 /// element change, we may also need to restyle things with id, class, and
 /// attribute selectors. Doing this conservatively is expensive, and so we use
@@ -55,17 +55,17 @@ impl HeapSizeOf for RestyleHint {
 /// Gecko does this differently for element states, and passes a mask called
 /// mStateMask, which indicates the states that need to be ignored during
 /// selector matching. This saves an ElementWrapper allocation and an additional
 /// selector match call at the expense of additional complexity inside the
 /// selector matching logic. This only works for boolean states though, so we
 /// still need to take the ElementWrapper approach for attribute-dependent
 /// style. So we do it the same both ways for now to reduce complexity, but it's
 /// worth measuring the performance impact (if any) of the mStateMask approach.
-pub trait ElementSnapshot : Sized + MatchAttr<Impl=TheSelectorImpl> {
+pub trait ElementSnapshot : Sized + MatchAttr<Impl=SelectorImpl> {
     /// The state of the snapshot, if any.
     fn state(&self) -> Option<ElementState>;
 
     /// If this snapshot contains attribute information.
     fn has_attrs(&self) -> bool;
 
     /// The ID attribute per this snapshot. Should only be called if
     /// `has_attrs()` returns true.
@@ -98,102 +98,102 @@ impl<'a, E> ElementWrapper<'a, E>
     pub fn new_with_snapshot(el: E, snapshot: &'a Snapshot) -> ElementWrapper<'a, E> {
         ElementWrapper { element: el, snapshot: Some(snapshot) }
     }
 }
 
 impl<'a, E> MatchAttr for ElementWrapper<'a, E>
     where E: ElementExt,
 {
-    type Impl = TheSelectorImpl;
+    type Impl = SelectorImpl;
 
-    fn match_attr_has(&self, attr: &AttrSelector<TheSelectorImpl>) -> bool {
+    fn match_attr_has(&self, attr: &AttrSelector<SelectorImpl>) -> bool {
         match self.snapshot {
             Some(snapshot) if snapshot.has_attrs()
                 => snapshot.match_attr_has(attr),
             _   => self.element.match_attr_has(attr)
         }
     }
 
     fn match_attr_equals(&self,
-                         attr: &AttrSelector<TheSelectorImpl>,
+                         attr: &AttrSelector<SelectorImpl>,
                          value: &AttrValue) -> bool {
         match self.snapshot {
             Some(snapshot) if snapshot.has_attrs()
                 => snapshot.match_attr_equals(attr, value),
             _   => self.element.match_attr_equals(attr, value)
         }
     }
 
     fn match_attr_equals_ignore_ascii_case(&self,
-                                           attr: &AttrSelector<TheSelectorImpl>,
+                                           attr: &AttrSelector<SelectorImpl>,
                                            value: &AttrValue) -> bool {
         match self.snapshot {
             Some(snapshot) if snapshot.has_attrs()
                 => snapshot.match_attr_equals_ignore_ascii_case(attr, value),
             _   => self.element.match_attr_equals_ignore_ascii_case(attr, value)
         }
     }
 
     fn match_attr_includes(&self,
-                           attr: &AttrSelector<TheSelectorImpl>,
+                           attr: &AttrSelector<SelectorImpl>,
                            value: &AttrValue) -> bool {
         match self.snapshot {
             Some(snapshot) if snapshot.has_attrs()
                 => snapshot.match_attr_includes(attr, value),
             _   => self.element.match_attr_includes(attr, value)
         }
     }
 
     fn match_attr_dash(&self,
-                       attr: &AttrSelector<TheSelectorImpl>,
+                       attr: &AttrSelector<SelectorImpl>,
                        value: &AttrValue) -> bool {
         match self.snapshot {
             Some(snapshot) if snapshot.has_attrs()
                 => snapshot.match_attr_dash(attr, value),
             _   => self.element.match_attr_dash(attr, value)
         }
     }
 
     fn match_attr_prefix(&self,
-                         attr: &AttrSelector<TheSelectorImpl>,
+                         attr: &AttrSelector<SelectorImpl>,
                          value: &AttrValue) -> bool {
         match self.snapshot {
             Some(snapshot) if snapshot.has_attrs()
                 => snapshot.match_attr_prefix(attr, value),
             _   => self.element.match_attr_prefix(attr, value)
         }
     }
 
     fn match_attr_substring(&self,
-                            attr: &AttrSelector<TheSelectorImpl>,
+                            attr: &AttrSelector<SelectorImpl>,
                             value: &AttrValue) -> bool {
         match self.snapshot {
             Some(snapshot) if snapshot.has_attrs()
                 => snapshot.match_attr_substring(attr, value),
             _   => self.element.match_attr_substring(attr, value)
         }
     }
 
     fn match_attr_suffix(&self,
-                         attr: &AttrSelector<TheSelectorImpl>,
+                         attr: &AttrSelector<SelectorImpl>,
                          value: &AttrValue) -> bool {
         match self.snapshot {
             Some(snapshot) if snapshot.has_attrs()
                 => snapshot.match_attr_suffix(attr, value),
             _   => self.element.match_attr_suffix(attr, value)
         }
     }
 }
 
 impl<'a, E> Element for ElementWrapper<'a, E>
-    where E: ElementExt<Impl=TheSelectorImpl>
+    where E: ElementExt<Impl=SelectorImpl>
 {
     fn match_non_ts_pseudo_class(&self, pseudo_class: NonTSPseudoClass) -> bool {
-        let flag = TheSelectorImpl::pseudo_class_state_flag(&pseudo_class);
+        let flag = SelectorImpl::pseudo_class_state_flag(&pseudo_class);
         if flag == ElementState::empty() {
             self.element.match_non_ts_pseudo_class(pseudo_class)
         } else {
             match self.snapshot.and_then(|s| s.state()) {
                 Some(snapshot_state) => snapshot_state.contains(flag),
                 _   => self.element.match_non_ts_pseudo_class(pseudo_class)
             }
         }
@@ -218,21 +218,21 @@ impl<'a, E> Element for ElementWrapper<'
     fn next_sibling_element(&self) -> Option<Self> {
         self.element.next_sibling_element().map(ElementWrapper::new)
     }
 
     fn is_html_element_in_html_document(&self) -> bool {
         self.element.is_html_element_in_html_document()
     }
 
-    fn get_local_name(&self) -> &<Self::Impl as SelectorImpl>::BorrowedLocalName {
+    fn get_local_name(&self) -> &<Self::Impl as ::selectors::SelectorImpl>::BorrowedLocalName {
         self.element.get_local_name()
     }
 
-    fn get_namespace(&self) -> &<Self::Impl as SelectorImpl>::BorrowedNamespaceUrl {
+    fn get_namespace(&self) -> &<Self::Impl as ::selectors::SelectorImpl>::BorrowedNamespaceUrl {
         self.element.get_namespace()
     }
 
     fn get_id(&self) -> Option<Atom> {
         match self.snapshot {
             Some(snapshot) if snapshot.has_attrs()
                 => snapshot.id_attr(),
             _   => self.element.get_id()
@@ -260,24 +260,24 @@ impl<'a, E> Element for ElementWrapper<'
         match self.snapshot {
             Some(snapshot) if snapshot.has_attrs()
                 => snapshot.each_class(callback),
             _   => self.element.each_class(callback)
         }
     }
 }
 
-fn selector_to_state(sel: &SimpleSelector<TheSelectorImpl>) -> ElementState {
+fn selector_to_state(sel: &SimpleSelector<SelectorImpl>) -> ElementState {
     match *sel {
-        SimpleSelector::NonTSPseudoClass(ref pc) => TheSelectorImpl::pseudo_class_state_flag(pc),
+        SimpleSelector::NonTSPseudoClass(ref pc) => SelectorImpl::pseudo_class_state_flag(pc),
         _ => ElementState::empty(),
     }
 }
 
-fn is_attr_selector(sel: &SimpleSelector<TheSelectorImpl>) -> bool {
+fn is_attr_selector(sel: &SimpleSelector<SelectorImpl>) -> bool {
     match *sel {
         SimpleSelector::ID(_) |
         SimpleSelector::Class(_) |
         SimpleSelector::AttrExists(_) |
         SimpleSelector::AttrEqual(_, _, _) |
         SimpleSelector::AttrIncludes(_, _) |
         SimpleSelector::AttrDashMatch(_, _) |
         SimpleSelector::AttrPrefixMatch(_, _) |
@@ -336,17 +336,17 @@ impl Sensitivities {
 /// even though those selectors may not appear on their own in any stylesheet.
 /// This allows us to quickly scan through the dependency sites of all style
 /// rules and determine the maximum effect that a given state or attribute
 /// change may have on the style of elements in the document.
 #[derive(Debug)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 struct Dependency {
     #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
-    selector: Arc<ComplexSelector<TheSelectorImpl>>,
+    selector: Arc<ComplexSelector<SelectorImpl>>,
     hint: RestyleHint,
     sensitivities: Sensitivities,
 }
 
 /// A set of dependencies for a given stylist.
 ///
 /// Note that there are measurable perf wins from storing them separately
 /// depending on what kind of change they affect, and its also not a big deal to
@@ -383,17 +383,17 @@ impl DependencySet {
             common_deps: vec![],
         }
     }
 
     pub fn len(&self) -> usize {
         self.common_deps.len() + self.attr_deps.len() + self.state_deps.len()
     }
 
-    pub fn note_selector(&mut self, selector: &Arc<ComplexSelector<TheSelectorImpl>>) {
+    pub fn note_selector(&mut self, selector: &Arc<ComplexSelector<SelectorImpl>>) {
         let mut cur = selector;
         let mut combinator: Option<Combinator> = None;
         loop {
             let mut sensitivities = Sensitivities::new();
             for s in &cur.compound_selector {
                 sensitivities.states.insert(selector_to_state(s));
                 if !sensitivities.attrs {
                     sensitivities.attrs = is_attr_selector(s);
--- a/servo/components/style/selector_parser.rs
+++ b/servo/components/style/selector_parser.rs
@@ -1,44 +1,62 @@
 /* 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/. */
 
 //! The pseudo-classes and pseudo-elements supported by the style system.
 
+use cssparser::Parser as CssParser;
 use matching::{common_style_affecting_attributes, CommonStyleAffectingAttributeMode};
 use selectors::Element;
-use selectors::parser::{AttrSelector, SelectorImpl};
+use selectors::parser::{AttrSelector, SelectorList};
+use stylesheets::{Origin, Namespaces};
 
-pub type AttrValue = <TheSelectorImpl as SelectorImpl>::AttrValue;
+pub type AttrValue = <SelectorImpl as ::selectors::SelectorImpl>::AttrValue;
 
 #[cfg(feature = "servo")]
 pub use servo::selector_parser::*;
 
 #[cfg(feature = "gecko")]
 pub use gecko::selector_parser::*;
 
 #[cfg(feature = "servo")]
-pub use servo::selector_parser::ServoSelectorImpl as TheSelectorImpl;
-
-#[cfg(feature = "gecko")]
-pub use gecko::selector_parser::GeckoSelectorImpl as TheSelectorImpl;
-
-#[cfg(feature = "servo")]
 pub use servo::selector_parser::ServoElementSnapshot as Snapshot;
 
 #[cfg(feature = "gecko")]
 pub use gecko::snapshot::GeckoElementSnapshot as Snapshot;
 
 #[cfg(feature = "servo")]
 pub use servo::restyle_damage::ServoRestyleDamage as RestyleDamage;
 
 #[cfg(feature = "gecko")]
 pub use gecko::restyle_damage::GeckoRestyleDamage as RestyleDamage;
 
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub struct SelectorParser<'a> {
+    pub stylesheet_origin: Origin,
+    pub namespaces: &'a Namespaces,
+}
+
+impl<'a> SelectorParser<'a> {
+    pub fn parse_author_origin_no_namespace(input: &str)
+                                            -> Result<SelectorList<SelectorImpl>, ()> {
+        let namespaces = Namespaces::default();
+        let parser = SelectorParser {
+            stylesheet_origin: Origin::Author,
+            namespaces: &namespaces,
+        };
+        SelectorList::parse(&parser, &mut CssParser::new(input))
+    }
+
+    pub fn in_user_agent_stylesheet(&self) -> bool {
+        matches!(self.stylesheet_origin, Origin::UserAgent)
+    }
+}
+
 /// This function determines if a pseudo-element is eagerly cascaded or not.
 ///
 /// Eagerly cascaded pseudo-elements are "normal" pseudo-elements (i.e.
 /// `::before` and `::after`). They inherit styles normally as another
 /// selector would do, and they're part of the cascade.
 ///
 /// Lazy pseudo-elements are affected by selector matching, but they're only
 /// computed when needed, and not before. They're useful for general
@@ -76,21 +94,21 @@ impl PseudoElementCascadeType {
     }
 
     #[inline]
     pub fn is_precomputed(&self) -> bool {
         *self == PseudoElementCascadeType::Precomputed
     }
 }
 
-pub trait ElementExt: Element<Impl=TheSelectorImpl> {
+pub trait ElementExt: Element<Impl=SelectorImpl> {
     fn is_link(&self) -> bool;
 }
 
-impl TheSelectorImpl {
+impl SelectorImpl {
     #[inline]
     pub fn each_eagerly_cascaded_pseudo_element<F>(mut fun: F)
         where F: FnMut(PseudoElement)
     {
         Self::each_pseudo_element(|pseudo| {
             if Self::pseudo_element_cascade_type(&pseudo).is_eager() {
                 fun(pseudo)
             }
@@ -104,28 +122,28 @@ impl TheSelectorImpl {
         Self::each_pseudo_element(|pseudo| {
             if Self::pseudo_element_cascade_type(&pseudo).is_precomputed() {
                 fun(pseudo)
             }
         })
     }
 }
 
-pub fn attr_exists_selector_is_shareable(attr_selector: &AttrSelector<TheSelectorImpl>) -> bool {
+pub fn attr_exists_selector_is_shareable(attr_selector: &AttrSelector<SelectorImpl>) -> bool {
     // NB(pcwalton): If you update this, remember to update the corresponding list in
     // `can_share_style_with()` as well.
     common_style_affecting_attributes().iter().any(|common_attr_info| {
         common_attr_info.attr_name == attr_selector.name && match common_attr_info.mode {
             CommonStyleAffectingAttributeMode::IsPresent(_) => true,
             CommonStyleAffectingAttributeMode::IsEqual(..) => false,
         }
     })
 }
 
-pub fn attr_equals_selector_is_shareable(attr_selector: &AttrSelector<TheSelectorImpl>,
+pub fn attr_equals_selector_is_shareable(attr_selector: &AttrSelector<SelectorImpl>,
                                          value: &AttrValue) -> bool {
     // FIXME(pcwalton): Remove once we start actually supporting RTL text. This is in
     // here because the UA style otherwise disables all style sharing completely.
     // FIXME(SimonSapin): should this be the attribute *name* rather than value?
     atom!("dir") == *value ||
     common_style_affecting_attributes().iter().any(|common_attr_info| {
         common_attr_info.attr_name == attr_selector.name && match common_attr_info.mode {
             CommonStyleAffectingAttributeMode::IsEqual(ref target_value, _) => {
--- a/servo/components/style/servo/selector_parser.rs
+++ b/servo/components/style/servo/selector_parser.rs
@@ -2,20 +2,21 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use {Atom, Prefix, Namespace, LocalName};
 use attr::{AttrIdentifier, AttrValue};
 use cssparser::ToCss;
 use element_state::ElementState;
 use restyle_hints::ElementSnapshot;
-use selector_parser::{ElementExt, PseudoElementCascadeType, TheSelectorImpl};
+use selector_parser::{ElementExt, PseudoElementCascadeType, SelectorParser};
 use selector_parser::{attr_equals_selector_is_shareable, attr_exists_selector_is_shareable};
 use selectors::{Element, MatchAttrGeneric};
-use selectors::parser::{AttrSelector, ParserContext, SelectorImpl};
+use selectors::parser::AttrSelector;
+use std::borrow::Cow;
 use std::fmt;
 
 /// NB: If you add to this list, be sure to update `each_pseudo_element` too.
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 pub enum PseudoElement {
     Before,
     After,
@@ -145,19 +146,19 @@ impl NonTSPseudoClass {
             Visited |
             ServoNonZeroBorder => ElementState::empty(),
         }
     }
 }
 
 #[derive(Clone, Debug, PartialEq)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-pub struct ServoSelectorImpl;
+pub struct SelectorImpl;
 
-impl SelectorImpl for ServoSelectorImpl {
+impl ::selectors::SelectorImpl for SelectorImpl {
     type PseudoElement = PseudoElement;
     type NonTSPseudoClass = NonTSPseudoClass;
 
     type AttrValue = String;
     type Identifier = Atom;
     type ClassName = Atom;
     type LocalName = LocalName;
     type NamespacePrefix = Prefix;
@@ -168,116 +169,126 @@ impl SelectorImpl for ServoSelectorImpl 
     fn attr_exists_selector_is_shareable(attr_selector: &AttrSelector<Self>) -> bool {
         attr_exists_selector_is_shareable(attr_selector)
     }
 
     fn attr_equals_selector_is_shareable(attr_selector: &AttrSelector<Self>,
                                          value: &Self::AttrValue) -> bool {
         attr_equals_selector_is_shareable(attr_selector, value)
     }
+}
 
-    fn parse_non_ts_pseudo_class(context: &ParserContext<TheSelectorImpl>,
-                                 name: &str) -> Result<NonTSPseudoClass, ()> {
+impl<'a> ::selectors::Parser for SelectorParser<'a> {
+    type Impl = SelectorImpl;
+
+    fn parse_non_ts_pseudo_class(&self, name: Cow<str>) -> Result<NonTSPseudoClass, ()> {
         use self::NonTSPseudoClass::*;
-        let pseudo_class = match_ignore_ascii_case! { name,
+        let pseudo_class = match_ignore_ascii_case! { &name,
             "any-link" => AnyLink,
             "link" => Link,
             "visited" => Visited,
             "active" => Active,
             "focus" => Focus,
             "hover" => Hover,
             "enabled" => Enabled,
             "disabled" => Disabled,
             "checked" => Checked,
             "indeterminate" => Indeterminate,
             "read-write" => ReadWrite,
             "read-only" => ReadOnly,
             "placeholder-shown" => PlaceholderShown,
             "target" => Target,
             "-servo-nonzero-border" => {
-                if !context.in_user_agent_stylesheet {
+                if !self.in_user_agent_stylesheet() {
                     return Err(());
                 }
                 ServoNonZeroBorder
             },
             _ => return Err(())
         };
 
         Ok(pseudo_class)
     }
 
-    fn parse_pseudo_element(context: &ParserContext<TheSelectorImpl>,
-                            name: &str) -> Result<PseudoElement, ()> {
+    fn parse_pseudo_element(&self, name: Cow<str>) -> Result<PseudoElement, ()> {
         use self::PseudoElement::*;
-        let pseudo_element = match_ignore_ascii_case! { name,
+        let pseudo_element = match_ignore_ascii_case! { &name,
             "before" => Before,
             "after" => After,
             "selection" => Selection,
             "-servo-details-summary" => {
-                if !context.in_user_agent_stylesheet {
+                if !self.in_user_agent_stylesheet() {
                     return Err(())
                 }
                 DetailsSummary
             },
             "-servo-details-content" => {
-                if !context.in_user_agent_stylesheet {
+                if !self.in_user_agent_stylesheet() {
                     return Err(())
                 }
                 DetailsContent
             },
             "-servo-input-text" => {
-                if !context.in_user_agent_stylesheet {
+                if !self.in_user_agent_stylesheet() {
                     return Err(())
                 }
                 ServoInputText
             },
             "-servo-table-wrapper" => {
-                if !context.in_user_agent_stylesheet {
+                if !self.in_user_agent_stylesheet() {
                     return Err(())
                 }
                 ServoTableWrapper
             },
             "-servo-anonymous-table-wrapper" => {
-                if !context.in_user_agent_stylesheet {
+                if !self.in_user_agent_stylesheet() {
                     return Err(())
                 }
                 ServoAnonymousTableWrapper
             },
             "-servo-anonymous-table" => {
-                if !context.in_user_agent_stylesheet {
+                if !self.in_user_agent_stylesheet() {
                     return Err(())
                 }
                 ServoAnonymousTable
             },
             "-servo-anonymous-table-row" => {
-                if !context.in_user_agent_stylesheet {
+                if !self.in_user_agent_stylesheet() {
                     return Err(())
                 }
                 ServoAnonymousTableRow
             },
             "-servo-anonymous-table-cell" => {
-                if !context.in_user_agent_stylesheet {
+                if !self.in_user_agent_stylesheet() {
                     return Err(())
                 }
                 ServoAnonymousTableCell
             },
             "-servo-anonymous-block" => {
-                if !context.in_user_agent_stylesheet {
+                if !self.in_user_agent_stylesheet() {
                     return Err(())
                 }
                 ServoAnonymousBlock
             },
             _ => return Err(())
         };
 
         Ok(pseudo_element)
     }
+
+    fn default_namespace(&self) -> Option<Namespace> {
+        self.namespaces.default.clone()
+    }
+
+    fn namespace_for_prefix(&self, prefix: &Prefix) -> Option<Namespace> {
+        self.namespaces.prefixes.get(prefix).cloned()
+    }
 }
 
-impl ServoSelectorImpl {
+impl SelectorImpl {
     #[inline]
     pub fn pseudo_element_cascade_type(pseudo: &PseudoElement) -> PseudoElementCascadeType {
         pseudo.cascade_type()
     }
 
     #[inline]
     pub fn each_pseudo_element<F>(mut fun: F)
         where F: FnMut(PseudoElement) {
@@ -363,28 +374,28 @@ impl ElementSnapshot for ServoElementSna
             for class in v.as_tokens() {
                 callback(class);
             }
         }
     }
 }
 
 impl MatchAttrGeneric for ServoElementSnapshot {
-    type Impl = ServoSelectorImpl;
+    type Impl = SelectorImpl;
 
-    fn match_attr<F>(&self, attr: &AttrSelector<ServoSelectorImpl>, test: F) -> bool
+    fn match_attr<F>(&self, attr: &AttrSelector<SelectorImpl>, test: F) -> bool
         where F: Fn(&str) -> bool
     {
         use selectors::parser::NamespaceConstraint;
         let html = self.is_html_element_in_html_document;
         let local_name = if html { &attr.lower_name } else { &attr.name };
         match attr.namespace {
             NamespaceConstraint::Specific(ref ns) => self.get_attr(&ns.url, local_name),
             NamespaceConstraint::Any => self.get_attr_ignore_ns(local_name),
         }.map_or(false, |v| test(v))
     }
 }
 
-impl<E: Element<Impl=TheSelectorImpl>> ElementExt for E {
+impl<E: Element<Impl=SelectorImpl>> ElementExt for E {
     fn is_link(&self) -> bool {
         self.match_non_ts_pseudo_class(NonTSPseudoClass::AnyLink)
     }
 }
--- a/servo/components/style/stylesheets.rs
+++ b/servo/components/style/stylesheets.rs
@@ -11,24 +11,25 @@ use cssparser::ToCss as ParserToCss;
 use encoding::EncodingRef;
 use error_reporting::ParseErrorReporter;
 use font_face::{FontFaceRule, parse_font_face_block};
 use keyframes::{Keyframe, parse_keyframe_list};
 use media_queries::{Device, MediaList, parse_media_query_list};
 use parking_lot::RwLock;
 use parser::{ParserContext, ParserContextExtraData, log_css_error};
 use properties::{PropertyDeclarationBlock, parse_property_declaration_list};
-use selector_parser::TheSelectorImpl;
-use selectors::parser::{Selector, parse_selector_list};
+use selector_parser::{SelectorImpl, SelectorParser};
+use selectors::parser::SelectorList;
 use servo_url::ServoUrl;
 use std::cell::Cell;
 use std::fmt;
 use std::sync::Arc;
 use std::sync::atomic::{AtomicBool, Ordering};
 use style_traits::ToCss;
+use stylist::FnvHashMap;
 use viewport::ViewportRule;
 
 
 /// Each style rule has an origin, which determines where it enters the cascade.
 ///
 /// http://dev.w3.org/csswg/css-cascade/#cascading-origins
 #[derive(Clone, PartialEq, Eq, Copy, Debug)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
@@ -38,16 +39,23 @@ pub enum Origin {
 
     /// http://dev.w3.org/csswg/css-cascade/#cascade-origin-author
     Author,
 
     /// http://dev.w3.org/csswg/css-cascade/#cascade-origin-user
     User,
 }
 
+#[derive(Default)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub struct Namespaces {
+    pub default: Option<Namespace>,
+    pub prefixes: FnvHashMap<Prefix , Namespace>,
+}
+
 #[derive(Debug, Clone)]
 pub struct CssRules(pub Arc<RwLock<Vec<CssRule>>>);
 
 impl From<Vec<CssRule>> for CssRules {
     fn from(other: Vec<CssRule>) -> Self {
         CssRules(Arc::new(RwLock::new(other)))
     }
 }
@@ -183,40 +191,25 @@ impl ToCss for MediaRule {
             try!(rule.to_css(dest));
         }
         dest.write_str(" }")
     }
 }
 
 #[derive(Debug)]
 pub struct StyleRule {
-    pub selectors: Vec<Selector<TheSelectorImpl>>,
+    pub selectors: SelectorList<SelectorImpl>,
     pub block: Arc<RwLock<PropertyDeclarationBlock>>,
 }
 
-impl StyleRule {
-    /// Serialize the group of selectors for this rule.
-    ///
-    /// https://drafts.csswg.org/cssom/#serialize-a-group-of-selectors
-    pub fn selectors_to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
-        let mut iter = self.selectors.iter();
-        try!(iter.next().unwrap().to_css(dest));
-        for selector in iter {
-            try!(write!(dest, ", "));
-            try!(selector.to_css(dest));
-        }
-        Ok(())
-    }
-}
-
 impl ToCss for StyleRule {
     // https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSStyleRule
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
         // Step 1
-        try!(self.selectors_to_css(dest));
+        try!(self.selectors.to_css(dest));
         // Step 2
         try!(dest.write_str(" { "));
         // Step 3
         let declaration_block = self.block.read();
         try!(declaration_block.to_css(dest));
         // Step 4
         if declaration_block.declarations.len() > 0 {
             try!(write!(dest, " "));
@@ -241,17 +234,20 @@ impl Stylesheet {
         let (string, _) = decode_stylesheet_bytes(
             bytes, protocol_encoding_label, environment_encoding);
         Stylesheet::from_str(&string, base_url, origin, media, error_reporter, extra_data)
     }
 
     pub fn from_str(css: &str, base_url: ServoUrl, origin: Origin, media: MediaList,
                     error_reporter: Box<ParseErrorReporter + Send>,
                     extra_data: ParserContextExtraData) -> Stylesheet {
+        let mut namespaces = Namespaces::default();
         let rule_parser = TopLevelRuleParser {
+            stylesheet_origin: origin,
+            namespaces: &mut namespaces,
             context: ParserContext::new_with_extra_data(origin, &base_url, error_reporter.clone(),
                                                         extra_data),
             state: Cell::new(State::Start),
         };
         let mut input = Parser::new(css);
         input.look_for_viewport_percentages();
 
         let mut rules = vec![];
@@ -351,37 +347,31 @@ macro_rules! rule_filter {
 rule_filter! {
     effective_style_rules(Style => StyleRule),
     effective_media_rules(Media => MediaRule),
     effective_font_face_rules(FontFace => FontFaceRule),
     effective_viewport_rules(Viewport => ViewportRule),
     effective_keyframes_rules(Keyframes => KeyframesRule),
 }
 
-fn parse_nested_rules(context: &ParserContext, input: &mut Parser) -> CssRules {
-    let mut iter = RuleListParser::new_for_nested_rule(input,
-                                                       NestedRuleParser { context: context });
-    let mut rules = Vec::new();
-    while let Some(result) = iter.next() {
-        match result {
-            Ok(rule) => rules.push(rule),
-            Err(range) => {
-                let pos = range.start;
-                let message = format!("Unsupported rule: '{}'", iter.input.slice(range));
-                log_css_error(iter.input, pos, &*message, &context);
-            }
+struct TopLevelRuleParser<'a> {
+    stylesheet_origin: Origin,
+    namespaces: &'a mut Namespaces,
+    context: ParserContext<'a>,
+    state: Cell<State>,
+}
+
+impl<'b> TopLevelRuleParser<'b> {
+    fn nested<'a: 'b>(&'a self) -> NestedRuleParser<'a, 'b> {
+        NestedRuleParser {
+            stylesheet_origin: self.stylesheet_origin,
+            context: &self.context,
+            namespaces: self.namespaces,
         }
     }
-    rules.into()
-}
-
-
-struct TopLevelRuleParser<'a> {
-    context: ParserContext<'a>,
-    state: Cell<State>,
 }
 
 #[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
 enum State {
     Start = 1,
     Imports = 2,
     Namespaces = 3,
     Body = 4,
@@ -420,21 +410,20 @@ impl<'a> AtRuleParser for TopLevelRulePa
                 if self.state.get() <= State::Namespaces {
                     self.state.set(State::Namespaces);
 
                     let prefix_result = input.try(|input| input.expect_ident());
                     let url = Namespace::from(try!(input.expect_url_or_string()));
 
                     let opt_prefix = if let Ok(prefix) = prefix_result {
                         let prefix = Prefix::from(prefix);
-                        self.context.selector_context.namespace_prefixes.insert(
-                            prefix.clone(), url.clone());
+                        self.namespaces.prefixes.insert(prefix.clone(), url.clone());
                         Some(prefix)
                     } else {
-                        self.context.selector_context.default_namespace = Some(url.clone());
+                        self.namespaces.default = Some(url.clone());
                         None
                     };
 
                     return Ok(AtRuleType::WithoutBlock(CssRule::Namespace(Arc::new(RwLock::new(
                         NamespaceRule {
                             prefix: opt_prefix,
                             url: url,
                         }
@@ -445,49 +434,67 @@ impl<'a> AtRuleParser for TopLevelRulePa
             },
             // @charset is removed by rust-cssparser if it’s the first rule in the stylesheet
             // anything left is invalid.
             "charset" => return Err(()), // (insert appropriate error message)
             _ => {}
         }
 
         self.state.set(State::Body);
-        AtRuleParser::parse_prelude(&mut NestedRuleParser { context: &self.context }, name, input)
+        AtRuleParser::parse_prelude(&mut self.nested(), name, input)
     }
 
     #[inline]
     fn parse_block(&mut self, prelude: AtRulePrelude, input: &mut Parser) -> Result<CssRule, ()> {
-        AtRuleParser::parse_block(&mut NestedRuleParser { context: &self.context }, prelude, input)
+        AtRuleParser::parse_block(&mut self.nested(), prelude, input)
     }
 }
 
 
 impl<'a> QualifiedRuleParser for TopLevelRuleParser<'a> {
-    type Prelude = Vec<Selector<TheSelectorImpl>>;
+    type Prelude = SelectorList<SelectorImpl>;
     type QualifiedRule = CssRule;
 
     #[inline]
-    fn parse_prelude(&mut self, input: &mut Parser) -> Result<Vec<Selector<TheSelectorImpl>>, ()> {
+    fn parse_prelude(&mut self, input: &mut Parser) -> Result<SelectorList<SelectorImpl>, ()> {
         self.state.set(State::Body);
-        QualifiedRuleParser::parse_prelude(&mut NestedRuleParser { context: &self.context }, input)
+        QualifiedRuleParser::parse_prelude(&mut self.nested(), input)
     }
 
     #[inline]
-    fn parse_block(&mut self, prelude: Vec<Selector<TheSelectorImpl>>, input: &mut Parser)
+    fn parse_block(&mut self, prelude: SelectorList<SelectorImpl>, input: &mut Parser)
                    -> Result<CssRule, ()> {
-        QualifiedRuleParser::parse_block(&mut NestedRuleParser { context: &self.context },
-                                         prelude, input)
+        QualifiedRuleParser::parse_block(&mut self.nested(), prelude, input)
     }
 }
 
-
+#[derive(Clone)]  // shallow, relatively cheap clone
 struct NestedRuleParser<'a, 'b: 'a> {
+    stylesheet_origin: Origin,
     context: &'a ParserContext<'b>,
+    namespaces: &'b Namespaces,
 }
 
+impl<'a, 'b> NestedRuleParser<'a, 'b> {
+    fn parse_nested_rules(&self, input: &mut Parser) -> CssRules {
+        let mut iter = RuleListParser::new_for_nested_rule(input, self.clone());
+        let mut rules = Vec::new();
+        while let Some(result) = iter.next() {
+            match result {
+                Ok(rule) => rules.push(rule),
+                Err(range) => {
+                    let pos = range.start;
+                    let message = format!("Unsupported rule: '{}'", iter.input.slice(range));
+                    log_css_error(iter.input, pos, &*message, self.context);
+                }
+            }
+        }
+        rules.into()
+    }
+}
 
 impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> {
     type Prelude = AtRulePrelude;
     type AtRule = CssRule;
 
     fn parse_prelude(&mut self, name: &str, input: &mut Parser)
                      -> Result<AtRuleType<AtRulePrelude, CssRule>, ()> {
         match_ignore_ascii_case! { name,
@@ -523,17 +530,17 @@ impl<'a, 'b> AtRuleParser for NestedRule
         match prelude {
             AtRulePrelude::FontFace => {
                 Ok(CssRule::FontFace(Arc::new(RwLock::new(
                     try!(parse_font_face_block(self.context, input))))))
             }
             AtRulePrelude::Media(media_queries) => {
                 Ok(CssRule::Media(Arc::new(RwLock::new(MediaRule {
                     media_queries: media_queries,
-                    rules: parse_nested_rules(self.context, input),
+                    rules: self.parse_nested_rules(input),
                 }))))
             }
             AtRulePrelude::Viewport => {
                 Ok(CssRule::Viewport(Arc::new(RwLock::new(
                     try!(ViewportRule::parse(input, self.context))))))
             }
             AtRulePrelude::Keyframes(name) => {
                 Ok(CssRule::Keyframes(Arc::new(RwLock::new(KeyframesRule {
@@ -541,23 +548,27 @@ impl<'a, 'b> AtRuleParser for NestedRule
                     keyframes: parse_keyframe_list(&self.context, input),
                 }))))
             }
         }
     }
 }
 
 impl<'a, 'b> QualifiedRuleParser for NestedRuleParser<'a, 'b> {
-    type Prelude = Vec<Selector<TheSelectorImpl>>;
+    type Prelude = SelectorList<SelectorImpl>;
     type QualifiedRule = CssRule;
 
-    fn parse_prelude(&mut self, input: &mut Parser) -> Result<Vec<Selector<TheSelectorImpl>>, ()> {
-        parse_selector_list(&self.context.selector_context, input)
+    fn parse_prelude(&mut self, input: &mut Parser) -> Result<SelectorList<SelectorImpl>, ()> {
+        let selector_parser = SelectorParser {
+            stylesheet_origin: self.stylesheet_origin,
+            namespaces: self.namespaces,
+        };
+        SelectorList::parse(&selector_parser, input)
     }
 
-    fn parse_block(&mut self, prelude: Vec<Selector<TheSelectorImpl>>, input: &mut Parser)
+    fn parse_block(&mut self, prelude: SelectorList<SelectorImpl>, input: &mut Parser)
                    -> Result<CssRule, ()> {
         Ok(CssRule::Style(Arc::new(RwLock::new(StyleRule {
             selectors: prelude,
             block: Arc::new(RwLock::new(parse_property_declaration_list(self.context, input)))
         }))))
     }
 }
--- a/servo/components/style/stylist.rs
+++ b/servo/components/style/stylist.rs
@@ -11,17 +11,17 @@ use error_reporting::StdoutErrorReporter
 use keyframes::KeyframesAnimation;
 use media_queries::{Device, MediaType};
 use parking_lot::RwLock;
 use properties::{self, CascadeFlags, ComputedValues, INHERIT_ALL, Importance};
 use properties::{PropertyDeclaration, PropertyDeclarationBlock};
 use quickersort::sort_by;
 use restyle_hints::{RestyleHint, DependencySet};
 use rule_tree::{RuleTree, StrongRuleNode, StyleSource};
-use selector_parser::{ElementExt, TheSelectorImpl, PseudoElement, Snapshot};
+use selector_parser::{ElementExt, SelectorImpl, PseudoElement, Snapshot};
 use selectors::Element;
 use selectors::bloom::BloomFilter;
 use selectors::matching::{AFFECTED_BY_STYLE_ATTRIBUTE, AFFECTED_BY_PRESENTATIONAL_HINTS};
 use selectors::matching::{MatchingReason, StyleRelations, matches_complex_selector};
 use selectors::parser::{Selector, SimpleSelector, LocalName as LocalNameSelector, ComplexSelector};
 use sink::Push;
 use smallvec::VecLike;
 use std::borrow::Borrow;
@@ -84,22 +84,22 @@ pub struct Stylist {
 
     rules_source_order: usize,
 
     /// Selector dependencies used to compute restyle hints.
     state_deps: DependencySet,
 
     /// Selectors in the page affecting siblings
     #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
-    sibling_affecting_selectors: Vec<Selector<TheSelectorImpl>>,
+    sibling_affecting_selectors: Vec<Selector<SelectorImpl>>,
 
     /// Selectors in the page matching elements with non-common style-affecting
     /// attributes.
     #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
-    non_common_style_affecting_attributes_selectors: Vec<Selector<TheSelectorImpl>>,
+    non_common_style_affecting_attributes_selectors: Vec<Selector<SelectorImpl>>,
 }
 
 impl Stylist {
     #[inline]
     pub fn new(device: Device) -> Self {
         let mut stylist = Stylist {
             viewport_constraints: None,
             device: device,
@@ -114,17 +114,17 @@ impl Stylist {
             rule_tree: RuleTree::new(),
             state_deps: DependencySet::new(),
 
             // XXX remember resetting them!
             sibling_affecting_selectors: vec![],
             non_common_style_affecting_attributes_selectors: vec![]
         };
 
-        TheSelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| {
+        SelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| {
             stylist.pseudos_map.insert(pseudo, PerPseudoElementSelectorMap::new());
         });
 
         // FIXME: Add iso-8859-9.css when the document’s encoding is ISO-8859-8.
 
         stylist
     }
 
@@ -134,17 +134,17 @@ impl Stylist {
                   stylesheets_changed: bool) -> bool {
         if !(self.is_device_dirty || stylesheets_changed) {
             return false;
         }
 
         self.element_map = PerPseudoElementSelectorMap::new();
         self.pseudos_map = Default::default();
         self.animations = Default::default();
-        TheSelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| {
+        SelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| {
             self.pseudos_map.insert(pseudo, PerPseudoElementSelectorMap::new());
         });
 
         self.precomputed_pseudo_element_decls = Default::default();
         self.rules_source_order = 0;
         self.state_deps.clear();
 
         self.sibling_affecting_selectors.clear();
@@ -184,17 +184,17 @@ impl Stylist {
         }
         borrow_self_field!(pseudos_map, element_map, state_deps, sibling_affecting_selectors,
                            non_common_style_affecting_attributes_selectors, rules_source_order,
                            animations, precomputed_pseudo_element_decls);
         stylesheet.effective_rules(&self.device, |rule| {
             match *rule {
                 CssRule::Style(ref style_rule) => {
                     let guard = style_rule.read();
-                    for selector in &guard.selectors {
+                    for selector in &guard.selectors.0 {
                         let map = if let Some(ref pseudo) = selector.pseudo_element {
                             pseudos_map
                                 .entry(pseudo.clone())
                                 .or_insert_with(PerPseudoElementSelectorMap::new)
                                 .borrow_for_origin(&stylesheet.origin)
                         } else {
                             element_map.borrow_for_origin(&stylesheet.origin)
                         };
@@ -203,17 +203,17 @@ impl Stylist {
                             selector: selector.complex_selector.clone(),
                             style_rule: style_rule.clone(),
                             specificity: selector.specificity,
                             source_order: *rules_source_order,
                         });
                     }
                     *rules_source_order += 1;
 
-                    for selector in &guard.selectors {
+                    for selector in &guard.selectors.0 {
                         state_deps.note_selector(&selector.complex_selector);
                         if selector.affects_siblings() {
                             sibling_affecting_selectors.push(selector.clone());
                         }
 
                         if selector.matches_non_common_style_affecting_attribute() {
                             non_common_style_affecting_attributes_selectors.push(selector.clone());
                         }
@@ -241,17 +241,17 @@ impl Stylist {
         debug!("Stylist stats:");
         debug!(" - Got {} sibling-affecting selectors",
                sibling_affecting_selectors.len());
         debug!(" - Got {} non-common-style-attribute-affecting selectors",
                non_common_style_affecting_attributes_selectors.len());
         debug!(" - Got {} deps for style-hint calculation",
                state_deps.len());
 
-        TheSelectorImpl::each_precomputed_pseudo_element(|pseudo| {
+        SelectorImpl::each_precomputed_pseudo_element(|pseudo| {
             // TODO: Consider not doing this and just getting the rules on the
             // fly. It should be a bit slower, but we'd take rid of the
             // extra field, and avoid this precomputation entirely.
             if let Some(map) = pseudos_map.remove(&pseudo) {
                 let mut declarations = vec![];
 
                 map.user_agent.get_universal_rules(&mut declarations);
 
@@ -266,17 +266,17 @@ impl Stylist {
     /// If `inherit_all` is true, then all properties are inherited from the parent; otherwise,
     /// non-inherited properties are reset to their initial values. The flow constructor uses this
     /// flag when constructing anonymous flows.
     pub fn precomputed_values_for_pseudo(&self,
                                          pseudo: &PseudoElement,
                                          parent: Option<&Arc<ComputedValues>>,
                                          inherit_all: bool)
                                          -> Option<(Arc<ComputedValues>, StrongRuleNode)> {
-        debug_assert!(TheSelectorImpl::pseudo_element_cascade_type(pseudo).is_precomputed());
+        debug_assert!(SelectorImpl::pseudo_element_cascade_type(pseudo).is_precomputed());
         if let Some(declarations) = self.precomputed_pseudo_element_decls.get(pseudo) {
             // FIXME(emilio): When we've taken rid of the cascade we can just
             // use into_iter.
             let rule_node =
                 self.rule_tree.insert_ordered_rules(
                     declarations.iter().map(|a| (a.source.clone(), a.importance)));
 
             let mut flags = CascadeFlags::empty();
@@ -325,21 +325,21 @@ impl Stylist {
             .0
     }
 
     pub fn lazily_compute_pseudo_element_style<E>(&self,
                                                   element: &E,
                                                   pseudo: &PseudoElement,
                                                   parent: &Arc<ComputedValues>)
                                                   -> Option<(Arc<ComputedValues>, StrongRuleNode)>
-        where E: Element<Impl=TheSelectorImpl> +
+        where E: Element<Impl=SelectorImpl> +
               fmt::Debug +
               PresentationalHintsSynthetizer
     {
-        debug_assert!(TheSelectorImpl::pseudo_element_cascade_type(pseudo).is_lazy());
+        debug_assert!(SelectorImpl::pseudo_element_cascade_type(pseudo).is_lazy());
         if self.pseudos_map.get(pseudo).is_none() {
             return None;
         }
 
         let mut declarations = vec![];
 
         self.push_applicable_declarations(element,
                                           None,
@@ -413,26 +413,26 @@ impl Stylist {
     pub fn push_applicable_declarations<E, V>(
                                         &self,
                                         element: &E,
                                         parent_bf: Option<&BloomFilter>,
                                         style_attribute: Option<&Arc<RwLock<PropertyDeclarationBlock>>>,
                                         pseudo_element: Option<&PseudoElement>,
                                         applicable_declarations: &mut V,
                                         reason: MatchingReason) -> StyleRelations
-        where E: Element<Impl=TheSelectorImpl> +
+        where E: Element<Impl=SelectorImpl> +
                  fmt::Debug +
                  PresentationalHintsSynthetizer,
               V: Push<ApplicableDeclarationBlock> + VecLike<ApplicableDeclarationBlock>
     {
         debug_assert!(!self.is_device_dirty);
         debug_assert!(style_attribute.is_none() || pseudo_element.is_none(),
                       "Style attributes do not apply to pseudo-elements");
         debug_assert!(pseudo_element.is_none() ||
-                      !TheSelectorImpl::pseudo_element_cascade_type(pseudo_element.as_ref().unwrap())
+                      !SelectorImpl::pseudo_element_cascade_type(pseudo_element.as_ref().unwrap())
                         .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();
@@ -726,17 +726,17 @@ impl SelectorMap {
     /// Sort the Rules at the end to maintain cascading order.
     pub fn get_all_matching_rules<E, V>(&self,
                                         element: &E,
                                         parent_bf: Option<&BloomFilter>,
                                         matching_rules_list: &mut V,
                                         relations: &mut StyleRelations,
                                         reason: MatchingReason,
                                         importance: Importance)
-        where E: Element<Impl=TheSelectorImpl>,
+        where E: Element<Impl=SelectorImpl>,
               V: VecLike<ApplicableDeclarationBlock>
     {
         if self.empty {
             return
         }
 
         // At the end, we're going to sort the rules that we added, so remember where we began.
         let init_len = matching_rules_list.len();
@@ -826,17 +826,17 @@ impl SelectorMap {
         element: &E,
         parent_bf: Option<&BloomFilter>,
         hash: &FnvHashMap<Str, Vec<Rule>>,
         key: &BorrowedStr,
         matching_rules: &mut Vector,
         relations: &mut StyleRelations,
         reason: MatchingReason,
         importance: Importance)
-        where E: Element<Impl=TheSelectorImpl>,
+        where E: Element<Impl=SelectorImpl>,
               Str: Borrow<BorrowedStr> + Eq + Hash,
               BorrowedStr: Eq + Hash,
               Vector: VecLike<ApplicableDeclarationBlock>
     {
         if let Some(rules) = hash.get(key) {
             SelectorMap::get_matching_rules(element,
                                             parent_bf,
                                             rules,
@@ -851,17 +851,17 @@ impl SelectorMap {
     #[allow(unsafe_code)]
     fn get_matching_rules<E, V>(element: &E,
                                 parent_bf: Option<&BloomFilter>,
                                 rules: &[Rule],
                                 matching_rules: &mut V,
                                 relations: &mut StyleRelations,
                                 reason: MatchingReason,
                                 importance: Importance)
-        where E: Element<Impl=TheSelectorImpl>,
+        where E: Element<Impl=SelectorImpl>,
               V: VecLike<ApplicableDeclarationBlock>
     {
         for rule in rules.iter() {
             let guard = rule.style_rule.read();
             let block = guard.block.read();
             let any_declaration_for_importance = if importance.important() {
                 block.any_important()
             } else {
@@ -922,17 +922,17 @@ impl SelectorMap {
                 return Some(class.clone());
             }
         }
 
         None
     }
 
     /// Retrieve the name if it is a type selector, or None otherwise.
-    pub fn get_local_name(rule: &Rule) -> Option<LocalNameSelector<TheSelectorImpl>> {
+    pub fn get_local_name(rule: &Rule) -> Option<LocalNameSelector<SelectorImpl>> {
         for ss in &rule.selector.compound_selector {
             if let SimpleSelector::LocalName(ref n) = *ss {
                 return Some(LocalNameSelector {
                     name: n.name.clone(),
                     lower_name: n.lower_name.clone(),
                 })
             }
         }
@@ -943,17 +943,17 @@ impl SelectorMap {
 
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 #[derive(Clone, Debug)]
 pub struct Rule {
     // This is an Arc because Rule will essentially be cloned for every element
     // that it matches. Selector contains an owned vector (through
     // ComplexSelector) and we want to avoid the allocation.
     #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
-    pub selector: Arc<ComplexSelector<TheSelectorImpl>>,
+    pub selector: Arc<ComplexSelector<SelectorImpl>>,
     #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
     pub style_rule: Arc<RwLock<StyleRule>>,
     pub source_order: usize,
     pub specificity: u32,
 }
 
 impl Rule {
     fn to_applicable_declaration_block(&self, importance: Importance) -> ApplicableDeclarationBlock {
--- a/servo/docs/components/style.md
+++ b/servo/docs/components/style.md
@@ -15,17 +15,17 @@ aims to integrate Servo's style system i
 The main generic trait is [selectors' SelectorImpl][selector-impl], that has all
 the logic related to parsing pseudo-elements and other pseudo-classes appart
 from [tree-structural ones][tree-structural-pseudo-classes].
 
 Servo [extends][selector-impl-ext] that trait in order to allow a few more
 things to be shared between Stylo and Servo.
 
 The main Servo implementation (the one that is used in regular builds) is
-[ServoSelectorImpl][servo-selector-impl].
+[SelectorImpl][servo-selector-impl].
 
 <a name="dom-glue"></a>
 ## DOM glue
 
 In order to keep DOM, layout and style in different modules, there are a few
 traits involved.
 
 Style's [`dom` traits][style-dom-traits] (`TDocument`, `TElement`, `TNode`,
@@ -134,17 +134,17 @@ pseudo-elements**.
 Feel free to ping @SimonSapin, @mbrubeck or @emilio on irc, and please mention
 that you didn't find it here so it can be added :)
 
 [style-doc]: http://doc.servo.org/style/index.html
 [wiki-styling-overview]: https://github.com/servo/servo/wiki/Styling-overview
 [stylo]: https://public.etherpad-mozilla.org/p/stylo
 [selector-impl]: http://doc.servo.org/selectors/parser/trait.SelectorImpl.html
 [selector-impl-ext]: http://doc.servo.org/style/selector_parser/trait.SelectorImplExt.html
-[servo-selector-impl]: http://doc.servo.org/style/servo_selector_parser/struct.ServoSelectorImpl.html
+[servo-selector-impl]: http://doc.servo.org/style/servo_selector_parser/struct.SelectorImpl.html
 [tree-structural-pseudo-classes]: https://www.w3.org/TR/selectors4/#structural-pseudos
 [style-dom-traits]: http://doc.servo.org/style/dom/index.html
 [layout-wrapper]: http://doc.servo.org/layout/wrapper/index.html
 [pseudo-cascade-type]: http://doc.servo.org/style/selector_parser/enum.PseudoElementCascadeType.html
 [servo-pseudo-elements]: http://doc.servo.org/style/selector_parser/enum.PseudoElement.html
 [mdn-pseudo-before]: https://developer.mozilla.org/en/docs/Web/CSS/::before
 [mdn-pseudo-after]: https://developer.mozilla.org/en/docs/Web/CSS/::after
 [mdn-pseudo-selection]: https://developer.mozilla.org/en/docs/Web/CSS/::selection
--- a/servo/ports/cef/Cargo.lock
+++ b/servo/ports/cef/Cargo.lock
@@ -1153,17 +1153,17 @@ dependencies = [
  "ordered-float 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "plugins 0.0.1",
  "profile_traits 0.0.1",
  "range 0.0.1",
  "rayon 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "script_layout_interface 0.0.1",
  "script_traits 0.0.1",
- "selectors 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "selectors 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_atoms 0.0.1",
  "servo_url 0.0.1",
  "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "style 0.0.1",
  "style_traits 0.0.1",
@@ -1193,17 +1193,17 @@ dependencies = [
  "net_traits 0.0.1",
  "parking_lot 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "plugins 0.0.1",
  "profile_traits 0.0.1",
  "rayon 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "script 0.0.1",
  "script_layout_interface 0.0.1",
  "script_traits 0.0.1",
- "selectors 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "selectors 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_url 0.0.1",
  "style 0.0.1",
  "util 0.0.1",
  "webrender_traits 0.9.0 (git+https://github.com/servo/webrender)",
 ]
 
@@ -2014,17 +2014,17 @@ dependencies = [
  "profile_traits 0.0.1",
  "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "range 0.0.1",
  "ref_slice 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.1.76 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "script_layout_interface 0.0.1",
  "script_traits 0.0.1",
- "selectors 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "selectors 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_atoms 0.0.1",
  "servo_url 0.0.1",
  "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "style 0.0.1",
  "style_traits 0.0.1",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "tinyfiledialogs 0.1.0 (git+https://github.com/jdm/tinyfiledialogs)",
@@ -2053,17 +2053,17 @@ dependencies = [
  "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "plugins 0.0.1",
  "profile_traits 0.0.1",
  "range 0.0.1",
  "script_traits 0.0.1",
- "selectors 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "selectors 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_atoms 0.0.1",
  "servo_url 0.0.1",
  "style 0.0.1",
 ]
 
 [[package]]
 name = "script_traits"
 version = "0.0.1"
@@ -2092,17 +2092,17 @@ dependencies = [
  "servo_url 0.0.1",
  "style_traits 0.0.1",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "selectors"
-version = "0.14.0"
+version = "0.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -2369,17 +2369,17 @@ dependencies = [
  "ordered-float 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "owning_ref 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "plugins 0.0.1",
  "quickersort 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
- "selectors 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "selectors 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_atoms 0.0.1",
  "servo_url 0.0.1",
  "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "style_traits 0.0.1",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-segmentation 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3091,17 +3091,17 @@ dependencies = [
 "checksum rayon 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b6a6e05e0e6b703e9f2ad266eb63f3712e693a17a2702b95a23de14ce8defa9"
 "checksum ref_slice 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "546bb4aa91c85f232732cc5b3c8097ea97ae9a77304f9ab4df8b203ff7672dad"
 "checksum regex 0.1.76 (registry+https://github.com/rust-lang/crates.io-index)" = "63b49f873f36ddc838d773972511e5fed2ef7350885af07d58e2f48ce8073dcd"
 "checksum regex-syntax 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279401017ae31cf4e15344aa3f085d0e2e5c1e70067289ef906906fdbe92c8fd"
 "checksum rustc-demangle 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c4c2d35b2ed94cec4fad26a36eee4d6eff394ce70a8ceea064b0b6ca42ea4cf0"
 "checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b"
 "checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084"
 "checksum scoped_threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3ef399c8893e8cb7aa9696e895427fab3a6bf265977bb96e126f24ddd2cda85a"
-"checksum selectors 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f8d3498861f4486e7e1d5c56eabf2b0e461f92bcbf45a3ac30cae0f3d5cdd0"
+"checksum selectors 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75b127ac14249f6ce720277f6a163b3837706e9dc1ad4e2948db55f262f11a97"
 "checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac"
 "checksum serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)" = "784e249221c84265caeb1e2fe48aeada86f67f5acb151bd3903c4585969e43f6"
 "checksum serde_codegen 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)" = "c3b932a3bb4d729e39aa04cc5e2f2ac70ba239a5a151d2dc9a1956fd6a2f7c15"
 "checksum serde_codegen_internals 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "318f7e77aa5187391d74aaf4553d2189f56b0ce25e963414c951b97877ffdcec"
 "checksum serde_derive 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)" = "c6a73f0e5fc193668afa2a714bf8397063af46e6c8df72686e53fbac15b2e38c"
 "checksum serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e10f8a9d94b06cf5d3bef66475f04c8ff90950f1be7004c357ff9472ccbaebc"
 "checksum servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "21069a884c33fe6ee596975e1f3849ed88c4ec857fbaf11d33672d8ebe051217"
 "checksum servo-fontconfig 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "93f799b649b4a2bf362398910eca35240704c7e765e780349b2bb1070d892262"
--- a/servo/ports/geckolib/Cargo.lock
+++ b/servo/ports/geckolib/Cargo.lock
@@ -6,17 +6,17 @@ dependencies = [
  "cssparser 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "selectors 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "selectors 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_url 0.0.1",
  "style 0.0.1",
  "style_traits 0.0.1",
  "stylo_tests 0.0.1",
 ]
 
 [[package]]
 name = "aho-corasick"
@@ -314,17 +314,17 @@ source = "registry+https://github.com/ru
 
 [[package]]
 name = "rustc-serialize"
 version = "0.3.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "selectors"
-version = "0.14.0"
+version = "0.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -367,17 +367,17 @@ dependencies = [
  "num_cpus 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "ordered-float 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "owning_ref 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "quickersort 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
- "selectors 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "selectors 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_url 0.0.1",
  "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "style_traits 0.0.1",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-segmentation 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "util 0.0.1",
  "walkdir 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -401,17 +401,17 @@ dependencies = [
  "env_logger 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "geckoservo 0.0.1",
  "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "selectors 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "selectors 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_url 0.0.1",
  "style 0.0.1",
  "style_traits 0.0.1",
 ]
 
 [[package]]
 name = "thread-id"
 version = "2.0.0"
@@ -560,17 +560,17 @@ source = "registry+https://github.com/ru
 "checksum parking_lot 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3562f3de7bdff194212be82366abf5c6565aff8a433b71c53c63d0e7c9913878"
 "checksum parking_lot_core 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "06f24c980718110494e9cfb7db7438895c3f54505101bb6170329d5e43a53f64"
 "checksum quickersort 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e952ea7699262481636004bc4ab8afaccf2bc13f91b79d1aee6617bd8fc39651"
 "checksum rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2791d88c6defac799c3f20d74f094ca33b9332612d9aef9078519c82e4fe04a5"
 "checksum rayon 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b6a6e05e0e6b703e9f2ad266eb63f3712e693a17a2702b95a23de14ce8defa9"
 "checksum regex 0.1.76 (registry+https://github.com/rust-lang/crates.io-index)" = "63b49f873f36ddc838d773972511e5fed2ef7350885af07d58e2f48ce8073dcd"
 "checksum regex-syntax 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279401017ae31cf4e15344aa3f085d0e2e5c1e70067289ef906906fdbe92c8fd"
 "checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b"
-"checksum selectors 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f8d3498861f4486e7e1d5c56eabf2b0e461f92bcbf45a3ac30cae0f3d5cdd0"
+"checksum selectors 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75b127ac14249f6ce720277f6a163b3837706e9dc1ad4e2948db55f262f11a97"
 "checksum serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)" = "784e249221c84265caeb1e2fe48aeada86f67f5acb151bd3903c4585969e43f6"
 "checksum smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "fcc8d19212aacecf95e4a7a2179b26f7aeb9732a915cf01f05b0d3e044865410"
 "checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
 "checksum thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "55dd963dbaeadc08aa7266bf7f91c3154a7805e32bb94b820b769d2ef3b4744d"
 "checksum time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "3c7ec6d62a20df54e07ab3b78b9a3932972f4b7981de295563686849eb3989af"
 "checksum unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c1f7ceb96afdfeedee42bade65a0d585a6a0106f681b6749c8ff4daa8df30b3f"
 "checksum unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "26643a2f83bac55f1976fb716c10234485f9202dcd65cfbdf9da49867b271172"
 "checksum unicode-segmentation 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b905d0fc2a1f0befd86b0e72e31d1787944efef9d38b9358a9e92a69757f7e3b"
--- a/servo/ports/geckolib/Cargo.toml
+++ b/servo/ports/geckolib/Cargo.toml
@@ -14,15 +14,15 @@ app_units = "0.3"
 cssparser = {version = "0.7"}
 env_logger = "0.3"
 euclid = "0.10.1"
 lazy_static = "0.2"
 libc = "0.2"
 log = {version = "0.3.5", features = ["release_max_level_info"]}
 num_cpus = "1.1.0"
 parking_lot = "0.3"
-selectors = "0.14"
+selectors = "0.15"
 servo_url = {path = "../../components/url"}
 style = {path = "../../components/style", features = ["gecko"]}
 style_traits = {path = "../../components/style_traits"}
 
 [dev-dependencies]
 stylo_tests = {path = "../../tests/unit/stylo"}
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -11,17 +11,17 @@ use servo_url::ServoUrl;
 use std::fmt::Write;
 use std::mem::transmute;
 use std::sync::{Arc, Mutex};
 use style::arc_ptr_eq;
 use style::context::{LocalStyleContextCreationInfo, ReflowGoal, SharedStyleContext};
 use style::dom::{NodeInfo, StylingMode, TElement, TNode};
 use style::error_reporting::StdoutErrorReporter;
 use style::gecko::data::{NUM_THREADS, PerDocumentStyleData};
-use style::gecko::selector_parser::{GeckoSelectorImpl, PseudoElement};
+use style::gecko::selector_parser::{SelectorImpl, PseudoElement};
 use style::gecko::snapshot::GeckoElementSnapshot;
 use style::gecko::traversal::RecalcStyleOnly;
 use style::gecko::wrapper::{GeckoElement, GeckoNode};
 use style::gecko::wrapper::DUMMY_BASE_URL;
 use style::gecko_bindings::bindings::{RawGeckoElementBorrowed, RawGeckoNodeBorrowed};
 use style::gecko_bindings::bindings::{RawServoDeclarationBlockBorrowed, RawServoDeclarationBlockStrong};
 use style::gecko_bindings::bindings::{RawServoStyleSetBorrowed, RawServoStyleSetOwned};
 use style::gecko_bindings::bindings::{RawServoStyleSheetBorrowed, ServoComputedValuesBorrowed};
@@ -345,17 +345,17 @@ pub extern "C" fn Servo_ComputedValues_G
 
     // The stylist consumes stylesheets lazily.
     let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
     data.flush_stylesheets();
 
     let element = GeckoElement(match_element);
 
 
-    match GeckoSelectorImpl::pseudo_element_cascade_type(&pseudo) {
+    match SelectorImpl::pseudo_element_cascade_type(&pseudo) {
         PseudoElementCascadeType::Eager => {
             let maybe_computed = element.get_pseudo_style(&pseudo);
             maybe_computed.map_or_else(parent_or_null, FFIArcHelpers::into_strong)
         }
         PseudoElementCascadeType::Lazy => {
             let parent = ComputedValues::as_arc(&parent_style);
             data.stylist
                 .lazily_compute_pseudo_element_style(&element, &pseudo, parent)
--- a/servo/ports/servo/Cargo.lock
+++ b/servo/ports/servo/Cargo.lock
@@ -1232,17 +1232,17 @@ dependencies = [
  "ordered-float 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "plugins 0.0.1",
  "profile_traits 0.0.1",
  "range 0.0.1",
  "rayon 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "script_layout_interface 0.0.1",
  "script_traits 0.0.1",
- "selectors 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "selectors 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_atoms 0.0.1",
  "servo_url 0.0.1",
  "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "style 0.0.1",
  "style_traits 0.0.1",
@@ -1279,17 +1279,17 @@ dependencies = [
  "net_traits 0.0.1",
  "parking_lot 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "plugins 0.0.1",
  "profile_traits 0.0.1",
  "rayon 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "script 0.0.1",
  "script_layout_interface 0.0.1",
  "script_traits 0.0.1",
- "selectors 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "selectors 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_url 0.0.1",
  "style 0.0.1",
  "util 0.0.1",
  "webrender_traits 0.9.0 (git+https://github.com/servo/webrender)",
 ]
 
@@ -2164,17 +2164,17 @@ dependencies = [
  "profile_traits 0.0.1",
  "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "range 0.0.1",
  "ref_slice 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.1.76 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "script_layout_interface 0.0.1",
  "script_traits 0.0.1",
- "selectors 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "selectors 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_atoms 0.0.1",
  "servo_url 0.0.1",
  "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "style 0.0.1",
  "style_traits 0.0.1",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "tinyfiledialogs 0.1.0 (git+https://github.com/jdm/tinyfiledialogs)",
@@ -2203,17 +2203,17 @@ dependencies = [
  "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "plugins 0.0.1",
  "profile_traits 0.0.1",
  "range 0.0.1",
  "script_traits 0.0.1",
- "selectors 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "selectors 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_atoms 0.0.1",
  "servo_url 0.0.1",
  "style 0.0.1",
 ]
 
 [[package]]
 name = "script_tests"
 version = "0.0.1"
@@ -2252,17 +2252,17 @@ dependencies = [
  "servo_url 0.0.1",
  "style_traits 0.0.1",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "selectors"
-version = "0.14.0"
+version = "0.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -2536,17 +2536,17 @@ dependencies = [
  "ordered-float 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "owning_ref 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "plugins 0.0.1",
  "quickersort 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
- "selectors 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "selectors 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_atoms 0.0.1",
  "servo_url 0.0.1",
  "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "style_traits 0.0.1",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-segmentation 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2560,17 +2560,17 @@ version = "0.0.1"
 dependencies = [
  "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "html5ever-atoms 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "owning_ref 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
- "selectors 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "selectors 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_atoms 0.0.1",
  "servo_url 0.0.1",
  "style 0.0.1",
  "style_traits 0.0.1",
  "util 0.0.1",
 ]
 
 [[package]]
@@ -3301,17 +3301,17 @@ dependencies = [
 "checksum rayon 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b6a6e05e0e6b703e9f2ad266eb63f3712e693a17a2702b95a23de14ce8defa9"
 "checksum ref_slice 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "546bb4aa91c85f232732cc5b3c8097ea97ae9a77304f9ab4df8b203ff7672dad"
 "checksum regex 0.1.76 (registry+https://github.com/rust-lang/crates.io-index)" = "63b49f873f36ddc838d773972511e5fed2ef7350885af07d58e2f48ce8073dcd"
 "checksum regex-syntax 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279401017ae31cf4e15344aa3f085d0e2e5c1e70067289ef906906fdbe92c8fd"
 "checksum rustc-demangle 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c4c2d35b2ed94cec4fad26a36eee4d6eff394ce70a8ceea064b0b6ca42ea4cf0"
 "checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b"
 "checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084"
 "checksum scoped_threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3ef399c8893e8cb7aa9696e895427fab3a6bf265977bb96e126f24ddd2cda85a"
-"checksum selectors 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f8d3498861f4486e7e1d5c56eabf2b0e461f92bcbf45a3ac30cae0f3d5cdd0"
+"checksum selectors 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75b127ac14249f6ce720277f6a163b3837706e9dc1ad4e2948db55f262f11a97"
 "checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac"
 "checksum semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2d5b7638a1f03815d94e88cb3b3c08e87f0db4d683ef499d1836aaf70a45623f"
 "checksum serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)" = "784e249221c84265caeb1e2fe48aeada86f67f5acb151bd3903c4585969e43f6"
 "checksum serde_codegen 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)" = "c3b932a3bb4d729e39aa04cc5e2f2ac70ba239a5a151d2dc9a1956fd6a2f7c15"
 "checksum serde_codegen_internals 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "318f7e77aa5187391d74aaf4553d2189f56b0ce25e963414c951b97877ffdcec"
 "checksum serde_derive 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)" = "c6a73f0e5fc193668afa2a714bf8397063af46e6c8df72686e53fbac15b2e38c"
 "checksum serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e10f8a9d94b06cf5d3bef66475f04c8ff90950f1be7004c357ff9472ccbaebc"
 "checksum servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "21069a884c33fe6ee596975e1f3849ed88c4ec857fbaf11d33672d8ebe051217"
--- a/servo/tests/unit/style/Cargo.toml
+++ b/servo/tests/unit/style/Cargo.toml
@@ -11,15 +11,15 @@ doctest = false
 
 [dependencies]
 app_units = "0.3"
 cssparser = {version = "0.7", features = ["heap_size"]}
 euclid = "0.10.1"
 owning_ref = "0.2.2"
 parking_lot = "0.3"
 rustc-serialize = "0.3"
-selectors = "0.14"
+selectors = "0.15"
 html5ever-atoms = "0.1"
 servo_atoms = {path = "../../../components/atoms"}
 style = {path = "../../../components/style"}
 style_traits = {path = "../../../components/style_traits"}
 servo_url = {path = "../../../components/url"}
 util = {path = "../../../components/util"}
--- a/servo/tests/unit/style/parsing/selectors.rs
+++ b/servo/tests/unit/style/parsing/selectors.rs
@@ -1,21 +1,25 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use cssparser::{Parser, ToCss};
-use selectors::parser::{Selector, ParserContext, parse_selector_list};
-use style::selector_parser::TheSelectorImpl;
+use selectors::parser::SelectorList;
+use style::selector_parser::{SelectorImpl, SelectorParser};
+use style::stylesheets::{Origin, Namespaces};
 
-fn parse(input: &mut Parser) -> Result<Selector<TheSelectorImpl>, ()> {
-    let mut context = ParserContext::new();
-    context.in_user_agent_stylesheet = true;
-    context.namespace_prefixes.insert("svg".into(), ns!(svg));
-    parse_selector_list(&context, input).map(|mut vec| vec.pop().unwrap())
+fn parse(input: &mut Parser) -> Result<SelectorList<SelectorImpl>, ()> {
+    let mut ns = Namespaces::default();
+    ns.prefixes.insert("svg".into(), ns!(svg));
+    let parser = SelectorParser {
+        stylesheet_origin: Origin::UserAgent,
+        namespaces: &ns,
+    };
+    SelectorList::parse(&parser, input)
 }
 
 #[test]
 fn test_selectors() {
     assert_roundtrip!(parse, "div");
     assert_roundtrip!(parse, "svg|circle");
     assert_roundtrip!(parse, "p:before", "p::before");
     assert_roundtrip!(parse, "[border = \"0\"]:-servo-nonzero-border ~ ::-servo-details-summary");
--- a/servo/tests/unit/style/stylesheets.rs
+++ b/servo/tests/unit/style/stylesheets.rs
@@ -1,13 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use cssparser::{self, Parser, SourcePosition};
+use cssparser::{self, Parser as CssParser, SourcePosition};
 use html5ever_atoms::{Namespace as NsAtom};
 use media_queries::CSSErrorReporterTest;
 use parking_lot::RwLock;
 use selectors::parser::*;
 use servo_atoms::Atom;
 use servo_url::ServoUrl;
 use std::borrow::ToOwned;
 use std::sync::Arc;
@@ -58,17 +58,17 @@ fn test_parse_stylesheet() {
         media: Default::default(),
         dirty_on_viewport_size_change: AtomicBool::new(false),
         rules: vec![
             CssRule::Namespace(Arc::new(RwLock::new(NamespaceRule {
                 prefix: None,
                 url: NsAtom::from("http://www.w3.org/1999/xhtml")
             }))),
             CssRule::Style(Arc::new(RwLock::new(StyleRule {
-                selectors: vec![
+                selectors: SelectorList(vec![
                     Selector {
                         complex_selector: Arc::new(ComplexSelector {
                             compound_selector: vec![
                                 SimpleSelector::Namespace(Namespace {
                                     prefix: None,
                                     url: NsAtom::from("http://www.w3.org/1999/xhtml")
                                 }),
                                 SimpleSelector::LocalName(LocalName {
@@ -84,30 +84,30 @@ fn test_parse_stylesheet() {
                                     }),
                                 }, "hidden".to_owned(), CaseSensitivity::CaseInsensitive)
                             ],
                             next: None,
                         }),
                         pseudo_element: None,
                         specificity: (0 << 20) + (1 << 10) + (1 << 0),
                     },
-                ],
+                ]),
                 block: Arc::new(RwLock::new(PropertyDeclarationBlock {
                     declarations: vec![
                         (PropertyDeclaration::Display(DeclaredValue::Value(
                             longhands::display::SpecifiedValue::none)),
                          Importance::Important),
                         (PropertyDeclaration::Custom(Atom::from("a"), DeclaredValue::Inherit),
                          Importance::Important),
                     ],
                     important_count: 2,
                 })),
             }))),
             CssRule::Style(Arc::new(RwLock::new(StyleRule {
-                selectors: vec![
+                selectors: SelectorList(vec![
                     Selector {
                         complex_selector: Arc::new(ComplexSelector {
                             compound_selector: vec![
                                 SimpleSelector::Namespace(Namespace {
                                     prefix: None,
                                     url: NsAtom::from("http://www.w3.org/1999/xhtml")
                                 }),
                                 SimpleSelector::LocalName(LocalName {
@@ -132,28 +132,28 @@ fn test_parse_stylesheet() {
                                     lower_name: local_name!("body"),
                                 }),
                             ],
                             next: None,
                         }),
                         pseudo_element: None,
                         specificity: (0 << 20) + (0 << 10) + (1 << 0),
                     },
-                ],
+                ]),
                 block: Arc::new(RwLock::new(PropertyDeclarationBlock {
                     declarations: vec![
                         (PropertyDeclaration::Display(DeclaredValue::Value(
                             longhands::display::SpecifiedValue::block)),
                          Importance::Normal),
                     ],
                     important_count: 0,
                 })),
             }))),
             CssRule::Style(Arc::new(RwLock::new(StyleRule {
-                selectors: vec![
+                selectors: SelectorList(vec![
                     Selector {
                         complex_selector: Arc::new(ComplexSelector {
                             compound_selector: vec![
                                 SimpleSelector::Namespace(Namespace {
                                     prefix: None,
                                     url: NsAtom::from("http://www.w3.org/1999/xhtml")
                                 }),
                                 SimpleSelector::Class(Atom::from("ok")),
@@ -167,17 +167,17 @@ fn test_parse_stylesheet() {
                                     SimpleSelector::ID(Atom::from("d1")),
                                 ],
                                 next: None,
                             }), Combinator::Child)),
                         }),
                         pseudo_element: None,
                         specificity: (1 << 20) + (1 << 10) + (0 << 0),
                     },
-                ],
+                ]),
                 block: Arc::new(RwLock::new(PropertyDeclarationBlock {
                     declarations: vec![
                         (PropertyDeclaration::BackgroundColor(DeclaredValue::Value(
                             longhands::background_color::SpecifiedValue {
                                 authored: Some("blue".to_owned()),
                                 parsed: cssparser::Color::RGBA(cssparser::RGBA {
                                     red: 0., green: 0., blue: 1., alpha: 1.
                                 }),
@@ -277,17 +277,17 @@ impl CSSInvalidErrorReporterTest {
     pub fn new() -> CSSInvalidErrorReporterTest {
         return CSSInvalidErrorReporterTest{
             errors: Arc::new(Mutex::new(Vec::new()))
         }
     }
 }
 
 impl ParseErrorReporter for CSSInvalidErrorReporterTest {
-    fn report_error(&self, input: &mut Parser, position: SourcePosition, message: &str) {
+    fn report_error(&self, input: &mut CssParser, position: SourcePosition, message: &str) {
         let location = input.source_location(position);
 
         let errors = self.errors.clone();
         let mut errors = errors.lock().unwrap();
 
         errors.push(
             CSSError{
                 line: location.line,
--- a/servo/tests/unit/style/stylist.rs
+++ b/servo/tests/unit/style/stylist.rs
@@ -1,46 +1,44 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use cssparser::Parser;
 use html5ever_atoms::LocalName;
 use parking_lot::RwLock;
-use selectors::parser::{LocalName as LocalNameSelector, ParserContext, parse_selector_list};
+use selectors::parser::LocalName as LocalNameSelector;
 use servo_atoms::Atom;
 use std::sync::Arc;
 use style::properties::{PropertyDeclarationBlock, PropertyDeclaration, DeclaredValue};
 use style::properties::{longhands, Importance};
+use style::selector_parser::SelectorParser;
 use style::stylesheets::StyleRule;
 use style::stylist::{Rule, SelectorMap};
 use style::thread_state;
 
 /// Helper method to get some Rules from selector strings.
 /// Each sublist of the result contains the Rules for one StyleRule.
 fn get_mock_rules(css_selectors: &[&str]) -> Vec<Vec<Rule>> {
     css_selectors.iter().enumerate().map(|(i, selectors)| {
-        let context = ParserContext::new();
-        let selectors =
-            parse_selector_list(&context, &mut Parser::new(*selectors)).unwrap();
+        let selectors = SelectorParser::parse_author_origin_no_namespace(selectors).unwrap();
 
         let rule = Arc::new(RwLock::new(StyleRule {
             selectors: selectors,
             block: Arc::new(RwLock::new(PropertyDeclarationBlock {
                 declarations: vec![
                     (PropertyDeclaration::Display(DeclaredValue::Value(
                         longhands::display::SpecifiedValue::block)),
                      Importance::Normal),
                 ],
                 important_count: 0,
             })),
         }));
 
         let guard = rule.read();
-        guard.selectors.iter().map(|s| {
+        guard.selectors.0.iter().map(|s| {
             Rule {
                 selector: s.complex_selector.clone(),
                 style_rule: rule.clone(),
                 specificity: s.specificity,
                 source_order: i,
             }
         }).collect()
     }).collect()
--- a/servo/tests/unit/stylo/Cargo.toml
+++ b/servo/tests/unit/stylo/Cargo.toml
@@ -16,13 +16,13 @@ app_units = "0.3"
 cssparser = {version = "0.7"}
 env_logger = "0.3"
 euclid = "0.10.1"
 lazy_static = "0.2"
 libc = "0.2"
 log = {version = "0.3.5", features = ["release_max_level_info"]}
 num_cpus = "1.1.0"
 parking_lot = "0.3"
-selectors = "0.14"
+selectors = "0.15"
 servo_url = {path = "../../../components/url"}
 style_traits = {path = "../../../components/style_traits"}
 geckoservo = {path = "../../../ports/geckolib"}
 style = {path = "../../../components/style", features = ["gecko"]}