diff --git a/components/selectors/parser.rs b/components/selectors/parser.rs index 6be95b5d018c..0eacc595ef41 100644 --- a/components/selectors/parser.rs +++ b/components/selectors/parser.rs @@ -55,6 +55,7 @@ pub enum SelectorParseErrorKind<'i> { EmptySelector, DanglingCombinator, NonSimpleSelectorInNegation, + NonCompoundSelector, UnexpectedTokenInAttributeSelector(Token<'i>), PseudoElementExpectedColon(Token<'i>), PseudoElementExpectedIdent(Token<'i>), @@ -209,6 +210,33 @@ impl SelectorList { } } +/// Parse a comma separated list of compound selectors. +pub fn parse_compound_selector_list<'i, 't, P, Impl>( + parser: &P, + input: &mut CssParser<'i, 't>, +) -> Result]>, ParseError<'i, P::Error>> +where + P: Parser<'i, Impl=Impl>, + Impl: SelectorImpl, +{ + let location = input.current_source_location(); + let selectors = input.parse_comma_separated(|input| { + Selector::parse(parser, input) + })?; + + // Ensure they're actually all compound selectors. + if selectors + .iter() + .flat_map(|x| x.iter_raw_match_order()) + .any(|s| s.is_combinator()) { + return Err(location.new_custom_error( + SelectorParseErrorKind::NonCompoundSelector + )) + } + + Ok(selectors.into_boxed_slice()) +} + /// Ancestor hashes for the bloom filter. We precompute these and store them /// inline with selectors to optimize cache performance during matching. /// This matters a lot. diff --git a/components/style/gecko/selector_parser.rs b/components/style/gecko/selector_parser.rs index 827e832ebcdc..a1882611907b 100644 --- a/components/style/gecko/selector_parser.rs +++ b/components/style/gecko/selector_parser.rs @@ -11,7 +11,7 @@ use gecko_bindings::structs::RawServoSelectorList; use gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI}; use selector_parser::{Direction, SelectorParser, PseudoElementCascadeType}; use selectors::SelectorList; -use selectors::parser::{Selector, SelectorMethods, SelectorParseErrorKind}; +use selectors::parser::{self as selector_parser, Selector, SelectorMethods, SelectorParseErrorKind}; use selectors::visitor::SelectorVisitor; use std::fmt; use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace}; @@ -399,16 +399,12 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> { NonTSPseudoClass::Dir(Box::new(direction)) }, "-moz-any" => { - let selectors = parser.parse_comma_separated(|input| { - Selector::parse(self, input) - })?; - // Selectors inside `:-moz-any` may not include combinators. - if selectors.iter().flat_map(|x| x.iter_raw_match_order()).any(|s| s.is_combinator()) { - return Err(parser.new_custom_error( - SelectorParseErrorKind::UnexpectedIdent("-moz-any".into()) - )) - } - NonTSPseudoClass::MozAny(selectors.into_boxed_slice()) + NonTSPseudoClass::MozAny( + selector_parser::parse_compound_selector_list( + self, + parser, + )? + ) } _ => return Err(parser.new_custom_error( SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name.clone())