diff --git a/components/selectors/parser.rs b/components/selectors/parser.rs index 2fc5ad02d39..ccb4b943226 100644 --- a/components/selectors/parser.rs +++ b/components/selectors/parser.rs @@ -276,6 +276,11 @@ pub trait Parser<'i> { false } + /// Whether to allow forgiving selector-list parsing. + fn allow_forgiving_selectors(&self) -> bool { + true + } + /// Parses non-tree-structural pseudo-classes. Tree structural pseudo-classes, /// like `:first-child`, are built into this library. /// @@ -400,7 +405,11 @@ impl SelectorList { Ok(selector) => values.push(selector), Err(err) => match recovery { ParseErrorRecovery::DiscardList => return Err(err), - ParseErrorRecovery::IgnoreInvalidSelector => {}, + ParseErrorRecovery::IgnoreInvalidSelector => { + if !parser.allow_forgiving_selectors() { + return Err(err); + } + }, }, } diff --git a/components/style/gecko/pseudo_element_definition.mako.rs b/components/style/gecko/pseudo_element_definition.mako.rs index dd6d1aad227..eab97c61bea 100644 --- a/components/style/gecko/pseudo_element_definition.mako.rs +++ b/components/style/gecko/pseudo_element_definition.mako.rs @@ -184,7 +184,7 @@ impl PseudoElement { /// /// Returns `None` if the pseudo-element is not recognised. #[inline] - pub fn from_slice(name: &str) -> Option { + pub fn from_slice(name: &str, allow_unkown_webkit: bool) -> Option { // We don't need to support tree pseudos because functional // pseudo-elements needs arguments, and thus should be created // via other methods. @@ -209,7 +209,7 @@ impl PseudoElement { return PseudoElement::tree_pseudo_element(name, Box::new([])) } const WEBKIT_PREFIX: &str = "-webkit-"; - if starts_with_ignore_ascii_case(name, WEBKIT_PREFIX) { + if allow_unkown_webkit && starts_with_ignore_ascii_case(name, WEBKIT_PREFIX) { let part = string_as_ascii_lowercase(&name[WEBKIT_PREFIX.len()..]); return Some(PseudoElement::UnknownWebkit(part.into())); } diff --git a/components/style/gecko/selector_parser.rs b/components/style/gecko/selector_parser.rs index aee0ce7fe35..6c975862f19 100644 --- a/components/style/gecko/selector_parser.rs +++ b/components/style/gecko/selector_parser.rs @@ -320,6 +320,11 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> { function.eq_ignore_ascii_case("-moz-any") } + #[inline] + fn allow_forgiving_selectors(&self) -> bool { + !self.for_supports_rule + } + fn parse_non_ts_pseudo_class( &self, location: SourceLocation, @@ -373,7 +378,8 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> { location: SourceLocation, name: CowRcStr<'i>, ) -> Result> { - if let Some(pseudo) = PseudoElement::from_slice(&name) { + let allow_unkown_webkit = !self.for_supports_rule; + if let Some(pseudo) = PseudoElement::from_slice(&name, allow_unkown_webkit) { if self.is_pseudo_element_enabled(&pseudo) { return Ok(pseudo); } diff --git a/components/style/selector_parser.rs b/components/style/selector_parser.rs index 1af4d6ff07a..c401fe431ce 100644 --- a/components/style/selector_parser.rs +++ b/components/style/selector_parser.rs @@ -47,6 +47,8 @@ pub struct SelectorParser<'a> { /// The extra URL data of the stylesheet, which is used to look up /// whether we are parsing a chrome:// URL style sheet. pub url_data: &'a UrlExtraData, + /// Whether we're parsing selectors for `@supports` + pub for_supports_rule: bool, } impl<'a> SelectorParser<'a> { @@ -63,6 +65,7 @@ impl<'a> SelectorParser<'a> { stylesheet_origin: Origin::Author, namespaces: &namespaces, url_data, + for_supports_rule: false, }; let mut input = ParserInput::new(input); SelectorList::parse(&parser, &mut CssParser::new(&mut input)) diff --git a/components/style/stylesheets/rule_parser.rs b/components/style/stylesheets/rule_parser.rs index 646a7dbbfd2..9cc2696463b 100644 --- a/components/style/stylesheets/rule_parser.rs +++ b/components/style/stylesheets/rule_parser.rs @@ -785,6 +785,7 @@ impl<'a, 'b, 'i> QualifiedRuleParser<'i> for NestedRuleParser<'a, 'b> { stylesheet_origin: self.context.stylesheet_origin, namespaces: self.namespaces, url_data: self.context.url_data, + for_supports_rule: false, }; let selectors = SelectorList::parse(&selector_parser, input)?; if self.context.error_reporting_enabled() { diff --git a/components/style/stylesheets/supports_rule.rs b/components/style/stylesheets/supports_rule.rs index 0cc4c6746b9..071509bd181 100644 --- a/components/style/stylesheets/supports_rule.rs +++ b/components/style/stylesheets/supports_rule.rs @@ -385,29 +385,12 @@ impl RawSelector { namespaces, stylesheet_origin: context.stylesheet_origin, url_data: context.url_data, + for_supports_rule: true, }; - #[allow(unused_variables)] - let selector = Selector::::parse(&parser, input) + Selector::::parse(&parser, input) .map_err(|_| input.new_custom_error(()))?; - #[cfg(feature = "gecko")] - { - use crate::selector_parser::PseudoElement; - use selectors::parser::Component; - - let has_any_unknown_webkit_pseudo = selector.has_pseudo_element() && - selector.iter_raw_match_order().any(|component| { - matches!( - *component, - Component::PseudoElement(PseudoElement::UnknownWebkit(..)) - ) - }); - if has_any_unknown_webkit_pseudo { - return Err(input.new_custom_error(())); - } - } - Ok(()) }) .is_ok()