Accept argument-less tree pseudo-element selector. draft
authorXidorn Quan <me@upsuper.org>
Tue, 17 Oct 2017 16:25:48 +1100
changeset 683741 03c4d8544848a7c5eaeba849bc71bf5d84fe655d
parent 683740 24dd2a88b6197bf3004a9a4ce2ae42ae4c735d79
child 683742 2e684ce0e0b7ae169fbc47a9d4d9cf860eb61af9
push id85454
push userxquan@mozilla.com
push dateFri, 20 Oct 2017 05:32:42 +0000
milestone58.0a1
Accept argument-less tree pseudo-element selector. MozReview-Commit-ID: CVOa7CNdiRf
servo/components/style/gecko/generated/pseudo_element_definition.rs
servo/components/style/gecko/pseudo_element_definition.mako.rs
servo/components/style/gecko/selector_parser.rs
--- a/servo/components/style/gecko/generated/pseudo_element_definition.rs
+++ b/servo/components/style/gecko/generated/pseudo_element_definition.rs
@@ -866,16 +866,36 @@ None
         }
     }
 
     /// Get a PseudoInfo for a pseudo
     pub fn pseudo_info(&self) -> (*mut structs::nsAtom, CSSPseudoElementType) {
         (self.atom().as_ptr(), self.pseudo_type())
     }
 
+    /// Get the argument list of a tree pseudo-element.
+    #[inline]
+    pub fn tree_pseudo_args(&self) -> Option<&[Atom]> {
+        match *self {
+            PseudoElement::MozTreeColumn(ref args) => Some(args),
+            PseudoElement::MozTreeRow(ref args) => Some(args),
+            PseudoElement::MozTreeSeparator(ref args) => Some(args),
+            PseudoElement::MozTreeCell(ref args) => Some(args),
+            PseudoElement::MozTreeIndentation(ref args) => Some(args),
+            PseudoElement::MozTreeLine(ref args) => Some(args),
+            PseudoElement::MozTreeTwisty(ref args) => Some(args),
+            PseudoElement::MozTreeImage(ref args) => Some(args),
+            PseudoElement::MozTreeCellText(ref args) => Some(args),
+            PseudoElement::MozTreeCheckbox(ref args) => Some(args),
+            PseudoElement::MozTreeProgressmeter(ref args) => Some(args),
+            PseudoElement::MozTreeDropFeedback(ref args) => Some(args),
+            _ => None,
+        }
+    }
+
     /// Construct a pseudo-element from an `Atom`.
     #[inline]
     pub fn from_atom(atom: &Atom) -> Option<Self> {
                 if atom == &atom!(":after") {
                     return Some(PseudoElement::After);
                 }
                 if atom == &atom!(":before") {
                     return Some(PseudoElement::Before);
@@ -1763,36 +1783,25 @@ impl ToCss for PseudoElement {
                 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) => {
+        if let Some(args) = self.tree_pseudo_args() {
+            if !args.is_empty() {
                 dest.write_char('(')?;
                 let mut iter = args.iter();
                 if let Some(first) = iter.next() {
                     serialize_identifier(&first.to_string(), dest)?;
                     for item in iter {
                         dest.write_str(", ")?;
                         serialize_identifier(&item.to_string(), dest)?;
                     }
                 }
-                dest.write_char(')')
+                dest.write_char(')')?;
             }
-            _ => Ok(()),
         }
+        Ok(())
     }
 }
--- a/servo/components/style/gecko/pseudo_element_definition.mako.rs
+++ b/servo/components/style/gecko/pseudo_element_definition.mako.rs
@@ -142,16 +142,27 @@ impl PseudoElement {
         }
     }
 
     /// Get a PseudoInfo for a pseudo
     pub fn pseudo_info(&self) -> (*mut structs::nsAtom, CSSPseudoElementType) {
         (self.atom().as_ptr(), self.pseudo_type())
     }
 
+    /// Get the argument list of a tree pseudo-element.
+    #[inline]
+    pub fn tree_pseudo_args(&self) -> Option<<&[Atom]> {
+        match *self {
+            % for pseudo in TREE_PSEUDOS:
+            PseudoElement::${pseudo.capitalized()}(ref args) => Some(args),
+            % endfor
+            _ => None,
+        }
+    }
+
     /// Construct a pseudo-element from an `Atom`.
     #[inline]
     pub fn from_atom(atom: &Atom) -> Option<Self> {
         % for pseudo in PSEUDOS:
             % if pseudo.is_tree_pseudo_element():
                 // We cannot generate ${pseudo_element_variant(pseudo)} from just an atom.
             % else:
                 if atom == &atom!("${pseudo.value}") {
@@ -223,26 +234,25 @@ impl PseudoElement {
 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:
                 ${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)} => {
+        if let Some(args) = self.tree_pseudo_args() {
+            if !args.is_empty() {
                 dest.write_char('(')?;
                 let mut iter = args.iter();
                 if let Some(first) = iter.next() {
                     serialize_identifier(&first.to_string(), dest)?;
                     for item in iter {
                         dest.write_str(", ")?;
                         serialize_identifier(&item.to_string(), dest)?;
                     }
                 }
-                dest.write_char(')')
+                dest.write_char(')')?;
             }
-            _ => Ok(()),
         }
+        Ok(())
     }
 }
--- a/servo/components/style/gecko/selector_parser.rs
+++ b/servo/components/style/gecko/selector_parser.rs
@@ -374,16 +374,23 @@ impl<'a, 'i> ::selectors::Parser<'i> for
         } else {
             Err(parser.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name)))
         }
     }
 
     fn parse_pseudo_element(&self, location: SourceLocation, name: CowRcStr<'i>)
                             -> Result<PseudoElement, ParseError<'i>> {
         PseudoElement::from_slice(&name, self.in_user_agent_stylesheet())
+            .or_else(|| {
+                if name.starts_with("-moz-tree-") {
+                    PseudoElement::tree_pseudo_element(&name, Box::new([]))
+                } else {
+                    None
+                }
+            })
             .ok_or(location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name.clone())))
     }
 
     fn parse_functional_pseudo_element<'t>(&self, name: CowRcStr<'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,