servo: Merge #17687 - Support parsing ::-moz-tree-* pseudo-elements selector (from upsuper:tree-pseudo); r=heycam
authorXidorn Quan <me@upsuper.org>
Wed, 12 Jul 2017 03:35:37 -0700
changeset 419579 5756ad3145df67f429d6f3d1c807ffc02f02de17
parent 419578 7404c5c961cc7cce97228fa32b40d78a77c0f2dd
child 419580 0298f90e13371b16d36efe8a555487b8ed9d1957
push id1517
push userjlorenzo@mozilla.com
push dateThu, 14 Sep 2017 16:50:54 +0000
treeherdermozilla-release@3b41fd564418 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs1348488
milestone56.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
servo: Merge #17687 - Support parsing ::-moz-tree-* pseudo-elements selector (from upsuper:tree-pseudo); r=heycam This is the Servo side change of [bug 1348488](https://bugzilla.mozilla.org/show_bug.cgi?id=1348488). Source-Repo: https://github.com/servo/servo Source-Revision: ce52c16a8fcb056d1b9b9418304f22bc15dae160
servo/components/selectors/gecko_like_types.rs
servo/components/selectors/parser.rs
servo/components/selectors/size_of_tests.rs
servo/components/style/gecko/generated/atom_macro.rs
servo/components/style/gecko/generated/pseudo_element_definition.rs
servo/components/style/gecko/pseudo_element.rs
servo/components/style/gecko/pseudo_element_definition.mako.rs
servo/components/style/gecko/regen_atoms.py
servo/components/style/gecko/selector_parser.rs
servo/components/style/selector_parser.rs
servo/components/style/servo/selector_parser.rs
--- a/servo/components/selectors/gecko_like_types.rs
+++ b/servo/components/selectors/gecko_like_types.rs
@@ -12,15 +12,16 @@ pub enum PseudoClass {
     String(Box<[u16]>),
     MozAny(Box<[()]>),
 }
 
 #[derive(Eq, PartialEq, Clone, Debug)]
 pub enum PseudoElement {
     A,
     B,
+    Tree(Box<[String]>),
 }
 
 #[derive(Eq, PartialEq, Clone, Debug, Default)]
 pub struct Atom(usize);
 
 #[derive(Eq, PartialEq, Clone)]
 pub struct Impl;
--- a/servo/components/selectors/parser.rs
+++ b/servo/components/selectors/parser.rs
@@ -126,16 +126,22 @@ with_bounds! {
     [Clone + Eq]
     [From<String> + for<'a> From<&'a str>]
 }
 
 pub trait Parser<'i> {
     type Impl: SelectorImpl;
     type Error: 'i;
 
+    /// Whether the name is a pseudo-element that can be specified with
+    /// the single colon syntax in addition to the double-colon syntax.
+    fn is_pseudo_element_allows_single_colon(name: &CompactCowStr<'i>) -> bool {
+        is_css2_pseudo_element(name)
+    }
+
     /// This function can return an "Err" pseudo-element in order to support CSS2.1
     /// pseudo-elements.
     fn parse_non_ts_pseudo_class(&self, name: CompactCowStr<'i>)
                                  -> Result<<Self::Impl as SelectorImpl>::NonTSPseudoClass,
                                            ParseError<'i, SelectorParseError<'i, Self::Error>>> {
         Err(ParseError::Custom(SelectorParseError::UnexpectedIdent(name)))
     }
 
@@ -148,16 +154,23 @@ pub trait Parser<'i> {
     }
 
     fn parse_pseudo_element(&self, name: CompactCowStr<'i>)
                             -> Result<<Self::Impl as SelectorImpl>::PseudoElement,
                                       ParseError<'i, SelectorParseError<'i, Self::Error>>> {
         Err(ParseError::Custom(SelectorParseError::UnexpectedIdent(name)))
     }
 
+    fn parse_functional_pseudo_element<'t>
+        (&self, name: CompactCowStr<'i>, _arguments: &mut CssParser<'i, 't>)
+         -> Result<<Self::Impl as SelectorImpl>::PseudoElement,
+                   ParseError<'i, SelectorParseError<'i, Self::Error>>> {
+        Err(ParseError::Custom(SelectorParseError::UnexpectedIdent(name)))
+    }
+
     fn default_namespace(&self) -> Option<<Self::Impl as SelectorImpl>::NamespaceUrl> {
         None
     }
 
     fn namespace_for_prefix(&self, _prefix: &<Self::Impl as SelectorImpl>::NamespacePrefix)
                             -> Option<<Self::Impl as SelectorImpl>::NamespaceUrl> {
         None
     }
@@ -1466,16 +1479,27 @@ fn parse_nth_pseudo_class<'i, 't, Impl, 
                                               -> Result<Component<Impl>,
                                                         ParseError<'i, SelectorParseError<'i, E>>>
 where Impl: SelectorImpl, F: FnOnce(i32, i32) -> Component<Impl> {
     let (a, b) = parse_nth(input)?;
     Ok(selector(a, b))
 }
 
 
+/// Returns whether the name corresponds to a CSS2 pseudo-element that
+/// can be specified with the single colon syntax (in addition to the
+/// double-colon syntax, which can be used for all pseudo-elements).
+pub fn is_css2_pseudo_element<'i>(name: &CompactCowStr<'i>) -> bool {
+    // ** Do not add to this list! **
+    return name.eq_ignore_ascii_case("before") ||
+           name.eq_ignore_ascii_case("after") ||
+           name.eq_ignore_ascii_case("first-line") ||
+           name.eq_ignore_ascii_case("first-letter");
+}
+
 /// Parse a simple selector other than a type selector.
 ///
 /// * `Err(())`: Invalid selector, abort
 /// * `Ok(None)`: Not a simple selector, could be something else. `input` was not consumed.
 /// * `Ok(Some(_))`: Parsed a simple selector or pseudo-element
 fn parse_one_simple_selector<'i, 't, P, E, Impl>(parser: &P,
                                                  input: &mut CssParser<'i, 't>,
                                                  inside_negation: bool)
@@ -1485,63 +1509,58 @@ fn parse_one_simple_selector<'i, 't, P, 
 {
     let start_position = input.position();
     match input.next_including_whitespace() {
         Ok(Token::IDHash(id)) => {
             let id = Component::ID(from_cow_str(id.into()));
             Ok(Some(SimpleSelectorParseResult::SimpleSelector(id)))
         }
         Ok(Token::Delim('.')) => {
-            match input.next_including_whitespace() {
-                Ok(Token::Ident(class)) => {
+            match input.next_including_whitespace()? {
+                Token::Ident(class) => {
                     let class = Component::Class(from_cow_str(class.into()));
                     Ok(Some(SimpleSelectorParseResult::SimpleSelector(class)))
                 }
-                Ok(t) => Err(ParseError::Basic(BasicParseError::UnexpectedToken(t))),
-                Err(e) => Err(ParseError::Basic(e)),
+                t => Err(ParseError::Basic(BasicParseError::UnexpectedToken(t))),
             }
         }
         Ok(Token::SquareBracketBlock) => {
             let attr = input.parse_nested_block(|input| parse_attribute_selector(parser, input))?;
             Ok(Some(SimpleSelectorParseResult::SimpleSelector(attr)))
         }
         Ok(Token::Colon) => {
-            match input.next_including_whitespace() {
-                Ok(Token::Ident(name)) => {
-                    // Supported CSS 2.1 pseudo-elements only.
-                    // ** Do not add to this list! **
-                    if name.eq_ignore_ascii_case("before") ||
-                       name.eq_ignore_ascii_case("after") ||
-                       name.eq_ignore_ascii_case("first-line") ||
-                       name.eq_ignore_ascii_case("first-letter") {
-                        let pseudo_element = P::parse_pseudo_element(parser, name)?;
-                        Ok(Some(SimpleSelectorParseResult::PseudoElement(pseudo_element)))
-                    } else {
-                        let pseudo_class = parse_simple_pseudo_class(parser, name)?;
-                        Ok(Some(SimpleSelectorParseResult::SimpleSelector(pseudo_class)))
-                    }
-                }
-                Ok(Token::Function(name)) => {
-                    let pseudo = input.parse_nested_block(|input| {
+            let (is_single_colon, next_token) = match input.next_including_whitespace()? {
+                Token::Colon => (false, input.next_including_whitespace()?),
+                t => (true, t),
+            };
+            let (name, is_functional) = match next_token {
+                Token::Ident(name) => (name, false),
+                Token::Function(name) => (name, true),
+                t => return Err(ParseError::Basic(BasicParseError::UnexpectedToken(t))),
+            };
+            let is_pseudo_element = !is_single_colon ||
+                P::is_pseudo_element_allows_single_colon(&name);
+            if is_pseudo_element {
+                let pseudo_element = if is_functional {
+                    input.parse_nested_block(|input| {
+                        P::parse_functional_pseudo_element(parser, name, input)
+                    })?
+                } else {
+                    P::parse_pseudo_element(parser, name)?
+                };
+                Ok(Some(SimpleSelectorParseResult::PseudoElement(pseudo_element)))
+            } else {
+                let pseudo_class = if is_functional {
+                    input.parse_nested_block(|input| {
                         parse_functional_pseudo_class(parser, input, name, inside_negation)
-                    })?;
-                    Ok(Some(SimpleSelectorParseResult::SimpleSelector(pseudo)))
-                }
-                Ok(Token::Colon) => {
-                    match input.next_including_whitespace() {
-                        Ok(Token::Ident(name)) => {
-                            let pseudo = P::parse_pseudo_element(parser, name)?;
-                            Ok(Some(SimpleSelectorParseResult::PseudoElement(pseudo)))
-                        }
-                        Ok(t) => Err(ParseError::Basic(BasicParseError::UnexpectedToken(t))),
-                        Err(e) => Err(ParseError::Basic(e)),
-                    }
-                }
-                Ok(t) => Err(ParseError::Basic(BasicParseError::UnexpectedToken(t))),
-                Err(e) => Err(ParseError::Basic(e)),
+                    })?
+                } else {
+                    parse_simple_pseudo_class(parser, name)?
+                };
+                Ok(Some(SimpleSelectorParseResult::SimpleSelector(pseudo_class)))
             }
         }
         _ => {
             input.reset(start_position);
             Ok(None)
         }
     }
 }
--- a/servo/components/selectors/size_of_tests.rs
+++ b/servo/components/selectors/size_of_tests.rs
@@ -7,17 +7,17 @@ use gecko_like_types;
 use gecko_like_types::*;
 use parser;
 use parser::*;
 use precomputed_hash::PrecomputedHash;
 use std::fmt;
 use visitor::SelectorVisitor;
 
 size_of_test!(size_of_selector, Selector<Impl>, 8);
-size_of_test!(size_of_pseudo_element, gecko_like_types::PseudoElement, 1);
+size_of_test!(size_of_pseudo_element, gecko_like_types::PseudoElement, 24);
 
 size_of_test!(size_of_component, Component<Impl>, 32);
 size_of_test!(size_of_pseudo_class, PseudoClass, 24);
 
 impl parser::PseudoElement for gecko_like_types::PseudoElement {
     type Impl = Impl;
 }
 
--- a/servo/components/style/gecko/generated/atom_macro.rs
+++ b/servo/components/style/gecko/generated/atom_macro.rs
@@ -5109,40 +5109,40 @@ cfg_if! {
             #[link_name = "_ZN14nsCSSAnonBoxes8rubyBaseE"]
             pub static nsCSSAnonBoxes_rubyBase: *mut nsICSSAnonBoxPseudo;
             #[link_name = "_ZN14nsCSSAnonBoxes17rubyBaseContainerE"]
             pub static nsCSSAnonBoxes_rubyBaseContainer: *mut nsICSSAnonBoxPseudo;
             #[link_name = "_ZN14nsCSSAnonBoxes8rubyTextE"]
             pub static nsCSSAnonBoxes_rubyText: *mut nsICSSAnonBoxPseudo;
             #[link_name = "_ZN14nsCSSAnonBoxes17rubyTextContainerE"]
             pub static nsCSSAnonBoxes_rubyTextContainer: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "_ZN14nsCSSAnonBoxes13moztreecolumnE"]
-            pub static nsCSSAnonBoxes_moztreecolumn: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "_ZN14nsCSSAnonBoxes10moztreerowE"]
-            pub static nsCSSAnonBoxes_moztreerow: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "_ZN14nsCSSAnonBoxes16moztreeseparatorE"]
-            pub static nsCSSAnonBoxes_moztreeseparator: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "_ZN14nsCSSAnonBoxes11moztreecellE"]
-            pub static nsCSSAnonBoxes_moztreecell: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "_ZN14nsCSSAnonBoxes18moztreeindentationE"]
-            pub static nsCSSAnonBoxes_moztreeindentation: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "_ZN14nsCSSAnonBoxes11moztreelineE"]
-            pub static nsCSSAnonBoxes_moztreeline: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "_ZN14nsCSSAnonBoxes13moztreetwistyE"]
-            pub static nsCSSAnonBoxes_moztreetwisty: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "_ZN14nsCSSAnonBoxes12moztreeimageE"]
-            pub static nsCSSAnonBoxes_moztreeimage: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "_ZN14nsCSSAnonBoxes15moztreecelltextE"]
-            pub static nsCSSAnonBoxes_moztreecelltext: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "_ZN14nsCSSAnonBoxes15moztreecheckboxE"]
-            pub static nsCSSAnonBoxes_moztreecheckbox: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "_ZN14nsCSSAnonBoxes20moztreeprogressmeterE"]
-            pub static nsCSSAnonBoxes_moztreeprogressmeter: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "_ZN14nsCSSAnonBoxes19moztreedropfeedbackE"]
-            pub static nsCSSAnonBoxes_moztreedropfeedback: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "_ZN14nsCSSAnonBoxes13mozTreeColumnE"]
+            pub static nsCSSAnonBoxes_mozTreeColumn: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "_ZN14nsCSSAnonBoxes10mozTreeRowE"]
+            pub static nsCSSAnonBoxes_mozTreeRow: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "_ZN14nsCSSAnonBoxes16mozTreeSeparatorE"]
+            pub static nsCSSAnonBoxes_mozTreeSeparator: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "_ZN14nsCSSAnonBoxes11mozTreeCellE"]
+            pub static nsCSSAnonBoxes_mozTreeCell: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "_ZN14nsCSSAnonBoxes18mozTreeIndentationE"]
+            pub static nsCSSAnonBoxes_mozTreeIndentation: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "_ZN14nsCSSAnonBoxes11mozTreeLineE"]
+            pub static nsCSSAnonBoxes_mozTreeLine: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "_ZN14nsCSSAnonBoxes13mozTreeTwistyE"]
+            pub static nsCSSAnonBoxes_mozTreeTwisty: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "_ZN14nsCSSAnonBoxes12mozTreeImageE"]
+            pub static nsCSSAnonBoxes_mozTreeImage: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "_ZN14nsCSSAnonBoxes15mozTreeCellTextE"]
+            pub static nsCSSAnonBoxes_mozTreeCellText: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "_ZN14nsCSSAnonBoxes15mozTreeCheckboxE"]
+            pub static nsCSSAnonBoxes_mozTreeCheckbox: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "_ZN14nsCSSAnonBoxes20mozTreeProgressmeterE"]
+            pub static nsCSSAnonBoxes_mozTreeProgressmeter: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "_ZN14nsCSSAnonBoxes19mozTreeDropFeedbackE"]
+            pub static nsCSSAnonBoxes_mozTreeDropFeedback: *mut nsICSSAnonBoxPseudo;
             #[link_name = "_ZN14nsCSSAnonBoxes21mozSVGMarkerAnonChildE"]
             pub static nsCSSAnonBoxes_mozSVGMarkerAnonChild: *mut nsICSSAnonBoxPseudo;
             #[link_name = "_ZN14nsCSSAnonBoxes23mozSVGOuterSVGAnonChildE"]
             pub static nsCSSAnonBoxes_mozSVGOuterSVGAnonChild: *mut nsICSSAnonBoxPseudo;
             #[link_name = "_ZN14nsCSSAnonBoxes20mozSVGForeignContentE"]
             pub static nsCSSAnonBoxes_mozSVGForeignContent: *mut nsICSSAnonBoxPseudo;
             #[link_name = "_ZN14nsCSSAnonBoxes10mozSVGTextE"]
             pub static nsCSSAnonBoxes_mozSVGText: *mut nsICSSAnonBoxPseudo;
