Bug 1341642 - Part 2: Stylo: Add support for :-moz-empty-except-children-with-localname pseudo-class r?SimonSapin draft
authorNazım Can Altınova <canaltinova@gmail.com>
Thu, 16 Mar 2017 00:08:37 +0300
changeset 499481 b870a2dab8e4ff308f192980d4e55390a5ba52ad
parent 499480 d0a03e26055253e172ec190c50e7d1ea9d52726b
child 549369 4d62b8977df0b4952ec0bc4fa218516d8c93a446
push id49427
push userbmo:canaltinova@gmail.com
push dateWed, 15 Mar 2017 21:29:38 +0000
reviewersSimonSapin
bugs1341642
milestone55.0a1
Bug 1341642 - Part 2: Stylo: Add support for :-moz-empty-except-children-with-localname pseudo-class r?SimonSapin MozReview-Commit-ID: LccrhQTFgyE
servo/components/style/gecko/selector_parser.rs
servo/components/style/gecko/wrapper.rs
--- 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::ToCss;
+use cssparser::{ToCss, Parser};
 use element_state::ElementState;
 use gecko_bindings::structs::CSSPseudoClassType;
 use gecko_bindings::structs::nsIAtom;
 use selector_parser::{SelectorParser, PseudoElementCascadeType};
 use selector_parser::{attr_equals_selector_is_shareable, attr_exists_selector_is_shareable};
 use selectors::parser::AttrSelector;
 use std::borrow::Cow;
 use std::fmt;
@@ -142,62 +142,71 @@ macro_rules! pseudo_class_list {
     ($(($css:expr, $name:ident, $_gecko_type:tt, $_state:tt, $_flags:tt),)*) => {
         #[doc = "Our representation of a non tree-structural pseudo-class."]
         #[derive(Clone, Debug, PartialEq, Eq, Hash)]
         pub enum NonTSPseudoClass {
             $(
                 #[doc = $css]
                 $name,
             )*
+            /// Non-standard: `:-moz-empty-except-children-with-localname` pseudo-class.
+            MozEmptyExceptChildrenWithLocalname(Atom),
         }
     }
 }
 include!("non_ts_pseudo_class_list.rs");
 
 impl ToCss for NonTSPseudoClass {
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
         macro_rules! pseudo_class_list {
             ($(($css:expr, $name:ident, $_gecko_type:tt, $_state:tt, $_flags:tt),)*) => {
                 match *self {
-                    $(NonTSPseudoClass::$name => concat!(":", $css),)*
+                    $(NonTSPseudoClass::$name => dest.write_str(concat!(":", $css)),)*
+                    NonTSPseudoClass::MozEmptyExceptChildrenWithLocalname(ref local_name) => {
+                        dest.write_str(":-moz-empty-except-children-with-localname(")?;
+                        dest.write_str(&*local_name.to_string())?;
+                        dest.write_str(")")
+                    }
                 }
             }
         }
-        dest.write_str(include!("non_ts_pseudo_class_list.rs"))
+        include!("non_ts_pseudo_class_list.rs")
     }
 }
 
 impl NonTSPseudoClass {
     /// A pseudo-class is internal if it can only be used inside
     /// user agent style sheets.
     pub fn is_internal(&self) -> bool {
         macro_rules! check_flag {
             (_) => (false);
             ($flags:expr) => ($flags.contains(PSEUDO_CLASS_INTERNAL));
         }
         macro_rules! pseudo_class_list {
             ($(($_css:expr, $name:ident, $_gecko_type:tt, $_state:tt, $flags:tt),)*) => {
                 match *self {
                     $(NonTSPseudoClass::$name => check_flag!($flags),)*
+                    NonTSPseudoClass::MozEmptyExceptChildrenWithLocalname(_) => false,
                 }
             }
         }
         include!("non_ts_pseudo_class_list.rs")
     }
 
     /// Get the state flag associated with a pseudo-class, if any.
     pub fn state_flag(&self) -> ElementState {
         macro_rules! flag {
             (_) => (ElementState::empty());
             ($state:ident) => (::element_state::$state);
         }
         macro_rules! pseudo_class_list {
             ($(($_css:expr, $name:ident, $_gecko_type:tt, $state:tt, $_flags:tt),)*) => {
                 match *self {
                     $(NonTSPseudoClass::$name => flag!($state),)*
+                    NonTSPseudoClass::MozEmptyExceptChildrenWithLocalname(_) => flag!(_),
                 }
             }
         }
         include!("non_ts_pseudo_class_list.rs")
     }
 
     /// Convert NonTSPseudoClass to Gecko's CSSPseudoClassType.
     pub fn to_gecko_pseudoclasstype(&self) -> Option<CSSPseudoClassType> {
@@ -205,16 +214,19 @@ impl NonTSPseudoClass {
             (_) => (None);
             ($gecko_type:ident) =>
                 (Some(::gecko_bindings::structs::CSSPseudoClassType::$gecko_type));
         }
         macro_rules! pseudo_class_list {
             ($(($_css:expr, $name:ident, $gecko_type:tt, $_state:tt, $_flags:tt),)*) => {
                 match *self {
                     $(NonTSPseudoClass::$name => gecko_type!($gecko_type),)*
+                    NonTSPseudoClass::MozEmptyExceptChildrenWithLocalname(_) => {
+                        gecko_type!(mozEmptyExceptChildrenWithLocalname)
+                    },
                 }
             }
         }
         include!("non_ts_pseudo_class_list.rs")
     }
 }
 
 /// The dummy struct we use to implement our selector parsing.
@@ -259,16 +271,27 @@ impl<'a> ::selectors::Parser for Selecto
         let pseudo_class = include!("non_ts_pseudo_class_list.rs");
         if !pseudo_class.is_internal() || self.in_user_agent_stylesheet() {
             Ok(pseudo_class)
         } else {
             Err(())
         }
     }
 
+    fn parse_non_ts_functional_pseudo_class(&self, name: Cow<str>, parser: &mut Parser)
+                                            -> Result<NonTSPseudoClass, ()> {
+        match_ignore_ascii_case! { &name,
+            "-moz-empty-except-children-with-localname" => {
+                let local_name = parser.expect_ident()?;
+                Ok(NonTSPseudoClass::MozEmptyExceptChildrenWithLocalname(Atom::from(local_name)))
+            },
+            _ => Err(())
+        }
+    }
+
     fn parse_pseudo_element(&self, name: Cow<str>) -> Result<PseudoElement, ()> {
         match PseudoElement::from_slice(&name, self.in_user_agent_stylesheet()) {
             Some(pseudo) => Ok(pseudo),
             None => Err(()),
         }
     }
 
     fn default_namespace(&self) -> Option<Namespace> {
--- a/servo/components/style/gecko/wrapper.rs
+++ b/servo/components/style/gecko/wrapper.rs
@@ -663,16 +663,20 @@ impl<'le> ::selectors::Element for Gecko
             },
             NonTSPseudoClass::ReadOnly => {
                 !self.get_state().contains(pseudo_class.state_flag())
             }
 
             NonTSPseudoClass::MozTableBorderNonzero |
             NonTSPseudoClass::MozBrowserFrame => unsafe {
                 Gecko_MatchesElement(pseudo_class.to_gecko_pseudoclasstype().unwrap(), self.0)
+            },
+            NonTSPseudoClass::MozEmptyExceptChildrenWithLocalname(ref _local_name) => {
+                // TODO: implement here
+                false
             }
         }
     }
 
     fn get_id(&self) -> Option<Atom> {
         let ptr = unsafe {
             bindings::Gecko_AtomAttrValue(self.0,
                                           atom!("id").as_ptr())