aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Matthews <josh@joshmatthews.net>2017-07-06 13:59:31 -0400
committerJosh Matthews <josh@joshmatthews.net>2017-07-10 20:46:12 -0400
commit0b43d0072ce8112b661daef2a9b52fc95143308c (patch)
tree8d06812456367650dc20efccd2fc3f1b8c2fbd5c
parenta08371e8eb343bd6372aa60d7658ff4b7bb5da15 (diff)
downloadservo-0b43d0072ce8112b661daef2a9b52fc95143308c.tar.gz
servo-0b43d0072ce8112b661daef2a9b52fc95143308c.zip
stylo: Update rust-cssparser; extract more specific error types when reporting (bug 1352669).
-rw-r--r--Cargo.lock26
-rw-r--r--components/canvas/Cargo.toml2
-rw-r--r--components/canvas_traits/Cargo.toml2
-rw-r--r--components/script/Cargo.toml2
-rw-r--r--components/script_layout_interface/Cargo.toml2
-rw-r--r--components/selectors/Cargo.toml2
-rw-r--r--components/selectors/parser.rs7
-rw-r--r--components/style/Cargo.toml2
-rw-r--r--components/style/custom_properties.rs8
-rw-r--r--components/style/error_reporting.rs10
-rw-r--r--components/style/properties/declaration_block.rs11
-rw-r--r--components/style/properties/properties.mako.rs11
-rw-r--r--components/style/stylesheets/rule_parser.rs12
-rw-r--r--components/style_traits/Cargo.toml2
-rw-r--r--components/style_traits/lib.rs14
-rw-r--r--ports/geckolib/Cargo.toml2
-rw-r--r--ports/geckolib/error_reporter.rs254
-rw-r--r--tests/unit/gfx/Cargo.toml2
-rw-r--r--tests/unit/style/Cargo.toml2
-rw-r--r--tests/unit/style/stylesheets.rs23
-rw-r--r--tests/unit/stylo/Cargo.toml2
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"}