@@ -10238,40 +10238,40 @@ cfg_if! {
             #[link_name = "?rubyBase@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
             pub static nsCSSAnonBoxes_rubyBase: *mut nsICSSAnonBoxPseudo;
             #[link_name = "?rubyBaseContainer@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
             pub static nsCSSAnonBoxes_rubyBaseContainer: *mut nsICSSAnonBoxPseudo;
             #[link_name = "?rubyText@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
             pub static nsCSSAnonBoxes_rubyText: *mut nsICSSAnonBoxPseudo;
             #[link_name = "?rubyTextContainer@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
             pub static nsCSSAnonBoxes_rubyTextContainer: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "?moztreecolumn@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
-            pub static nsCSSAnonBoxes_moztreecolumn: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "?moztreerow@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
-            pub static nsCSSAnonBoxes_moztreerow: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "?moztreeseparator@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
-            pub static nsCSSAnonBoxes_moztreeseparator: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "?moztreecell@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
-            pub static nsCSSAnonBoxes_moztreecell: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "?moztreeindentation@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
-            pub static nsCSSAnonBoxes_moztreeindentation: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "?moztreeline@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
-            pub static nsCSSAnonBoxes_moztreeline: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "?moztreetwisty@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
-            pub static nsCSSAnonBoxes_moztreetwisty: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "?moztreeimage@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
-            pub static nsCSSAnonBoxes_moztreeimage: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "?moztreecelltext@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
-            pub static nsCSSAnonBoxes_moztreecelltext: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "?moztreecheckbox@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
-            pub static nsCSSAnonBoxes_moztreecheckbox: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "?moztreeprogressmeter@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
-            pub static nsCSSAnonBoxes_moztreeprogressmeter: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "?moztreedropfeedback@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
-            pub static nsCSSAnonBoxes_moztreedropfeedback: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "?mozTreeColumn@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
+            pub static nsCSSAnonBoxes_mozTreeColumn: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "?mozTreeRow@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
+            pub static nsCSSAnonBoxes_mozTreeRow: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "?mozTreeSeparator@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
+            pub static nsCSSAnonBoxes_mozTreeSeparator: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "?mozTreeCell@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
+            pub static nsCSSAnonBoxes_mozTreeCell: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "?mozTreeIndentation@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
+            pub static nsCSSAnonBoxes_mozTreeIndentation: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "?mozTreeLine@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
+            pub static nsCSSAnonBoxes_mozTreeLine: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "?mozTreeTwisty@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
+            pub static nsCSSAnonBoxes_mozTreeTwisty: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "?mozTreeImage@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
+            pub static nsCSSAnonBoxes_mozTreeImage: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "?mozTreeCellText@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
+            pub static nsCSSAnonBoxes_mozTreeCellText: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "?mozTreeCheckbox@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
+            pub static nsCSSAnonBoxes_mozTreeCheckbox: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "?mozTreeProgressmeter@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
+            pub static nsCSSAnonBoxes_mozTreeProgressmeter: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "?mozTreeDropFeedback@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
+            pub static nsCSSAnonBoxes_mozTreeDropFeedback: *mut nsICSSAnonBoxPseudo;
             #[link_name = "?mozSVGMarkerAnonChild@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
             pub static nsCSSAnonBoxes_mozSVGMarkerAnonChild: *mut nsICSSAnonBoxPseudo;
             #[link_name = "?mozSVGOuterSVGAnonChild@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
             pub static nsCSSAnonBoxes_mozSVGOuterSVGAnonChild: *mut nsICSSAnonBoxPseudo;
             #[link_name = "?mozSVGForeignContent@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
             pub static nsCSSAnonBoxes_mozSVGForeignContent: *mut nsICSSAnonBoxPseudo;
             #[link_name = "?mozSVGText@nsCSSAnonBoxes@@2PEAVnsICSSAnonBoxPseudo@@EA"]
             pub static nsCSSAnonBoxes_mozSVGText: *mut nsICSSAnonBoxPseudo;
@@ -15367,40 +15367,40 @@ cfg_if! {
             #[link_name = "\x01?rubyBase@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
             pub static nsCSSAnonBoxes_rubyBase: *mut nsICSSAnonBoxPseudo;
             #[link_name = "\x01?rubyBaseContainer@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
             pub static nsCSSAnonBoxes_rubyBaseContainer: *mut nsICSSAnonBoxPseudo;
             #[link_name = "\x01?rubyText@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
             pub static nsCSSAnonBoxes_rubyText: *mut nsICSSAnonBoxPseudo;
             #[link_name = "\x01?rubyTextContainer@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
             pub static nsCSSAnonBoxes_rubyTextContainer: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "\x01?moztreecolumn@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
-            pub static nsCSSAnonBoxes_moztreecolumn: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "\x01?moztreerow@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
-            pub static nsCSSAnonBoxes_moztreerow: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "\x01?moztreeseparator@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
-            pub static nsCSSAnonBoxes_moztreeseparator: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "\x01?moztreecell@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
-            pub static nsCSSAnonBoxes_moztreecell: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "\x01?moztreeindentation@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
-            pub static nsCSSAnonBoxes_moztreeindentation: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "\x01?moztreeline@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
-            pub static nsCSSAnonBoxes_moztreeline: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "\x01?moztreetwisty@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
-            pub static nsCSSAnonBoxes_moztreetwisty: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "\x01?moztreeimage@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
-            pub static nsCSSAnonBoxes_moztreeimage: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "\x01?moztreecelltext@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
-            pub static nsCSSAnonBoxes_moztreecelltext: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "\x01?moztreecheckbox@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
-            pub static nsCSSAnonBoxes_moztreecheckbox: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "\x01?moztreeprogressmeter@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
-            pub static nsCSSAnonBoxes_moztreeprogressmeter: *mut nsICSSAnonBoxPseudo;
-            #[link_name = "\x01?moztreedropfeedback@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
-            pub static nsCSSAnonBoxes_moztreedropfeedback: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "\x01?mozTreeColumn@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
+            pub static nsCSSAnonBoxes_mozTreeColumn: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "\x01?mozTreeRow@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
+            pub static nsCSSAnonBoxes_mozTreeRow: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "\x01?mozTreeSeparator@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
+            pub static nsCSSAnonBoxes_mozTreeSeparator: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "\x01?mozTreeCell@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
+            pub static nsCSSAnonBoxes_mozTreeCell: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "\x01?mozTreeIndentation@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
+            pub static nsCSSAnonBoxes_mozTreeIndentation: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "\x01?mozTreeLine@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
+            pub static nsCSSAnonBoxes_mozTreeLine: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "\x01?mozTreeTwisty@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
+            pub static nsCSSAnonBoxes_mozTreeTwisty: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "\x01?mozTreeImage@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
+            pub static nsCSSAnonBoxes_mozTreeImage: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "\x01?mozTreeCellText@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
+            pub static nsCSSAnonBoxes_mozTreeCellText: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "\x01?mozTreeCheckbox@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
+            pub static nsCSSAnonBoxes_mozTreeCheckbox: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "\x01?mozTreeProgressmeter@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
+            pub static nsCSSAnonBoxes_mozTreeProgressmeter: *mut nsICSSAnonBoxPseudo;
+            #[link_name = "\x01?mozTreeDropFeedback@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
+            pub static nsCSSAnonBoxes_mozTreeDropFeedback: *mut nsICSSAnonBoxPseudo;
             #[link_name = "\x01?mozSVGMarkerAnonChild@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
             pub static nsCSSAnonBoxes_mozSVGMarkerAnonChild: *mut nsICSSAnonBoxPseudo;
             #[link_name = "\x01?mozSVGOuterSVGAnonChild@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
             pub static nsCSSAnonBoxes_mozSVGOuterSVGAnonChild: *mut nsICSSAnonBoxPseudo;
             #[link_name = "\x01?mozSVGForeignContent@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
             pub static nsCSSAnonBoxes_mozSVGForeignContent: *mut nsICSSAnonBoxPseudo;
             #[link_name = "\x01?mozSVGText@nsCSSAnonBoxes@@2PAVnsICSSAnonBoxPseudo@@A"]
             pub static nsCSSAnonBoxes_mozSVGText: *mut nsICSSAnonBoxPseudo;
@@ -20500,39 +20500,39 @@ macro_rules! atom {
   { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_rubyBase as *mut _) } };
 (":-moz-ruby-base-container") =>
   { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_rubyBaseContainer as *mut _) } };
 (":-moz-ruby-text") =>
   { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_rubyText as *mut _) } };
 (":-moz-ruby-text-container") =>
   { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_rubyTextContainer as *mut _) } };
 (":-moz-tree-column") =>
-  { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_moztreecolumn as *mut _) } };
+  { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_mozTreeColumn as *mut _) } };
 (":-moz-tree-row") =>
-  { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_moztreerow as *mut _) } };
+  { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_mozTreeRow as *mut _) } };
 (":-moz-tree-separator") =>
-  { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_moztreeseparator as *mut _) } };
+  { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_mozTreeSeparator as *mut _) } };
 (":-moz-tree-cell") =>
-  { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_moztreecell as *mut _) } };
+  { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_mozTreeCell as *mut _) } };
 (":-moz-tree-indentation") =>
-  { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_moztreeindentation as *mut _) } };
+  { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_mozTreeIndentation as *mut _) } };
 (":-moz-tree-line") =>
-  { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_moztreeline as *mut _) } };
+  { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_mozTreeLine as *mut _) } };
 (":-moz-tree-twisty") =>
-  { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_moztreetwisty as *mut _) } };
+  { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_mozTreeTwisty as *mut _) } };
 (":-moz-tree-image") =>
-  { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_moztreeimage as *mut _) } };
+  { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_mozTreeImage as *mut _) } };
 (":-moz-tree-cell-text") =>
-  { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_moztreecelltext as *mut _) } };
+  { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_mozTreeCellText as *mut _) } };
 (":-moz-tree-checkbox") =>
-  { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_moztreecheckbox as *mut _) } };
+  { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_mozTreeCheckbox as *mut _) } };
 (":-moz-tree-progressmeter") =>
-  { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_moztreeprogressmeter as *mut _) } };
+  { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_mozTreeProgressmeter as *mut _) } };
 (":-moz-tree-drop-feedback") =>
-  { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_moztreedropfeedback as *mut _) } };
+  { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_mozTreeDropFeedback as *mut _) } };
 (":-moz-svg-marker-anon-child") =>
   { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_mozSVGMarkerAnonChild as *mut _) } };
 (":-moz-svg-outer-svg-anon-child") =>
   { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_mozSVGOuterSVGAnonChild as *mut _) } };
 (":-moz-svg-foreign-content") =>
   { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_mozSVGForeignContent as *mut _) } };
 (":-moz-svg-text") =>
   { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsCSSAnonBoxes_mozSVGText as *mut _) } };
