diff options
38 files changed, 963 insertions, 314 deletions
diff --git a/components/layout/layout_task.rs b/components/layout/layout_task.rs index 1a8311e0a78..b6c8a9b4989 100644 --- a/components/layout/layout_task.rs +++ b/components/layout/layout_task.rs @@ -979,7 +979,7 @@ impl LayoutTask { // FIXME: implement used value computation for line-height property => { rw_data.resolved_style_response = - style.computed_value_to_string(property.as_slice()); + style.computed_value_to_string(property.as_slice()).ok(); } }; } diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 337f7799138..2cd65557bee 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -650,7 +650,7 @@ impl Element { if let &mut Some(ref mut declarations) = &mut *inline_declarations { let index = declarations.normal .iter() - .position(|decl| decl.name() == property); + .position(|decl| decl.matches(property)); if let Some(index) = index { Arc::make_mut(&mut declarations.normal).remove(index); return; @@ -658,7 +658,7 @@ impl Element { let index = declarations.important .iter() - .position(|decl| decl.name() == property); + .position(|decl| decl.matches(property)); if let Some(index) = index { Arc::make_mut(&mut declarations.important).remove(index); return; @@ -715,7 +715,8 @@ impl Element { let to = Arc::make_mut(to); let mut new_from = Vec::new(); for declaration in from.drain(..) { - if properties.contains(&declaration.name()) { + let name = declaration.name(); + if properties.iter().any(|p| name == **p) { to.push(declaration) } else { new_from.push(declaration) diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 64b32314511..4207962112d 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -137,7 +137,7 @@ version = "0.0.1" dependencies = [ "azure 0.1.0 (git+https://github.com/servo/rust-azure)", "canvas_traits 0.0.1", - "cssparser 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "gfx_traits 0.0.1", "gleam 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -154,7 +154,7 @@ name = "canvas_traits" version = "0.0.1" dependencies = [ "azure 0.1.0 (git+https://github.com/servo/rust-azure)", - "cssparser 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "gfx_traits 0.0.1", "ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)", @@ -290,7 +290,7 @@ dependencies = [ [[package]] name = "cssparser" -version = "0.3.6" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "encoding 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", @@ -929,7 +929,7 @@ dependencies = [ "canvas 0.0.1", "canvas_traits 0.0.1", "clock_ticks 0.0.6 (git+https://github.com/tomaka/clock_ticks)", - "cssparser 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "encoding 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1414,7 +1414,7 @@ dependencies = [ "bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "canvas 0.0.1", "canvas_traits 0.0.1", - "cssparser 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "devtools_traits 0.0.1", "encoding 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1480,7 +1480,7 @@ version = "0.1.0" source = "git+https://github.com/servo/rust-selectors#572353b3209af040cd3e6261978b09c7f8122844" dependencies = [ "bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cssparser 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "quickersort 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1622,7 +1622,7 @@ name = "style" version = "0.0.1" dependencies = [ "bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cssparser 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "encoding 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1647,7 +1647,7 @@ dependencies = [ name = "style_tests" version = "0.0.1" dependencies = [ - "cssparser 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "selectors 0.1.0 (git+https://github.com/servo/rust-selectors)", "string_cache 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1662,7 +1662,7 @@ dependencies = [ name = "style_traits" version = "0.0.1" dependencies = [ - "cssparser 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1784,7 +1784,7 @@ version = "0.0.1" dependencies = [ "azure 0.1.0 (git+https://github.com/servo/rust-azure)", "bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cssparser 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "html5ever 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/components/style/Cargo.toml b/components/style/Cargo.toml index c67bf713616..c9a5427e47d 100644 --- a/components/style/Cargo.toml +++ b/components/style/Cargo.toml @@ -23,7 +23,7 @@ git = "https://github.com/servo/rust-selectors" features = ["unstable"] [dependencies.cssparser] -version = "0.3.6" +version = "0.3.9" features = [ "serde-serialization" ] [dependencies.url] diff --git a/components/style/custom_properties.rs b/components/style/custom_properties.rs index 7a8ce7c2c67..4a6f5076f56 100644 --- a/components/style/custom_properties.rs +++ b/components/style/custom_properties.rs @@ -2,96 +2,135 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use cssparser::{Parser, Token, SourcePosition}; +use cssparser::{Parser, Token, SourcePosition, Delimiter, TokenSerializationType, ToCss}; use properties::DeclaredValue; +use std::ascii::AsciiExt; use std::collections::{HashMap, HashSet}; +use std::fmt; use std::sync::Arc; use string_cache::Atom; +use util::mem::HeapSizeOf; // Does not include the `--` prefix pub type Name = Atom; // https://drafts.csswg.org/css-variables/#typedef-custom-property-name -pub fn parse_name(s: &str) -> Result<Name, ()> { +pub fn parse_name(s: &str) -> Result<&str, ()> { if s.starts_with("--") { - Ok(Atom::from_slice(&s[2..])) + Ok(&s[2..]) } else { Err(()) } } #[derive(Clone, PartialEq)] -pub struct Value { - /// In CSS syntax - value: String, +pub struct SpecifiedValue { + css: String, + + first_token_type: TokenSerializationType, + last_token_type: TokenSerializationType, /// Custom property names in var() functions. references: HashSet<Name>, } -pub struct BorrowedValue<'a> { - value: &'a str, +pub struct BorrowedSpecifiedValue<'a> { + css: &'a str, + first_token_type: TokenSerializationType, + last_token_type: TokenSerializationType, references: Option<&'a HashSet<Name>>, } -pub fn parse(input: &mut Parser) -> Result<Value, ()> { +#[derive(Clone, HeapSizeOf)] +pub struct ComputedValue { + css: String, + first_token_type: TokenSerializationType, + last_token_type: TokenSerializationType, +} + +impl ToCss for SpecifiedValue { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + dest.write_str(&self.css) + } +} + +impl ToCss for ComputedValue { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + dest.write_str(&self.css) + } +} + +pub type ComputedValuesMap = HashMap<Name, ComputedValue>; + +impl ComputedValue { + fn empty() -> ComputedValue { + ComputedValue { + css: String::new(), + last_token_type: TokenSerializationType::nothing(), + first_token_type: TokenSerializationType::nothing(), + } + } + + fn push(&mut self, css: &str, css_first_token_type: TokenSerializationType, + css_last_token_type: TokenSerializationType) { + self.first_token_type.set_if_nothing(css_first_token_type); + // If self.first_token_type was nothing, + // self.last_token_type is also nothing and this will be false: + if self.last_token_type.needs_separator_when_before(css_first_token_type) { + self.css.push_str("/**/") + } + self.css.push_str(css); + self.last_token_type = css_last_token_type + } + + fn push_from(&mut self, position: (SourcePosition, TokenSerializationType), + input: &Parser, last_token_type: TokenSerializationType) { + self.push(input.slice_from(position.0), position.1, last_token_type) + } + + fn push_variable(&mut self, variable: &ComputedValue) { + self.push(&variable.css, variable.first_token_type, variable.last_token_type) + } +} + +pub fn parse(input: &mut Parser) -> Result<SpecifiedValue, ()> { let start = input.position(); let mut references = Some(HashSet::new()); - // FIXME: don’t consume a top-level `!` as that would prevent parsing `!important`. - // Maybe using Parser::parse_until_before? - try!(parse_declaration_value(input, &mut references)); - Ok(Value { - value: input.slice_from(start).to_owned(), + let (first, last) = try!(parse_declaration_value(input, &mut references)); + Ok(SpecifiedValue { + css: input.slice_from(start).to_owned(), + first_token_type: first, + last_token_type: last, references: references.unwrap(), }) } /// https://drafts.csswg.org/css-syntax-3/#typedef-declaration-value pub fn parse_declaration_value(input: &mut Parser, references: &mut Option<HashSet<Name>>) - -> Result<(), ()> { - if input.is_exhausted() { + -> Result<(TokenSerializationType, TokenSerializationType), ()> { + input.parse_until_before(Delimiter::Bang | Delimiter::Semicolon, |input| { // Need at least one token - return Err(()) - } - while let Ok(token) = input.next() { - match token { - Token::BadUrl | - Token::BadString | - Token::CloseParenthesis | - Token::CloseSquareBracket | - Token::CloseCurlyBracket | - - Token::Semicolon | - Token::Delim('!') => { - return Err(()) - } - - Token::Function(ref name) if name == "var" => { - try!(input.parse_nested_block(|input| { - parse_var_function(input, references) - })); - } + let start_position = input.position(); + try!(input.next_including_whitespace()); + input.reset(start_position); - Token::Function(_) | - Token::ParenthesisBlock | - Token::CurlyBracketBlock | - Token::SquareBracketBlock => { - try!(input.parse_nested_block(|input| { - parse_declaration_value_block(input, references) - })); - } - - _ => {} - } - } - Ok(()) + parse_declaration_value_block(input, references) + }) } /// Like parse_declaration_value, /// but accept `!` and `;` since they are only invalid at the top level fn parse_declaration_value_block(input: &mut Parser, references: &mut Option<HashSet<Name>>) - -> Result<(), ()> { - while let Ok(token) = input.next() { + -> Result<(TokenSerializationType, TokenSerializationType), ()> { + let mut first_token_type = TokenSerializationType::nothing(); + let mut last_token_type = TokenSerializationType::nothing(); + while let Ok(token) = input.next_including_whitespace_and_comments() { + first_token_type.set_if_nothing(token.serialization_type()); + // This may be OpenParen when it should be Other (for the closing paren) + // but that doesn’t make a difference since OpenParen is only special + // when it comes *after* an identifier (it would turn into a function) + // but a "last" token will only be concantenated *before* another unrelated token. + last_token_type = token.serialization_type(); match token { Token::BadUrl | Token::BadString | @@ -101,7 +140,7 @@ fn parse_declaration_value_block(input: &mut Parser, references: &mut Option<Has return Err(()) } - Token::Function(ref name) if name == "var" => { + Token::Function(ref name) if name.eq_ignore_ascii_case("var") => { try!(input.parse_nested_block(|input| { parse_var_function(input, references) })); @@ -119,7 +158,7 @@ fn parse_declaration_value_block(input: &mut Parser, references: &mut Option<Has _ => {} } } - Ok(()) + Ok((first_token_type, last_token_type)) } // If the var function is valid, return Ok((custom_property_name, fallback)) @@ -131,37 +170,44 @@ fn parse_var_function<'i, 't>(input: &mut Parser<'i, 't>, references: &mut Optio try!(parse_declaration_value(input, references)); } if let Some(ref mut refs) = *references { - refs.insert(name); + refs.insert(Atom::from_slice(name)); } Ok(()) } /// Add one custom property declaration to a map, /// unless another with the same name was already there. -pub fn cascade<'a>(custom_properties: &mut Option<HashMap<&'a Name, BorrowedValue<'a>>>, - inherited: &'a Option<Arc<HashMap<Name, String>>>, +pub fn cascade<'a>(custom_properties: &mut Option<HashMap<&'a Name, BorrowedSpecifiedValue<'a>>>, + inherited: &'a Option<Arc<HashMap<Name, ComputedValue>>>, seen: &mut HashSet<&'a Name>, name: &'a Name, - value: &'a DeclaredValue<Value>) { + specified_value: &'a DeclaredValue<SpecifiedValue>) { let was_not_already_present = seen.insert(name); if was_not_already_present { let map = match *custom_properties { Some(ref mut map) => map, None => { *custom_properties = Some(match *inherited { - Some(ref inherited) => inherited.iter().map(|(key, value)| { - (key, BorrowedValue { value: &value, references: None }) + Some(ref inherited) => inherited.iter().map(|(key, inherited_value)| { + (key, BorrowedSpecifiedValue { + css: &inherited_value.css, + first_token_type: inherited_value.first_token_type, + last_token_type: inherited_value.last_token_type, + references: None + }) }).collect(), None => HashMap::new(), }); custom_properties.as_mut().unwrap() } }; - match *value { - DeclaredValue::Value(ref value) => { - map.insert(name, BorrowedValue { - value: &value.value, - references: Some(&value.references), + match *specified_value { + DeclaredValue::Value(ref specified_value) => { + map.insert(name, BorrowedSpecifiedValue { + css: &specified_value.css, + first_token_type: specified_value.first_token_type, + last_token_type: specified_value.last_token_type, + references: Some(&specified_value.references), }); }, DeclaredValue::WithVariables { .. } => unreachable!(), @@ -173,10 +219,10 @@ pub fn cascade<'a>(custom_properties: &mut Option<HashMap<&'a Name, BorrowedValu } } -pub fn finish_cascade(custom_properties: Option<HashMap<&Name, BorrowedValue>>, - inherited: &Option<Arc<HashMap<Name, String>>>) - -> Option<Arc<HashMap<Name, String>>> { - if let Some(mut map) = custom_properties { +pub fn finish_cascade(specified_values_map: Option<HashMap<&Name, BorrowedSpecifiedValue>>, + inherited: &Option<Arc<HashMap<Name, ComputedValue>>>) + -> Option<Arc<HashMap<Name, ComputedValue>>> { + if let Some(mut map) = specified_values_map { remove_cycles(&mut map); Some(Arc::new(substitute_all(map, inherited))) } else { @@ -186,7 +232,7 @@ pub fn finish_cascade(custom_properties: Option<HashMap<&Name, BorrowedValue>>, /// https://drafts.csswg.org/css-variables/#cycles /// The initial value of a custom property is represented by this property not being in the map. -fn remove_cycles(map: &mut HashMap<&Name, BorrowedValue>) { +fn remove_cycles(map: &mut HashMap<&Name, BorrowedSpecifiedValue>) { let mut to_remove = HashSet::new(); { let mut visited = HashSet::new(); @@ -194,7 +240,7 @@ fn remove_cycles(map: &mut HashMap<&Name, BorrowedValue>) { for name in map.keys() { walk(map, name, &mut stack, &mut visited, &mut to_remove); - fn walk<'a>(map: &HashMap<&'a Name, BorrowedValue<'a>>, + fn walk<'a>(map: &HashMap<&'a Name, BorrowedSpecifiedValue<'a>>, name: &'a Name, stack: &mut Vec<&'a Name>, visited: &mut HashSet<&'a Name>, @@ -228,114 +274,150 @@ fn remove_cycles(map: &mut HashMap<&Name, BorrowedValue>) { } /// Replace `var()` functions for all custom properties. -fn substitute_all(custom_properties: HashMap<&Name, BorrowedValue>, - inherited: &Option<Arc<HashMap<Name, String>>>) - -> HashMap<Name, String> { - let mut substituted_map = HashMap::new(); +fn substitute_all(specified_values_map: HashMap<&Name, BorrowedSpecifiedValue>, + inherited: &Option<Arc<HashMap<Name, ComputedValue>>>) + -> HashMap<Name, ComputedValue> { + let mut computed_values_map = HashMap::new(); let mut invalid = HashSet::new(); - for (&name, value) in &custom_properties { - // If this value is invalid at computed-time it won’t be inserted in substituted_map. + for (&name, value) in &specified_values_map { + // If this value is invalid at computed-time it won’t be inserted in computed_values_map. // Nothing else to do. let _ = substitute_one( - name, value, &custom_properties, inherited, None, &mut substituted_map, &mut invalid); + name, value, &specified_values_map, inherited, None, + &mut computed_values_map, &mut invalid); } - substituted_map + computed_values_map } /// Replace `var()` functions for one custom property. /// Also recursively record results for other custom properties referenced by `var()` functions. /// Return `Err(())` for invalid at computed time. +/// or `Ok(last_token_type that was pushed to partial_computed_value)` otherwise. fn substitute_one(name: &Name, - value: &BorrowedValue, - custom_properties: &HashMap<&Name, BorrowedValue>, - inherited: &Option<Arc<HashMap<Name, String>>>, - substituted: Option<&mut String>, - substituted_map: &mut HashMap<Name, String>, + specified_value: &BorrowedSpecifiedValue, + specified_values_map: &HashMap<&Name, BorrowedSpecifiedValue>, + inherited: &Option<Arc<HashMap<Name, ComputedValue>>>, + partial_computed_value: Option<&mut ComputedValue>, + computed_values_map: &mut HashMap<Name, ComputedValue>, invalid: &mut HashSet<Name>) - -> Result<(), ()> { - if let Some(value) = substituted_map.get(name) { - if let Some(substituted) = substituted { - substituted.push_str(value) + -> Result<TokenSerializationType, ()> { + if let Some(computed_value) = computed_values_map.get(name) { + if let Some(partial_computed_value) = partial_computed_value { + partial_computed_value.push_variable(computed_value) } - return Ok(()) + return Ok(computed_value.last_token_type) } if invalid.contains(name) { return Err(()); } - let value = if value.references.map(|set| set.is_empty()) == Some(false) { - let mut substituted = String::new(); - let mut input = Parser::new(&value.value); - let mut start = input.position(); - if substitute_block(&mut input, &mut start, &mut substituted, &mut |name, substituted| { - if let Some(value) = custom_properties.get(name) { - substitute_one(name, value, custom_properties, inherited, - Some(substituted), substituted_map, invalid) - } else { - Err(()) + let computed_value = if specified_value.references.map(|set| set.is_empty()) == Some(false) { + let mut partial_computed_value = ComputedValue::empty(); + let mut input = Parser::new(&specified_value.css); + let mut position = (input.position(), specified_value.first_token_type); + let result = substitute_block( + &mut input, &mut position, &mut partial_computed_value, + &mut |name, partial_computed_value| { + if let Some(other_specified_value) = specified_values_map.get(name) { + substitute_one(name, other_specified_value, specified_values_map, inherited, + Some(partial_computed_value), computed_values_map, invalid) + } else { + Err(()) + } } - }).is_ok() { - substituted.push_str(input.slice_from(start)); - substituted + ); + if let Ok(last_token_type) = result { + partial_computed_value.push_from(position, &input, last_token_type); + partial_computed_value } else { // Invalid at computed-value time. Use the inherited value. - if let Some(value) = inherited.as_ref().and_then(|i| i.get(name)) { - value.clone() + if let Some(inherited_value) = inherited.as_ref().and_then(|i| i.get(name)) { + inherited_value.clone() } else { invalid.insert(name.clone()); return Err(()) } } } else { - value.value.to_owned() + // The specified value contains no var() reference + ComputedValue { + css: specified_value.css.to_owned(), + first_token_type: specified_value.first_token_type, + last_token_type: specified_value.last_token_type, + } }; - if let Some(substituted) = substituted { - substituted.push_str(&value) + if let Some(partial_computed_value) = partial_computed_value { + partial_computed_value.push_variable(&computed_value) } - substituted_map.insert(name.clone(), value); - Ok(()) + let last_token_type = computed_value.last_token_type; + computed_values_map.insert(name.clone(), computed_value); + Ok(last_token_type) } /// Replace `var()` functions in an arbitrary bit of input. /// /// The `substitute_one` callback is called for each `var()` function in `input`. /// If the variable has its initial value, -/// the callback should return `Err(())` and leave `substituted` unchanged. +/// the callback should return `Err(())` and leave `partial_computed_value` unchanged. /// Otherwise, it should push the value of the variable (with its own `var()` functions replaced) -/// to `substituted` and return `Ok(())`. +/// to `partial_computed_value` and return `Ok(last_token_type of what was pushed)` /// /// Return `Err(())` if `input` is invalid at computed-value time. +/// or `Ok(last_token_type that was pushed to partial_computed_value)` otherwise. fn substitute_block<F>(input: &mut Parser, - start: &mut SourcePosition, - substituted: &mut String, + position: &mut (SourcePosition, TokenSerializationType), + partial_computed_value: &mut ComputedValue, substitute_one: &mut F) - -> Result<(), ()> - where F: FnMut(&Name, &mut String) -> Result<(), ()> { + -> Result<TokenSerializationType, ()> + where F: FnMut(&Name, &mut ComputedValue) -> Result<TokenSerializationType, ()> { + let mut last_token_type = TokenSerializationType::nothing(); + let mut set_position_at_next_iteration = false; loop { - let input_slice = input.slice_from(*start); - let token = if let Ok(token) = input.next() { token } else { break }; + let before_this_token = input.position(); + let next = input.next_including_whitespace_and_comments(); + if set_position_at_next_iteration { + *position = (before_this_token, match next { + Ok(ref token) => token.serialization_type(), + Err(()) => TokenSerializationType::nothing(), + }); + set_position_at_next_iteration = false; + } + let token = if let Ok(token) = next { + token + } else { + break + }; match token { - Token::Function(ref name) if name == "var" => { - substituted.push_str(input_slice); + Token::Function(ref name) if name.eq_ignore_ascii_case("var") => { + partial_computed_value.push( + input.slice(position.0..before_this_token), position.1, last_token_type); try!(input.parse_nested_block(|input| { // parse_var_function() ensures neither .unwrap() will fail. let name = input.expect_ident().unwrap(); - let name = parse_name(&name).unwrap(); + let name = Atom::from_slice(parse_name(&name).unwrap()); - if substitute_one(&name, substituted).is_ok() { + if let Ok(last) = substitute_one(&name, partial_computed_value) { + last_token_type = last; // Skip over the fallback, as `parse_nested_block` would return `Err` // if we don’t consume all of `input`. // FIXME: Add a specialized method to cssparser to do this with less work. while let Ok(_) = input.next() {} } else { try!(input.expect_comma()); - let mut start = input.position(); - try!(substitute_block(input, &mut start, substituted, substitute_one)); - substituted.push_str(input.slice_from(start)); + let position = input.position(); + let first_token_type = input.next_including_whitespace_and_comments() + // parse_var_function() ensures that .unwrap() will not fail. + .unwrap() + .serialization_type(); + input.reset(position); + let mut position = (position, first_token_type); + last_token_type = try!(substitute_block( + input, &mut position, partial_computed_value, substitute_one)); + partial_computed_value.push_from(position, input, last_token_type); } Ok(()) })); - *start = input.position(); + set_position_at_next_iteration = true } Token::Function(_) | @@ -343,11 +425,13 @@ fn substitute_block<F>(input: &mut Parser, Token::CurlyBracketBlock | Token::SquareBracketBlock => { try!(input.parse_nested_block(|input| { - substitute_block(input, start, substituted, substitute_one) + substitute_block(input, position, partial_computed_value, substitute_one) })); + // It’s the same type for CloseCurlyBracket and CloseSquareBracket. + last_token_type = Token::CloseParenthesis.serialization_type(); } - _ => {} + _ => last_token_type = token.serialization_type() } } // FIXME: deal with things being implicitly closed at the end of the input. E.g. @@ -356,31 +440,27 @@ fn substitute_block<F>(input: &mut Parser, // <p style="background: var(--color) var(--image) top left; --image: url('a.png"></p> // </div> // ``` - Ok(()) + Ok(last_token_type) } /// Replace `var()` functions for a non-custom property. /// Return `Err(())` for invalid at computed time. -pub fn substitute(input: &str, custom_properties: &Option<Arc<HashMap<Name, String>>>) +pub fn substitute(input: &str, first_token_type: TokenSerializationType, + computed_values_map: &Option<Arc<HashMap<Name, ComputedValue>>>) -> Result<String, ()> { - let empty_map; - let custom_properties = if let &Some(ref arc) = custom_properties { - &**arc - } else { - empty_map = HashMap::new(); - &empty_map - }; - let mut substituted = String::new(); + let mut substituted = ComputedValue::empty(); let mut input = Parser::new(input); - let mut start = input.position(); - try!(substitute_block(&mut input, &mut start, &mut substituted, &mut |name, substituted| { - if let Some(value) = custom_properties.get(name) { - substituted.push_str(value); - Ok(()) - } else { - Err(()) + let mut position = (input.position(), first_token_type); + let last_token_type = try!(substitute_block( + &mut input, &mut position, &mut substituted, &mut |name, substituted| { + if let Some(value) = computed_values_map.as_ref().and_then(|map| map.get(name)) { + substituted.push_variable(value); + Ok(value.last_token_type) + } else { + Err(()) + } } - })); - substituted.push_str(input.slice_from(start)); - Ok(substituted) + )); + substituted.push_from(position, &input, last_token_type); + Ok(substituted.css) } diff --git a/components/style/lib.rs b/components/style/lib.rs index 60e137a1ab0..425a5eafb06 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -5,6 +5,7 @@ #![feature(arc_unique)] #![feature(box_syntax)] #![feature(box_patterns)] +#![feature(concat_idents)] #![feature(core_intrinsics)] #![feature(custom_attribute)] #![feature(custom_derive)] diff --git a/components/style/properties.mako.rs b/components/style/properties.mako.rs index 79e1a5e7182..374b9b875d0 100644 --- a/components/style/properties.mako.rs +++ b/components/style/properties.mako.rs @@ -5,8 +5,7 @@ // This file is a Mako template: http://www.makotemplates.org/ use std::ascii::AsciiExt; -use std::borrow::ToOwned; -use std::collections::{HashSet, HashMap}; +use std::collections::HashSet; use std::default::Default; use std::fmt; use std::fmt::Debug; @@ -16,7 +15,7 @@ use std::mem; use std::sync::Arc; use cssparser::{Parser, Color, RGBA, AtRuleParser, DeclarationParser, - DeclarationListParser, parse_important, ToCss}; + DeclarationListParser, parse_important, ToCss, TokenSerializationType}; use url::Url; use util::geometry::Au; use util::logical_geometry::{LogicalMargin, PhysicalSide, WritingMode}; @@ -115,6 +114,7 @@ pub mod longhands { derived_from=derived_from, custom_cascade=custom_cascade, experimental=experimental) + property.style_struct = THIS_STYLE_STRUCT THIS_STYLE_STRUCT.longhands.append(property) LONGHANDS.append(property) LONGHANDS_BY_NAME[name] = property @@ -128,7 +128,7 @@ pub mod longhands { % if derived_from is None: use cssparser::Parser; use parser::ParserContext; - use properties::{CSSWideKeyword, DeclaredValue}; + use properties::{CSSWideKeyword, DeclaredValue, Shorthand}; % endif use properties::longhands; use properties::property_bit_field::PropertyBitField; @@ -157,7 +157,7 @@ pub mod longhands { return } seen.set_${property.ident}(); - let computed_value = substitute_variables( + let computed_value = ::properties::substitute_variables_${property.ident}( declared_value, &style.custom_properties, |value| match *value { DeclaredValue::Value(ref specified_value) => { specified_value.to_computed_value(&context) @@ -193,29 +193,6 @@ pub mod longhands { % endif } % if derived_from is None: - pub fn substitute_variables<F, R>(value: &DeclaredValue<SpecifiedValue>, - custom_properties: &Option<Arc<HashMap<Atom, String>>>, - f: F) - -> R - where F: FnOnce(&DeclaredValue<SpecifiedValue>) -> R { - if let DeclaredValue::WithVariables { ref css, ref base_url } = *value { - f(& - ::custom_properties::substitute(css, custom_properties) - .and_then(|css| { - // As of this writing, only the base URL is used for property values: - let context = ParserContext::new( - ::stylesheets::Origin::Author, base_url); - parse_specified(&context, &mut Parser::new(&css)) - }) - .unwrap_or( - // Invalid at computed-value time. - DeclaredValue::${"Inherit" if THIS_STYLE_STRUCT.inherited else "Initial"} - ) - ) - } else { - f(value) - } - } pub fn parse_declared(context: &ParserContext, input: &mut Parser) -> Result<DeclaredValue<SpecifiedValue>, ()> { match input.try(CSSWideKeyword::parse) { @@ -227,13 +204,19 @@ pub mod longhands { input.look_for_var_functions(); let start = input.position(); let specified = parse_specified(context, input); + if specified.is_err() { + while let Ok(_) = input.next() {} // Look for var() after the error. + } let var = input.seen_var_functions(); if specified.is_err() && var { input.reset(start); - try!(::custom_properties::parse_declaration_value(input, &mut None)); + let (first_token_type, _) = try!( + ::custom_properties::parse_declaration_value(input, &mut None)); return Ok(DeclaredValue::WithVariables { css: input.slice_from(start).to_owned(), + first_token_type: first_token_type, base_url: context.base_url.clone(), + from_shorthand: Shorthand::None, }) } specified @@ -4881,7 +4864,7 @@ pub mod shorthands { pub mod ${shorthand.ident} { use cssparser::Parser; use parser::ParserContext; - use properties::longhands; + use properties::{longhands, PropertyDeclaration, DeclaredValue, Shorthand}; pub struct Longhands { % for sub_property in shorthand.sub_properties: @@ -4890,8 +4873,46 @@ pub mod shorthands { % endfor } + pub fn parse(context: &ParserContext, input: &mut Parser, + declarations: &mut Vec<PropertyDeclaration>) + -> Result<(), ()> { + input.look_for_var_functions(); + let start = input.position(); + let value = parse_value(context, input); + let var = input.seen_var_functions(); + if let Ok(value) = value { + % for sub_property in shorthand.sub_properties: + declarations.push(PropertyDeclaration::${sub_property.camel_case}( + match value.${sub_property.ident} { + Some(value) => DeclaredValue::Value(value), + None => DeclaredValue::Initial, + } + )); + % endfor + Ok(()) + } else if var { + input.reset(start); + let (first_token_type, _) = try!( + ::custom_properties::parse_declaration_value(input, &mut None)); + let css = input.slice_from(start); + % for sub_property in shorthand.sub_properties: + declarations.push(PropertyDeclaration::${sub_property.camel_case}( + DeclaredValue::WithVariables { + css: css.to_owned(), + first_token_type: first_token_type, + base_url: context.base_url.clone(), + from_shorthand: Shorthand::${shorthand.camel_case}, + } + )); + % endfor + Ok(()) + } else { + Err(()) + } + } + #[allow(unused_variables)] - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { + pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { ${caller.body()} } } @@ -5582,6 +5603,55 @@ mod property_bit_field { } } +% for property in LONGHANDS: + % if property.derived_from is None: + fn substitute_variables_${property.ident}<F, R>( + value: &DeclaredValue<longhands::${property.ident}::SpecifiedValue>, + custom_properties: &Option<Arc<::custom_properties::ComputedValuesMap>>, + f: F) + -> R + where F: FnOnce(&DeclaredValue<longhands::${property.ident}::SpecifiedValue>) -> R + { + if let DeclaredValue::WithVariables { + ref css, first_token_type, ref base_url, from_shorthand + } = *value { + f(& + ::custom_properties::substitute(css, first_token_type, custom_properties) + .and_then(|css| { + // As of this writing, only the base URL is used for property values: + let context = ParserContext::new( + ::stylesheets::Origin::Author, base_url); + Parser::new(&css).parse_entirely(|input| { + match from_shorthand { + Shorthand::None => { + longhands::${property.ident}::parse_specified(&context, input) + } + % for shorthand in SHORTHANDS: + % if property in shorthand.sub_properties: + Shorthand::${shorthand.camel_case} => { + shorthands::${shorthand.ident}::parse_value(&context, input) + .map(|result| match result.${property.ident} { + Some(value) => DeclaredValue::Value(value), + None => DeclaredValue::Initial, + }) + } + % endif + % endfor + _ => unreachable!() + } + }) + }) + .unwrap_or( + // Invalid at computed-value time. + DeclaredValue::${"Inherit" if property.style_struct.inherited else "Initial"} + ) + ) + } else { + f(value) + } + } + % endif +% endfor /// Declarations are stored in reverse order. /// Overridden declarations are skipped. @@ -5720,11 +5790,24 @@ impl CSSWideKeyword { } } +#[derive(Clone, Copy, Eq, PartialEq, Debug)] +pub enum Shorthand { + None, + % for property in SHORTHANDS: + ${property.camel_case}, + % endfor +} + #[derive(Clone, PartialEq, Eq, Debug)] pub enum DeclaredValue<T> { Value(T), - WithVariables { css: String, base_url: Url }, + WithVariables { + css: String, + first_token_type: TokenSerializationType, + base_url: Url, + from_shorthand: Shorthand + }, Initial, Inherit, // There is no Unset variant here. @@ -5732,13 +5815,17 @@ pub enum DeclaredValue<T> { // depending on whether the property is inherited. } -impl<T: ToCss> DeclaredValue<T> { - pub fn specified_value(&self) -> String { +impl<T: ToCss> ToCss for DeclaredValue<T> { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { match *self { - DeclaredValue::Value(ref inner) => inner.to_css_string(), - DeclaredValue::WithVariables { ref css, .. } => css.clone(), - DeclaredValue::Initial => "initial".to_owned(), - DeclaredValue::Inherit => "inherit".to_owned(), + DeclaredValue::Value(ref inner) => inner.to_css(dest), + DeclaredValue::WithVariables { ref css, from_shorthand: Shorthand::None, .. } => { + dest.write_str(css) + } + // https://drafts.csswg.org/css-variables/#variables-in-shorthands + DeclaredValue::WithVariables { .. } => Ok(()), + DeclaredValue::Initial => dest.write_str("initial"), + DeclaredValue::Inherit => dest.write_str("inherit"), } } } @@ -5748,7 +5835,7 @@ pub enum PropertyDeclaration { % for property in LONGHANDS: ${property.camel_case}(DeclaredValue<longhands::${property.ident}::SpecifiedValue>), % endfor - Custom(::custom_properties::Name, DeclaredValue<::custom_properties::Value>), + Custom(::custom_properties::Name, DeclaredValue<::custom_properties::SpecifiedValue>), } @@ -5760,15 +5847,52 @@ pub enum PropertyDeclarationParseResult { ValidOrIgnoredDeclaration, } +#[derive(Eq, PartialEq, Clone)] +pub enum PropertyDeclarationName { + Longhand(&'static str), + Custom(::custom_properties::Name), + Internal +} + +impl PartialEq<str> for PropertyDeclarationName { + fn eq(&self, other: &str) -> bool { + match *self { + PropertyDeclarationName::Longhand(n) => n == other, + PropertyDeclarationName::Custom(ref n) => { + ::custom_properties::parse_name(other) == Ok(&**n) + } + PropertyDeclarationName::Internal => false, + } + } +} + +impl fmt::Display for PropertyDeclarationName { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + PropertyDeclarationName::Longhand(n) => f.write_str(n), + PropertyDeclarationName::Custom(ref n) => { + try!(f.write_str("--")); + f.write_str(n) + } + PropertyDeclarationName::Internal => Ok(()), + } + } +} + impl PropertyDeclaration { - pub fn name(&self) -> &'static str { + pub fn name(&self) -> PropertyDeclarationName { match *self { % for property in LONGHANDS: % if property.derived_from is None: - PropertyDeclaration::${property.camel_case}(..) => "${property.name}", + PropertyDeclaration::${property.camel_case}(..) => { + PropertyDeclarationName::Longhand("${property.name}") + } % endif % endfor - _ => "", + PropertyDeclaration::Custom(ref name, _) => { + PropertyDeclarationName::Custom(name.clone()) + } + _ => PropertyDeclarationName::Internal, } } @@ -5777,10 +5901,11 @@ impl PropertyDeclaration { % for property in LONGHANDS: % if property.derived_from is None: PropertyDeclaration::${property.camel_case}(ref value) => - value.specified_value(), + value.to_css_string(), % endif % endfor - ref decl => panic!("unsupported property declaration: {:?}", decl.name()), + PropertyDeclaration::Custom(_, ref value) => value.to_css_string(), + ref decl => panic!("unsupported property declaration: {}", decl.name()), } } @@ -5793,6 +5918,9 @@ impl PropertyDeclaration { } % endif % endfor + PropertyDeclaration::Custom(ref declaration_name, _) => { + ::custom_properties::parse_name(name) == Ok(&**declaration_name) + } _ => false, } } @@ -5809,7 +5937,7 @@ impl PropertyDeclaration { Err(()) => return PropertyDeclarationParseResult::InvalidValue, } }; - result_list.push(PropertyDeclaration::Custom(name, value)); + result_list.push(PropertyDeclaration::Custom(Atom::from_slice(name), value)); return PropertyDeclarationParseResult::ValidOrIgnoredDeclaration; } match_ignore_ascii_case! { name, @@ -5865,18 +5993,8 @@ impl PropertyDeclaration { % endfor PropertyDeclarationParseResult::ValidOrIgnoredDeclaration }, - Err(()) => match shorthands::${shorthand.ident}::parse(context, input) { - Ok(result) => { - % for sub_property in shorthand.sub_properties: - result_list.push(PropertyDeclaration::${sub_property.camel_case}( - match result.${sub_property.ident} { - Some(value) => DeclaredValue::Value(value), - None => DeclaredValue::Initial, - } - )); - % endfor - PropertyDeclarationParseResult::ValidOrIgnoredDeclaration - }, + Err(()) => match shorthands::${shorthand.ident}::parse(context, input, result_list) { + Ok(()) => PropertyDeclarationParseResult::ValidOrIgnoredDeclaration, Err(()) => PropertyDeclarationParseResult::InvalidValue, } } @@ -5919,7 +6037,7 @@ pub struct ComputedValues { % for style_struct in STYLE_STRUCTS: ${style_struct.ident}: Arc<style_structs::${style_struct.name}>, % endfor - custom_properties: Option<Arc<HashMap<::custom_properties::Name, String>>>, + custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>, shareable: bool, pub writing_mode: WritingMode, pub root_font_size: Au, @@ -6077,14 +6195,19 @@ impl ComputedValues { } % endfor - pub fn computed_value_to_string(&self, name: &str) -> Option<String> { + pub fn computed_value_to_string(&self, name: &str) -> Result<String, ()> { match name { % for style_struct in STYLE_STRUCTS: % for longhand in style_struct.longhands: - "${longhand.name}" => Some(self.${style_struct.ident}.${longhand.ident}.to_css_string()), + "${longhand.name}" => Ok(self.${style_struct.ident}.${longhand.ident}.to_css_string()), % endfor % endfor - _ => None + _ => { + let name = try!(::custom_properties::parse_name(name)); + let map = try!(self.custom_properties.as_ref().ok_or(())); + let value = try!(map.get(&Atom::from_slice(name)).ok_or(())); + Ok(value.to_css_string()) + } } } } @@ -6153,7 +6276,7 @@ fn cascade_with_cached_declarations( shareable: bool, parent_style: &ComputedValues, cached_style: &ComputedValues, - custom_properties: Option<Arc<HashMap<Atom, String>>>, + custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>, context: &computed::Context) -> ComputedValues { % for style_struct in STYLE_STRUCTS: @@ -6182,7 +6305,7 @@ fn cascade_with_cached_declarations( } seen.set_${property.ident}(); let computed_value = - longhands::${property.ident}::substitute_variables( + substitute_variables_${property.ident}( declared_value, &custom_properties, |value| match *value { DeclaredValue::Value(ref specified_value) => specified_value.to_computed_value(context), @@ -6354,7 +6477,7 @@ pub fn cascade(viewport_size: Size2D<Au>, // This assumes that the computed and specified values have the same Rust type. macro_rules! get_specified( ($style_struct_getter: ident, $property: ident, $declared_value: expr) => { - longhands::$property::substitute_variables( + concat_idents!(substitute_variables_, $property)( $declared_value, &custom_properties, |value| match *value { DeclaredValue::Value(specified_value) => specified_value, DeclaredValue::Initial => longhands::$property::get_initial_value(), @@ -6374,7 +6497,7 @@ pub fn cascade(viewport_size: Size2D<Au>, for declaration in sub_list.declarations.iter().rev() { match *declaration { PropertyDeclaration::FontSize(ref value) => { - context.font_size = longhands::font_size::substitute_variables( + context.font_size = substitute_variables_font_size( value, &custom_properties, |value| match *value { DeclaredValue::Value(ref specified_value) => { match specified_value.0 { @@ -6395,7 +6518,7 @@ pub fn cascade(viewport_size: Size2D<Au>, ); } PropertyDeclaration::Color(ref value) => { - context.color = longhands::color::substitute_variables( + context.color = substitute_variables_color( value, &custom_properties, |value| match *value { DeclaredValue::Value(ref specified_value) => { specified_value.parsed @@ -6700,7 +6823,7 @@ pub fn is_supported_property(property: &str) -> bool { "${property.name}" => true, % endfor "${LONGHANDS[-1].name}" => true - _ => false + _ => property.starts_with("--") } } diff --git a/components/util/mem.rs b/components/util/mem.rs index f336d22be0e..7f83099b06e 100644 --- a/components/util/mem.rs +++ b/components/util/mem.rs @@ -15,7 +15,7 @@ use std::sync::Arc; use azure::azure_hl::Color; use cssparser::Color as CSSParserColor; -use cssparser::RGBA; +use cssparser::{RGBA, TokenSerializationType}; use cursor::Cursor; use euclid::length::Length; use euclid::scale_factor::ScaleFactor; @@ -414,6 +414,7 @@ known_heap_size!(0, Rect<T>, Point2D<T>, Size2D<T>, Matrix2D<T>, SideOffsets2D<T known_heap_size!(0, Length<T, U>, ScaleFactor<T, U, V>); known_heap_size!(0, Au, WritingMode, CSSParserColor, Color, RGBA, Cursor, Matrix4, Atom, Namespace); -known_heap_size!(0, JSVal, PagePx, ViewportPx, DevicePixel, QuirksMode, OsRng, RawStatus, LengthOrPercentageOrAuto); +known_heap_size!(0, JSVal, PagePx, ViewportPx, DevicePixel, QuirksMode, OsRng, RawStatus); +known_heap_size!(0, TokenSerializationType, LengthOrPercentageOrAuto); known_heap_size!(0, PseudoElement, Combinator, str); diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index c10a232265b..90c9e8e3e1e 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -129,7 +129,7 @@ version = "0.0.1" dependencies = [ "azure 0.1.0 (git+https://github.com/servo/rust-azure)", "canvas_traits 0.0.1", - "cssparser 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "gfx_traits 0.0.1", "gleam 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -146,7 +146,7 @@ name = "canvas_traits" version = "0.0.1" dependencies = [ "azure 0.1.0 (git+https://github.com/servo/rust-azure)", - "cssparser 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "gfx_traits 0.0.1", "ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)", @@ -282,7 +282,7 @@ dependencies = [ [[package]] name = "cssparser" -version = "0.3.6" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "encoding 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", @@ -880,7 +880,7 @@ dependencies = [ "canvas 0.0.1", "canvas_traits 0.0.1", "clock_ticks 0.0.6 (git+https://github.com/tomaka/clock_ticks)", - "cssparser 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "encoding 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1348,7 +1348,7 @@ dependencies = [ "bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "canvas 0.0.1", "canvas_traits 0.0.1", - "cssparser 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "devtools_traits 0.0.1", "encoding 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1406,7 +1406,7 @@ version = "0.1.0" source = "git+https://github.com/servo/rust-selectors#572353b3209af040cd3e6261978b09c7f8122844" dependencies = [ "bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cssparser 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "quickersort 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1581,7 +1581,7 @@ name = "style" version = "0.0.1" dependencies = [ "bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cssparser 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "encoding 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1606,7 +1606,7 @@ dependencies = [ name = "style_traits" version = "0.0.1" dependencies = [ - "cssparser 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1728,7 +1728,7 @@ version = "0.0.1" dependencies = [ "azure 0.1.0 (git+https://github.com/servo/rust-azure)", "bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cssparser 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "html5ever 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ports/gonk/Cargo.lock b/ports/gonk/Cargo.lock index 2974aa69209..31eef4562ca 100644 --- a/ports/gonk/Cargo.lock +++ b/ports/gonk/Cargo.lock @@ -110,7 +110,7 @@ version = "0.0.1" dependencies = [ "azure 0.1.0 (git+https://github.com/servo/rust-azure)", "canvas_traits 0.0.1", - "cssparser 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "gfx_traits 0.0.1", "gleam 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -127,7 +127,7 @@ name = "canvas_traits" version = "0.0.1" dependencies = [ "azure 0.1.0 (git+https://github.com/servo/rust-azure)", - "cssparser 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "gfx_traits 0.0.1", "ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)", @@ -252,7 +252,7 @@ dependencies = [ [[package]] name = "cssparser" -version = "0.3.6" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "encoding 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", @@ -764,7 +764,7 @@ dependencies = [ "canvas 0.0.1", "canvas_traits 0.0.1", "clock_ticks 0.0.6 (git+https://github.com/tomaka/clock_ticks)", - "cssparser 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "encoding 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1214,7 +1214,7 @@ dependencies = [ "bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "canvas 0.0.1", "canvas_traits 0.0.1", - "cssparser 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "devtools_traits 0.0.1", "encoding 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1272,7 +1272,7 @@ version = "0.1.0" source = "git+https://github.com/servo/rust-selectors#572353b3209af040cd3e6261978b09c7f8122844" dependencies = [ "bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cssparser 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "quickersort 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1427,7 +1427,7 @@ name = "style" version = "0.0.1" dependencies = [ "bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cssparser 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "encoding 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1452,7 +1452,7 @@ dependencies = [ name = "style_traits" version = "0.0.1" dependencies = [ - "cssparser 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1563,7 +1563,7 @@ version = "0.0.1" dependencies = [ "azure 0.1.0 (git+https://github.com/servo/rust-azure)", "bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cssparser 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "html5ever 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/tests/wpt/metadata-css/css-variables-1_dev/html/css-vars-custom-property-inheritance.htm.ini b/tests/wpt/metadata-css/css-variables-1_dev/html/css-vars-custom-property-inheritance.htm.ini deleted file mode 100644 index 87fee1c5ce8..00000000000 --- a/tests/wpt/metadata-css/css-variables-1_dev/html/css-vars-custom-property-inheritance.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[css-vars-custom-property-inheritance.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-declaration-08.htm.ini b/tests/wpt/metadata-css/css-variables-1_dev/html/variable-declaration-08.htm.ini deleted file mode 100644 index 83e66d3a80e..00000000000 --- a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-declaration-08.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[variable-declaration-08.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-declaration-14.htm.ini b/tests/wpt/metadata-css/css-variables-1_dev/html/variable-declaration-14.htm.ini deleted file mode 100644 index 1b565847071..00000000000 --- a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-declaration-14.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[variable-declaration-14.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-declaration-20.htm.ini b/tests/wpt/metadata-css/css-variables-1_dev/html/variable-declaration-20.htm.ini deleted file mode 100644 index e3de1be4109..00000000000 --- a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-declaration-20.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[variable-declaration-20.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-declaration-24.htm.ini b/tests/wpt/metadata-css/css-variables-1_dev/html/variable-declaration-24.htm.ini deleted file mode 100644 index ba980233612..00000000000 --- a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-declaration-24.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[variable-declaration-24.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-declaration-26.htm.ini b/tests/wpt/metadata-css/css-variables-1_dev/html/variable-declaration-26.htm.ini deleted file mode 100644 index 98c918745b5..00000000000 --- a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-declaration-26.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[variable-declaration-26.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-declaration-37.htm.ini b/tests/wpt/metadata-css/css-variables-1_dev/html/variable-declaration-37.htm.ini deleted file mode 100644 index 6c8b66e14c0..00000000000 --- a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-declaration-37.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[variable-declaration-37.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-declaration-53.htm.ini b/tests/wpt/metadata-css/css-variables-1_dev/html/variable-declaration-53.htm.ini deleted file mode 100644 index bc25e718bd5..00000000000 --- a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-declaration-53.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[variable-declaration-53.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-declaration-54.htm.ini b/tests/wpt/metadata-css/css-variables-1_dev/html/variable-declaration-54.htm.ini deleted file mode 100644 index 362a722c3e7..00000000000 --- a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-declaration-54.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[variable-declaration-54.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-declaration-55.htm.ini b/tests/wpt/metadata-css/css-variables-1_dev/html/variable-declaration-55.htm.ini deleted file mode 100644 index ca63a2f84da..00000000000 --- a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-declaration-55.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[variable-declaration-55.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-03.htm.ini b/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-03.htm.ini deleted file mode 100644 index d845cc12cd8..00000000000 --- a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-03.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[variable-reference-03.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-04.htm.ini b/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-04.htm.ini deleted file mode 100644 index fba032c2710..00000000000 --- a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-04.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[variable-reference-04.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-13.htm.ini b/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-13.htm.ini deleted file mode 100644 index 7f832f8cdac..00000000000 --- a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-13.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[variable-reference-13.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-14.htm.ini b/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-14.htm.ini deleted file mode 100644 index dd849805038..00000000000 --- a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-14.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[variable-reference-14.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-15.htm.ini b/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-15.htm.ini deleted file mode 100644 index 7dcf1687aab..00000000000 --- a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-15.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[variable-reference-15.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-18.htm.ini b/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-18.htm.ini deleted file mode 100644 index e09c394fc76..00000000000 --- a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-18.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[variable-reference-18.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-19.htm.ini b/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-19.htm.ini deleted file mode 100644 index 3847b908e1b..00000000000 --- a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-19.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[variable-reference-19.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-20.htm.ini b/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-20.htm.ini deleted file mode 100644 index 4ab2b3816af..00000000000 --- a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-20.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[variable-reference-20.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-26.htm.ini b/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-26.htm.ini deleted file mode 100644 index ebd0652279f..00000000000 --- a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-26.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[variable-reference-26.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-27.htm.ini b/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-27.htm.ini deleted file mode 100644 index 8a36f19f2e7..00000000000 --- a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-27.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[variable-reference-27.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-36.htm.ini b/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-36.htm.ini deleted file mode 100644 index d052a96d261..00000000000 --- a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-36.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[variable-reference-36.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-38.htm.ini b/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-38.htm.ini deleted file mode 100644 index ae8c7dd94be..00000000000 --- a/tests/wpt/metadata-css/css-variables-1_dev/html/variable-reference-38.htm.ini +++ /dev/null @@ -1,3 +0,0 @@ -[variable-reference-38.htm] - type: reftest - expected: FAIL diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index 9f187275bd7..3cd5550686c 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -281,6 +281,24 @@ ] }, "testharness": { + "css/test_variable_legal_values.html": [ + { + "path": "css/test_variable_legal_values.html", + "url": "/_mozilla/css/test_variable_legal_values.html" + } + ], + "css/test_variable_serialization_computed.html": [ + { + "path": "css/test_variable_serialization_computed.html", + "url": "/_mozilla/css/test_variable_serialization_computed.html" + } + ], + "css/test_variable_serialization_specified.html": [ + { + "path": "css/test_variable_serialization_specified.html", + "url": "/_mozilla/css/test_variable_serialization_specified.html" + } + ], "mozilla/DOMParser.html": [ { "path": "mozilla/DOMParser.html", diff --git a/tests/wpt/mozilla/meta/css/test_variable_serialization_computed.html.ini b/tests/wpt/mozilla/meta/css/test_variable_serialization_computed.html.ini new file mode 100644 index 00000000000..1e88bbd62e9 --- /dev/null +++ b/tests/wpt/mozilla/meta/css/test_variable_serialization_computed.html.ini @@ -0,0 +1,56 @@ +[test_variable_serialization_computed.html] + type: testharness + [subtest #20 with `--a: var(--b)var(--c); --b:orange; --c:red;`] + expected: FAIL + + [subtest #21 with `--a: var(--b)var(--c,red); --b:orange;`] + expected: FAIL + + [subtest #22 with `--a: var(--b,orange)var(--c); --c:red;`] + expected: FAIL + + [subtest #23 with `counter-reset: var(--a)red; --a:orange;`] + expected: FAIL + + [subtest #24 with `--a: var(--b)var(--c); --c:[c\]; --b:('ab`] + expected: FAIL + + [subtest #25 with `--a: '`] + expected: FAIL + + [subtest #26 with `--a: '\\`] + expected: FAIL + + [subtest #27 with `--a: \\`] + expected: FAIL + + [subtest #28 with `--a: "`] + expected: FAIL + + [subtest #29 with `--a: "\\`] + expected: FAIL + + [subtest #30 with `--a: /* abc `] + expected: FAIL + + [subtest #31 with `--a: /* abc *`] + expected: FAIL + + [subtest #32 with `--a: url(http://example.org/`] + expected: FAIL + + [subtest #33 with `--a: url(http://example.org/\\`] + expected: FAIL + + [subtest #34 with `--a: url('http://example.org/`] + expected: FAIL + + [subtest #35 with `--a: url('http://example.org/\\`] + expected: FAIL + + [subtest #36 with `--a: url("http://example.org/`] + expected: FAIL + + [subtest #37 with `--a: url("http://example.org/\\`] + expected: FAIL + diff --git a/tests/wpt/mozilla/meta/css/test_variable_serialization_specified.html.ini b/tests/wpt/mozilla/meta/css/test_variable_serialization_specified.html.ini new file mode 100644 index 00000000000..b4b7a38b3f5 --- /dev/null +++ b/tests/wpt/mozilla/meta/css/test_variable_serialization_specified.html.ini @@ -0,0 +1,116 @@ +[test_variable_serialization_specified.html] + type: testharness + [`var(--a)` is unchanged by specified value serialization] + expected: FAIL + + [`var(--a) ` is unchanged by specified value serialization] + expected: FAIL + + [`var( --a ) ` is unchanged by specified value serialization] + expected: FAIL + + [`var(--a, )` is unchanged by specified value serialization] + expected: FAIL + + [`var(--a,/**/a)` is unchanged by specified value serialization] + expected: FAIL + + [`1px var(--a)` is unchanged by specified value serialization] + expected: FAIL + + [`var(--a) 1px` is unchanged by specified value serialization] + expected: FAIL + + [`something 3px url(whereever) calc(var(--a) + 1px)` is unchanged by specified value serialization] + expected: FAIL + + [`var(--a)var(--b)` is unchanged by specified value serialization] + expected: FAIL + + [`var(--a, var(--b, var(--c, black)))` is unchanged by specified value serialization] + expected: FAIL + + [`var(--a) <!--` is unchanged by specified value serialization] + expected: FAIL + + [`--> var(--a)` is unchanged by specified value serialization] + expected: FAIL + + [`{ [ var(--a) \] }` is unchanged by specified value serialization] + expected: FAIL + + [`[;\] var(--a)` is unchanged by specified value serialization] + expected: FAIL + + [`var(--a,(;))` is unchanged by specified value serialization] + expected: FAIL + + [`VAR(--a)` is unchanged by specified value serialization] + expected: FAIL + + [`var(--0)` is unchanged by specified value serialization] + expected: FAIL + + [`var(--\\30)` is unchanged by specified value serialization] + expected: FAIL + + [`var(--\\d800)` is unchanged by specified value serialization] + expected: FAIL + + [`var(--\\ffffff)` is unchanged by specified value serialization] + expected: FAIL + + [`var(--a` becomes `var(--a)` in specified value serialization] + expected: FAIL + + [`var(--a , ` becomes `var(--a , )` in specified value serialization] + expected: FAIL + + [`var(--a, ` becomes `var(--a, )` in specified value serialization] + expected: FAIL + + [`var(--a, var(--b` becomes `var(--a, var(--b))` in specified value serialization] + expected: FAIL + + [`var(--a /* unclosed comment` becomes `var(--a /* unclosed comment*/)` in specified value serialization] + expected: FAIL + + [`var(--a /* unclosed comment *` becomes `var(--a /* unclosed comment */)` in specified value serialization] + expected: FAIL + + [`[{(((var(--a` becomes `[{(((var(--a))))}\]` in specified value serialization] + expected: FAIL + + [`var(--a, "unclosed string` becomes `var(--a, "unclosed string")` in specified value serialization] + expected: FAIL + + [`var(--a, 'unclosed string` becomes `var(--a, 'unclosed string')` in specified value serialization] + expected: FAIL + + [`var(--a) "unclosed string\\` becomes `var(--a) "unclosed string"` in specified value serialization] + expected: FAIL + + [`var(--a) 'unclosed string\\` becomes `var(--a) 'unclosed string'` in specified value serialization] + expected: FAIL + + [`var(--a) \\` becomes `var(--a) \\�` in specified value serialization] + expected: FAIL + + [`var(--a) url(unclosedurl` becomes `var(--a) url(unclosedurl)` in specified value serialization] + expected: FAIL + + [`var(--a) url('unclosedurl` becomes `var(--a) url('unclosedurl')` in specified value serialization] + expected: FAIL + + [`var(--a) url("unclosedurl` becomes `var(--a) url("unclosedurl")` in specified value serialization] + expected: FAIL + + [`var(--a) url(unclosedurl\\` becomes `var(--a) url(unclosedurl\\�)` in specified value serialization] + expected: FAIL + + [`var(--a) url('unclosedurl\\` becomes `var(--a) url('unclosedurl')` in specified value serialization] + expected: FAIL + + [`var(--a) url("unclosedurl\\` becomes `var(--a) url("unclosedurl")` in specified value serialization] + expected: FAIL + diff --git a/tests/wpt/mozilla/tests/css/test_variable_legal_values.html b/tests/wpt/mozilla/tests/css/test_variable_legal_values.html new file mode 100644 index 00000000000..22826c4d29c --- /dev/null +++ b/tests/wpt/mozilla/tests/css/test_variable_legal_values.html @@ -0,0 +1,119 @@ +<!DOCTYPE html> +<html><head> + <title>CSS Variables Allowed Syntax</title> + <link href="http://dbaron.org/" rel="author" title="L. David Baron"> + <link href="http://mozilla.com/" rel="author" title="Mozilla Corporation"> + <link href="http://www.w3.org/TR/css-variables-1/#defining-variables" rel="help"> + <meta content='The <value> type used in the syntax above is defined as anything matching the "value" production in CSS 2.1 Chapter 4.1 [CSS21].' name="assert"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +<script id="metadata_cache">/* +{ + "percentage": { "assert": "Value allowed within variable: percentage" }, + "number": { "assert": "Value allowed within variable: number" }, + "length": { "assert": "Value allowed within variable: length" }, + "time": { "assert": "Value allowed within variable: time" }, + "function": { "assert": "Value allowed within variable: function" }, + "nested_function": { "assert": "Value allowed within variable: nested function" }, + "parentheses": { "assert": "Value allowed within variable: parentheses" }, + "braces": { "assert": "Value allowed within variable: braces" }, + "brackets": { "assert": "Value allowed within variable: brackets" }, + "at_keyword_unknown": { "assert": "Value allowed within variable: at-keyword (unknown)" }, + "at_keyword_known": { "assert": "Value allowed within variable: at-keyword (known)" }, + "at_keyword_unknown_and_block": { "assert": "Value allowed within variable: at-keyword (unknown) and block" }, + "at_keyword_known_and_block": { "assert": "Value allowed within variable: at-keyword (known) and block" }, + "unbalanced_close_bracket_at_toplevel": { "assert": "Value not allowed within variable: unbalanced close bracket at toplevel" }, + "unbalanced_close_paren_at_toplevel": { "assert": "Value not allowed within variable: unbalanced close paren at toplevel" }, + "unbalanced_close_bracket_in_something_balanced": { "assert": "Value not allowed within variable: unbalanced close bracket in something balanced" }, + "unbalanced_close_paren_in_something_balanced": { "assert": "Value not allowed within variable: unbalanced close paren in something balanced" }, + "unbalanced_close_brace_in_something_balanced": { "assert": "Value not allowed within variable: unbalanced close brace in something balanced" }, + "CDO_at_top_level": { "assert": "Value allowed within variable: CDO at top level" }, + "CDC_at_top_level": { "assert": "Value allowed within variable: CDC at top level" }, + "semicolon_not_at_top_level_value_unused": { "assert": "Value allowed within variable: semicolon not at top level (value -> unused)" }, + "CDO_not_at_top_level_value_unused": { "assert": "Value allowed within variable: CDO not at top level (value -> unused)" }, + "CDC_not_at_top_level_value_unused": { "assert": "Value allowed within variable: CDC not at top level (value -> unused)" } +} +*/</script> +</head> +<body onload="run()"> +<div id="log"></div> +<div id="test"></div> +<script> +setup({ "explicit_done": true }); + +function run() { + // Setup the iframe + var div = document.getElementById("test"); + var test_cs = window.getComputedStyle(div, ""); + + var initial_cs = test_cs.backgroundColor; + div.setAttribute("style", "background-color: green"); + var green_cs = test_cs.backgroundColor; + div.setAttribute("style", "background-color: red"); + var red_cs = test_cs.backgroundColor; + + function description_to_name(description) { + return description.replace(/\W+/g, "_").replace(/^_/, "").replace(/_$/, ""); + } + + function assert_allowed_variable_value(value, description) { + test(function() { + div.setAttribute("style", + " --test: red;\n" + + " --test: " + value + ";\n" + + " background-color: red;\n" + + " background-color: var(--test);\n" + + ""); + assert_not_equals(initial_cs, red_cs); + assert_equals(initial_cs, test_cs.backgroundColor); + }, + description_to_name(description), + { assert: "Value allowed within variable: " + description }); + } + + function assert_disallowed_balanced_variable_value(value, description) { + test(function() { + div.setAttribute("style", + " --test: green;\n" + + " --test: " + value + ";\n" + + " background-color: red;\n" + + " background-color: var(--test);\n" + + ""); + assert_not_equals(green_cs, red_cs); + assert_equals(green_cs, test_cs.backgroundColor); + }, + description_to_name(description), + { assert: "Value not allowed within variable: " + description }); + } + + assert_allowed_variable_value("25%", "percentage"); + assert_allowed_variable_value("37", "number"); + assert_allowed_variable_value("12em", "length"); + assert_allowed_variable_value("75ms", "time"); + assert_allowed_variable_value("foo()", "function"); + assert_allowed_variable_value("foo(bar())", "nested function"); + assert_allowed_variable_value("( )", "parentheses"); + assert_allowed_variable_value("{ }", "braces"); + assert_allowed_variable_value("[ ]", "brackets"); + assert_allowed_variable_value("@foobar", "at-keyword (unknown)"); + assert_allowed_variable_value("@media", "at-keyword (known)"); + assert_allowed_variable_value("@foobar {}", "at-keyword (unknown) and block"); + assert_allowed_variable_value("@media {}", "at-keyword (known) and block"); + assert_disallowed_balanced_variable_value("]", "unbalanced close bracket at toplevel"); + assert_disallowed_balanced_variable_value(")", "unbalanced close paren at toplevel"); + assert_disallowed_balanced_variable_value("(])", "unbalanced close bracket in something balanced"); + assert_disallowed_balanced_variable_value("[)]", "unbalanced close paren in something balanced"); + assert_disallowed_balanced_variable_value("(})", "unbalanced close brace in something balanced"); + assert_allowed_variable_value("<!--", "CDO at top level"); + assert_allowed_variable_value("-->", "CDC at top level"); + assert_allowed_variable_value("(;)", "semicolon not at top level (value -> unused)"); + assert_allowed_variable_value("(<!--)", "CDO not at top level (value -> unused)"); + assert_allowed_variable_value("(-->)", "CDC not at top level (value -> unused)"); + + done(); +} + +</script> + + +</body></html> diff --git a/tests/wpt/mozilla/tests/css/test_variable_serialization_computed.html b/tests/wpt/mozilla/tests/css/test_variable_serialization_computed.html new file mode 100644 index 00000000000..a7f0b63d1c4 --- /dev/null +++ b/tests/wpt/mozilla/tests/css/test_variable_serialization_computed.html @@ -0,0 +1,79 @@ +<!DOCTYPE html> +<title>Test serialization of computed CSS variable values</title> +<!-- + +Adapted from https://dxr.mozilla.org/mozilla-central/source/layout/style/test/test_variable_serialization_computed.html + +NOTE: CSS does not define the exact serialization of whitespace and comments +(see https://drafts.csswg.org/css-syntax/#serialization) +so an implementation could fail this test but still be conforming. + +--> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<div> + <span></span> +</div> + +<script> +// Each entry is an entire declaration followed by the property to check and +// its expected computed value. +var values = [ + ["", "--z", "an-inherited-value"], + ["--a: ", "--a", " "], + ["--a: initial", "--a", ""], + ["--z: initial", "--z", ""], + ["--a: inherit", "--a", ""], + ["--z: inherit", "--z", "an-inherited-value"], + ["--a: unset", "--a", ""], + ["--z: unset", "--z", "an-inherited-value"], + ["--a: 1px", "--a", " 1px"], + ["--a: var(--a)", "--a", ""], + ["--a: var(--b)", "--a", ""], + ["--a: var(--b); --b: 1px", "--a", " 1px"], + ["--a: var(--b, 1px)", "--a", " 1px"], + ["--a: var(--a, 1px)", "--a", ""], + ["--a: something 3px url(whereever) calc(var(--a) + 1px)", "--a", ""], + ["--a: something 3px url(whereever) calc(var(--b,1em) + 1px)", "--a", " something 3px url(whereever) calc(1em + 1px)"], + ["--a: var(--b, var(--c, var(--d, Black)))", "--a", " Black"], + ["--a: a var(--b) c; --b:b", "--a", " a b c"], + ["--a: a var(--b,b var(--c) d) e; --c:c", "--a", " a b c d e"], + ["--a: var(--b)red; --b:orange;", "--a", " orange/**/red"], + ["--a: var(--b)var(--c); --b:orange; --c:red;", "--a", " orange/**/red"], + ["--a: var(--b)var(--c,red); --b:orange;", "--a", " orange/**/red"], + ["--a: var(--b,orange)var(--c); --c:red;", "--a", " orange/**/red"], + ["counter-reset: var(--a)red; --a:orange;", "counter-reset", "orange 0 red 0"], + ["--a: var(--b)var(--c); --c:[c]; --b:('ab", "--a", " ('ab')[c]"], + ["--a: '", "--a", " ''"], + ["--a: '\\", "--a", " ''"], + ["--a: \\", "--a", " \\\ufffd"], + ["--a: \"", "--a", " \"\""], + ["--a: \"\\", "--a", " \"\""], + ["--a: /* abc ", "--a", " /* abc */"], + ["--a: /* abc *", "--a", " /* abc */"], + ["--a: url(http://example.org/", "--a", " url(http://example.org/)"], + ["--a: url(http://example.org/\\", "--a", " url(http://example.org/\\\ufffd)"], + ["--a: url('http://example.org/", "--a", " url('http://example.org/')"], + ["--a: url('http://example.org/\\", "--a", " url('http://example.org/')"], + ["--a: url(\"http://example.org/", "--a", " url(\"http://example.org/\")"], + ["--a: url(\"http://example.org/\\", "--a", " url(\"http://example.org/\")"] +]; + +var div = document.querySelector("div"); +var span = document.querySelector("span"); + +div.setAttribute("style", "--z:an-inherited-value"); + +values.forEach(function(entry, i) { + var declaration = entry[0]; + var property = entry[1]; + var expected = entry[2]; + test(function() { + span.setAttribute("style", declaration); + var cs = getComputedStyle(span, ""); + assert_equals(cs.getPropertyValue(property), expected); + }, "subtest #" + i + " with `" + declaration + "`"); +}); +</script> diff --git a/tests/wpt/mozilla/tests/css/test_variable_serialization_specified.html b/tests/wpt/mozilla/tests/css/test_variable_serialization_specified.html new file mode 100644 index 00000000000..cbb9e01e3fb --- /dev/null +++ b/tests/wpt/mozilla/tests/css/test_variable_serialization_specified.html @@ -0,0 +1,121 @@ +<!DOCTYPE html> +<title>Test serialization of specified CSS variable values</title> +<!-- + +Adapted from https://dxr.mozilla.org/mozilla-central/source/layout/style/test/test_variable_serialization_specified.html + +NOTE: CSS does not define the exact serialization of whitespace and comments +(see https://drafts.csswg.org/css-syntax/#serialization) +so an implementation could fail this test but still be conforming. + +--> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<div id=div1></div> + +<script> +// Values that should be serialized back to the same string. +var values_with_unchanged_specified_value_serialization = [ + "var(--a)", + "var(--a)", + "var(--a) ", + "var( --a ) ", + "var(--a, )", + "var(--a,/**/a)", + "1px var(--a)", + "var(--a) 1px", + "something 3px url(whereever) calc(var(--a) + 1px)", + "var(--a)", + "var(--a)var(--b)", + "var(--a, var(--b, var(--c, black)))", + "var(--a) <!--", + "--> var(--a)", + "{ [ var(--a) ] }", + "[;] var(--a)", + "var(--a,(;))", + "VAR(--a)", + "var(--0)", + "var(--\\30)", + "var(--\\d800)", + "var(--\\ffffff)", +]; + +// Values that serialize differently, due to additional implied closing +// characters at EOF. +var values_with_changed_specified_value_serialization = [ + ["var(--a", "var(--a)"], + ["var(--a , ", "var(--a , )"], + ["var(--a, ", "var(--a, )"], + ["var(--a, var(--b", "var(--a, var(--b))"], + ["var(--a /* unclosed comment", "var(--a /* unclosed comment*/)"], + ["var(--a /* unclosed comment *", "var(--a /* unclosed comment */)"], + ["[{(((var(--a", "[{(((var(--a))))}]"], + ["var(--a, \"unclosed string", "var(--a, \"unclosed string\")"], + ["var(--a, 'unclosed string", "var(--a, 'unclosed string')"], + ["var(--a) \"unclosed string\\", "var(--a) \"unclosed string\""], + ["var(--a) 'unclosed string\\", "var(--a) 'unclosed string'"], + ["var(--a) \\", "var(--a) \\\ufffd"], + ["var(--a) url(unclosedurl", "var(--a) url(unclosedurl)"], + ["var(--a) url('unclosedurl", "var(--a) url('unclosedurl')"], + ["var(--a) url(\"unclosedurl", "var(--a) url(\"unclosedurl\")"], + ["var(--a) url(unclosedurl\\", "var(--a) url(unclosedurl\\\ufffd)"], + ["var(--a) url('unclosedurl\\", "var(--a) url('unclosedurl')"], + ["var(--a) url(\"unclosedurl\\", "var(--a) url(\"unclosedurl\")"], +]; + +var div1 = document.getElementById("div1"); + +function test_specified_value_serialization(value, expected) { + // Test setting value on a custom property with setProperty. + div1.style.setProperty("--test", value, ""); + assert_equals(div1.style.getPropertyValue("--test"), expected, + "value with identical serialization set on custom property with setProperty"); + + // Test setting value on a custom property via style sheet parsing. + div1.setAttribute("style", "--test:" + value); + assert_equals(div1.style.getPropertyValue("--test"), expected, + "value with identical serialization set on custom property via parsing"); + + // Test setting value on a non-custom longhand property with setProperty. + div1.style.setProperty("color", value, ""); + assert_equals(div1.style.getPropertyValue("color"), expected, + "value with identical serialization set on non-custom longhand property with setProperty"); + + // Test setting value on a non-custom longhand property via style sheet parsing. + div1.setAttribute("style", "color:" + value); + assert_equals(div1.style.getPropertyValue("color"), expected, + "value with identical serialization set on non-custom longhand property via parsing"); + + // Test setting value on a non-custom shorthand property with setProperty. + div1.style.setProperty("margin", value, ""); + assert_equals(div1.style.getPropertyValue("margin"), expected, + "value with identical serialization set on non-custom shorthand property with setProperty"); + + // Test setting value on a non-custom shorthand property via style sheet parsing. + div1.setAttribute("style", "margin:" + value); + assert_equals(div1.style.getPropertyValue("margin"), expected, + "value with identical serialization set on non-custom shorthand property via parsing"); + + // Clean up. + div1.style.removeProperty("--test"); + div1.style.removeProperty("color"); + div1.style.removeProperty("margin"); +} + +/* +function test(f) { f() } +function assert_equals(a, b, m) { if (a == b) { console.log("`"+a+"`", "`"+b+"`", m) } } +*/ + +values_with_unchanged_specified_value_serialization.forEach(function(value) { + test(function() { test_specified_value_serialization(value, value) }, + "`" + value + "` is unchanged by specified value serialization"); +}); + +values_with_changed_specified_value_serialization.forEach(function(pair) { + test(function() { test_specified_value_serialization(pair[0], pair[1]) }, + "`" + pair[0] + "` becomes `" + pair[1] + "` in specified value serialization"); +}); +</script> |