diff --git a/components/selectors/builder.rs b/components/selectors/builder.rs index 7195d63f14c..99a8f086915 100644 --- a/components/selectors/builder.rs +++ b/components/selectors/builder.rs @@ -90,6 +90,12 @@ impl SelectorBuilder { self.simple_selectors.is_empty() } + /// Returns true if combinators have ever been pushed to this builder. + #[inline(always)] + pub fn has_combinators(&self) -> bool { + !self.combinators.is_empty() + } + /// Consumes the builder, producing a Selector. #[inline(always)] pub fn build(&mut self, parsed_pseudo: bool) -> ThinArc> { diff --git a/components/selectors/parser.rs b/components/selectors/parser.rs index bbc1dc4a246..8cacbe6f3a2 100644 --- a/components/selectors/parser.rs +++ b/components/selectors/parser.rs @@ -49,18 +49,23 @@ fn to_ascii_lowercase(s: &str) -> Cow { #[derive(Clone, Debug, PartialEq)] pub enum SelectorParseError<'i, T> { PseudoElementInComplexSelector, - NoQualifiedNameInAttributeSelector, - TooManyCompoundSelectorComponentsInNegation, - NegationSelectorComponentNotNamespace, - NegationSelectorComponentNotLocalName, + NoQualifiedNameInAttributeSelector(Token<'i>), EmptySelector, + DanglingCombinator, NonSimpleSelectorInNegation, - UnexpectedTokenInAttributeSelector, - PseudoElementExpectedColon, - PseudoElementExpectedIdent, - UnsupportedPseudoClass, + UnexpectedTokenInAttributeSelector(Token<'i>), + PseudoElementExpectedColon(Token<'i>), + PseudoElementExpectedIdent(Token<'i>), + NoIdentForPseudo(Token<'i>), + UnsupportedPseudoClassOrElement(CowRcStr<'i>), UnexpectedIdent(CowRcStr<'i>), ExpectedNamespace(CowRcStr<'i>), + ExpectedBarInAttr(Token<'i>), + BadValueInAttr(Token<'i>), + InvalidQualNameInAttr(Token<'i>), + ExplicitNamespaceUnexpectedToken(Token<'i>), + ClassNeedsIdent(Token<'i>), + EmptyNegation, Custom(T), } @@ -136,7 +141,7 @@ pub trait Parser<'i> { fn parse_non_ts_pseudo_class(&self, name: CowRcStr<'i>) -> Result<::NonTSPseudoClass, ParseError<'i, SelectorParseError<'i, Self::Error>>> { - Err(ParseError::Custom(SelectorParseError::UnexpectedIdent(name))) + Err(ParseError::Custom(SelectorParseError::UnsupportedPseudoClassOrElement(name))) } fn parse_non_ts_functional_pseudo_class<'t> @@ -144,20 +149,20 @@ pub trait Parser<'i> { -> Result<::NonTSPseudoClass, ParseError<'i, SelectorParseError<'i, Self::Error>>> { - Err(ParseError::Custom(SelectorParseError::UnexpectedIdent(name))) + Err(ParseError::Custom(SelectorParseError::UnsupportedPseudoClassOrElement(name))) } fn parse_pseudo_element(&self, name: CowRcStr<'i>) -> Result<::PseudoElement, ParseError<'i, SelectorParseError<'i, Self::Error>>> { - Err(ParseError::Custom(SelectorParseError::UnexpectedIdent(name))) + Err(ParseError::Custom(SelectorParseError::UnsupportedPseudoClassOrElement(name))) } fn parse_functional_pseudo_element<'t> (&self, name: CowRcStr<'i>, _arguments: &mut CssParser<'i, 't>) -> Result<::PseudoElement, ParseError<'i, SelectorParseError<'i, Self::Error>>> { - Err(ParseError::Custom(SelectorParseError::UnexpectedIdent(name))) + Err(ParseError::Custom(SelectorParseError::UnsupportedPseudoClassOrElement(name))) } fn default_namespace(&self) -> Option<::NamespaceUrl> { @@ -1041,7 +1046,12 @@ fn parse_selector<'i, 't, P, E, Impl>( let mut parsed_pseudo_element; 'outer_loop: loop { // Parse a sequence of simple selectors. - parsed_pseudo_element = parse_compound_selector(parser, input, &mut builder)?; + parsed_pseudo_element = match parse_compound_selector(parser, input, &mut builder) { + Ok(result) => result, + Err(ParseError::Custom(SelectorParseError::EmptySelector)) if builder.has_combinators() => + return Err(SelectorParseError::DanglingCombinator.into()), + Err(e) => return Err(e), + }; if parsed_pseudo_element { break; } @@ -1106,9 +1116,10 @@ fn parse_type_selector<'i, 't, P, E, Impl, S>(parser: &P, input: &mut CssParser< Impl: SelectorImpl, S: Push>, { - match parse_qualified_name(parser, input, /* in_attr_selector = */ false)? { - None => Ok(false), - Some((namespace, local_name)) => { + match parse_qualified_name(parser, input, /* in_attr_selector = */ false) { + Err(ParseError::Basic(BasicParseError::EndOfInput)) | + Ok(OptionalQName::None(_)) => Ok(false), + Ok(OptionalQName::Some(namespace, local_name)) => { match namespace { QNamePrefix::ImplicitAnyNamespace => {} QNamePrefix::ImplicitDefaultNamespace(url) => { @@ -1157,6 +1168,7 @@ fn parse_type_selector<'i, 't, P, E, Impl, S>(parser: &P, input: &mut CssParser< } Ok(true) } + Err(e) => Err(e) } } @@ -1176,13 +1188,19 @@ enum QNamePrefix { ExplicitNamespace(Impl::NamespacePrefix, Impl::NamespaceUrl), // `prefix|foo` } +enum OptionalQName<'i, Impl: SelectorImpl> { + Some(QNamePrefix, Option>), + None(Token<'i>), +} + /// * `Err(())`: Invalid selector, abort -/// * `Ok(None)`: Not a simple selector, could be something else. `input` was not consumed. -/// * `Ok(Some((namespace, local_name)))`: `None` for the local name means a `*` universal selector +/// * `Ok(None(token))`: Not a simple selector, could be something else. `input` was not consumed, +/// but the token is still returned. +/// * `Ok(Some(namespace, local_name))`: `None` for the local name means a `*` universal selector fn parse_qualified_name<'i, 't, P, E, Impl> (parser: &P, input: &mut CssParser<'i, 't>, in_attr_selector: bool) - -> Result, Option>)>, + -> Result, ParseError<'i, SelectorParseError<'i, E>>> where P: Parser<'i, Impl=Impl, Error=E>, Impl: SelectorImpl { @@ -1191,18 +1209,19 @@ fn parse_qualified_name<'i, 't, P, E, Impl> Some(url) => QNamePrefix::ImplicitDefaultNamespace(url), None => QNamePrefix::ImplicitAnyNamespace, }; - Ok(Some((namespace, local_name))) + Ok(OptionalQName::Some(namespace, local_name)) }; let explicit_namespace = |input: &mut CssParser<'i, 't>, namespace| { match input.next_including_whitespace() { Ok(&Token::Delim('*')) if !in_attr_selector => { - Ok(Some((namespace, None))) + Ok(OptionalQName::Some(namespace, None)) }, Ok(&Token::Ident(ref local_name)) => { - Ok(Some((namespace, Some(local_name.clone())))) + Ok(OptionalQName::Some(namespace, Some(local_name.clone()))) }, - Ok(t) => Err(ParseError::Basic(BasicParseError::UnexpectedToken(t.clone()))), + Ok(t) if in_attr_selector => Err(SelectorParseError::InvalidQualNameInAttr(t.clone()).into()), + Ok(t) => Err(SelectorParseError::ExplicitNamespaceUnexpectedToken(t.clone()).into()), Err(e) => Err(ParseError::Basic(e)), } }; @@ -1223,7 +1242,7 @@ fn parse_qualified_name<'i, 't, P, E, Impl> _ => { input.reset(&after_ident); if in_attr_selector { - Ok(Some((QNamePrefix::ImplicitNoNamespace, Some(value)))) + Ok(OptionalQName::Some(QNamePrefix::ImplicitNoNamespace, Some(value))) } else { default_namespace(Some(value)) } @@ -1241,7 +1260,7 @@ fn parse_qualified_name<'i, 't, P, E, Impl> input.reset(&after_star); if in_attr_selector { match result { - Ok(t) => Err(ParseError::Basic(BasicParseError::UnexpectedToken(t))), + Ok(t) => Err(SelectorParseError::ExpectedBarInAttr(t).into()), Err(e) => Err(ParseError::Basic(e)), } } else { @@ -1253,9 +1272,13 @@ fn parse_qualified_name<'i, 't, P, E, Impl> Ok(Token::Delim('|')) => { explicit_namespace(input, QNamePrefix::ExplicitNoNamespace) } - _ => { + Ok(t) => { input.reset(&start); - Ok(None) + Ok(OptionalQName::None(t)) + } + Err(e) => { + input.reset(&start); + Err(e.into()) } } } @@ -1269,9 +1292,10 @@ fn parse_attribute_selector<'i, 't, P, E, Impl>(parser: &P, input: &mut CssParse let namespace; let local_name; match parse_qualified_name(parser, input, /* in_attr_selector = */ true)? { - None => return Err(ParseError::Custom(SelectorParseError::NoQualifiedNameInAttributeSelector)), - Some((_, None)) => unreachable!(), - Some((ns, Some(ln))) => { + OptionalQName::None(t) => + return Err(ParseError::Custom(SelectorParseError::NoQualifiedNameInAttributeSelector(t))), + OptionalQName::Some(_, None) => unreachable!(), + OptionalQName::Some(ns, Some(ln)) => { local_name = ln; namespace = match ns { QNamePrefix::ImplicitNoNamespace | @@ -1292,10 +1316,7 @@ fn parse_attribute_selector<'i, 't, P, E, Impl>(parser: &P, input: &mut CssParse } } - let operator; - let value; - let never_matches; - match input.next() { + let operator = match input.next() { // [foo] Err(_) => { let local_name_lower = to_ascii_lowercase(&local_name).as_ref().into(); @@ -1317,43 +1338,38 @@ fn parse_attribute_selector<'i, 't, P, E, Impl>(parser: &P, input: &mut CssParse } // [foo=bar] - Ok(&Token::Delim('=')) => { - value = input.expect_ident_or_string()?.clone(); - never_matches = false; - operator = AttrSelectorOperator::Equal; - } + Ok(&Token::Delim('=')) => AttrSelectorOperator::Equal, // [foo~=bar] - Ok(&Token::IncludeMatch) => { - value = input.expect_ident_or_string()?.clone(); - never_matches = value.is_empty() || value.contains(SELECTOR_WHITESPACE); - operator = AttrSelectorOperator::Includes; - } + Ok(&Token::IncludeMatch) => AttrSelectorOperator::Includes, // [foo|=bar] - Ok(&Token::DashMatch) => { - value = input.expect_ident_or_string()?.clone(); - never_matches = false; - operator = AttrSelectorOperator::DashMatch; - } + Ok(&Token::DashMatch) => AttrSelectorOperator::DashMatch, // [foo^=bar] - Ok(&Token::PrefixMatch) => { - value = input.expect_ident_or_string()?.clone(); - never_matches = value.is_empty(); - operator = AttrSelectorOperator::Prefix; - } + Ok(&Token::PrefixMatch) => AttrSelectorOperator::Prefix, // [foo*=bar] - Ok(&Token::SubstringMatch) => { - value = input.expect_ident_or_string()?.clone(); - never_matches = value.is_empty(); - operator = AttrSelectorOperator::Substring; - } + Ok(&Token::SubstringMatch) => AttrSelectorOperator::Substring, // [foo$=bar] - Ok(&Token::SuffixMatch) => { - value = input.expect_ident_or_string()?.clone(); - never_matches = value.is_empty(); - operator = AttrSelectorOperator::Suffix; + Ok(&Token::SuffixMatch) => AttrSelectorOperator::Suffix, + Ok(t) => return Err(SelectorParseError::UnexpectedTokenInAttributeSelector(t.clone()).into()) + }; + + let value = match input.expect_ident_or_string() { + Ok(t) => t.clone(), + Err(BasicParseError::UnexpectedToken(t)) => + return Err(SelectorParseError::BadValueInAttr(t.clone()).into()), + Err(e) => return Err(e.into()), + }; + let never_matches = match operator { + AttrSelectorOperator::Equal | + AttrSelectorOperator::DashMatch => false, + + AttrSelectorOperator::Includes => { + value.is_empty() || value.contains(SELECTOR_WHITESPACE) } - _ => return Err(SelectorParseError::UnexpectedTokenInAttributeSelector.into()) - } + + AttrSelectorOperator::Prefix | + AttrSelectorOperator::Substring | + AttrSelectorOperator::Suffix => value.is_empty() + }; let mut case_sensitivity = parse_attribute_flags(input)?; @@ -1429,13 +1445,19 @@ fn parse_negation<'i, 't, P, E, Impl>(parser: &P, // Get exactly one simple selector. The parse logic in the caller will verify // that there are no trailing tokens after we're done. - if !parse_type_selector(parser, input, &mut sequence)? { + let is_type_sel = match parse_type_selector(parser, input, &mut sequence) { + Ok(result) => result, + Err(ParseError::Basic(BasicParseError::EndOfInput)) => + return Err(SelectorParseError::EmptyNegation.into()), + Err(e) => return Err(e.into()), + }; + if !is_type_sel { match parse_one_simple_selector(parser, input, /* inside_negation = */ true)? { Some(SimpleSelectorParseResult::SimpleSelector(s)) => { sequence.push(s); }, None => { - return Err(ParseError::Custom(SelectorParseError::EmptySelector)); + return Err(ParseError::Custom(SelectorParseError::EmptyNegation)); }, Some(SimpleSelectorParseResult::PseudoElement(_)) => { return Err(ParseError::Custom(SelectorParseError::NonSimpleSelectorInNegation)); @@ -1492,20 +1514,21 @@ fn parse_compound_selector<'i, 't, P, E, Impl>( match input.next_including_whitespace() { Ok(&Token::Colon) => {}, Ok(&Token::WhiteSpace(_)) | Err(_) => break, - _ => return Err(SelectorParseError::PseudoElementExpectedColon.into()), + Ok(t) => + return Err(SelectorParseError::PseudoElementExpectedColon(t.clone()).into()), } // TODO(emilio): Functional pseudo-classes too? // We don't need it for now. - let name = match input.next_including_whitespace() { - Ok(&Token::Ident(ref name)) => name.clone(), - _ => return Err(SelectorParseError::PseudoElementExpectedIdent.into()), + let name = match input.next_including_whitespace()? { + &Token::Ident(ref name) => name.clone(), + t => return Err(SelectorParseError::NoIdentForPseudo(t.clone()).into()), }; let pseudo_class = - P::parse_non_ts_pseudo_class(parser, name)?; + P::parse_non_ts_pseudo_class(parser, name.clone())?; if !p.supports_pseudo_class(&pseudo_class) { - return Err(SelectorParseError::UnsupportedPseudoClass.into()); + return Err(SelectorParseError::UnsupportedPseudoClassOrElement(name).into()); } state_selectors.push(Component::NonTSPseudoClass(pseudo_class)); } @@ -1604,7 +1627,7 @@ fn parse_one_simple_selector<'i, 't, P, E, Impl>(parser: &P, let class = Component::Class(class.as_ref().into()); Ok(Some(SimpleSelectorParseResult::SimpleSelector(class))) } - ref t => Err(ParseError::Basic(BasicParseError::UnexpectedToken(t.clone()))), + ref t => Err(SelectorParseError::ClassNeedsIdent(t.clone()).into()), } } Ok(Token::SquareBracketBlock) => { @@ -1619,7 +1642,7 @@ fn parse_one_simple_selector<'i, 't, P, E, Impl>(parser: &P, 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))), + t => return Err(SelectorParseError::PseudoElementExpectedIdent(t).into()), }; let is_pseudo_element = !is_single_colon || P::is_pseudo_element_allows_single_colon(&name); diff --git a/components/style/gecko/selector_parser.rs b/components/style/gecko/selector_parser.rs index 21c12305e6a..8000c0af5f4 100644 --- a/components/style/gecko/selector_parser.rs +++ b/components/style/gecko/selector_parser.rs @@ -308,7 +308,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> { keyword: [$(($k_css:expr, $k_name:ident, $k_gecko_type:tt, $k_state:tt, $k_flags:tt),)*]) => { match_ignore_ascii_case! { &name, $($css => NonTSPseudoClass::$name,)* - _ => return Err(::selectors::parser::SelectorParseError::UnexpectedIdent( + _ => return Err(::selectors::parser::SelectorParseError::UnsupportedPseudoClassOrElement( name.clone()).into()) } } @@ -317,7 +317,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> { if self.is_pseudo_class_enabled(&pseudo_class) { Ok(pseudo_class) } else { - Err(SelectorParseError::UnexpectedIdent(name).into()) + Err(SelectorParseError::UnsupportedPseudoClassOrElement(name).into()) } } @@ -354,7 +354,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> { } NonTSPseudoClass::MozAny(selectors.into_boxed_slice()) } - _ => return Err(SelectorParseError::UnexpectedIdent(name.clone()).into()) + _ => return Err(SelectorParseError::UnsupportedPseudoClassOrElement(name.clone()).into()) } } } @@ -362,13 +362,13 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> { if self.is_pseudo_class_enabled(&pseudo_class) { Ok(pseudo_class) } else { - Err(SelectorParseError::UnexpectedIdent(name).into()) + Err(SelectorParseError::UnsupportedPseudoClassOrElement(name).into()) } } fn parse_pseudo_element(&self, name: CowRcStr<'i>) -> Result> { PseudoElement::from_slice(&name, self.in_user_agent_stylesheet()) - .ok_or(SelectorParseError::UnexpectedIdent(name.clone()).into()) + .ok_or(SelectorParseError::UnsupportedPseudoClassOrElement(name.clone()).into()) } fn parse_functional_pseudo_element<'t>(&self, name: CowRcStr<'i>, @@ -392,7 +392,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> { return Ok(pseudo); } } - Err(SelectorParseError::UnexpectedIdent(name.clone()).into()) + Err(SelectorParseError::UnsupportedPseudoClassOrElement(name.clone()).into()) } fn default_namespace(&self) -> Option { diff --git a/ports/geckolib/error_reporter.rs b/ports/geckolib/error_reporter.rs index 28d7648d2f0..09875015ed6 100644 --- a/ports/geckolib/error_reporter.rs +++ b/ports/geckolib/error_reporter.rs @@ -161,7 +161,7 @@ fn token_to_str<'a>(t: Token<'a>) -> String { format!("{}{}", i, escape_css_ident(&*unit)), Token::Dimension { value, ref unit, .. } => format!("{}{}", value, escape_css_ident(&*unit)), - Token::WhiteSpace(_) => "whitespace".into(), + Token::WhiteSpace(s) => s.into(), Token::Comment(_) => "comment".into(), Token::Colon => ":".into(), Token::Semicolon => ";".into(), @@ -194,7 +194,7 @@ enum Action { trait ErrorHelpers<'a> { fn error_data(self) -> (CowRcStr<'a>, ParseError<'a>); - fn error_params(self) -> (ErrorString<'a>, Option>); + fn error_params(self) -> ErrorParams<'a>; fn to_gecko_message(&self) -> (Option<&'static [u8]>, &'static [u8], Action); } @@ -203,7 +203,9 @@ fn extract_error_param<'a>(err: ParseError<'a>) -> Option> { CssParseError::Basic(BasicParseError::UnexpectedToken(t)) => ErrorString::UnexpectedToken(t), - CssParseError::Basic(BasicParseError::AtRuleInvalid(i)) => + CssParseError::Basic(BasicParseError::AtRuleInvalid(i)) | + CssParseError::Custom(SelectorParseError::Custom( + StyleParseError::UnsupportedAtRule(i))) => ErrorString::Snippet(format!("@{}", escape_css_ident(&i)).into()), CssParseError::Custom(SelectorParseError::Custom( @@ -214,9 +216,6 @@ fn extract_error_param<'a>(err: ParseError<'a>) -> Option> { CssParseError::Custom(SelectorParseError::UnexpectedIdent(ident)) => ErrorString::Ident(ident), - CssParseError::Custom(SelectorParseError::ExpectedNamespace(namespace)) => - ErrorString::Ident(namespace), - CssParseError::Custom(SelectorParseError::Custom( StyleParseError::PropertyDeclaration( PropertyDeclarationParseError::UnknownProperty(property)))) => @@ -236,17 +235,54 @@ fn extract_value_error_param<'a>(err: ValueParseError<'a>) -> ErrorString<'a> { } } +struct ErrorParams<'a> { + prefix_param: Option>, + main_param: Option>, +} + /// If an error parameter is present in the given error, return it. Additionally return /// a second parameter if it exists, for use in the prefix for the eventual error message. -fn extract_error_params<'a>(err: ParseError<'a>) -> Option<(ErrorString<'a>, Option>)> { - match err { +fn extract_error_params<'a>(err: ParseError<'a>) -> Option> { + let (main, prefix) = match err { CssParseError::Custom(SelectorParseError::Custom( StyleParseError::PropertyDeclaration( PropertyDeclarationParseError::InvalidValue(property, Some(e))))) => - Some((ErrorString::Snippet(property.into()), Some(extract_value_error_param(e)))), + (Some(ErrorString::Snippet(property.into())), Some(extract_value_error_param(e))), - err => extract_error_param(err).map(|e| (e, None)), - } + CssParseError::Custom(SelectorParseError::UnexpectedTokenInAttributeSelector(t)) | + CssParseError::Custom(SelectorParseError::BadValueInAttr(t)) | + CssParseError::Custom(SelectorParseError::ExpectedBarInAttr(t)) | + CssParseError::Custom(SelectorParseError::NoQualifiedNameInAttributeSelector(t)) | + CssParseError::Custom(SelectorParseError::InvalidQualNameInAttr(t)) | + CssParseError::Custom(SelectorParseError::ExplicitNamespaceUnexpectedToken(t)) | + CssParseError::Custom(SelectorParseError::PseudoElementExpectedIdent(t)) | + CssParseError::Custom(SelectorParseError::NoIdentForPseudo(t)) | + CssParseError::Custom(SelectorParseError::ClassNeedsIdent(t)) | + CssParseError::Custom(SelectorParseError::PseudoElementExpectedColon(t)) => + (None, Some(ErrorString::UnexpectedToken(t))), + + CssParseError::Custom(SelectorParseError::ExpectedNamespace(namespace)) => + (None, Some(ErrorString::Ident(namespace))), + + CssParseError::Custom(SelectorParseError::UnsupportedPseudoClassOrElement(p)) => + (None, Some(ErrorString::Ident(p))), + + CssParseError::Custom(SelectorParseError::EmptySelector) | + CssParseError::Custom(SelectorParseError::DanglingCombinator) => + (None, None), + + CssParseError::Custom(SelectorParseError::EmptyNegation) => + (None, Some(ErrorString::Snippet(")".into()))), + + err => match extract_error_param(err) { + Some(e) => (Some(e), None), + None => return None, + } + }; + Some(ErrorParams { + main_param: main, + prefix_param: prefix, + }) } impl<'a> ErrorHelpers<'a> for ContextualParseError<'a> { @@ -273,9 +309,12 @@ impl<'a> ErrorHelpers<'a> for ContextualParseError<'a> { } } - fn error_params(self) -> (ErrorString<'a>, Option>) { + fn error_params(self) -> ErrorParams<'a> { let (s, error) = self.error_data(); - extract_error_params(error).unwrap_or((ErrorString::Snippet(s), None)) + extract_error_params(error).unwrap_or_else(|| ErrorParams { + main_param: Some(ErrorString::Snippet(s)), + prefix_param: None + }) } fn to_gecko_message(&self) -> (Option<&'static [u8]>, &'static [u8], Action) { @@ -303,15 +342,52 @@ impl<'a> ErrorHelpers<'a> for ContextualParseError<'a> { (b"PEKeyframeBadName\0", Action::Nothing), ContextualParseError::UnsupportedKeyframePropertyDeclaration(..) => (b"PEBadSelectorKeyframeRuleIgnored\0", Action::Nothing), - ContextualParseError::InvalidRule( - _, CssParseError::Custom(SelectorParseError::ExpectedNamespace(_))) => - (b"PEUnknownNamespacePrefix\0", Action::Nothing), ContextualParseError::InvalidRule( _, CssParseError::Custom(SelectorParseError::Custom( StyleParseError::UnexpectedTokenWithinNamespace(_)))) => (b"PEAtNSUnexpected\0", Action::Nothing), - ContextualParseError::InvalidRule(..) => - (b"PEBadSelectorRSIgnored\0", Action::Nothing), + ContextualParseError::InvalidRule( + _, CssParseError::Basic(BasicParseError::AtRuleInvalid(_))) | + ContextualParseError::InvalidRule( + _, CssParseError::Custom(SelectorParseError::Custom( + StyleParseError::UnsupportedAtRule(_)))) => + (b"PEUnknownAtRule\0", Action::Nothing), + ContextualParseError::InvalidRule(_, ref err) => { + let prefix = match *err { + CssParseError::Custom(SelectorParseError::UnexpectedTokenInAttributeSelector(_)) => + Some(&b"PEAttSelUnexpected\0"[..]), + CssParseError::Custom(SelectorParseError::ExpectedBarInAttr(_)) => + Some(&b"PEAttSelNoBar\0"[..]), + CssParseError::Custom(SelectorParseError::BadValueInAttr(_)) => + Some(&b"PEAttSelBadValue\0"[..]), + CssParseError::Custom(SelectorParseError::NoQualifiedNameInAttributeSelector(_)) => + Some(&b"PEAttributeNameOrNamespaceExpected\0"[..]), + CssParseError::Custom(SelectorParseError::InvalidQualNameInAttr(_)) => + Some(&b"PEAttributeNameExpected\0"[..]), + CssParseError::Custom(SelectorParseError::ExplicitNamespaceUnexpectedToken(_)) => + Some(&b"PETypeSelNotType\0"[..]), + CssParseError::Custom(SelectorParseError::ExpectedNamespace(_)) => + Some(&b"PEUnknownNamespacePrefix\0"[..]), + CssParseError::Custom(SelectorParseError::EmptySelector) => + Some(&b"PESelectorGroupNoSelector\0"[..]), + CssParseError::Custom(SelectorParseError::DanglingCombinator) => + Some(&b"PESelectorGroupExtraCombinator\0"[..]), + CssParseError::Custom(SelectorParseError::UnsupportedPseudoClassOrElement(_)) => + Some(&b"PEPseudoSelUnknown\0"[..]), + CssParseError::Custom(SelectorParseError::PseudoElementExpectedColon(_)) => + Some(&b"PEPseudoSelEndOrUserActionPC\0"[..]), + CssParseError::Custom(SelectorParseError::NoIdentForPseudo(_)) => + Some(&b"PEPseudoClassArgNotIdent\0"[..]), + CssParseError::Custom(SelectorParseError::PseudoElementExpectedIdent(_)) => + Some(&b"PEPseudoSelBadName\0"[..]), + CssParseError::Custom(SelectorParseError::ClassNeedsIdent(_)) => + Some(&b"PEClassSelNotIdent\0"[..]), + CssParseError::Custom(SelectorParseError::EmptyNegation) => + Some(&b"PENegationBadArg\0"[..]), + _ => None, + }; + return (prefix, b"PEBadSelectorRSIgnored\0", Action::Nothing); + } ContextualParseError::UnsupportedRule(..) => (b"PEDeclDropped\0", Action::Nothing), ContextualParseError::UnsupportedViewportDescriptorDeclaration(..) | @@ -340,17 +416,20 @@ impl ParseErrorReporter for ErrorReporter { Action::Skip => b"PEDeclSkipped\0".as_ptr(), Action::Drop => b"PEDeclDropped\0".as_ptr(), }; - let (param, pre_param) = error.error_params(); - let param = param.into_str(); + let params = error.error_params(); + let param = params.main_param; + let pre_param = params.prefix_param; + let param = param.map(|p| p.into_str()); let pre_param = pre_param.map(|p| p.into_str()); + let param_ptr = param.as_ref().map_or(ptr::null(), |p| p.as_ptr()); let pre_param_ptr = pre_param.as_ref().map_or(ptr::null(), |p| p.as_ptr()); // The CSS source text is unused and will be removed in bug 1381188. let source = ""; unsafe { Gecko_ReportUnexpectedCSSError(self.0, name.as_ptr() as *const _, - param.as_ptr() as *const _, - param.len() as u32, + param_ptr as *const _, + param.as_ref().map_or(0, |p| p.len()) as u32, pre.map_or(ptr::null(), |p| p.as_ptr()) as *const _, pre_param_ptr as *const _, pre_param.as_ref().map_or(0, |p| p.len()) as u32,