--- a/servo/components/style/gecko/generated/pseudo_element_definition.rs
+++ b/servo/components/style/gecko/generated/pseudo_element_definition.rs
@@ -135,39 +135,39 @@ pub enum PseudoElement {
         RubyBase,
         /// :-moz-ruby-base-container
         RubyBaseContainer,
         /// :-moz-ruby-text
         RubyText,
         /// :-moz-ruby-text-container
         RubyTextContainer,
         /// :-moz-tree-column
-        Moztreecolumn,
+        MozTreeColumn(Box<[String]>),
         /// :-moz-tree-row
-        Moztreerow,
+        MozTreeRow(Box<[String]>),
         /// :-moz-tree-separator
-        Moztreeseparator,
+        MozTreeSeparator(Box<[String]>),
         /// :-moz-tree-cell
-        Moztreecell,
+        MozTreeCell(Box<[String]>),
         /// :-moz-tree-indentation
-        Moztreeindentation,
+        MozTreeIndentation(Box<[String]>),
         /// :-moz-tree-line
-        Moztreeline,
+        MozTreeLine(Box<[String]>),
         /// :-moz-tree-twisty
-        Moztreetwisty,
+        MozTreeTwisty(Box<[String]>),
         /// :-moz-tree-image
-        Moztreeimage,
+        MozTreeImage(Box<[String]>),
         /// :-moz-tree-cell-text
-        Moztreecelltext,
+        MozTreeCellText(Box<[String]>),
         /// :-moz-tree-checkbox
-        Moztreecheckbox,
+        MozTreeCheckbox(Box<[String]>),
         /// :-moz-tree-progressmeter
-        Moztreeprogressmeter,
+        MozTreeProgressmeter(Box<[String]>),
         /// :-moz-tree-drop-feedback
-        Moztreedropfeedback,
+        MozTreeDropFeedback(Box<[String]>),
         /// :-moz-svg-marker-anon-child
         MozSVGMarkerAnonChild,
         /// :-moz-svg-outer-svg-anon-child
         MozSVGOuterSVGAnonChild,
         /// :-moz-svg-foreign-content
         MozSVGForeignContent,
         /// :-moz-svg-text
         MozSVGText,
@@ -181,19 +181,25 @@ pub const EAGER_PSEUDO_COUNT: usize = 4;
 /// The list of eager pseudos.
 pub const EAGER_PSEUDOS: [PseudoElement; EAGER_PSEUDO_COUNT] = [
     PseudoElement::Before,
     PseudoElement::After,
     PseudoElement::FirstLine,
     PseudoElement::FirstLetter,
 ];
 
+
+
+
+
+
 impl PseudoElement {
-    /// Executes a closure with each pseudo-element as an argument.
-    pub fn each<F>(mut fun: F)
+    /// Executes a closure with each simple (not functional)
+    /// pseudo-element as an argument.
+    pub fn each_simple<F>(mut fun: F)
         where F: FnMut(Self),
     {
             fun(PseudoElement::After);
             fun(PseudoElement::Before);
             fun(PseudoElement::Backdrop);
             fun(PseudoElement::Cue);
             fun(PseudoElement::FirstLetter);
             fun(PseudoElement::FirstLine);
@@ -253,28 +259,16 @@ impl PseudoElement {
             fun(PseudoElement::ViewportScroll);
             fun(PseudoElement::AnonymousFlexItem);
             fun(PseudoElement::AnonymousGridItem);
             fun(PseudoElement::Ruby);
             fun(PseudoElement::RubyBase);
             fun(PseudoElement::RubyBaseContainer);
             fun(PseudoElement::RubyText);
             fun(PseudoElement::RubyTextContainer);
-            fun(PseudoElement::Moztreecolumn);
-            fun(PseudoElement::Moztreerow);
-            fun(PseudoElement::Moztreeseparator);
-            fun(PseudoElement::Moztreecell);
-            fun(PseudoElement::Moztreeindentation);
-            fun(PseudoElement::Moztreeline);
-            fun(PseudoElement::Moztreetwisty);
-            fun(PseudoElement::Moztreeimage);
-            fun(PseudoElement::Moztreecelltext);
-            fun(PseudoElement::Moztreecheckbox);
-            fun(PseudoElement::Moztreeprogressmeter);
-            fun(PseudoElement::Moztreedropfeedback);
             fun(PseudoElement::MozSVGMarkerAnonChild);
             fun(PseudoElement::MozSVGOuterSVGAnonChild);
             fun(PseudoElement::MozSVGForeignContent);
             fun(PseudoElement::MozSVGText);
     }
 
     /// Get the pseudo-element as an atom.
     #[inline]
@@ -342,385 +336,278 @@ impl PseudoElement {
                 PseudoElement::ViewportScroll => atom!(":-moz-viewport-scroll"),
                 PseudoElement::AnonymousFlexItem => atom!(":-moz-anonymous-flex-item"),
                 PseudoElement::AnonymousGridItem => atom!(":-moz-anonymous-grid-item"),
                 PseudoElement::Ruby => atom!(":-moz-ruby"),
                 PseudoElement::RubyBase => atom!(":-moz-ruby-base"),
                 PseudoElement::RubyBaseContainer => atom!(":-moz-ruby-base-container"),
                 PseudoElement::RubyText => atom!(":-moz-ruby-text"),
                 PseudoElement::RubyTextContainer => atom!(":-moz-ruby-text-container"),
-                PseudoElement::Moztreecolumn => atom!(":-moz-tree-column"),
-                PseudoElement::Moztreerow => atom!(":-moz-tree-row"),
-                PseudoElement::Moztreeseparator => atom!(":-moz-tree-separator"),
-                PseudoElement::Moztreecell => atom!(":-moz-tree-cell"),
-                PseudoElement::Moztreeindentation => atom!(":-moz-tree-indentation"),
-                PseudoElement::Moztreeline => atom!(":-moz-tree-line"),
-                PseudoElement::Moztreetwisty => atom!(":-moz-tree-twisty"),
-                PseudoElement::Moztreeimage => atom!(":-moz-tree-image"),
-                PseudoElement::Moztreecelltext => atom!(":-moz-tree-cell-text"),
-                PseudoElement::Moztreecheckbox => atom!(":-moz-tree-checkbox"),
-                PseudoElement::Moztreeprogressmeter => atom!(":-moz-tree-progressmeter"),
-                PseudoElement::Moztreedropfeedback => atom!(":-moz-tree-drop-feedback"),
+                PseudoElement::MozTreeColumn(..) => atom!(":-moz-tree-column"),
+                PseudoElement::MozTreeRow(..) => atom!(":-moz-tree-row"),
+                PseudoElement::MozTreeSeparator(..) => atom!(":-moz-tree-separator"),
+                PseudoElement::MozTreeCell(..) => atom!(":-moz-tree-cell"),
+                PseudoElement::MozTreeIndentation(..) => atom!(":-moz-tree-indentation"),
+                PseudoElement::MozTreeLine(..) => atom!(":-moz-tree-line"),
+                PseudoElement::MozTreeTwisty(..) => atom!(":-moz-tree-twisty"),
+                PseudoElement::MozTreeImage(..) => atom!(":-moz-tree-image"),
+                PseudoElement::MozTreeCellText(..) => atom!(":-moz-tree-cell-text"),
+                PseudoElement::MozTreeCheckbox(..) => atom!(":-moz-tree-checkbox"),
+                PseudoElement::MozTreeProgressmeter(..) => atom!(":-moz-tree-progressmeter"),
+                PseudoElement::MozTreeDropFeedback(..) => atom!(":-moz-tree-drop-feedback"),
                 PseudoElement::MozSVGMarkerAnonChild => atom!(":-moz-svg-marker-anon-child"),
                 PseudoElement::MozSVGOuterSVGAnonChild => atom!(":-moz-svg-outer-svg-anon-child"),
                 PseudoElement::MozSVGForeignContent => atom!(":-moz-svg-foreign-content"),
                 PseudoElement::MozSVGText => atom!(":-moz-svg-text"),
         }
     }
 
     /// Whether this pseudo-element is an anonymous box.
     #[inline]
     fn is_anon_box(&self) -> bool {
         match *self {
-                PseudoElement::After => false,
-                PseudoElement::Before => false,
-                PseudoElement::Backdrop => false,
-                PseudoElement::Cue => false,
-                PseudoElement::FirstLetter => false,
-                PseudoElement::FirstLine => false,
-                PseudoElement::MozSelection => false,
-                PseudoElement::MozFocusInner => false,
-                PseudoElement::MozFocusOuter => false,
-                PseudoElement::MozListBullet => false,
-                PseudoElement::MozListNumber => false,
-                PseudoElement::MozMathAnonymous => false,
-                PseudoElement::MozNumberWrapper => false,
-                PseudoElement::MozNumberText => false,
-                PseudoElement::MozNumberSpinBox => false,
-                PseudoElement::MozNumberSpinUp => false,
-                PseudoElement::MozNumberSpinDown => false,
-                PseudoElement::MozProgressBar => false,
-                PseudoElement::MozRangeTrack => false,
-                PseudoElement::MozRangeProgress => false,
-                PseudoElement::MozRangeThumb => false,
-                PseudoElement::MozMeterBar => false,
-                PseudoElement::MozPlaceholder => false,
-                PseudoElement::Placeholder => false,
-                PseudoElement::MozColorSwatch => false,
-                PseudoElement::MozText => true,
-                PseudoElement::OofPlaceholder => true,
-                PseudoElement::FirstLetterContinuation => true,
-                PseudoElement::MozBlockInsideInlineWrapper => true,
-                PseudoElement::MozMathMLAnonymousBlock => true,
-                PseudoElement::MozXULAnonymousBlock => true,
-                PseudoElement::HorizontalFramesetBorder => true,
-                PseudoElement::VerticalFramesetBorder => true,
-                PseudoElement::MozLineFrame => true,
-                PseudoElement::ButtonContent => true,
-                PseudoElement::CellContent => true,
-                PseudoElement::DropDownList => true,
-                PseudoElement::FieldsetContent => true,
-                PseudoElement::FramesetBlank => true,
-                PseudoElement::MozDisplayComboboxControlFrame => true,
-                PseudoElement::HtmlCanvasContent => true,
-                PseudoElement::InlineTable => true,
-                PseudoElement::Table => true,
-                PseudoElement::TableCell => true,
-                PseudoElement::TableColGroup => true,
-                PseudoElement::TableCol => true,
-                PseudoElement::TableWrapper => true,
-                PseudoElement::TableRowGroup => true,
-                PseudoElement::TableRow => true,
-                PseudoElement::Canvas => true,
-                PseudoElement::PageBreak => true,
-                PseudoElement::Page => true,
-                PseudoElement::PageContent => true,
-                PseudoElement::PageSequence => true,
-                PseudoElement::ScrolledContent => true,
-                PseudoElement::ScrolledCanvas => true,
-                PseudoElement::ScrolledPageSequence => true,
-                PseudoElement::ColumnContent => true,
-                PseudoElement::Viewport => true,
-                PseudoElement::ViewportScroll => true,
-                PseudoElement::AnonymousFlexItem => true,
-                PseudoElement::AnonymousGridItem => true,
-                PseudoElement::Ruby => true,
-                PseudoElement::RubyBase => true,
-                PseudoElement::RubyBaseContainer => true,
-                PseudoElement::RubyText => true,
-                PseudoElement::RubyTextContainer => true,
-                PseudoElement::Moztreecolumn => true,
-                PseudoElement::Moztreerow => true,
-                PseudoElement::Moztreeseparator => true,
-                PseudoElement::Moztreecell => true,
-                PseudoElement::Moztreeindentation => true,
-                PseudoElement::Moztreeline => true,
-                PseudoElement::Moztreetwisty => true,
-                PseudoElement::Moztreeimage => true,
-                PseudoElement::Moztreecelltext => true,
-                PseudoElement::Moztreecheckbox => true,
-                PseudoElement::Moztreeprogressmeter => true,
-                PseudoElement::Moztreedropfeedback => true,
-                PseudoElement::MozSVGMarkerAnonChild => true,
-                PseudoElement::MozSVGOuterSVGAnonChild => true,
-                PseudoElement::MozSVGForeignContent => true,
-                PseudoElement::MozSVGText => true,
+                    PseudoElement::MozText => true,
+                    PseudoElement::OofPlaceholder => true,
+                    PseudoElement::FirstLetterContinuation => true,
+                    PseudoElement::MozBlockInsideInlineWrapper => true,
+                    PseudoElement::MozMathMLAnonymousBlock => true,
+                    PseudoElement::MozXULAnonymousBlock => true,
+                    PseudoElement::HorizontalFramesetBorder => true,
+                    PseudoElement::VerticalFramesetBorder => true,
+                    PseudoElement::MozLineFrame => true,
+                    PseudoElement::ButtonContent => true,
+                    PseudoElement::CellContent => true,
+                    PseudoElement::DropDownList => true,
+                    PseudoElement::FieldsetContent => true,
+                    PseudoElement::FramesetBlank => true,
+                    PseudoElement::MozDisplayComboboxControlFrame => true,
+                    PseudoElement::HtmlCanvasContent => true,
+                    PseudoElement::InlineTable => true,
+                    PseudoElement::Table => true,
+                    PseudoElement::TableCell => true,
+                    PseudoElement::TableColGroup => true,
+                    PseudoElement::TableCol => true,
+                    PseudoElement::TableWrapper => true,
+                    PseudoElement::TableRowGroup => true,
+                    PseudoElement::TableRow => true,
+                    PseudoElement::Canvas => true,
+                    PseudoElement::PageBreak => true,
+                    PseudoElement::Page => true,
+                    PseudoElement::PageContent => true,
+                    PseudoElement::PageSequence => true,
+                    PseudoElement::ScrolledContent => true,
+                    PseudoElement::ScrolledCanvas => true,
+                    PseudoElement::ScrolledPageSequence => true,
+                    PseudoElement::ColumnContent => true,
+                    PseudoElement::Viewport => true,
+                    PseudoElement::ViewportScroll => true,
+                    PseudoElement::AnonymousFlexItem => true,
+                    PseudoElement::AnonymousGridItem => true,
+                    PseudoElement::Ruby => true,
+                    PseudoElement::RubyBase => true,
+                    PseudoElement::RubyBaseContainer => true,
+                    PseudoElement::RubyText => true,
+                    PseudoElement::RubyTextContainer => true,
+                    PseudoElement::MozTreeColumn(..) => true,
+                    PseudoElement::MozTreeRow(..) => true,
+                    PseudoElement::MozTreeSeparator(..) => true,
+                    PseudoElement::MozTreeCell(..) => true,
+                    PseudoElement::MozTreeIndentation(..) => true,
+                    PseudoElement::MozTreeLine(..) => true,
+                    PseudoElement::MozTreeTwisty(..) => true,
+                    PseudoElement::MozTreeImage(..) => true,
+                    PseudoElement::MozTreeCellText(..) => true,
+                    PseudoElement::MozTreeCheckbox(..) => true,
+                    PseudoElement::MozTreeProgressmeter(..) => true,
+                    PseudoElement::MozTreeDropFeedback(..) => true,
+                    PseudoElement::MozSVGMarkerAnonChild => true,
+                    PseudoElement::MozSVGOuterSVGAnonChild => true,
+                    PseudoElement::MozSVGForeignContent => true,
+                    PseudoElement::MozSVGText => true,
+            _ => false,
         }
     }
 
     /// Whether this pseudo-element is eagerly-cascaded.
     #[inline]
     pub fn is_eager(&self) -> bool {
         matches!(*self,
                  PseudoElement::Before | PseudoElement::After | PseudoElement::FirstLine | PseudoElement::FirstLetter)
     }
 
     /// Gets the flags associated to this pseudo-element, or 0 if it's an
     /// anonymous box.
     pub fn flags(&self) -> u32 {
         match *self {
-                PseudoElement::After => {
-                        structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_after
-                }
-                PseudoElement::Before => {
-                        structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_before
-                }
-                PseudoElement::Backdrop => {
-                        structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_backdrop
-                }
-                PseudoElement::Cue => {
-                        structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_cue
-                }
-                PseudoElement::FirstLetter => {
-                        structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_firstLetter
-                }
-                PseudoElement::FirstLine => {
-                        structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_firstLine
-                }
-                PseudoElement::MozSelection => {
-                        structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozSelection
-                }
-                PseudoElement::MozFocusInner => {
-                        structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozFocusInner
-                }
-                PseudoElement::MozFocusOuter => {
-                        structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozFocusOuter
-                }
-                PseudoElement::MozListBullet => {
-                        structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozListBullet
-                }
-                PseudoElement::MozListNumber => {
-                        structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozListNumber
-                }
-                PseudoElement::MozMathAnonymous => {
-                        structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozMathAnonymous
-                }
-                PseudoElement::MozNumberWrapper => {
-                        structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozNumberWrapper
-                }
-                PseudoElement::MozNumberText => {
-                        structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozNumberText
-                }
-                PseudoElement::MozNumberSpinBox => {
-                        structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozNumberSpinBox
-                }
-                PseudoElement::MozNumberSpinUp => {
-                        structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozNumberSpinUp
-                }
-                PseudoElement::MozNumberSpinDown => {
-                        structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozNumberSpinDown
-                }
-                PseudoElement::MozProgressBar => {
-                        structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozProgressBar
-                }
-                PseudoElement::MozRangeTrack => {
-                        structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozRangeTrack
-                }
-                PseudoElement::MozRangeProgress => {
-                        structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozRangeProgress
-                }
-                PseudoElement::MozRangeThumb => {
-                        structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozRangeThumb
-                }
-                PseudoElement::MozMeterBar => {
-                        structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozMeterBar
-                }
-                PseudoElement::MozPlaceholder => {
-                        structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozPlaceholder
-                }
-                PseudoElement::Placeholder => {
-                        structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_placeholder
-                }
-                PseudoElement::MozColorSwatch => {
-                        structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozColorSwatch
-                }
-                PseudoElement::MozText => {
-                        0
-                }
-                PseudoElement::OofPlaceholder => {
-                        0
-                }
-                PseudoElement::FirstLetterContinuation => {
-                        0
-                }
-                PseudoElement::MozBlockInsideInlineWrapper => {
-                        0
-                }
-                PseudoElement::MozMathMLAnonymousBlock => {
-                        0
-                }
-                PseudoElement::MozXULAnonymousBlock => {
-                        0
-                }
-                PseudoElement::HorizontalFramesetBorder => {
-                        0
-                }
-                PseudoElement::VerticalFramesetBorder => {
-                        0
-                }
-                PseudoElement::MozLineFrame => {
-                        0
-                }
-                PseudoElement::ButtonContent => {
-                        0
-                }
-                PseudoElement::CellContent => {
-                        0
-                }
-                PseudoElement::DropDownList => {
-                        0
-                }
-                PseudoElement::FieldsetContent => {
-                        0
-                }
-                PseudoElement::FramesetBlank => {
-                        0
-                }
-                PseudoElement::MozDisplayComboboxControlFrame => {
-                        0
-                }
-                PseudoElement::HtmlCanvasContent => {
-                        0
-                }
-                PseudoElement::InlineTable => {
-                        0
-                }
-                PseudoElement::Table => {
-                        0
-                }
-                PseudoElement::TableCell => {
-                        0
-                }
-                PseudoElement::TableColGroup => {
-                        0
-                }
-                PseudoElement::TableCol => {
-                        0
-                }
-                PseudoElement::TableWrapper => {
-                        0
-                }
-                PseudoElement::TableRowGroup => {
-                        0
-                }
-                PseudoElement::TableRow => {
-                        0
-                }
-                PseudoElement::Canvas => {
-                        0
-                }
-                PseudoElement::PageBreak => {
-                        0
-                }
-                PseudoElement::Page => {
-                        0
-                }
-                PseudoElement::PageContent => {
-                        0
-                }
-                PseudoElement::PageSequence => {
-                        0
-                }
-                PseudoElement::ScrolledContent => {
-                        0
-                }
-                PseudoElement::ScrolledCanvas => {
-                        0
-                }
-                PseudoElement::ScrolledPageSequence => {
-                        0
-                }
-                PseudoElement::ColumnContent => {
-                        0
-                }
-                PseudoElement::Viewport => {
-                        0
-                }
-                PseudoElement::ViewportScroll => {
-                        0
-                }
-                PseudoElement::AnonymousFlexItem => {
-                        0
-                }
-                PseudoElement::AnonymousGridItem => {
-                        0
-                }
-                PseudoElement::Ruby => {
-                        0
-                }
-                PseudoElement::RubyBase => {
-                        0
-                }
-                PseudoElement::RubyBaseContainer => {
-                        0
-                }
-                PseudoElement::RubyText => {
-                        0
-                }
-                PseudoElement::RubyTextContainer => {
-                        0
-                }
-                PseudoElement::Moztreecolumn => {
-                        0
-                }
-                PseudoElement::Moztreerow => {
-                        0
-                }
-                PseudoElement::Moztreeseparator => {
-                        0
-                }
-                PseudoElement::Moztreecell => {
-                        0
-                }
-                PseudoElement::Moztreeindentation => {
-                        0
-                }
-                PseudoElement::Moztreeline => {
-                        0
-                }
-                PseudoElement::Moztreetwisty => {
-                        0
-                }
-                PseudoElement::Moztreeimage => {
-                        0
-                }
-                PseudoElement::Moztreecelltext => {
-                        0
-                }
-                PseudoElement::Moztreecheckbox => {
-                        0
-                }
-                PseudoElement::Moztreeprogressmeter => {
-                        0
-                }
-                PseudoElement::Moztreedropfeedback => {
-                        0
-                }
-                PseudoElement::MozSVGMarkerAnonChild => {
-                        0
-                }
-                PseudoElement::MozSVGOuterSVGAnonChild => {
-                        0
-                }
-                PseudoElement::MozSVGForeignContent => {
-                        0
-                }
-                PseudoElement::MozSVGText => {
-                        0
-                }
+                PseudoElement::After =>
+                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_after,
+                PseudoElement::Before =>
+                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_before,
+                PseudoElement::Backdrop =>
+                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_backdrop,
+                PseudoElement::Cue =>
+                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_cue,
+                PseudoElement::FirstLetter =>
+                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_firstLetter,
+                PseudoElement::FirstLine =>
+                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_firstLine,
+                PseudoElement::MozSelection =>
+                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozSelection,
+                PseudoElement::MozFocusInner =>
+                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozFocusInner,
+                PseudoElement::MozFocusOuter =>
+                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozFocusOuter,
+                PseudoElement::MozListBullet =>
+                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozListBullet,
+                PseudoElement::MozListNumber =>
+                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozListNumber,
+                PseudoElement::MozMathAnonymous =>
+                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozMathAnonymous,
+                PseudoElement::MozNumberWrapper =>
+                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozNumberWrapper,
+                PseudoElement::MozNumberText =>
+                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozNumberText,
+                PseudoElement::MozNumberSpinBox =>
+                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozNumberSpinBox,
+                PseudoElement::MozNumberSpinUp =>
+                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozNumberSpinUp,
+                PseudoElement::MozNumberSpinDown =>
+                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozNumberSpinDown,
+                PseudoElement::MozProgressBar =>
+                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozProgressBar,
+                PseudoElement::MozRangeTrack =>
+                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozRangeTrack,
+                PseudoElement::MozRangeProgress =>
+                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozRangeProgress,
+                PseudoElement::MozRangeThumb =>
+                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozRangeThumb,
+                PseudoElement::MozMeterBar =>
+                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozMeterBar,
+                PseudoElement::MozPlaceholder =>
+                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozPlaceholder,
+                PseudoElement::Placeholder =>
+                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_placeholder,
+                PseudoElement::MozColorSwatch =>
+                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_mozColorSwatch,
+                PseudoElement::MozText =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::OofPlaceholder =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::FirstLetterContinuation =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::MozBlockInsideInlineWrapper =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::MozMathMLAnonymousBlock =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::MozXULAnonymousBlock =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::HorizontalFramesetBorder =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::VerticalFramesetBorder =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::MozLineFrame =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::ButtonContent =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::CellContent =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::DropDownList =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::FieldsetContent =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::FramesetBlank =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::MozDisplayComboboxControlFrame =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::HtmlCanvasContent =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::InlineTable =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::Table =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::TableCell =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::TableColGroup =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::TableCol =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::TableWrapper =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::TableRowGroup =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::TableRow =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::Canvas =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::PageBreak =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::Page =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::PageContent =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::PageSequence =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::ScrolledContent =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::ScrolledCanvas =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::ScrolledPageSequence =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::ColumnContent =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::Viewport =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::ViewportScroll =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::AnonymousFlexItem =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::AnonymousGridItem =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::Ruby =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::RubyBase =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::RubyBaseContainer =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::RubyText =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::RubyTextContainer =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::MozTreeColumn(..) =>
+                    0,
+                PseudoElement::MozTreeRow(..) =>
+                    0,
+                PseudoElement::MozTreeSeparator(..) =>
+                    0,
+                PseudoElement::MozTreeCell(..) =>
+                    0,
+                PseudoElement::MozTreeIndentation(..) =>
+                    0,
+                PseudoElement::MozTreeLine(..) =>
+                    0,
+                PseudoElement::MozTreeTwisty(..) =>
+                    0,
+                PseudoElement::MozTreeImage(..) =>
+                    0,
+                PseudoElement::MozTreeCellText(..) =>
+                    0,
+                PseudoElement::MozTreeCheckbox(..) =>
+                    0,
+                PseudoElement::MozTreeProgressmeter(..) =>
+                    0,
+                PseudoElement::MozTreeDropFeedback(..) =>
+                    0,
+                PseudoElement::MozSVGMarkerAnonChild =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::MozSVGOuterSVGAnonChild =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::MozSVGForeignContent =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                PseudoElement::MozSVGText =>
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
         }
     }
 
     /// Construct a pseudo-element from a `CSSPseudoElementType`.
     #[inline]
     pub fn from_pseudo_type(type_: CSSPseudoElementType) -> Option<Self> {
         match type_ {
                     CSSPseudoElementType::after => {
@@ -926,52 +813,28 @@ impl PseudoElement {
                     return Some(PseudoElement::RubyBaseContainer);
                 }
                 if atom == &atom!(":-moz-ruby-text") {
                     return Some(PseudoElement::RubyText);
                 }
                 if atom == &atom!(":-moz-ruby-text-container") {
                     return Some(PseudoElement::RubyTextContainer);
                 }
-                if atom == &atom!(":-moz-tree-column") {
-                    return Some(PseudoElement::Moztreecolumn);
-                }
-                if atom == &atom!(":-moz-tree-row") {
-                    return Some(PseudoElement::Moztreerow);
-                }
-                if atom == &atom!(":-moz-tree-separator") {
-                    return Some(PseudoElement::Moztreeseparator);
-                }
-                if atom == &atom!(":-moz-tree-cell") {
-                    return Some(PseudoElement::Moztreecell);
-                }
-                if atom == &atom!(":-moz-tree-indentation") {
-                    return Some(PseudoElement::Moztreeindentation);
-                }
-                if atom == &atom!(":-moz-tree-line") {
-                    return Some(PseudoElement::Moztreeline);
-                }
-                if atom == &atom!(":-moz-tree-twisty") {
-                    return Some(PseudoElement::Moztreetwisty);
-                }
-                if atom == &atom!(":-moz-tree-image") {
-                    return Some(PseudoElement::Moztreeimage);
-                }
-                if atom == &atom!(":-moz-tree-cell-text") {
-                    return Some(PseudoElement::Moztreecelltext);
-                }
-                if atom == &atom!(":-moz-tree-checkbox") {
-                    return Some(PseudoElement::Moztreecheckbox);
-                }
-                if atom == &atom!(":-moz-tree-progressmeter") {
-                    return Some(PseudoElement::Moztreeprogressmeter);
-                }
-                if atom == &atom!(":-moz-tree-drop-feedback") {
-                    return Some(PseudoElement::Moztreedropfeedback);
-                }
+                // We cannot generate PseudoElement::MozTreeColumn(..) from just an atom.
+                // We cannot generate PseudoElement::MozTreeRow(..) from just an atom.
+                // We cannot generate PseudoElement::MozTreeSeparator(..) from just an atom.
+                // We cannot generate PseudoElement::MozTreeCell(..) from just an atom.
+                // We cannot generate PseudoElement::MozTreeIndentation(..) from just an atom.
+                // We cannot generate PseudoElement::MozTreeLine(..) from just an atom.
+                // We cannot generate PseudoElement::MozTreeTwisty(..) from just an atom.
+                // We cannot generate PseudoElement::MozTreeImage(..) from just an atom.
+                // We cannot generate PseudoElement::MozTreeCellText(..) from just an atom.
+                // We cannot generate PseudoElement::MozTreeCheckbox(..) from just an atom.
+                // We cannot generate PseudoElement::MozTreeProgressmeter(..) from just an atom.
+                // We cannot generate PseudoElement::MozTreeDropFeedback(..) from just an atom.
                 if atom == &atom!(":-moz-svg-marker-anon-child") {
                     return Some(PseudoElement::MozSVGMarkerAnonChild);
                 }
                 if atom == &atom!(":-moz-svg-outer-svg-anon-child") {
                     return Some(PseudoElement::MozSVGOuterSVGAnonChild);
                 }
                 if atom == &atom!(":-moz-svg-foreign-content") {
                     return Some(PseudoElement::MozSVGForeignContent);
@@ -988,517 +851,535 @@ impl PseudoElement {
     /// If we're not in a user-agent stylesheet, we will never parse anonymous
     /// box pseudo-elements.
     ///
     /// Returns `None` if the pseudo-element is not recognised.
     #[inline]
     pub fn from_slice(s: &str, in_ua_stylesheet: bool) -> Option<Self> {
         use std::ascii::AsciiExt;
 
+        // We don't need to support tree pseudos because functional
+        // pseudo-elements needs arguments, and thus should be created
+        // via other methods.
             if in_ua_stylesheet || PseudoElement::After.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("after") {
-                    return Some(PseudoElement::After)
+                    return Some(PseudoElement::After);
                 }
             }
             if in_ua_stylesheet || PseudoElement::Before.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("before") {
-                    return Some(PseudoElement::Before)
+                    return Some(PseudoElement::Before);
                 }
             }
             if in_ua_stylesheet || PseudoElement::Backdrop.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("backdrop") {
-                    return Some(PseudoElement::Backdrop)
+                    return Some(PseudoElement::Backdrop);
                 }
             }
             if in_ua_stylesheet || PseudoElement::Cue.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("cue") {
-                    return Some(PseudoElement::Cue)
+                    return Some(PseudoElement::Cue);
                 }
             }
             if in_ua_stylesheet || PseudoElement::FirstLetter.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("first-letter") {
-                    return Some(PseudoElement::FirstLetter)
+                    return Some(PseudoElement::FirstLetter);
                 }
             }
             if in_ua_stylesheet || PseudoElement::FirstLine.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("first-line") {
-                    return Some(PseudoElement::FirstLine)
+                    return Some(PseudoElement::FirstLine);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozSelection.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-selection") {
-                    return Some(PseudoElement::MozSelection)
+                    return Some(PseudoElement::MozSelection);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozFocusInner.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-focus-inner") {
-                    return Some(PseudoElement::MozFocusInner)
+                    return Some(PseudoElement::MozFocusInner);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozFocusOuter.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-focus-outer") {
-                    return Some(PseudoElement::MozFocusOuter)
+                    return Some(PseudoElement::MozFocusOuter);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozListBullet.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-list-bullet") {
-                    return Some(PseudoElement::MozListBullet)
+                    return Some(PseudoElement::MozListBullet);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozListNumber.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-list-number") {
-                    return Some(PseudoElement::MozListNumber)
+                    return Some(PseudoElement::MozListNumber);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozMathAnonymous.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-math-anonymous") {
-                    return Some(PseudoElement::MozMathAnonymous)
+                    return Some(PseudoElement::MozMathAnonymous);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozNumberWrapper.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-number-wrapper") {
-                    return Some(PseudoElement::MozNumberWrapper)
+                    return Some(PseudoElement::MozNumberWrapper);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozNumberText.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-number-text") {
-                    return Some(PseudoElement::MozNumberText)
+                    return Some(PseudoElement::MozNumberText);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozNumberSpinBox.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-number-spin-box") {
-                    return Some(PseudoElement::MozNumberSpinBox)
+                    return Some(PseudoElement::MozNumberSpinBox);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozNumberSpinUp.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-number-spin-up") {
-                    return Some(PseudoElement::MozNumberSpinUp)
+                    return Some(PseudoElement::MozNumberSpinUp);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozNumberSpinDown.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-number-spin-down") {
-                    return Some(PseudoElement::MozNumberSpinDown)
+                    return Some(PseudoElement::MozNumberSpinDown);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozProgressBar.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-progress-bar") {
-                    return Some(PseudoElement::MozProgressBar)
+                    return Some(PseudoElement::MozProgressBar);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozRangeTrack.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-range-track") {
-                    return Some(PseudoElement::MozRangeTrack)
+                    return Some(PseudoElement::MozRangeTrack);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozRangeProgress.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-range-progress") {
-                    return Some(PseudoElement::MozRangeProgress)
+                    return Some(PseudoElement::MozRangeProgress);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozRangeThumb.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-range-thumb") {
-                    return Some(PseudoElement::MozRangeThumb)
+                    return Some(PseudoElement::MozRangeThumb);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozMeterBar.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-meter-bar") {
-                    return Some(PseudoElement::MozMeterBar)
+                    return Some(PseudoElement::MozMeterBar);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozPlaceholder.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-placeholder") {
-                    return Some(PseudoElement::MozPlaceholder)
+                    return Some(PseudoElement::MozPlaceholder);
                 }
             }
             if in_ua_stylesheet || PseudoElement::Placeholder.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("placeholder") {
-                    return Some(PseudoElement::Placeholder)
+                    return Some(PseudoElement::Placeholder);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozColorSwatch.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-color-swatch") {
-                    return Some(PseudoElement::MozColorSwatch)
+                    return Some(PseudoElement::MozColorSwatch);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozText.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-text") {
-                    return Some(PseudoElement::MozText)
+                    return Some(PseudoElement::MozText);
                 }
             }
             if in_ua_stylesheet || PseudoElement::OofPlaceholder.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-oof-placeholder") {
-                    return Some(PseudoElement::OofPlaceholder)
+                    return Some(PseudoElement::OofPlaceholder);
                 }
             }
             if in_ua_stylesheet || PseudoElement::FirstLetterContinuation.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-first-letter-continuation") {
