--- 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())