--- a/servo/components/selectors/parser.rs
+++ b/servo/components/selectors/parser.rs
@@ -148,16 +148,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
}
@@ -1465,16 +1472,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).
+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)
@@ -1497,47 +1515,44 @@ fn parse_one_simple_selector<'i, 't, P,
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()? {
- 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)))
- }
- }
- 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 || is_css2_pseudo_element(&name);
+ if !is_pseudo_element {
+ let pseudo_class = if !is_functional {
+ parse_simple_pseudo_class(parser, name)?
+ } else {
+ input.parse_nested_block(|input| {
parse_functional_pseudo_class(parser, input, name, inside_negation)
- })?;
- Ok(Some(SimpleSelectorParseResult::SimpleSelector(pseudo)))
- }
- Token::Colon => {
- match input.next_including_whitespace()? {
- Token::Ident(name) => {
- let pseudo = P::parse_pseudo_element(parser, name)?;
- Ok(Some(SimpleSelectorParseResult::PseudoElement(pseudo)))
- }
- t => Err(ParseError::Basic(BasicParseError::UnexpectedToken(t))),
- }
- }
- t => Err(ParseError::Basic(BasicParseError::UnexpectedToken(t))),
+ })?
+ };
+ Ok(Some(SimpleSelectorParseResult::SimpleSelector(pseudo_class)))
+ } else {
+ let pseudo_element = if !is_functional {
+ P::parse_pseudo_element(parser, name)?
+ } else {
+ input.parse_nested_block(|input| {
+ P::parse_functional_pseudo_element(parser, name, input)
+ })?
+ };
+ Ok(Some(SimpleSelectorParseResult::PseudoElement(pseudo_element)))
}
}
_ => {
input.reset(start_position);
Ok(None)
}
}
}