-                    return Some(PseudoElement::FirstLetterContinuation)
+                    return Some(PseudoElement::FirstLetterContinuation);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozBlockInsideInlineWrapper.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-block-inside-inline-wrapper") {
-                    return Some(PseudoElement::MozBlockInsideInlineWrapper)
+                    return Some(PseudoElement::MozBlockInsideInlineWrapper);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozMathMLAnonymousBlock.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-mathml-anonymous-block") {
-                    return Some(PseudoElement::MozMathMLAnonymousBlock)
+                    return Some(PseudoElement::MozMathMLAnonymousBlock);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozXULAnonymousBlock.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-xul-anonymous-block") {
-                    return Some(PseudoElement::MozXULAnonymousBlock)
+                    return Some(PseudoElement::MozXULAnonymousBlock);
                 }
             }
             if in_ua_stylesheet || PseudoElement::HorizontalFramesetBorder.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-hframeset-border") {
-                    return Some(PseudoElement::HorizontalFramesetBorder)
+                    return Some(PseudoElement::HorizontalFramesetBorder);
                 }
             }
             if in_ua_stylesheet || PseudoElement::VerticalFramesetBorder.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-vframeset-border") {
-                    return Some(PseudoElement::VerticalFramesetBorder)
+                    return Some(PseudoElement::VerticalFramesetBorder);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozLineFrame.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-line-frame") {
-                    return Some(PseudoElement::MozLineFrame)
+                    return Some(PseudoElement::MozLineFrame);
                 }
             }
             if in_ua_stylesheet || PseudoElement::ButtonContent.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-button-content") {
