diff options
author | Josh Matthews <josh@joshmatthews.net> | 2017-07-06 13:59:31 -0400 |
---|---|---|
committer | Josh Matthews <josh@joshmatthews.net> | 2017-07-10 20:46:12 -0400 |
commit | 0b43d0072ce8112b661daef2a9b52fc95143308c (patch) | |
tree | 8d06812456367650dc20efccd2fc3f1b8c2fbd5c | |
parent | a08371e8eb343bd6372aa60d7658ff4b7bb5da15 (diff) | |
download | servo-0b43d0072ce8112b661daef2a9b52fc95143308c.tar.gz servo-0b43d0072ce8112b661daef2a9b52fc95143308c.zip |
stylo: Update rust-cssparser; extract more specific error types when reporting (bug 1352669).
-rw-r--r-- | Cargo.lock | 26 | ||||
-rw-r--r-- | components/canvas/Cargo.toml | 2 | ||||
-rw-r--r-- | components/canvas_traits/Cargo.toml | 2 | ||||
-rw-r--r-- | components/script/Cargo.toml | 2 | ||||
-rw-r--r-- | components/script_layout_interface/Cargo.toml | 2 | ||||
-rw-r--r-- | components/selectors/Cargo.toml | 2 | ||||
-rw-r--r-- | components/selectors/parser.rs | 7 | ||||
-rw-r--r-- | components/style/Cargo.toml | 2 | ||||
-rw-r--r-- | components/style/custom_properties.rs | 8 | ||||
-rw-r--r-- | components/style/error_reporting.rs | 10 | ||||
-rw-r--r-- | components/style/properties/declaration_block.rs | 11 | ||||
-rw-r--r-- | components/style/properties/properties.mako.rs | 11 | ||||
-rw-r--r-- | components/style/stylesheets/rule_parser.rs | 12 | ||||
-rw-r--r-- | components/style_traits/Cargo.toml | 2 | ||||
-rw-r--r-- | components/style_traits/lib.rs | 14 | ||||
-rw-r--r-- | ports/geckolib/Cargo.toml | 2 | ||||
-rw-r--r-- | ports/geckolib/error_reporter.rs | 254 | ||||
-rw-r--r-- | tests/unit/gfx/Cargo.toml | 2 | ||||
-rw-r--r-- | tests/unit/style/Cargo.toml | 2 | ||||
-rw-r--r-- | tests/unit/style/stylesheets.rs | 23 | ||||
-rw-r--r-- | tests/unit/stylo/Cargo.toml | 2 |
21 files changed, 318 insertions, 80 deletions
diff --git a/Cargo.lock b/Cargo.lock index 02ee71c6823..1e1b8d66c47 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -325,7 +325,7 @@ version = "0.0.1" dependencies = [ "azure 0.19.0 (git+https://github.com/servo/rust-azure)", "canvas_traits 0.0.1", - "cssparser 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "gleam 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -340,7 +340,7 @@ dependencies = [ name = "canvas_traits" version = "0.0.1" dependencies = [ - "cssparser 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -585,7 +585,7 @@ dependencies = [ [[package]] name = "cssparser" -version = "0.16.1" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1017,7 +1017,7 @@ name = "geckoservo" version = "0.0.1" dependencies = [ "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cssparser 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1083,7 +1083,7 @@ dependencies = [ name = "gfx_tests" version = "0.0.1" dependencies = [ - "cssparser 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "gfx 0.0.1", "ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "style 0.0.1", @@ -2418,7 +2418,7 @@ dependencies = [ "caseless 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "cookie 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cssparser 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "deny_public_fields 0.0.1", "devtools_traits 0.0.1", "dom_struct 0.0.1", @@ -2491,7 +2491,7 @@ dependencies = [ "app_units 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "canvas_traits 0.0.1", - "cssparser 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "gfx_traits 0.0.1", "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2562,7 +2562,7 @@ name = "selectors" version = "0.19.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cssparser 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2954,7 +2954,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cssparser 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3007,7 +3007,7 @@ version = "0.0.1" dependencies = [ "app_units 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cssparser 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "html5ever 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3028,7 +3028,7 @@ version = "0.0.1" dependencies = [ "app_units 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cssparser 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3041,7 +3041,7 @@ name = "stylo_tests" version = "0.0.1" dependencies = [ "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cssparser 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "geckoservo 0.0.1", @@ -3624,7 +3624,7 @@ dependencies = [ "checksum core-foundation-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "41115a6aa5d3e1e5ef98148373f25971d1fad53818553f216495f9e67e90a624" "checksum core-graphics 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a9f841e9637adec70838c537cae52cb4c751cc6514ad05669b51d107c2021c79" "checksum core-text 5.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74ba2a7abdccb94fb6c00822addef48504182b285aa45a30e78286487888fcb4" -"checksum cssparser 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2842253baded8e712e9d8d80ebfe5ea8e95c5b27071e6a6db6080ca1e81c07d1" +"checksum cssparser 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e7063452c60432cb306ed54d538178c20792d47fa960c240ce6c083239ee55ec" "checksum cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "079adec4af52bb5275eadd004292028c79eb3c5f5b4ee8086a36d4197032f6df" "checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" "checksum dbus 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4aee01fb76ada3e5e7ca642ea6664ebf7308a810739ca2aca44909a1191ac254" diff --git a/components/canvas/Cargo.toml b/components/canvas/Cargo.toml index 42e8b853e53..cb9b9801937 100644 --- a/components/canvas/Cargo.toml +++ b/components/canvas/Cargo.toml @@ -12,7 +12,7 @@ path = "lib.rs" [dependencies] azure = {git = "https://github.com/servo/rust-azure"} canvas_traits = {path = "../canvas_traits"} -cssparser = "0.16.1" +cssparser = "0.17.0" euclid = "0.15" gleam = "0.4" ipc-channel = "0.8" diff --git a/components/canvas_traits/Cargo.toml b/components/canvas_traits/Cargo.toml index 1c6ca6bb1a4..d9cbf34cb75 100644 --- a/components/canvas_traits/Cargo.toml +++ b/components/canvas_traits/Cargo.toml @@ -10,7 +10,7 @@ name = "canvas_traits" path = "lib.rs" [dependencies] -cssparser = "0.16.1" +cssparser = "0.17.0" euclid = "0.15" heapsize = "0.4" heapsize_derive = "0.1" diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index 12f84eeaf12..c9ce38c1f35 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -35,7 +35,7 @@ byteorder = "1.0" canvas_traits = {path = "../canvas_traits"} caseless = "0.1.0" cookie = "0.6" -cssparser = "0.16.1" +cssparser = "0.17.0" deny_public_fields = {path = "../deny_public_fields"} devtools_traits = {path = "../devtools_traits"} dom_struct = {path = "../dom_struct"} diff --git a/components/script_layout_interface/Cargo.toml b/components/script_layout_interface/Cargo.toml index 73d1f506636..6a74eeda086 100644 --- a/components/script_layout_interface/Cargo.toml +++ b/components/script_layout_interface/Cargo.toml @@ -13,7 +13,7 @@ path = "lib.rs" app_units = "0.5" atomic_refcell = "0.1" canvas_traits = {path = "../canvas_traits"} -cssparser = "0.16.1" +cssparser = "0.17.0" euclid = "0.15" gfx_traits = {path = "../gfx_traits"} heapsize = "0.4" diff --git a/components/selectors/Cargo.toml b/components/selectors/Cargo.toml index 4a1ad7dd894..8a8ddfda946 100644 --- a/components/selectors/Cargo.toml +++ b/components/selectors/Cargo.toml @@ -25,7 +25,7 @@ unstable = [] [dependencies] bitflags = "0.7" matches = "0.1" -cssparser = "0.16.1" +cssparser = "0.17.0" log = "0.3" fnv = "1.0" phf = "0.7.18" diff --git a/components/selectors/parser.rs b/components/selectors/parser.rs index f341911a33c..676c1946822 100644 --- a/components/selectors/parser.rs +++ b/components/selectors/parser.rs @@ -59,7 +59,7 @@ pub enum SelectorParseError<'i, T> { PseudoElementExpectedIdent, UnsupportedPseudoClass, UnexpectedIdent(CompactCowStr<'i>), - ExpectedNamespace, + ExpectedNamespace(CompactCowStr<'i>), Custom(T), } @@ -1105,9 +1105,10 @@ fn parse_qualified_name<'i, 't, P, E, Impl> let position = input.position(); match input.next_including_whitespace() { Ok(Token::Delim('|')) => { - let prefix = from_cow_str(value.into()); + let prefix = from_cow_str(value.clone().into()); let result = parser.namespace_for_prefix(&prefix); - let url = result.ok_or(ParseError::Custom(SelectorParseError::ExpectedNamespace))?; + let url = result.ok_or(ParseError::Custom( + SelectorParseError::ExpectedNamespace(value.into())))?; explicit_namespace(input, QNamePrefix::ExplicitNamespace(prefix, url)) }, _ => { diff --git a/components/style/Cargo.toml b/components/style/Cargo.toml index 29a77455833..c6d23ab2b8c 100644 --- a/components/style/Cargo.toml +++ b/components/style/Cargo.toml @@ -38,7 +38,7 @@ bitflags = "0.7" bit-vec = "0.4.3" byteorder = "1.0" cfg-if = "0.1.0" -cssparser = "0.16.1" +cssparser = "0.17.0" encoding = {version = "0.2", optional = true} euclid = "0.15" fnv = "1.0" diff --git a/components/style/custom_properties.rs b/components/style/custom_properties.rs index 5b7c125739a..0f22a0b075c 100644 --- a/components/style/custom_properties.rs +++ b/components/style/custom_properties.rs @@ -280,10 +280,10 @@ fn parse_declaration_value_block<'i, 't> } token.serialization_type() } - Token::BadUrl => - return Err(StyleParseError::BadUrlInDeclarationValueBlock.into()), - Token::BadString => - return Err(StyleParseError::BadStringInDeclarationValueBlock.into()), + Token::BadUrl(u) => + return Err(StyleParseError::BadUrlInDeclarationValueBlock(u).into()), + Token::BadString(s) => + return Err(StyleParseError::BadStringInDeclarationValueBlock(s).into()), Token::CloseParenthesis => return Err(StyleParseError::UnbalancedCloseParenthesisInDeclarationValueBlock.into()), Token::CloseSquareBracket => diff --git a/components/style/error_reporting.rs b/components/style/error_reporting.rs index eda926f8cf3..09b7abf1c1d 100644 --- a/components/style/error_reporting.rs +++ b/components/style/error_reporting.rs @@ -76,8 +76,8 @@ impl<'a> ContextualParseError<'a> { Token::ParenthesisBlock => format!("parenthesis ("), Token::SquareBracketBlock => format!("square bracket ["), Token::CurlyBracketBlock => format!("curly bracket {{"), - Token::BadUrl => format!("bad url parse error"), - Token::BadString => format!("bad string parse error"), + Token::BadUrl(ref _u) => format!("bad url parse error"), + Token::BadString(ref _s) => format!("bad string parse error"), Token::CloseParenthesis => format!("unmatched close parenthesis"), Token::CloseSquareBracket => format!("unmatched close square bracket"), Token::CloseCurlyBracket => format!("unmatched close curly bracket"), @@ -88,11 +88,11 @@ impl<'a> ContextualParseError<'a> { match *err { CssParseError::Basic(BasicParseError::UnexpectedToken(ref t)) => format!("found unexpected {}", token_to_str(t)), - CssParseError::Basic(BasicParseError::ExpectedToken(ref t)) => - format!("expected {}", token_to_str(t)), CssParseError::Basic(BasicParseError::EndOfInput) => format!("unexpected end of input"), - CssParseError::Basic(BasicParseError::AtRuleInvalid) => + CssParseError::Basic(BasicParseError::AtRuleInvalid(ref i)) => + format!("@ rule invalid: {}", i), + CssParseError::Basic(BasicParseError::AtRuleBodyInvalid) => format!("@ rule invalid"), CssParseError::Basic(BasicParseError::QualifiedRuleInvalid) => format!("qualified rule invalid"), diff --git a/components/style/properties/declaration_block.rs b/components/style/properties/declaration_block.rs index a6695b7b40d..5a6eed8c5af 100644 --- a/components/style/properties/declaration_block.rs +++ b/components/style/properties/declaration_block.rs @@ -908,10 +908,17 @@ pub fn parse_one_declaration_into(declarations: &mut SourcePropertyDeclaration, parsing_mode, quirks_mode); let mut input = ParserInput::new(input); - Parser::new(&mut input).parse_entirely(|parser| { + let mut parser = Parser::new(&mut input); + let start = parser.position(); + parser.parse_entirely(|parser| { PropertyDeclaration::parse_into(declarations, id, &context, parser) .map_err(|e| e.into()) - }).map_err(|_| ()) + }).map_err(|err| { + let end = parser.position(); + let error = ContextualParseError::UnsupportedPropertyDeclaration( + parser.slice(start..end), err); + log_css_error(&mut parser, start, error, &context); + }) } /// A struct to parse property declarations. diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 2c6c7971846..de94c5a0fca 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -37,7 +37,8 @@ use properties::animated_properties::AnimatableLonghand; use selectors::parser::SelectorParseError; #[cfg(feature = "servo")] use servo_config::prefs::PREFS; use shared_lock::StylesheetGuards; -use style_traits::{PARSING_MODE_DEFAULT, HasViewportPercentage, ToCss, ParseError, PropertyDeclarationParseError}; +use style_traits::{PARSING_MODE_DEFAULT, HasViewportPercentage, ToCss, ParseError}; +use style_traits::{PropertyDeclarationParseError, StyleParseError}; use stylesheets::{CssRuleType, MallocSizeOf, MallocSizeOfFn, Origin, UrlExtraData}; #[cfg(feature = "servo")] use values::Either; use values::generics::text::LineHeight; @@ -1009,7 +1010,7 @@ impl PropertyId { match static_id(&property_name) { Some(&StaticId::Longhand(id)) => Ok(PropertyId::Longhand(id)), Some(&StaticId::Shorthand(id)) => Ok(PropertyId::Shorthand(id)), - None => Err(SelectorParseError::UnexpectedIdent(property_name).into()), + None => Err(StyleParseError::UnknownProperty(property_name).into()), } } @@ -1414,7 +1415,7 @@ impl PropertyDeclaration { Ok(keyword) => DeclaredValueOwned::CSSWideKeyword(keyword), Err(_) => match ::custom_properties::SpecifiedValue::parse(context, input) { Ok(value) => DeclaredValueOwned::Value(value), - Err(_) => return Err(PropertyDeclarationParseError::InvalidValue), + Err(_) => return Err(PropertyDeclarationParseError::InvalidValue(name.to_string())), } }; declarations.push(PropertyDeclaration::Custom(name, value)); @@ -1442,7 +1443,7 @@ impl PropertyDeclaration { declarations.push(value); Ok(()) }, - Err(_) => Err(PropertyDeclarationParseError::InvalidValue), + Err(_) => Err(PropertyDeclarationParseError::InvalidValue("${property.ident}".into())), } % else: Err(PropertyDeclarationParseError::UnknownProperty) @@ -1482,7 +1483,7 @@ impl PropertyDeclaration { }, Err(_) => { shorthands::${shorthand.ident}::parse_into(declarations, context, input) - .map_err(|_| PropertyDeclarationParseError::InvalidValue) + .map_err(|_| PropertyDeclarationParseError::InvalidValue("${shorthand.ident}".into())) } } } diff --git a/components/style/stylesheets/rule_parser.rs b/components/style/stylesheets/rule_parser.rs index b622ef1001a..3e9872b5a1c 100644 --- a/components/style/stylesheets/rule_parser.rs +++ b/components/style/stylesheets/rule_parser.rs @@ -7,7 +7,7 @@ use {Namespace, Prefix}; use counter_style::{parse_counter_style_body, parse_counter_style_name}; use cssparser::{AtRuleParser, AtRuleType, Parser, QualifiedRuleParser, RuleListParser}; -use cssparser::{CompactCowStr, SourceLocation}; +use cssparser::{CompactCowStr, SourceLocation, BasicParseError}; use error_reporting::ContextualParseError; use font_face::parse_font_face_block; use media_queries::{parse_media_query_list, MediaList}; @@ -184,7 +184,13 @@ impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> { self.state = State::Namespaces; let prefix_result = input.try(|input| input.expect_ident()); - let url = Namespace::from(Cow::from(input.expect_url_or_string()?)); + let maybe_namespace = match input.expect_url_or_string() { + Ok(url_or_string) => url_or_string, + Err(BasicParseError::UnexpectedToken(t)) => + return Err(StyleParseError::UnexpectedTokenWithinNamespace(t).into()), + Err(e) => return Err(e.into()), + }; + let url = Namespace::from(Cow::from(maybe_namespace)); let id = register_namespace(&url) .map_err(|()| StyleParseError::UnspecifiedError)?; @@ -509,7 +515,7 @@ fn get_location_with_offset( offset: u64 ) -> SourceLocation { SourceLocation { - line: location.line + offset as u32 - 1, + line: location.line + offset as u32, column: location.column, } } diff --git a/components/style_traits/Cargo.toml b/components/style_traits/Cargo.toml index feeeb7c786a..3473d710353 100644 --- a/components/style_traits/Cargo.toml +++ b/components/style_traits/Cargo.toml @@ -16,7 +16,7 @@ gecko = [] [dependencies] app_units = "0.5" bitflags = "0.7" -cssparser = "0.16.1" +cssparser = "0.17.0" euclid = "0.15" heapsize = {version = "0.4", optional = true} heapsize_derive = {version = "0.1", optional = true} diff --git a/components/style_traits/lib.rs b/components/style_traits/lib.rs index 7cb28e7f7c7..d6336ca9e0c 100644 --- a/components/style_traits/lib.rs +++ b/components/style_traits/lib.rs @@ -22,7 +22,7 @@ extern crate euclid; extern crate selectors; #[cfg(feature = "servo")] #[macro_use] extern crate serde; -use cssparser::CompactCowStr; +use cssparser::{CompactCowStr, Token}; use selectors::parser::SelectorParseError; /// Opaque type stored in type-unsafe work queues for parallel layout. @@ -81,9 +81,9 @@ pub type ParseError<'i> = cssparser::ParseError<'i, SelectorParseError<'i, Style /// Errors that can be encountered while parsing CSS values. pub enum StyleParseError<'i> { /// A bad URL token in a DVB. - BadUrlInDeclarationValueBlock, + BadUrlInDeclarationValueBlock(CompactCowStr<'i>), /// A bad string token in a DVB. - BadStringInDeclarationValueBlock, + BadStringInDeclarationValueBlock(CompactCowStr<'i>), /// Unexpected closing parenthesis in a DVB. UnbalancedCloseParenthesisInDeclarationValueBlock, /// Unexpected closing bracket in a DVB. @@ -110,17 +110,21 @@ pub enum StyleParseError<'i> { UnsupportedAtRule(CompactCowStr<'i>), /// A placeholder for many sources of errors that require more specific variants. UnspecifiedError, + /// An unexpected token was found within a namespace rule. + UnexpectedTokenWithinNamespace(Token<'i>), + /// An unknown CSS property was encountered. + UnknownProperty(CompactCowStr<'i>), } /// The result of parsing a property declaration. -#[derive(Eq, PartialEq, Copy, Clone, Debug)] +#[derive(Eq, PartialEq, Clone, Debug)] pub enum PropertyDeclarationParseError { /// The property declaration was for an unknown property. UnknownProperty, /// The property declaration was for a disabled experimental property. ExperimentalProperty, /// The property declaration contained an invalid value. - InvalidValue, + InvalidValue(String), /// The declaration contained an animation property, and we were parsing /// this as a keyframe block (so that property should be ignored). /// diff --git a/ports/geckolib/Cargo.toml b/ports/geckolib/Cargo.toml index d63a2819fe1..5c50eb6bf7a 100644 --- a/ports/geckolib/Cargo.toml +++ b/ports/geckolib/Cargo.toml @@ -16,7 +16,7 @@ gecko_debug = ["style/gecko_debug"] [dependencies] atomic_refcell = "0.1" -cssparser = "0.16.1" +cssparser = "0.17.0" env_logger = {version = "0.4", default-features = false} # disable `regex` to reduce code size libc = "0.2" log = {version = "0.3.5", features = ["release_max_level_info"]} diff --git a/ports/geckolib/error_reporter.rs b/ports/geckolib/error_reporter.rs index 77ce1f4ea12..cb7fae7e1a5 100644 --- a/ports/geckolib/error_reporter.rs +++ b/ports/geckolib/error_reporter.rs @@ -6,7 +6,9 @@ #![allow(unsafe_code)] -use cssparser::{Parser, SourcePosition}; +use cssparser::{Parser, SourcePosition, ParseError as CssParseError, Token, BasicParseError}; +use cssparser::CompactCowStr; +use selectors::parser::SelectorParseError; use style::error_reporting::{ParseErrorReporter, ContextualParseError}; use style::gecko_bindings::bindings::{Gecko_CreateCSSErrorReporter, Gecko_DestroyCSSErrorReporter}; use style::gecko_bindings::bindings::Gecko_ReportUnexpectedCSSError; @@ -15,6 +17,7 @@ use style::gecko_bindings::structs::ErrorReporter as GeckoErrorReporter; use style::gecko_bindings::structs::URLExtraData as RawUrlExtraData; use style::gecko_bindings::sugar::refptr::RefPtr; use style::stylesheets::UrlExtraData; +use style_traits::{ParseError, StyleParseError, PropertyDeclarationParseError}; /// Wrapper around an instance of Gecko's CSS error reporter. pub struct ErrorReporter(*mut GeckoErrorReporter); @@ -39,25 +42,239 @@ impl Drop for ErrorReporter { } } +enum ErrorString<'a> { + Snippet(CompactCowStr<'a>), + Ident(CompactCowStr<'a>), + UnexpectedToken(Token<'a>), +} + +impl<'a> ErrorString<'a> { + fn into_str(self) -> String { + match self { + ErrorString::Snippet(s) => s.into_owned(), + ErrorString::Ident(i) => escape_css_ident(&i), + ErrorString::UnexpectedToken(t) => token_to_str(t), + } + } +} + +// This is identical to the behaviour of cssparser::serialize_identifier, except that +// it uses numerical escapes for a larger set of characters. +fn escape_css_ident(ident: &str) -> String { + // The relevant parts of the CSS grammar are: + // ident ([-]?{nmstart}|[-][-]){nmchar}* + // nmstart [_a-z]|{nonascii}|{escape} + // nmchar [_a-z0-9-]|{nonascii}|{escape} + // nonascii [^\0-\177] + // escape {unicode}|\\[^\n\r\f0-9a-f] + // unicode \\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])? + // from http://www.w3.org/TR/CSS21/syndata.html#tokenization but + // modified for idents by + // http://dev.w3.org/csswg/cssom/#serialize-an-identifier and + // http://dev.w3.org/csswg/css-syntax/#would-start-an-identifier + if ident.is_empty() { + return ident.into() + } + + let mut escaped = String::new(); + + // A leading dash does not need to be escaped as long as it is not the + // *only* character in the identifier. + let mut iter = ident.chars().peekable(); + if iter.peek() == Some(&'-') { + if ident.len() == 1 { + return "\\-".into(); + } + + escaped.push('-'); + // Skip the first character. + let _ = iter.next(); + } + + // Escape a digit at the start (including after a dash), + // numerically. If we didn't escape it numerically, it would get + // interpreted as a numeric escape for the wrong character. + if iter.peek().map_or(false, |&c| '0' <= c && c <= '9') { + let ch = iter.next().unwrap(); + escaped.push_str(&format!("\\{:x} ", ch as u32)); + } + + while let Some(ch) = iter.next() { + if ch == '\0' { + escaped.push_str("\u{FFFD}"); + } else if ch < (0x20 as char) || (0x7f as char <= ch && ch < (0xA0 as char)) { + // Escape U+0000 through U+001F and U+007F through U+009F numerically. + escaped.push_str(&format!("\\{:x} ", ch as u32)); + } else { + // Escape ASCII non-identifier printables as a backslash plus + // the character. + if (ch < (0x7F as char)) && + ch != '_' && ch != '-' && + (ch < '0' || '9' < ch) && + (ch < 'A' || 'Z' < ch) && + (ch < 'a' || 'z' < ch) + { + escaped.push('\\'); + } + escaped.push(ch); + } + } + + escaped +} + +// This is identical to the behaviour of cssparser::CssStringWriter, except that +// the characters between 0x7F and 0xA0 as numerically escaped as well. +fn escape_css_string(s: &str) -> String { + let mut escaped = String::new(); + for ch in s.chars() { + if ch < ' ' || (ch >= (0x7F as char) && ch < (0xA0 as char)) { + escaped.push_str(&format!("\\{:x} ", ch as u32)); + } else { + if ch == '"' || ch == '\'' || ch == '\\' { + // Escape backslash and quote characters symbolically. + // It's not technically necessary to escape the quote + // character that isn't being used to delimit the string, + // but we do it anyway because that makes testing simpler. + escaped.push('\\'); + } + escaped.push(ch); + } + } + escaped +} + +fn token_to_str<'a>(t: Token<'a>) -> String { + match t { + Token::Ident(i) => escape_css_ident(&i), + Token::AtKeyword(kw) => format!("@{}", escape_css_ident(&kw)), + Token::Hash(h) | Token::IDHash(h) => format!("#{}", escape_css_ident(&h)), + Token::QuotedString(s) => format!("'{}'", escape_css_string(&s)), + Token::UnquotedUrl(u) => format!("'{}'", escape_css_string(&u)), + Token::Delim(d) => d.to_string(), + Token::Number { int_value: Some(i), .. } => i.to_string(), + Token::Number { value, .. } => value.to_string(), + Token::Percentage { int_value: Some(i), .. } => i.to_string(), + Token::Percentage { unit_value, .. } => unit_value.to_string(), + Token::Dimension { int_value: Some(i), ref unit, .. } => + format!("{}{}", i.to_string(), escape_css_ident(&unit.to_string())), + Token::Dimension { value, ref unit, .. } => + format!("{}{}", value.to_string(), escape_css_ident(&unit.to_string())), + Token::WhiteSpace(_) => "whitespace".into(), + Token::Comment(_) => "comment".into(), + Token::Colon => ":".into(), + Token::Semicolon => ";".into(), + Token::Comma => ",".into(), + Token::IncludeMatch => "~=".into(), + Token::DashMatch => "|=".into(), + Token::PrefixMatch => "^=".into(), + Token::SuffixMatch => "$=".into(), + Token::SubstringMatch => "*=".into(), + Token::Column => "||".into(), + Token::CDO => "<!--".into(), + Token::CDC => "-->".into(), + Token::Function(f) => format!("{}(", escape_css_ident(&f)), + Token::ParenthesisBlock => "(".into(), + Token::SquareBracketBlock => "[".into(), + Token::CurlyBracketBlock => "{".into(), + Token::BadUrl(url) => format!("url('{}", escape_css_string(&url)).into(), + Token::BadString(s) => format!("'{}", escape_css_string(&s)).into(), + Token::CloseParenthesis => "unmatched close parenthesis".into(), + Token::CloseSquareBracket => "unmatched close square bracket".into(), + Token::CloseCurlyBracket => "unmatched close curly bracket".into(), + } +} + trait ErrorHelpers<'a> { - fn to_gecko_message(&self) -> (&'static [u8], &'a str); + fn error_data(self) -> (CompactCowStr<'a>, ParseError<'a>); + fn error_param(self) -> ErrorString<'a>; + fn to_gecko_message(&self) -> &'static [u8]; } impl<'a> ErrorHelpers<'a> for ContextualParseError<'a> { - fn to_gecko_message(&self) -> (&'static [u8], &'a str) { + fn error_data(self) -> (CompactCowStr<'a>, ParseError<'a>) { + match self { + ContextualParseError::UnsupportedPropertyDeclaration(s, err) | + ContextualParseError::UnsupportedFontFaceDescriptor(s, err) | + ContextualParseError::InvalidKeyframeRule(s, err) | + ContextualParseError::UnsupportedKeyframePropertyDeclaration(s, err) | + ContextualParseError::InvalidRule(s, err) | + ContextualParseError::UnsupportedRule(s, err) | + ContextualParseError::UnsupportedViewportDescriptorDeclaration(s, err) | + ContextualParseError::UnsupportedCounterStyleDescriptorDeclaration(s, err) => + (s.into(), err), + ContextualParseError::InvalidCounterStyleWithoutSymbols(s) | + ContextualParseError::InvalidCounterStyleNotEnoughSymbols(s) => + (s.into(), StyleParseError::UnspecifiedError.into()), + ContextualParseError::InvalidCounterStyleWithoutAdditiveSymbols | + ContextualParseError::InvalidCounterStyleExtendsWithSymbols | + ContextualParseError::InvalidCounterStyleExtendsWithAdditiveSymbols => + ("".into(), StyleParseError::UnspecifiedError.into()) + } + } + + fn error_param(self) -> ErrorString<'a> { + match self.error_data() { + (_, CssParseError::Basic(BasicParseError::UnexpectedToken(t))) => + ErrorString::UnexpectedToken(t), + + (_, CssParseError::Basic(BasicParseError::AtRuleInvalid(i))) => + ErrorString::Snippet(format!("@{}", escape_css_ident(&i)).into()), + + (_, CssParseError::Custom(SelectorParseError::Custom( + StyleParseError::PropertyDeclaration( + PropertyDeclarationParseError::InvalidValue(property))))) => + ErrorString::Snippet(property.into()), + + (_, CssParseError::Custom(SelectorParseError::UnexpectedIdent(ident))) => + ErrorString::Ident(ident), + + (_, CssParseError::Custom(SelectorParseError::ExpectedNamespace(namespace))) => + ErrorString::Ident(namespace), + + (_, CssParseError::Custom(SelectorParseError::Custom( + StyleParseError::UnknownProperty(property)))) => + ErrorString::Ident(property), + + (_, CssParseError::Custom(SelectorParseError::Custom( + StyleParseError::UnexpectedTokenWithinNamespace(token)))) => + ErrorString::UnexpectedToken(token), + + (s, _) => ErrorString::Snippet(s) + } + } + + fn to_gecko_message(&self) -> &'static [u8] { match *self { - ContextualParseError::UnsupportedPropertyDeclaration(decl, _) => - (b"PEUnknownProperty\0", decl), - ContextualParseError::UnsupportedFontFaceDescriptor(decl, _) => - (b"PEUnknwnFontDesc\0", decl), - ContextualParseError::InvalidKeyframeRule(rule, _) => - (b"PEKeyframeBadName\0", rule), - ContextualParseError::UnsupportedKeyframePropertyDeclaration(decl, _) => - (b"PEBadSelectorKeyframeRuleIgnored\0", decl), - ContextualParseError::InvalidRule(rule, _) => - (b"PEDeclDropped\0", rule), - ContextualParseError::UnsupportedRule(rule, _) => - (b"PEDeclDropped\0", rule), + ContextualParseError::UnsupportedPropertyDeclaration( + _, CssParseError::Basic(BasicParseError::UnexpectedToken(_))) | + ContextualParseError::UnsupportedPropertyDeclaration( + _, CssParseError::Basic(BasicParseError::AtRuleInvalid(_))) => + b"PEParseDeclarationDeclExpected\0", + ContextualParseError::UnsupportedPropertyDeclaration( + _, CssParseError::Custom(SelectorParseError::Custom( + StyleParseError::PropertyDeclaration( + PropertyDeclarationParseError::InvalidValue(_))))) => + b"PEValueParsingError\0", + ContextualParseError::UnsupportedPropertyDeclaration(..) => + b"PEUnknownProperty\0", + ContextualParseError::UnsupportedFontFaceDescriptor(..) => + b"PEUnknwnFontDesc\0", + ContextualParseError::InvalidKeyframeRule(..) => + b"PEKeyframeBadName\0", + ContextualParseError::UnsupportedKeyframePropertyDeclaration(..) => + b"PEBadSelectorKeyframeRuleIgnored\0", + ContextualParseError::InvalidRule( + _, CssParseError::Custom(SelectorParseError::ExpectedNamespace(_))) => + b"PEUnknownNamespacePrefix\0", + ContextualParseError::InvalidRule( + _, CssParseError::Custom(SelectorParseError::Custom( + StyleParseError::UnexpectedTokenWithinNamespace(_)))) => + b"PEAtNSUnexpected\0", + ContextualParseError::InvalidRule(..) => + b"PEBadSelectorRSIgnored\0", + ContextualParseError::UnsupportedRule(..) => + b"PEDeclDropped\0", ContextualParseError::UnsupportedViewportDescriptorDeclaration(..) | ContextualParseError::UnsupportedCounterStyleDescriptorDeclaration(..) | ContextualParseError::InvalidCounterStyleWithoutSymbols(..) | @@ -65,7 +282,7 @@ impl<'a> ErrorHelpers<'a> for ContextualParseError<'a> { ContextualParseError::InvalidCounterStyleWithoutAdditiveSymbols | ContextualParseError::InvalidCounterStyleExtendsWithSymbols | ContextualParseError::InvalidCounterStyleExtendsWithAdditiveSymbols => - (b"PEUnknownAtRule\0", ""), + b"PEUnknownAtRule\0", } } } @@ -80,8 +297,9 @@ impl ParseErrorReporter for ErrorReporter { let location = input.source_location(position); let line_number = location.line + line_number_offset as u32; - let (name, param) = error.to_gecko_message(); - let source = ""; + let name = error.to_gecko_message(); + let param = error.error_param().into_str(); + let source = input.current_line(); unsafe { Gecko_ReportUnexpectedCSSError(self.0, name.as_ptr() as *const _, diff --git a/tests/unit/gfx/Cargo.toml b/tests/unit/gfx/Cargo.toml index 078ebb41aa9..ac840b7b2e8 100644 --- a/tests/unit/gfx/Cargo.toml +++ b/tests/unit/gfx/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" doctest = false [dependencies] -cssparser = "0.16.1" +cssparser = "0.17.0" gfx = {path = "../../../components/gfx"} ipc-channel = "0.8" style = {path = "../../../components/style"} diff --git a/tests/unit/style/Cargo.toml b/tests/unit/style/Cargo.toml index ed9b3cff1b6..f5121de85a3 100644 --- a/tests/unit/style/Cargo.toml +++ b/tests/unit/style/Cargo.toml @@ -15,7 +15,7 @@ testing = ["style/testing"] [dependencies] byteorder = "1.0" app_units = "0.5" -cssparser = "0.16.1" +cssparser = "0.17.0" euclid = "0.15" html5ever = "0.18" parking_lot = "0.3" diff --git a/tests/unit/style/stylesheets.rs b/tests/unit/style/stylesheets.rs index 6761be36ff2..9f72573db32 100644 --- a/tests/unit/style/stylesheets.rs +++ b/tests/unit/style/stylesheets.rs @@ -84,7 +84,7 @@ fn test_parse_stylesheet() { url: NsAtom::from("http://www.w3.org/1999/xhtml"), source_location: SourceLocation { line: 1, - column: 19, + column: 18, }, }))), CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule { @@ -114,7 +114,7 @@ fn test_parse_stylesheet() { ]))), source_location: SourceLocation { line: 3, - column: 9, + column: 8, }, }))), CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule { @@ -141,7 +141,7 @@ fn test_parse_stylesheet() { ]))), source_location: SourceLocation { line: 11, - column: 9, + column: 8, }, }))), CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule { @@ -203,7 +203,7 @@ fn test_parse_stylesheet() { ]))), source_location: SourceLocation { line: 15, - column: 9, + column: 8, }, }))), CssRule::Keyframes(Arc::new(stylesheet.shared_lock.wrap(KeyframesRule { @@ -235,7 +235,7 @@ fn test_parse_stylesheet() { vendor_prefix: None, source_location: SourceLocation { line: 16, - column: 19, + column: 18, }, }))) @@ -314,15 +314,16 @@ fn test_report_error_stylesheet() { let mut errors = errors.lock().unwrap(); let error = errors.pop().unwrap(); - assert_eq!("Unsupported property declaration: 'invalid: true;', found unexpected identifier true", error.message); - assert_eq!(10, error.line); - assert_eq!(9, error.column); + assert_eq!("Unsupported property declaration: 'invalid: true;', \ + Custom(UnknownProperty(\"invalid\"))", error.message); + assert_eq!(9, error.line); + assert_eq!(8, error.column); let error = errors.pop().unwrap(); assert_eq!("Unsupported property declaration: 'display: invalid;', \ - Custom(PropertyDeclaration(InvalidValue))", error.message); - assert_eq!(9, error.line); - assert_eq!(9, error.column); + Custom(PropertyDeclaration(InvalidValue(\"display\")))", error.message); + assert_eq!(8, error.line); + assert_eq!(8, error.column); // testing for the url assert_eq!(url, error.url); diff --git a/tests/unit/stylo/Cargo.toml b/tests/unit/stylo/Cargo.toml index 52dc50ea132..7034f9cbbe1 100644 --- a/tests/unit/stylo/Cargo.toml +++ b/tests/unit/stylo/Cargo.toml @@ -16,7 +16,7 @@ testing = ["style/testing"] [dependencies] atomic_refcell = "0.1" -cssparser = "0.16.1" +cssparser = "0.17.0" env_logger = "0.4" euclid = "0.15" geckoservo = {path = "../../../ports/geckolib"} |