-                    return Some(PseudoElement::ButtonContent)
+                    return Some(PseudoElement::ButtonContent);
                 }
             }
             if in_ua_stylesheet || PseudoElement::CellContent.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-cell-content") {
-                    return Some(PseudoElement::CellContent)
+                    return Some(PseudoElement::CellContent);
                 }
             }
             if in_ua_stylesheet || PseudoElement::DropDownList.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-dropdown-list") {
-                    return Some(PseudoElement::DropDownList)
+                    return Some(PseudoElement::DropDownList);
                 }
             }
             if in_ua_stylesheet || PseudoElement::FieldsetContent.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-fieldset-content") {
-                    return Some(PseudoElement::FieldsetContent)
+                    return Some(PseudoElement::FieldsetContent);
                 }
             }
             if in_ua_stylesheet || PseudoElement::FramesetBlank.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-frameset-blank") {
-                    return Some(PseudoElement::FramesetBlank)
+                    return Some(PseudoElement::FramesetBlank);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozDisplayComboboxControlFrame.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-display-comboboxcontrol-frame") {
-                    return Some(PseudoElement::MozDisplayComboboxControlFrame)
+                    return Some(PseudoElement::MozDisplayComboboxControlFrame);
                 }
             }
             if in_ua_stylesheet || PseudoElement::HtmlCanvasContent.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-html-canvas-content") {
-                    return Some(PseudoElement::HtmlCanvasContent)
+                    return Some(PseudoElement::HtmlCanvasContent);
                 }
             }
             if in_ua_stylesheet || PseudoElement::InlineTable.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-inline-table") {
-                    return Some(PseudoElement::InlineTable)
+                    return Some(PseudoElement::InlineTable);
                 }
             }
             if in_ua_stylesheet || PseudoElement::Table.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-table") {
-                    return Some(PseudoElement::Table)
+                    return Some(PseudoElement::Table);
                 }
             }
             if in_ua_stylesheet || PseudoElement::TableCell.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-table-cell") {
-                    return Some(PseudoElement::TableCell)
+                    return Some(PseudoElement::TableCell);
                 }
             }
             if in_ua_stylesheet || PseudoElement::TableColGroup.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-table-column-group") {
-                    return Some(PseudoElement::TableColGroup)
+                    return Some(PseudoElement::TableColGroup);
                 }
             }
             if in_ua_stylesheet || PseudoElement::TableCol.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-table-column") {
-                    return Some(PseudoElement::TableCol)
+                    return Some(PseudoElement::TableCol);
                 }
             }
             if in_ua_stylesheet || PseudoElement::TableWrapper.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-table-wrapper") {
-                    return Some(PseudoElement::TableWrapper)
+                    return Some(PseudoElement::TableWrapper);
                 }
             }
             if in_ua_stylesheet || PseudoElement::TableRowGroup.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-table-row-group") {
-                    return Some(PseudoElement::TableRowGroup)
+                    return Some(PseudoElement::TableRowGroup);
                 }
             }
             if in_ua_stylesheet || PseudoElement::TableRow.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-table-row") {
-                    return Some(PseudoElement::TableRow)
+                    return Some(PseudoElement::TableRow);
                 }
             }
             if in_ua_stylesheet || PseudoElement::Canvas.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-canvas") {
-                    return Some(PseudoElement::Canvas)
+                    return Some(PseudoElement::Canvas);
                 }
             }
             if in_ua_stylesheet || PseudoElement::PageBreak.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-pagebreak") {
-                    return Some(PseudoElement::PageBreak)
+                    return Some(PseudoElement::PageBreak);
                 }
             }
             if in_ua_stylesheet || PseudoElement::Page.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-page") {
-                    return Some(PseudoElement::Page)
+                    return Some(PseudoElement::Page);
                 }
             }
             if in_ua_stylesheet || PseudoElement::PageContent.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-pagecontent") {
-                    return Some(PseudoElement::PageContent)
+                    return Some(PseudoElement::PageContent);
                 }
             }
             if in_ua_stylesheet || PseudoElement::PageSequence.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-page-sequence") {
-                    return Some(PseudoElement::PageSequence)
+                    return Some(PseudoElement::PageSequence);
                 }
             }
             if in_ua_stylesheet || PseudoElement::ScrolledContent.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-scrolled-content") {
-                    return Some(PseudoElement::ScrolledContent)
+                    return Some(PseudoElement::ScrolledContent);
                 }
             }
             if in_ua_stylesheet || PseudoElement::ScrolledCanvas.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-scrolled-canvas") {
-                    return Some(PseudoElement::ScrolledCanvas)
+                    return Some(PseudoElement::ScrolledCanvas);
                 }
             }
             if in_ua_stylesheet || PseudoElement::ScrolledPageSequence.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-scrolled-page-sequence") {
-                    return Some(PseudoElement::ScrolledPageSequence)
+                    return Some(PseudoElement::ScrolledPageSequence);
                 }
             }
             if in_ua_stylesheet || PseudoElement::ColumnContent.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-column-content") {
-                    return Some(PseudoElement::ColumnContent)
+                    return Some(PseudoElement::ColumnContent);
                 }
             }
             if in_ua_stylesheet || PseudoElement::Viewport.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-viewport") {
-                    return Some(PseudoElement::Viewport)
+                    return Some(PseudoElement::Viewport);
                 }
             }
             if in_ua_stylesheet || PseudoElement::ViewportScroll.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-viewport-scroll") {
-                    return Some(PseudoElement::ViewportScroll)
+                    return Some(PseudoElement::ViewportScroll);
                 }
             }
             if in_ua_stylesheet || PseudoElement::AnonymousFlexItem.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-anonymous-flex-item") {
-                    return Some(PseudoElement::AnonymousFlexItem)
+                    return Some(PseudoElement::AnonymousFlexItem);
                 }
             }
             if in_ua_stylesheet || PseudoElement::AnonymousGridItem.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-anonymous-grid-item") {
-                    return Some(PseudoElement::AnonymousGridItem)
+                    return Some(PseudoElement::AnonymousGridItem);
                 }
             }
             if in_ua_stylesheet || PseudoElement::Ruby.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-ruby") {
-                    return Some(PseudoElement::Ruby)
+                    return Some(PseudoElement::Ruby);
                 }
             }
             if in_ua_stylesheet || PseudoElement::RubyBase.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-ruby-base") {
-                    return Some(PseudoElement::RubyBase)
+                    return Some(PseudoElement::RubyBase);
                 }
             }
             if in_ua_stylesheet || PseudoElement::RubyBaseContainer.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-ruby-base-container") {
-                    return Some(PseudoElement::RubyBaseContainer)
+                    return Some(PseudoElement::RubyBaseContainer);
                 }
             }
             if in_ua_stylesheet || PseudoElement::RubyText.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-ruby-text") {
-                    return Some(PseudoElement::RubyText)
+                    return Some(PseudoElement::RubyText);
                 }
             }
             if in_ua_stylesheet || PseudoElement::RubyTextContainer.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-ruby-text-container") {
-                    return Some(PseudoElement::RubyTextContainer)
-                }
-            }
-            if in_ua_stylesheet || PseudoElement::Moztreecolumn.exposed_in_non_ua_sheets() {
-                if s.eq_ignore_ascii_case("-moz-tree-column") {
-                    return Some(PseudoElement::Moztreecolumn)
-                }
-            }
-            if in_ua_stylesheet || PseudoElement::Moztreerow.exposed_in_non_ua_sheets() {
-                if s.eq_ignore_ascii_case("-moz-tree-row") {
-                    return Some(PseudoElement::Moztreerow)
-                }
-            }
-            if in_ua_stylesheet || PseudoElement::Moztreeseparator.exposed_in_non_ua_sheets() {
-                if s.eq_ignore_ascii_case("-moz-tree-separator") {
-                    return Some(PseudoElement::Moztreeseparator)
-                }
-            }
-            if in_ua_stylesheet || PseudoElement::Moztreecell.exposed_in_non_ua_sheets() {
-                if s.eq_ignore_ascii_case("-moz-tree-cell") {
-                    return Some(PseudoElement::Moztreecell)
-                }
-            }
-            if in_ua_stylesheet || PseudoElement::Moztreeindentation.exposed_in_non_ua_sheets() {
-                if s.eq_ignore_ascii_case("-moz-tree-indentation") {
-                    return Some(PseudoElement::Moztreeindentation)
-                }
-            }
-            if in_ua_stylesheet || PseudoElement::Moztreeline.exposed_in_non_ua_sheets() {
-                if s.eq_ignore_ascii_case("-moz-tree-line") {
-                    return Some(PseudoElement::Moztreeline)
-                }
-            }
-            if in_ua_stylesheet || PseudoElement::Moztreetwisty.exposed_in_non_ua_sheets() {
-                if s.eq_ignore_ascii_case("-moz-tree-twisty") {
-                    return Some(PseudoElement::Moztreetwisty)
-                }
-            }
-            if in_ua_stylesheet || PseudoElement::Moztreeimage.exposed_in_non_ua_sheets() {
-                if s.eq_ignore_ascii_case("-moz-tree-image") {
-                    return Some(PseudoElement::Moztreeimage)
-                }
-            }
-            if in_ua_stylesheet || PseudoElement::Moztreecelltext.exposed_in_non_ua_sheets() {
-                if s.eq_ignore_ascii_case("-moz-tree-cell-text") {
-                    return Some(PseudoElement::Moztreecelltext)
-                }
-            }
-            if in_ua_stylesheet || PseudoElement::Moztreecheckbox.exposed_in_non_ua_sheets() {
-                if s.eq_ignore_ascii_case("-moz-tree-checkbox") {
-                    return Some(PseudoElement::Moztreecheckbox)
-                }
-            }
-            if in_ua_stylesheet || PseudoElement::Moztreeprogressmeter.exposed_in_non_ua_sheets() {
-                if s.eq_ignore_ascii_case("-moz-tree-progressmeter") {
-                    return Some(PseudoElement::Moztreeprogressmeter)
-                }
-            }
-            if in_ua_stylesheet || PseudoElement::Moztreedropfeedback.exposed_in_non_ua_sheets() {
-                if s.eq_ignore_ascii_case("-moz-tree-drop-feedback") {
-                    return Some(PseudoElement::Moztreedropfeedback)
+                    return Some(PseudoElement::RubyTextContainer);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozSVGMarkerAnonChild.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-svg-marker-anon-child") {
-                    return Some(PseudoElement::MozSVGMarkerAnonChild)
+                    return Some(PseudoElement::MozSVGMarkerAnonChild);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozSVGOuterSVGAnonChild.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-svg-outer-svg-anon-child") {
-                    return Some(PseudoElement::MozSVGOuterSVGAnonChild)
+                    return Some(PseudoElement::MozSVGOuterSVGAnonChild);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozSVGForeignContent.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-svg-foreign-content") {
-                    return Some(PseudoElement::MozSVGForeignContent)
+                    return Some(PseudoElement::MozSVGForeignContent);
                 }
             }
             if in_ua_stylesheet || PseudoElement::MozSVGText.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("-moz-svg-text") {
-                    return Some(PseudoElement::MozSVGText)
+                    return Some(PseudoElement::MozSVGText);
                 }
             }
 
         None
     }
 
-    /// Returns the pseudo-element's definition as a string, with only one colon
-    /// before it.
-    pub fn as_str(&self) -> &'static str {
+    /// Constructs a tree pseudo-element from the given name and arguments.
+    /// "name" must start with "-moz-tree-".
+    ///
+    /// Returns `None` if the pseudo-element is not recognized.
+    #[inline]
+    pub fn tree_pseudo_element(name: &str, args: Box<[String]>) -> Option<Self> {
+        use std::ascii::AsciiExt;
+        debug_assert!(name.starts_with("-moz-tree-"));
+        let tree_part = &name[10..];
+            if tree_part.eq_ignore_ascii_case("column") {
+                return Some(PseudoElement::MozTreeColumn(args));
+            }
+            if tree_part.eq_ignore_ascii_case("row") {
+                return Some(PseudoElement::MozTreeRow(args));
+            }
+            if tree_part.eq_ignore_ascii_case("separator") {
+                return Some(PseudoElement::MozTreeSeparator(args));
+            }
+            if tree_part.eq_ignore_ascii_case("cell") {
+                return Some(PseudoElement::MozTreeCell(args));
+            }
+            if tree_part.eq_ignore_ascii_case("indentation") {
+                return Some(PseudoElement::MozTreeIndentation(args));
+            }
+            if tree_part.eq_ignore_ascii_case("line") {
+                return Some(PseudoElement::MozTreeLine(args));
+            }
+            if tree_part.eq_ignore_ascii_case("twisty") {
+                return Some(PseudoElement::MozTreeTwisty(args));
+            }
+            if tree_part.eq_ignore_ascii_case("image") {
+                return Some(PseudoElement::MozTreeImage(args));
+            }
+            if tree_part.eq_ignore_ascii_case("cell-text") {
+                return Some(PseudoElement::MozTreeCellText(args));
+            }
+            if tree_part.eq_ignore_ascii_case("checkbox") {
+                return Some(PseudoElement::MozTreeCheckbox(args));
+            }
+            if tree_part.eq_ignore_ascii_case("progressmeter") {
+                return Some(PseudoElement::MozTreeProgressmeter(args));
+            }
+            if tree_part.eq_ignore_ascii_case("drop-feedback") {
+                return Some(PseudoElement::MozTreeDropFeedback(args));
+            }
+        None
+    }
+}
+
+impl ToCss for PseudoElement {
+    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+        dest.write_char(':')?;
         match *self {
-            PseudoElement::After => ":after",
-            PseudoElement::Before => ":before",
-            PseudoElement::Backdrop => ":backdrop",
-            PseudoElement::Cue => ":cue",
-            PseudoElement::FirstLetter => ":first-letter",
-            PseudoElement::FirstLine => ":first-line",
-            PseudoElement::MozSelection => ":-moz-selection",
-            PseudoElement::MozFocusInner => ":-moz-focus-inner",
-            PseudoElement::MozFocusOuter => ":-moz-focus-outer",
-            PseudoElement::MozListBullet => ":-moz-list-bullet",
-            PseudoElement::MozListNumber => ":-moz-list-number",
-            PseudoElement::MozMathAnonymous => ":-moz-math-anonymous",
-            PseudoElement::MozNumberWrapper => ":-moz-number-wrapper",
-            PseudoElement::MozNumberText => ":-moz-number-text",
-            PseudoElement::MozNumberSpinBox => ":-moz-number-spin-box",
-            PseudoElement::MozNumberSpinUp => ":-moz-number-spin-up",
-            PseudoElement::MozNumberSpinDown => ":-moz-number-spin-down",
-            PseudoElement::MozProgressBar => ":-moz-progress-bar",
-            PseudoElement::MozRangeTrack => ":-moz-range-track",
-            PseudoElement::MozRangeProgress => ":-moz-range-progress",
-            PseudoElement::MozRangeThumb => ":-moz-range-thumb",
-            PseudoElement::MozMeterBar => ":-moz-meter-bar",
-            PseudoElement::MozPlaceholder => ":-moz-placeholder",
-            PseudoElement::Placeholder => ":placeholder",
-            PseudoElement::MozColorSwatch => ":-moz-color-swatch",
-            PseudoElement::MozText => ":-moz-text",
-            PseudoElement::OofPlaceholder => ":-moz-oof-placeholder",
-            PseudoElement::FirstLetterContinuation => ":-moz-first-letter-continuation",
-            PseudoElement::MozBlockInsideInlineWrapper => ":-moz-block-inside-inline-wrapper",
-            PseudoElement::MozMathMLAnonymousBlock => ":-moz-mathml-anonymous-block",
-            PseudoElement::MozXULAnonymousBlock => ":-moz-xul-anonymous-block",
-            PseudoElement::HorizontalFramesetBorder => ":-moz-hframeset-border",
-            PseudoElement::VerticalFramesetBorder => ":-moz-vframeset-border",
-            PseudoElement::MozLineFrame => ":-moz-line-frame",
-            PseudoElement::ButtonContent => ":-moz-button-content",
-            PseudoElement::CellContent => ":-moz-cell-content",
-            PseudoElement::DropDownList => ":-moz-dropdown-list",
-            PseudoElement::FieldsetContent => ":-moz-fieldset-content",
-            PseudoElement::FramesetBlank => ":-moz-frameset-blank",
-            PseudoElement::MozDisplayComboboxControlFrame => ":-moz-display-comboboxcontrol-frame",
-            PseudoElement::HtmlCanvasContent => ":-moz-html-canvas-content",
-            PseudoElement::InlineTable => ":-moz-inline-table",
-            PseudoElement::Table => ":-moz-table",
-            PseudoElement::TableCell => ":-moz-table-cell",
-            PseudoElement::TableColGroup => ":-moz-table-column-group",
-            PseudoElement::TableCol => ":-moz-table-column",
-            PseudoElement::TableWrapper => ":-moz-table-wrapper",
-            PseudoElement::TableRowGroup => ":-moz-table-row-group",
-            PseudoElement::TableRow => ":-moz-table-row",
-            PseudoElement::Canvas => ":-moz-canvas",
-            PseudoElement::PageBreak => ":-moz-pagebreak",
-            PseudoElement::Page => ":-moz-page",
-            PseudoElement::PageContent => ":-moz-pagecontent",
-            PseudoElement::PageSequence => ":-moz-page-sequence",
-            PseudoElement::ScrolledContent => ":-moz-scrolled-content",
-            PseudoElement::ScrolledCanvas => ":-moz-scrolled-canvas",
-            PseudoElement::ScrolledPageSequence => ":-moz-scrolled-page-sequence",
-            PseudoElement::ColumnContent => ":-moz-column-content",
-            PseudoElement::Viewport => ":-moz-viewport",
-            PseudoElement::ViewportScroll => ":-moz-viewport-scroll",
-            PseudoElement::AnonymousFlexItem => ":-moz-anonymous-flex-item",
-            PseudoElement::AnonymousGridItem => ":-moz-anonymous-grid-item",
-            PseudoElement::Ruby => ":-moz-ruby",
-            PseudoElement::RubyBase => ":-moz-ruby-base",
-            PseudoElement::RubyBaseContainer => ":-moz-ruby-base-container",
-            PseudoElement::RubyText => ":-moz-ruby-text",
-            PseudoElement::RubyTextContainer => ":-moz-ruby-text-container",
-            PseudoElement::Moztreecolumn => ":-moz-tree-column",
-            PseudoElement::Moztreerow => ":-moz-tree-row",
-            PseudoElement::Moztreeseparator => ":-moz-tree-separator",
-            PseudoElement::Moztreecell => ":-moz-tree-cell",
-            PseudoElement::Moztreeindentation => ":-moz-tree-indentation",
-            PseudoElement::Moztreeline => ":-moz-tree-line",
-            PseudoElement::Moztreetwisty => ":-moz-tree-twisty",
-            PseudoElement::Moztreeimage => ":-moz-tree-image",
-            PseudoElement::Moztreecelltext => ":-moz-tree-cell-text",
-            PseudoElement::Moztreecheckbox => ":-moz-tree-checkbox",
-            PseudoElement::Moztreeprogressmeter => ":-moz-tree-progressmeter",
-            PseudoElement::Moztreedropfeedback => ":-moz-tree-drop-feedback",
-            PseudoElement::MozSVGMarkerAnonChild => ":-moz-svg-marker-anon-child",
-            PseudoElement::MozSVGOuterSVGAnonChild => ":-moz-svg-outer-svg-anon-child",
-            PseudoElement::MozSVGForeignContent => ":-moz-svg-foreign-content",
-            PseudoElement::MozSVGText => ":-moz-svg-text",
+                PseudoElement::After => dest.write_str(":after")?,
+                PseudoElement::Before => dest.write_str(":before")?,
+                PseudoElement::Backdrop => dest.write_str(":backdrop")?,
+                PseudoElement::Cue => dest.write_str(":cue")?,
+                PseudoElement::FirstLetter => dest.write_str(":first-letter")?,
+                PseudoElement::FirstLine => dest.write_str(":first-line")?,
+                PseudoElement::MozSelection => dest.write_str(":-moz-selection")?,
+                PseudoElement::MozFocusInner => dest.write_str(":-moz-focus-inner")?,
+                PseudoElement::MozFocusOuter => dest.write_str(":-moz-focus-outer")?,
+                PseudoElement::MozListBullet => dest.write_str(":-moz-list-bullet")?,
+                PseudoElement::MozListNumber => dest.write_str(":-moz-list-number")?,
+                PseudoElement::MozMathAnonymous => dest.write_str(":-moz-math-anonymous")?,
+                PseudoElement::MozNumberWrapper => dest.write_str(":-moz-number-wrapper")?,
+                PseudoElement::MozNumberText => dest.write_str(":-moz-number-text")?,
+                PseudoElement::MozNumberSpinBox => dest.write_str(":-moz-number-spin-box")?,
+                PseudoElement::MozNumberSpinUp => dest.write_str(":-moz-number-spin-up")?,
+                PseudoElement::MozNumberSpinDown => dest.write_str(":-moz-number-spin-down")?,
+                PseudoElement::MozProgressBar => dest.write_str(":-moz-progress-bar")?,
+                PseudoElement::MozRangeTrack => dest.write_str(":-moz-range-track")?,
+                PseudoElement::MozRangeProgress => dest.write_str(":-moz-range-progress")?,
+                PseudoElement::MozRangeThumb => dest.write_str(":-moz-range-thumb")?,
+                PseudoElement::MozMeterBar => dest.write_str(":-moz-meter-bar")?,
+                PseudoElement::MozPlaceholder => dest.write_str(":-moz-placeholder")?,
+                PseudoElement::Placeholder => dest.write_str(":placeholder")?,
+                PseudoElement::MozColorSwatch => dest.write_str(":-moz-color-swatch")?,
+                PseudoElement::MozText => dest.write_str(":-moz-text")?,
+                PseudoElement::OofPlaceholder => dest.write_str(":-moz-oof-placeholder")?,
+                PseudoElement::FirstLetterContinuation => dest.write_str(":-moz-first-letter-continuation")?,
+                PseudoElement::MozBlockInsideInlineWrapper => dest.write_str(":-moz-block-inside-inline-wrapper")?,
+                PseudoElement::MozMathMLAnonymousBlock => dest.write_str(":-moz-mathml-anonymous-block")?,
+                PseudoElement::MozXULAnonymousBlock => dest.write_str(":-moz-xul-anonymous-block")?,
+                PseudoElement::HorizontalFramesetBorder => dest.write_str(":-moz-hframeset-border")?,
+                PseudoElement::VerticalFramesetBorder => dest.write_str(":-moz-vframeset-border")?,
+                PseudoElement::MozLineFrame => dest.write_str(":-moz-line-frame")?,
+                PseudoElement::ButtonContent => dest.write_str(":-moz-button-content")?,
+                PseudoElement::CellContent => dest.write_str(":-moz-cell-content")?,
+                PseudoElement::DropDownList => dest.write_str(":-moz-dropdown-list")?,
+                PseudoElement::FieldsetContent => dest.write_str(":-moz-fieldset-content")?,
+                PseudoElement::FramesetBlank => dest.write_str(":-moz-frameset-blank")?,
+                PseudoElement::MozDisplayComboboxControlFrame => dest.write_str(":-moz-display-comboboxcontrol-frame")?,
+                PseudoElement::HtmlCanvasContent => dest.write_str(":-moz-html-canvas-content")?,
+                PseudoElement::InlineTable => dest.write_str(":-moz-inline-table")?,
+                PseudoElement::Table => dest.write_str(":-moz-table")?,
+                PseudoElement::TableCell => dest.write_str(":-moz-table-cell")?,
+                PseudoElement::TableColGroup => dest.write_str(":-moz-table-column-group")?,
+                PseudoElement::TableCol => dest.write_str(":-moz-table-column")?,
+                PseudoElement::TableWrapper => dest.write_str(":-moz-table-wrapper")?,
+                PseudoElement::TableRowGroup => dest.write_str(":-moz-table-row-group")?,
+                PseudoElement::TableRow => dest.write_str(":-moz-table-row")?,
+                PseudoElement::Canvas => dest.write_str(":-moz-canvas")?,
+                PseudoElement::PageBreak => dest.write_str(":-moz-pagebreak")?,
+                PseudoElement::Page => dest.write_str(":-moz-page")?,
+                PseudoElement::PageContent => dest.write_str(":-moz-pagecontent")?,
+                PseudoElement::PageSequence => dest.write_str(":-moz-page-sequence")?,
+                PseudoElement::ScrolledContent => dest.write_str(":-moz-scrolled-content")?,
+                PseudoElement::ScrolledCanvas => dest.write_str(":-moz-scrolled-canvas")?,
+                PseudoElement::ScrolledPageSequence => dest.write_str(":-moz-scrolled-page-sequence")?,
+                PseudoElement::ColumnContent => dest.write_str(":-moz-column-content")?,
+                PseudoElement::Viewport => dest.write_str(":-moz-viewport")?,
+                PseudoElement::ViewportScroll => dest.write_str(":-moz-viewport-scroll")?,
+                PseudoElement::AnonymousFlexItem => dest.write_str(":-moz-anonymous-flex-item")?,
+                PseudoElement::AnonymousGridItem => dest.write_str(":-moz-anonymous-grid-item")?,
+                PseudoElement::Ruby => dest.write_str(":-moz-ruby")?,
+                PseudoElement::RubyBase => dest.write_str(":-moz-ruby-base")?,
+                PseudoElement::RubyBaseContainer => dest.write_str(":-moz-ruby-base-container")?,
+                PseudoElement::RubyText => dest.write_str(":-moz-ruby-text")?,
+                PseudoElement::RubyTextContainer => dest.write_str(":-moz-ruby-text-container")?,
+                PseudoElement::MozTreeColumn(..) => dest.write_str(":-moz-tree-column")?,
+                PseudoElement::MozTreeRow(..) => dest.write_str(":-moz-tree-row")?,
+                PseudoElement::MozTreeSeparator(..) => dest.write_str(":-moz-tree-separator")?,
+                PseudoElement::MozTreeCell(..) => dest.write_str(":-moz-tree-cell")?,
+                PseudoElement::MozTreeIndentation(..) => dest.write_str(":-moz-tree-indentation")?,
+                PseudoElement::MozTreeLine(..) => dest.write_str(":-moz-tree-line")?,
+                PseudoElement::MozTreeTwisty(..) => dest.write_str(":-moz-tree-twisty")?,
+                PseudoElement::MozTreeImage(..) => dest.write_str(":-moz-tree-image")?,
+                PseudoElement::MozTreeCellText(..) => dest.write_str(":-moz-tree-cell-text")?,
+                PseudoElement::MozTreeCheckbox(..) => dest.write_str(":-moz-tree-checkbox")?,
+                PseudoElement::MozTreeProgressmeter(..) => dest.write_str(":-moz-tree-progressmeter")?,
+                PseudoElement::MozTreeDropFeedback(..) => dest.write_str(":-moz-tree-drop-feedback")?,
+                PseudoElement::MozSVGMarkerAnonChild => dest.write_str(":-moz-svg-marker-anon-child")?,
+                PseudoElement::MozSVGOuterSVGAnonChild => dest.write_str(":-moz-svg-outer-svg-anon-child")?,
+                PseudoElement::MozSVGForeignContent => dest.write_str(":-moz-svg-foreign-content")?,
+                PseudoElement::MozSVGText => dest.write_str(":-moz-svg-text")?,
+        }
+        match *self {
+            PseudoElement::MozTreeColumn(ref args) |
+            PseudoElement::MozTreeRow(ref args) |
+            PseudoElement::MozTreeSeparator(ref args) |
+            PseudoElement::MozTreeCell(ref args) |
+            PseudoElement::MozTreeIndentation(ref args) |
+            PseudoElement::MozTreeLine(ref args) |
+            PseudoElement::MozTreeTwisty(ref args) |
+            PseudoElement::MozTreeImage(ref args) |
+            PseudoElement::MozTreeCellText(ref args) |
+            PseudoElement::MozTreeCheckbox(ref args) |
+            PseudoElement::MozTreeProgressmeter(ref args) |
+            PseudoElement::MozTreeDropFeedback(ref args) => {
+                dest.write_char('(')?;
+                let mut iter = args.iter();
+                if let Some(first) = iter.next() {
+                    serialize_identifier(first, dest)?;
+                    for item in iter {
+                        dest.write_str(", ")?;
+                        serialize_identifier(item, dest)?;
+                    }
+                }
+                dest.write_char(')')
+            }
+            _ => Ok(()),
         }
     }
 }
--- a/servo/components/style/gecko/pseudo_element.rs
+++ b/servo/components/style/gecko/pseudo_element.rs
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Gecko's definition of a pseudo-element.
 //!
 //! Note that a few autogenerated bits of this live in
 //! `pseudo_element_definition.mako.rs`. If you touch that file, you probably
 //! need to update the checked-in files for Servo.
 
-use cssparser::ToCss;
+use cssparser::{ToCss, serialize_identifier};
 use gecko_bindings::structs::{self, CSSPseudoElementType};
 use selector_parser::{NonTSPseudoClass, PseudoElementCascadeType, SelectorImpl};
 use std::fmt;
 use string_cache::Atom;
 
 include!(concat!(env!("OUT_DIR"), "/gecko/pseudo_element_definition.rs"));
 
 impl ::selectors::parser::PseudoElement for PseudoElement {
@@ -86,20 +86,16 @@ impl PseudoElement {
     /// Whether this pseudo-element is lazily-cascaded.
     #[inline]
     pub fn is_lazy(&self) -> bool {
         !self.is_eager() && !self.is_precomputed()
     }
 
     /// Whether this pseudo-element is web-exposed.
     pub fn exposed_in_non_ua_sheets(&self) -> bool {
-        if self.is_anon_box() {
-            return false;
-        }
-
         (self.flags() & structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY) == 0
     }
 
     /// Whether this pseudo-element supports user action selectors.
     pub fn supports_user_action_state(&self) -> bool {
         (self.flags() & structs::CSS_PSEUDO_ELEMENT_SUPPORTS_USER_ACTION_STATE) != 0
     }
 
@@ -113,15 +109,8 @@ impl PseudoElement {
     /// canonical one as it is.
     pub fn canonical(&self) -> PseudoElement {
         match *self {
             PseudoElement::MozPlaceholder => PseudoElement::Placeholder,
             _ => self.clone(),
         }
     }
 }
-
-impl ToCss for PseudoElement {
-    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
-        dest.write_char(':')?;
-        dest.write_str(self.as_str())
-    }
-}
--- a/servo/components/style/gecko/pseudo_element_definition.mako.rs
+++ b/servo/components/style/gecko/pseudo_element_definition.mako.rs
@@ -2,107 +2,125 @@
  * 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/. */
 
 /// Gecko's pseudo-element definition.
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 pub enum PseudoElement {
     % for pseudo in PSEUDOS:
         /// ${pseudo.value}
+        % if pseudo.is_tree_pseudo_element():
+        ${pseudo.capitalized()}(Box<[String]>),
+        % else:
         ${pseudo.capitalized()},
+        % endif
     % endfor
 }
 
 <% EAGER_PSEUDOS = ["Before", "After", "FirstLine", "FirstLetter"] %>
 
 /// The number of eager pseudo-elements.
 pub const EAGER_PSEUDO_COUNT: usize = ${len(EAGER_PSEUDOS)};
 
 /// The list of eager pseudos.
 pub const EAGER_PSEUDOS: [PseudoElement; EAGER_PSEUDO_COUNT] = [
     % for eager_pseudo_name in EAGER_PSEUDOS:
     PseudoElement::${eager_pseudo_name},
     % endfor
 ];
 
+<% TREE_PSEUDOS = [pseudo for pseudo in PSEUDOS if pseudo.is_tree_pseudo_element()] %>
+<% SIMPLE_PSEUDOS = [pseudo for pseudo in PSEUDOS if not pseudo.is_tree_pseudo_element()] %>
+
+<%def name="pseudo_element_variant(pseudo, tree_arg='..')">\
+PseudoElement::${pseudo.capitalized()}${"({})".format(tree_arg) if pseudo.is_tree_pseudo_element() else ""}\
+</%def>
+
 impl PseudoElement {
-    /// Executes a closure with each pseudo-element as an argument.
-    pub fn each<F>(mut fun: F)
+    /// Executes a closure with each simple (not functional)
+    /// pseudo-element as an argument.
+    pub fn each_simple<F>(mut fun: F)
         where F: FnMut(Self),
     {
-        % for pseudo in PSEUDOS:
-            fun(PseudoElement::${pseudo.capitalized()});
+        % for pseudo in SIMPLE_PSEUDOS:
+            fun(${pseudo_element_variant(pseudo)});
         % endfor
     }
 
     /// Get the pseudo-element as an atom.
     #[inline]
     pub fn atom(&self) -> Atom {
         match *self {
             % for pseudo in PSEUDOS:
-                PseudoElement::${pseudo.capitalized()} => atom!("${pseudo.value}"),
+                ${pseudo_element_variant(pseudo)} => atom!("${pseudo.value}"),
             % endfor
         }
     }
 
     /// Whether this pseudo-element is an anonymous box.
     #[inline]
     fn is_anon_box(&self) -> bool {
         match *self {
             % for pseudo in PSEUDOS:
-                PseudoElement::${pseudo.capitalized()} => ${str(pseudo.is_anon_box()).lower()},
+                % if pseudo.is_anon_box():
+                    ${pseudo_element_variant(pseudo)} => true,
+                % endif
             % endfor
+            _ => false,
         }
     }
 
     /// Whether this pseudo-element is eagerly-cascaded.
     #[inline]
     pub fn is_eager(&self) -> bool {
         matches!(*self,
                  ${" | ".join(map(lambda name: "PseudoElement::{}".format(name), EAGER_PSEUDOS))})
     }
 
     /// Gets the flags associated to this pseudo-element, or 0 if it's an
     /// anonymous box.
     pub fn flags(&self) -> u32 {
         match *self {
             % for pseudo in PSEUDOS:
-                PseudoElement::${pseudo.capitalized()} => {
-                    % if pseudo.is_anon_box():
-                        0
-                    % else:
-                        structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_${pseudo.original_ident}
-                    % endif
-                }
+                ${pseudo_element_variant(pseudo)} =>
+                % if pseudo.is_tree_pseudo_element():
+                    0,
+                % elif pseudo.is_anon_box():
+                    structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
+                % else:
+                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_${pseudo.original_ident},
+                % endif
             % endfor
         }
     }
 
     /// Construct a pseudo-element from a `CSSPseudoElementType`.
     #[inline]
     pub fn from_pseudo_type(type_: CSSPseudoElementType) -> Option<Self> {
         match type_ {
             % for pseudo in PSEUDOS:
                 % if not pseudo.is_anon_box():
                     CSSPseudoElementType::${pseudo.original_ident} => {
-                        Some(PseudoElement::${pseudo.capitalized()})
+                        Some(${pseudo_element_variant(pseudo)})
                     },
                 % endif
             % endfor
             _ => None,
         }
     }
 
     /// Construct a pseudo-element from an anonymous box `Atom`.
     #[inline]
     pub fn from_anon_box_atom(atom: &Atom) -> Option<Self> {
         % for pseudo in PSEUDOS:
-            % if pseudo.is_anon_box():
+            % if pseudo.is_tree_pseudo_element():
+                // We cannot generate ${pseudo_element_variant(pseudo)} from just an atom.
+            % elif pseudo.is_anon_box():
                 if atom == &atom!("${pseudo.value}") {
-                    return Some(PseudoElement::${pseudo.capitalized()});
+                    return Some(${pseudo_element_variant(pseudo)});
                 }
             % endif
         % endfor
         None
     }
 
     /// Constructs an atom from a string of text, and whether we're in a
     /// user-agent stylesheet.
@@ -110,29 +128,66 @@ impl PseudoElement {
     /// If we're not in a user-agent stylesheet, we will never parse anonymous
     /// box pseudo-elements.
     ///
     /// Returns `None` if the pseudo-element is not recognised.
     #[inline]
     pub fn from_slice(s: &str, in_ua_stylesheet: bool) -> Option<Self> {
         use std::ascii::AsciiExt;
 
-        % for pseudo in PSEUDOS:
-            if in_ua_stylesheet || PseudoElement::${pseudo.capitalized()}.exposed_in_non_ua_sheets() {
+        // We don't need to support tree pseudos because functional
+        // pseudo-elements needs arguments, and thus should be created
+        // via other methods.
+        % for pseudo in SIMPLE_PSEUDOS:
+            if in_ua_stylesheet || ${pseudo_element_variant(pseudo)}.exposed_in_non_ua_sheets() {
                 if s.eq_ignore_ascii_case("${pseudo.value[1:]}") {
-                    return Some(PseudoElement::${pseudo.capitalized()})
+                    return Some(${pseudo_element_variant(pseudo)});
                 }
             }
         % endfor
 
         None
     }
 
-    /// Returns the pseudo-element's definition as a string, with only one colon
-    /// before it.
-    pub fn as_str(&self) -> &'static str {
+    /// Constructs a tree pseudo-element from the given name and arguments.
+    /// "name" must start with "-moz-tree-".
+    ///
+    /// Returns `None` if the pseudo-element is not recognized.
+    #[inline]
+    pub fn tree_pseudo_element(name: &str, args: Box<[String]>) -> Option<Self> {
+        use std::ascii::AsciiExt;
+        debug_assert!(name.starts_with("-moz-tree-"));
+        let tree_part = &name[10..];
+        % for pseudo in TREE_PSEUDOS:
+            if tree_part.eq_ignore_ascii_case("${pseudo.value[11:]}") {
+                return Some(${pseudo_element_variant(pseudo, "args")});
+            }
+        % endfor
+        None
+    }
+}
+
+impl ToCss for PseudoElement {
+    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+        dest.write_char(':')?;
         match *self {
-        % for pseudo in PSEUDOS:
-            PseudoElement::${pseudo.capitalized()} => "${pseudo.value}",
-        % endfor
+            % for pseudo in PSEUDOS:
+                ${pseudo_element_variant(pseudo)} => dest.write_str("${pseudo.value}")?,
+            % endfor
+        }
+        match *self {
+            ${" |\n            ".join("PseudoElement::{}(ref args)".format(pseudo.capitalized())
+                                      for pseudo in TREE_PSEUDOS)} => {
+                dest.write_char('(')?;
+                let mut iter = args.iter();
+                if let Some(first) = iter.next() {
+                    serialize_identifier(first, dest)?;
+                    for item in iter {
+                        dest.write_str(", ")?;
+                        serialize_identifier(item, dest)?;
+                    }
+                }
+                dest.write_char(')')
+            }
+            _ => Ok(()),
         }
     }
 }
--- a/servo/components/style/gecko/regen_atoms.py
+++ b/servo/components/style/gecko/regen_atoms.py
@@ -98,16 +98,19 @@ class Atom:
         return self.source.TYPE
 
     def capitalized(self):
         return self.original_ident[0].upper() + self.original_ident[1:]
 
     def is_anon_box(self):
         return self.type() == "nsICSSAnonBoxPseudo"
 
+    def is_tree_pseudo_element(self):
+        return self.value.startswith(":-moz-tree-")
+
 
 def collect_atoms(objdir):
     atoms = []
     for source in SOURCES:
         path = os.path.abspath(os.path.join(objdir, source.FILE))
         print("cargo:rerun-if-changed={}".format(path))
         with open(path) as f:
             for line in f.readlines():
--- a/servo/components/style/gecko/selector_parser.rs
+++ b/servo/components/style/gecko/selector_parser.rs
@@ -1,15 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Gecko-specific bits for selector-parsing.
 
-use cssparser::{Parser, ToCss, CompactCowStr};
+use cssparser::{BasicParseError, Parser, ToCss, Token, CompactCowStr};
 use element_state::ElementState;
 use gecko_bindings::structs::CSSPseudoClassType;
 use selector_parser::{SelectorParser, PseudoElementCascadeType};
 use selectors::parser::{Selector, SelectorMethods, SelectorParseError};
 use selectors::visitor::SelectorVisitor;
 use std::fmt;
 use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
 use style_traits::{ParseError, StyleParseError};
@@ -262,16 +262,21 @@ impl ::selectors::SelectorImpl for Selec
                                 NonTSPseudoClass::Hover)
     }
 }
 
 impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
     type Impl = SelectorImpl;
     type Error = StyleParseError<'i>;
 
+    fn is_pseudo_element_allows_single_colon(name: &CompactCowStr<'i>) -> bool {
+        ::selectors::parser::is_css2_pseudo_element(name) ||
+            name.starts_with("-moz-tree-") // tree pseudo-elements
+    }
+
     fn parse_non_ts_pseudo_class(&self, name: CompactCowStr<'i>)
                                  -> Result<NonTSPseudoClass, ParseError<'i>> {
         macro_rules! pseudo_class_parse {
             (bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*],
              string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*],
              keyword: [$(($k_css:expr, $k_name:ident, $k_gecko_type:tt, $k_state:tt, $k_flags:tt),)*]) => {
                 match_ignore_ascii_case! { &name,
                     $($css => NonTSPseudoClass::$name,)*
@@ -333,16 +338,40 @@ impl<'a, 'i> ::selectors::Parser<'i> for
         }
     }
 
     fn parse_pseudo_element(&self, name: CompactCowStr<'i>) -> Result<PseudoElement, ParseError<'i>> {
         PseudoElement::from_slice(&name, self.in_user_agent_stylesheet())
             .ok_or(SelectorParseError::UnexpectedIdent(name.clone()).into())
     }
 
+    fn parse_functional_pseudo_element<'t>(&self, name: CompactCowStr<'i>,
+                                           parser: &mut Parser<'i, 't>)
+                                           -> Result<PseudoElement, ParseError<'i>> {
+        if name.starts_with("-moz-tree-") {
+            // Tree pseudo-elements can have zero or more arguments,
+            // separated by either comma or space.
+            let mut args = Vec::new();
+            loop {
+                match parser.next() {
+                    Ok(Token::Ident(ident)) => args.push(ident.into_owned()),
+                    Ok(Token::Comma) => {},
+                    Ok(t) => return Err(BasicParseError::UnexpectedToken(t).into()),
+                    Err(BasicParseError::EndOfInput) => break,
+                    _ => unreachable!("Parser::next() shouldn't return any other error"),
+                }
+            }
+            let args = args.into_boxed_slice();
+            if let Some(pseudo) = PseudoElement::tree_pseudo_element(&name, args) {
+                return Ok(pseudo);
+            }
+        }
+        Err(SelectorParseError::UnexpectedIdent(name.clone()).into())
+    }
+
     fn default_namespace(&self) -> Option<Namespace> {
         self.namespaces.default.clone().as_ref().map(|&(ref ns, _)| ns.clone())
     }
 
     fn namespace_for_prefix(&self, prefix: &Atom) -> Option<Namespace> {
         self.namespaces.prefixes.get(prefix).map(|&(ref ns, _)| ns.clone())
     }
 }
@@ -362,21 +391,21 @@ impl SelectorImpl {
     {
         for pseudo in &EAGER_PSEUDOS {
             fun(pseudo.clone())
         }
     }
 
 
     #[inline]
-    /// Executes a function for each pseudo-element.
-    pub fn each_pseudo_element<F>(fun: F)
+    /// Executes a function for each simple (not functional) pseudo-element.
+    pub fn each_simple_pseudo_element<F>(fun: F)
         where F: FnMut(PseudoElement),
     {
-        PseudoElement::each(fun)
+        PseudoElement::each_simple(fun)
     }
 
     #[inline]
     /// Returns the relevant state flag for a given non-tree-structural
     /// pseudo-class.
     pub fn pseudo_class_state_flag(pc: &NonTSPseudoClass) -> ElementState {
         pc.state_flag()
     }
--- a/servo/components/style/selector_parser.rs
+++ b/servo/components/style/selector_parser.rs
@@ -116,15 +116,15 @@ impl SelectorImpl {
     /// it.
     ///
     /// The optimization comment in `each_eagerly_cascaded_pseudo_element` also
     /// applies here.
     #[inline]
     pub fn each_precomputed_pseudo_element<F>(mut fun: F)
         where F: FnMut(PseudoElement),
     {
-        Self::each_pseudo_element(|pseudo| {
+        Self::each_simple_pseudo_element(|pseudo| {
             if pseudo.is_precomputed() {
                 fun(pseudo)
             }
         })
     }
 }
--- a/servo/components/style/servo/selector_parser.rs
+++ b/servo/components/style/servo/selector_parser.rs
@@ -23,17 +23,17 @@ use std::borrow::Cow;
 use std::fmt;
 use std::fmt::Debug;
 use std::mem;
 use std::ops::{Deref, DerefMut};
 use style_traits::{ParseError, StyleParseError};
 
 /// A pseudo-element, both public and private.
 ///
-/// NB: If you add to this list, be sure to update `each_pseudo_element` too.
+/// NB: If you add to this list, be sure to update `each_simple_pseudo_element` too.
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 #[allow(missing_docs)]
 #[repr(usize)]
 pub enum PseudoElement {
     // Eager pseudos. Keep these first so that eager_index() works.
     After = 0,
     Before,
@@ -480,17 +480,17 @@ impl SelectorImpl {
     {
         for i in 0..EAGER_PSEUDO_COUNT {
             fun(PseudoElement::from_eager_index(i));
         }
     }
 
     /// Executes `fun` for each pseudo-element.
     #[inline]
-    pub fn each_pseudo_element<F>(mut fun: F)
+    pub fn each_simple_pseudo_element<F>(mut fun: F)
         where F: FnMut(PseudoElement),
     {
         fun(PseudoElement::Before);
         fun(PseudoElement::After);
         fun(PseudoElement::DetailsContent);
         fun(PseudoElement::DetailsSummary);
         fun(PseudoElement::Selection);
         fun(PseudoElement::ServoText);