mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Auto merge of #7555 - SimonSapin:custom-properties++, r=mbrubeck
Custom properties, take 2 Support `var()` in shorthand properties, and fix various bugs. r? @pcwalton <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/7555) <!-- Reviewable:end -->
This commit is contained in:
commit
1b6d4daf85
38 changed files with 963 additions and 314 deletions
|
@ -979,7 +979,7 @@ impl LayoutTask {
|
||||||
// FIXME: implement used value computation for line-height
|
// FIXME: implement used value computation for line-height
|
||||||
property => {
|
property => {
|
||||||
rw_data.resolved_style_response =
|
rw_data.resolved_style_response =
|
||||||
style.computed_value_to_string(property.as_slice());
|
style.computed_value_to_string(property.as_slice()).ok();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -650,7 +650,7 @@ impl Element {
|
||||||
if let &mut Some(ref mut declarations) = &mut *inline_declarations {
|
if let &mut Some(ref mut declarations) = &mut *inline_declarations {
|
||||||
let index = declarations.normal
|
let index = declarations.normal
|
||||||
.iter()
|
.iter()
|
||||||
.position(|decl| decl.name() == property);
|
.position(|decl| decl.matches(property));
|
||||||
if let Some(index) = index {
|
if let Some(index) = index {
|
||||||
Arc::make_mut(&mut declarations.normal).remove(index);
|
Arc::make_mut(&mut declarations.normal).remove(index);
|
||||||
return;
|
return;
|
||||||
|
@ -658,7 +658,7 @@ impl Element {
|
||||||
|
|
||||||
let index = declarations.important
|
let index = declarations.important
|
||||||
.iter()
|
.iter()
|
||||||
.position(|decl| decl.name() == property);
|
.position(|decl| decl.matches(property));
|
||||||
if let Some(index) = index {
|
if let Some(index) = index {
|
||||||
Arc::make_mut(&mut declarations.important).remove(index);
|
Arc::make_mut(&mut declarations.important).remove(index);
|
||||||
return;
|
return;
|
||||||
|
@ -715,7 +715,8 @@ impl Element {
|
||||||
let to = Arc::make_mut(to);
|
let to = Arc::make_mut(to);
|
||||||
let mut new_from = Vec::new();
|
let mut new_from = Vec::new();
|
||||||
for declaration in from.drain(..) {
|
for declaration in from.drain(..) {
|
||||||
if properties.contains(&declaration.name()) {
|
let name = declaration.name();
|
||||||
|
if properties.iter().any(|p| name == **p) {
|
||||||
to.push(declaration)
|
to.push(declaration)
|
||||||
} else {
|
} else {
|
||||||
new_from.push(declaration)
|
new_from.push(declaration)
|
||||||
|
|
20
components/servo/Cargo.lock
generated
20
components/servo/Cargo.lock
generated
|
@ -137,7 +137,7 @@ version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"azure 0.1.0 (git+https://github.com/servo/rust-azure)",
|
"azure 0.1.0 (git+https://github.com/servo/rust-azure)",
|
||||||
"canvas_traits 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)",
|
||||||
"euclid 0.2.0 (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",
|
"gfx_traits 0.0.1",
|
||||||
"gleam 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"gleam 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -154,7 +154,7 @@ name = "canvas_traits"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"azure 0.1.0 (git+https://github.com/servo/rust-azure)",
|
"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)",
|
"euclid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"gfx_traits 0.0.1",
|
"gfx_traits 0.0.1",
|
||||||
"ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)",
|
"ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)",
|
||||||
|
@ -290,7 +290,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cssparser"
|
name = "cssparser"
|
||||||
version = "0.3.6"
|
version = "0.3.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"encoding 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
"encoding 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -929,7 +929,7 @@ dependencies = [
|
||||||
"canvas 0.0.1",
|
"canvas 0.0.1",
|
||||||
"canvas_traits 0.0.1",
|
"canvas_traits 0.0.1",
|
||||||
"clock_ticks 0.0.6 (git+https://github.com/tomaka/clock_ticks)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"canvas 0.0.1",
|
"canvas 0.0.1",
|
||||||
"canvas_traits 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",
|
"devtools_traits 0.0.1",
|
||||||
"encoding 0.2.32 (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)",
|
"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"
|
source = "git+https://github.com/servo/rust-selectors#572353b3209af040cd3e6261978b09c7f8122844"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"quickersort 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1622,7 +1622,7 @@ name = "style"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"fnv 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1647,7 +1647,7 @@ dependencies = [
|
||||||
name = "style_tests"
|
name = "style_tests"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
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)",
|
"euclid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"selectors 0.1.0 (git+https://github.com/servo/rust-selectors)",
|
"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)",
|
"string_cache 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1662,7 +1662,7 @@ dependencies = [
|
||||||
name = "style_traits"
|
name = "style_traits"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
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)",
|
"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)",
|
"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)",
|
"log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1784,7 +1784,7 @@ version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"azure 0.1.0 (git+https://github.com/servo/rust-azure)",
|
"azure 0.1.0 (git+https://github.com/servo/rust-azure)",
|
||||||
"bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"html5ever 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
|
@ -23,7 +23,7 @@ git = "https://github.com/servo/rust-selectors"
|
||||||
features = ["unstable"]
|
features = ["unstable"]
|
||||||
|
|
||||||
[dependencies.cssparser]
|
[dependencies.cssparser]
|
||||||
version = "0.3.6"
|
version = "0.3.9"
|
||||||
features = [ "serde-serialization" ]
|
features = [ "serde-serialization" ]
|
||||||
|
|
||||||
[dependencies.url]
|
[dependencies.url]
|
||||||
|
|
|
@ -2,96 +2,135 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* 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 properties::DeclaredValue;
|
||||||
|
use std::ascii::AsciiExt;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::fmt;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use string_cache::Atom;
|
use string_cache::Atom;
|
||||||
|
use util::mem::HeapSizeOf;
|
||||||
|
|
||||||
// Does not include the `--` prefix
|
// Does not include the `--` prefix
|
||||||
pub type Name = Atom;
|
pub type Name = Atom;
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-variables/#typedef-custom-property-name
|
// 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("--") {
|
if s.starts_with("--") {
|
||||||
Ok(Atom::from_slice(&s[2..]))
|
Ok(&s[2..])
|
||||||
} else {
|
} else {
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub struct Value {
|
pub struct SpecifiedValue {
|
||||||
/// In CSS syntax
|
css: String,
|
||||||
value: String,
|
|
||||||
|
first_token_type: TokenSerializationType,
|
||||||
|
last_token_type: TokenSerializationType,
|
||||||
|
|
||||||
/// Custom property names in var() functions.
|
/// Custom property names in var() functions.
|
||||||
references: HashSet<Name>,
|
references: HashSet<Name>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BorrowedValue<'a> {
|
pub struct BorrowedSpecifiedValue<'a> {
|
||||||
value: &'a str,
|
css: &'a str,
|
||||||
|
first_token_type: TokenSerializationType,
|
||||||
|
last_token_type: TokenSerializationType,
|
||||||
references: Option<&'a HashSet<Name>>,
|
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 start = input.position();
|
||||||
let mut references = Some(HashSet::new());
|
let mut references = Some(HashSet::new());
|
||||||
// FIXME: don’t consume a top-level `!` as that would prevent parsing `!important`.
|
let (first, last) = try!(parse_declaration_value(input, &mut references));
|
||||||
// Maybe using Parser::parse_until_before?
|
Ok(SpecifiedValue {
|
||||||
try!(parse_declaration_value(input, &mut references));
|
css: input.slice_from(start).to_owned(),
|
||||||
Ok(Value {
|
first_token_type: first,
|
||||||
value: input.slice_from(start).to_owned(),
|
last_token_type: last,
|
||||||
references: references.unwrap(),
|
references: references.unwrap(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://drafts.csswg.org/css-syntax-3/#typedef-declaration-value
|
/// https://drafts.csswg.org/css-syntax-3/#typedef-declaration-value
|
||||||
pub fn parse_declaration_value(input: &mut Parser, references: &mut Option<HashSet<Name>>)
|
pub fn parse_declaration_value(input: &mut Parser, references: &mut Option<HashSet<Name>>)
|
||||||
-> Result<(), ()> {
|
-> Result<(TokenSerializationType, TokenSerializationType), ()> {
|
||||||
if input.is_exhausted() {
|
input.parse_until_before(Delimiter::Bang | Delimiter::Semicolon, |input| {
|
||||||
// Need at least one token
|
// Need at least one token
|
||||||
return Err(())
|
let start_position = input.position();
|
||||||
}
|
try!(input.next_including_whitespace());
|
||||||
while let Ok(token) = input.next() {
|
input.reset(start_position);
|
||||||
match token {
|
|
||||||
Token::BadUrl |
|
|
||||||
Token::BadString |
|
|
||||||
Token::CloseParenthesis |
|
|
||||||
Token::CloseSquareBracket |
|
|
||||||
Token::CloseCurlyBracket |
|
|
||||||
|
|
||||||
Token::Semicolon |
|
parse_declaration_value_block(input, references)
|
||||||
Token::Delim('!') => {
|
})
|
||||||
return Err(())
|
|
||||||
}
|
|
||||||
|
|
||||||
Token::Function(ref name) if name == "var" => {
|
|
||||||
try!(input.parse_nested_block(|input| {
|
|
||||||
parse_var_function(input, references)
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
Token::Function(_) |
|
|
||||||
Token::ParenthesisBlock |
|
|
||||||
Token::CurlyBracketBlock |
|
|
||||||
Token::SquareBracketBlock => {
|
|
||||||
try!(input.parse_nested_block(|input| {
|
|
||||||
parse_declaration_value_block(input, references)
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Like parse_declaration_value,
|
/// Like parse_declaration_value,
|
||||||
/// but accept `!` and `;` since they are only invalid at the top level
|
/// 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>>)
|
fn parse_declaration_value_block(input: &mut Parser, references: &mut Option<HashSet<Name>>)
|
||||||
-> Result<(), ()> {
|
-> Result<(TokenSerializationType, TokenSerializationType), ()> {
|
||||||
while let Ok(token) = input.next() {
|
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 {
|
match token {
|
||||||
Token::BadUrl |
|
Token::BadUrl |
|
||||||
Token::BadString |
|
Token::BadString |
|
||||||
|
@ -101,7 +140,7 @@ fn parse_declaration_value_block(input: &mut Parser, references: &mut Option<Has
|
||||||
return Err(())
|
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| {
|
try!(input.parse_nested_block(|input| {
|
||||||
parse_var_function(input, references)
|
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))
|
// 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));
|
try!(parse_declaration_value(input, references));
|
||||||
}
|
}
|
||||||
if let Some(ref mut refs) = *references {
|
if let Some(ref mut refs) = *references {
|
||||||
refs.insert(name);
|
refs.insert(Atom::from_slice(name));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add one custom property declaration to a map,
|
/// Add one custom property declaration to a map,
|
||||||
/// unless another with the same name was already there.
|
/// unless another with the same name was already there.
|
||||||
pub fn cascade<'a>(custom_properties: &mut Option<HashMap<&'a Name, BorrowedValue<'a>>>,
|
pub fn cascade<'a>(custom_properties: &mut Option<HashMap<&'a Name, BorrowedSpecifiedValue<'a>>>,
|
||||||
inherited: &'a Option<Arc<HashMap<Name, String>>>,
|
inherited: &'a Option<Arc<HashMap<Name, ComputedValue>>>,
|
||||||
seen: &mut HashSet<&'a Name>,
|
seen: &mut HashSet<&'a Name>,
|
||||||
name: &'a Name,
|
name: &'a Name,
|
||||||
value: &'a DeclaredValue<Value>) {
|
specified_value: &'a DeclaredValue<SpecifiedValue>) {
|
||||||
let was_not_already_present = seen.insert(name);
|
let was_not_already_present = seen.insert(name);
|
||||||
if was_not_already_present {
|
if was_not_already_present {
|
||||||
let map = match *custom_properties {
|
let map = match *custom_properties {
|
||||||
Some(ref mut map) => map,
|
Some(ref mut map) => map,
|
||||||
None => {
|
None => {
|
||||||
*custom_properties = Some(match *inherited {
|
*custom_properties = Some(match *inherited {
|
||||||
Some(ref inherited) => inherited.iter().map(|(key, value)| {
|
Some(ref inherited) => inherited.iter().map(|(key, inherited_value)| {
|
||||||
(key, BorrowedValue { value: &value, references: None })
|
(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(),
|
}).collect(),
|
||||||
None => HashMap::new(),
|
None => HashMap::new(),
|
||||||
});
|
});
|
||||||
custom_properties.as_mut().unwrap()
|
custom_properties.as_mut().unwrap()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
match *value {
|
match *specified_value {
|
||||||
DeclaredValue::Value(ref value) => {
|
DeclaredValue::Value(ref specified_value) => {
|
||||||
map.insert(name, BorrowedValue {
|
map.insert(name, BorrowedSpecifiedValue {
|
||||||
value: &value.value,
|
css: &specified_value.css,
|
||||||
references: Some(&value.references),
|
first_token_type: specified_value.first_token_type,
|
||||||
|
last_token_type: specified_value.last_token_type,
|
||||||
|
references: Some(&specified_value.references),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
DeclaredValue::WithVariables { .. } => unreachable!(),
|
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>>,
|
pub fn finish_cascade(specified_values_map: Option<HashMap<&Name, BorrowedSpecifiedValue>>,
|
||||||
inherited: &Option<Arc<HashMap<Name, String>>>)
|
inherited: &Option<Arc<HashMap<Name, ComputedValue>>>)
|
||||||
-> Option<Arc<HashMap<Name, String>>> {
|
-> Option<Arc<HashMap<Name, ComputedValue>>> {
|
||||||
if let Some(mut map) = custom_properties {
|
if let Some(mut map) = specified_values_map {
|
||||||
remove_cycles(&mut map);
|
remove_cycles(&mut map);
|
||||||
Some(Arc::new(substitute_all(map, inherited)))
|
Some(Arc::new(substitute_all(map, inherited)))
|
||||||
} else {
|
} else {
|
||||||
|
@ -186,7 +232,7 @@ pub fn finish_cascade(custom_properties: Option<HashMap<&Name, BorrowedValue>>,
|
||||||
|
|
||||||
/// https://drafts.csswg.org/css-variables/#cycles
|
/// https://drafts.csswg.org/css-variables/#cycles
|
||||||
/// The initial value of a custom property is represented by this property not being in the map.
|
/// 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 to_remove = HashSet::new();
|
||||||
{
|
{
|
||||||
let mut visited = HashSet::new();
|
let mut visited = HashSet::new();
|
||||||
|
@ -194,7 +240,7 @@ fn remove_cycles(map: &mut HashMap<&Name, BorrowedValue>) {
|
||||||
for name in map.keys() {
|
for name in map.keys() {
|
||||||
walk(map, name, &mut stack, &mut visited, &mut to_remove);
|
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,
|
name: &'a Name,
|
||||||
stack: &mut Vec<&'a Name>,
|
stack: &mut Vec<&'a Name>,
|
||||||
visited: &mut HashSet<&'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.
|
/// Replace `var()` functions for all custom properties.
|
||||||
fn substitute_all(custom_properties: HashMap<&Name, BorrowedValue>,
|
fn substitute_all(specified_values_map: HashMap<&Name, BorrowedSpecifiedValue>,
|
||||||
inherited: &Option<Arc<HashMap<Name, String>>>)
|
inherited: &Option<Arc<HashMap<Name, ComputedValue>>>)
|
||||||
-> HashMap<Name, String> {
|
-> HashMap<Name, ComputedValue> {
|
||||||
let mut substituted_map = HashMap::new();
|
let mut computed_values_map = HashMap::new();
|
||||||
let mut invalid = HashSet::new();
|
let mut invalid = HashSet::new();
|
||||||
for (&name, value) in &custom_properties {
|
for (&name, value) in &specified_values_map {
|
||||||
// If this value is invalid at computed-time it won’t be inserted in substituted_map.
|
// If this value is invalid at computed-time it won’t be inserted in computed_values_map.
|
||||||
// Nothing else to do.
|
// Nothing else to do.
|
||||||
let _ = substitute_one(
|
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.
|
/// Replace `var()` functions for one custom property.
|
||||||
/// Also recursively record results for other custom properties referenced by `var()` functions.
|
/// Also recursively record results for other custom properties referenced by `var()` functions.
|
||||||
/// Return `Err(())` for invalid at computed time.
|
/// 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,
|
fn substitute_one(name: &Name,
|
||||||
value: &BorrowedValue,
|
specified_value: &BorrowedSpecifiedValue,
|
||||||
custom_properties: &HashMap<&Name, BorrowedValue>,
|
specified_values_map: &HashMap<&Name, BorrowedSpecifiedValue>,
|
||||||
inherited: &Option<Arc<HashMap<Name, String>>>,
|
inherited: &Option<Arc<HashMap<Name, ComputedValue>>>,
|
||||||
substituted: Option<&mut String>,
|
partial_computed_value: Option<&mut ComputedValue>,
|
||||||
substituted_map: &mut HashMap<Name, String>,
|
computed_values_map: &mut HashMap<Name, ComputedValue>,
|
||||||
invalid: &mut HashSet<Name>)
|
invalid: &mut HashSet<Name>)
|
||||||
-> Result<(), ()> {
|
-> Result<TokenSerializationType, ()> {
|
||||||
if let Some(value) = substituted_map.get(name) {
|
if let Some(computed_value) = computed_values_map.get(name) {
|
||||||
if let Some(substituted) = substituted {
|
if let Some(partial_computed_value) = partial_computed_value {
|
||||||
substituted.push_str(value)
|
partial_computed_value.push_variable(computed_value)
|
||||||
}
|
}
|
||||||
return Ok(())
|
return Ok(computed_value.last_token_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
if invalid.contains(name) {
|
if invalid.contains(name) {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
let value = if value.references.map(|set| set.is_empty()) == Some(false) {
|
let computed_value = if specified_value.references.map(|set| set.is_empty()) == Some(false) {
|
||||||
let mut substituted = String::new();
|
let mut partial_computed_value = ComputedValue::empty();
|
||||||
let mut input = Parser::new(&value.value);
|
let mut input = Parser::new(&specified_value.css);
|
||||||
let mut start = input.position();
|
let mut position = (input.position(), specified_value.first_token_type);
|
||||||
if substitute_block(&mut input, &mut start, &mut substituted, &mut |name, substituted| {
|
let result = substitute_block(
|
||||||
if let Some(value) = custom_properties.get(name) {
|
&mut input, &mut position, &mut partial_computed_value,
|
||||||
substitute_one(name, value, custom_properties, inherited,
|
&mut |name, partial_computed_value| {
|
||||||
Some(substituted), substituted_map, invalid)
|
if let Some(other_specified_value) = specified_values_map.get(name) {
|
||||||
} else {
|
substitute_one(name, other_specified_value, specified_values_map, inherited,
|
||||||
Err(())
|
Some(partial_computed_value), computed_values_map, invalid)
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}).is_ok() {
|
);
|
||||||
substituted.push_str(input.slice_from(start));
|
if let Ok(last_token_type) = result {
|
||||||
substituted
|
partial_computed_value.push_from(position, &input, last_token_type);
|
||||||
|
partial_computed_value
|
||||||
} else {
|
} else {
|
||||||
// Invalid at computed-value time. Use the inherited value.
|
// Invalid at computed-value time. Use the inherited value.
|
||||||
if let Some(value) = inherited.as_ref().and_then(|i| i.get(name)) {
|
if let Some(inherited_value) = inherited.as_ref().and_then(|i| i.get(name)) {
|
||||||
value.clone()
|
inherited_value.clone()
|
||||||
} else {
|
} else {
|
||||||
invalid.insert(name.clone());
|
invalid.insert(name.clone());
|
||||||
return Err(())
|
return Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} 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 {
|
if let Some(partial_computed_value) = partial_computed_value {
|
||||||
substituted.push_str(&value)
|
partial_computed_value.push_variable(&computed_value)
|
||||||
}
|
}
|
||||||
substituted_map.insert(name.clone(), value);
|
let last_token_type = computed_value.last_token_type;
|
||||||
Ok(())
|
computed_values_map.insert(name.clone(), computed_value);
|
||||||
|
Ok(last_token_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replace `var()` functions in an arbitrary bit of input.
|
/// Replace `var()` functions in an arbitrary bit of input.
|
||||||
///
|
///
|
||||||
/// The `substitute_one` callback is called for each `var()` function in `input`.
|
/// The `substitute_one` callback is called for each `var()` function in `input`.
|
||||||
/// If the variable has its initial value,
|
/// 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)
|
/// 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.
|
/// 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,
|
fn substitute_block<F>(input: &mut Parser,
|
||||||
start: &mut SourcePosition,
|
position: &mut (SourcePosition, TokenSerializationType),
|
||||||
substituted: &mut String,
|
partial_computed_value: &mut ComputedValue,
|
||||||
substitute_one: &mut F)
|
substitute_one: &mut F)
|
||||||
-> Result<(), ()>
|
-> Result<TokenSerializationType, ()>
|
||||||
where F: FnMut(&Name, &mut String) -> Result<(), ()> {
|
where F: FnMut(&Name, &mut ComputedValue) -> Result<TokenSerializationType, ()> {
|
||||||
|
let mut last_token_type = TokenSerializationType::nothing();
|
||||||
|
let mut set_position_at_next_iteration = false;
|
||||||
loop {
|
loop {
|
||||||
let input_slice = input.slice_from(*start);
|
let before_this_token = input.position();
|
||||||
let token = if let Ok(token) = input.next() { token } else { break };
|
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 {
|
match token {
|
||||||
Token::Function(ref name) if name == "var" => {
|
Token::Function(ref name) if name.eq_ignore_ascii_case("var") => {
|
||||||
substituted.push_str(input_slice);
|
partial_computed_value.push(
|
||||||
|
input.slice(position.0..before_this_token), position.1, last_token_type);
|
||||||
try!(input.parse_nested_block(|input| {
|
try!(input.parse_nested_block(|input| {
|
||||||
// parse_var_function() ensures neither .unwrap() will fail.
|
// parse_var_function() ensures neither .unwrap() will fail.
|
||||||
let name = input.expect_ident().unwrap();
|
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`
|
// Skip over the fallback, as `parse_nested_block` would return `Err`
|
||||||
// if we don’t consume all of `input`.
|
// if we don’t consume all of `input`.
|
||||||
// FIXME: Add a specialized method to cssparser to do this with less work.
|
// FIXME: Add a specialized method to cssparser to do this with less work.
|
||||||
while let Ok(_) = input.next() {}
|
while let Ok(_) = input.next() {}
|
||||||
} else {
|
} else {
|
||||||
try!(input.expect_comma());
|
try!(input.expect_comma());
|
||||||
let mut start = input.position();
|
let position = input.position();
|
||||||
try!(substitute_block(input, &mut start, substituted, substitute_one));
|
let first_token_type = input.next_including_whitespace_and_comments()
|
||||||
substituted.push_str(input.slice_from(start));
|
// 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(())
|
Ok(())
|
||||||
}));
|
}));
|
||||||
*start = input.position();
|
set_position_at_next_iteration = true
|
||||||
}
|
}
|
||||||
|
|
||||||
Token::Function(_) |
|
Token::Function(_) |
|
||||||
|
@ -343,11 +425,13 @@ fn substitute_block<F>(input: &mut Parser,
|
||||||
Token::CurlyBracketBlock |
|
Token::CurlyBracketBlock |
|
||||||
Token::SquareBracketBlock => {
|
Token::SquareBracketBlock => {
|
||||||
try!(input.parse_nested_block(|input| {
|
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.
|
// 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>
|
// <p style="background: var(--color) var(--image) top left; --image: url('a.png"></p>
|
||||||
// </div>
|
// </div>
|
||||||
// ```
|
// ```
|
||||||
Ok(())
|
Ok(last_token_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replace `var()` functions for a non-custom property.
|
/// Replace `var()` functions for a non-custom property.
|
||||||
/// Return `Err(())` for invalid at computed time.
|
/// 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, ()> {
|
-> Result<String, ()> {
|
||||||
let empty_map;
|
let mut substituted = ComputedValue::empty();
|
||||||
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 input = Parser::new(input);
|
let mut input = Parser::new(input);
|
||||||
let mut start = input.position();
|
let mut position = (input.position(), first_token_type);
|
||||||
try!(substitute_block(&mut input, &mut start, &mut substituted, &mut |name, substituted| {
|
let last_token_type = try!(substitute_block(
|
||||||
if let Some(value) = custom_properties.get(name) {
|
&mut input, &mut position, &mut substituted, &mut |name, substituted| {
|
||||||
substituted.push_str(value);
|
if let Some(value) = computed_values_map.as_ref().and_then(|map| map.get(name)) {
|
||||||
Ok(())
|
substituted.push_variable(value);
|
||||||
} else {
|
Ok(value.last_token_type)
|
||||||
Err(())
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}));
|
));
|
||||||
substituted.push_str(input.slice_from(start));
|
substituted.push_from(position, &input, last_token_type);
|
||||||
Ok(substituted)
|
Ok(substituted.css)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#![feature(arc_unique)]
|
#![feature(arc_unique)]
|
||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
|
#![feature(concat_idents)]
|
||||||
#![feature(core_intrinsics)]
|
#![feature(core_intrinsics)]
|
||||||
#![feature(custom_attribute)]
|
#![feature(custom_attribute)]
|
||||||
#![feature(custom_derive)]
|
#![feature(custom_derive)]
|
||||||
|
|
|
@ -5,8 +5,7 @@
|
||||||
// This file is a Mako template: http://www.makotemplates.org/
|
// This file is a Mako template: http://www.makotemplates.org/
|
||||||
|
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
use std::borrow::ToOwned;
|
use std::collections::HashSet;
|
||||||
use std::collections::{HashSet, HashMap};
|
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
@ -16,7 +15,7 @@ use std::mem;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use cssparser::{Parser, Color, RGBA, AtRuleParser, DeclarationParser,
|
use cssparser::{Parser, Color, RGBA, AtRuleParser, DeclarationParser,
|
||||||
DeclarationListParser, parse_important, ToCss};
|
DeclarationListParser, parse_important, ToCss, TokenSerializationType};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use util::geometry::Au;
|
use util::geometry::Au;
|
||||||
use util::logical_geometry::{LogicalMargin, PhysicalSide, WritingMode};
|
use util::logical_geometry::{LogicalMargin, PhysicalSide, WritingMode};
|
||||||
|
@ -115,6 +114,7 @@ pub mod longhands {
|
||||||
derived_from=derived_from,
|
derived_from=derived_from,
|
||||||
custom_cascade=custom_cascade,
|
custom_cascade=custom_cascade,
|
||||||
experimental=experimental)
|
experimental=experimental)
|
||||||
|
property.style_struct = THIS_STYLE_STRUCT
|
||||||
THIS_STYLE_STRUCT.longhands.append(property)
|
THIS_STYLE_STRUCT.longhands.append(property)
|
||||||
LONGHANDS.append(property)
|
LONGHANDS.append(property)
|
||||||
LONGHANDS_BY_NAME[name] = property
|
LONGHANDS_BY_NAME[name] = property
|
||||||
|
@ -128,7 +128,7 @@ pub mod longhands {
|
||||||
% if derived_from is None:
|
% if derived_from is None:
|
||||||
use cssparser::Parser;
|
use cssparser::Parser;
|
||||||
use parser::ParserContext;
|
use parser::ParserContext;
|
||||||
use properties::{CSSWideKeyword, DeclaredValue};
|
use properties::{CSSWideKeyword, DeclaredValue, Shorthand};
|
||||||
% endif
|
% endif
|
||||||
use properties::longhands;
|
use properties::longhands;
|
||||||
use properties::property_bit_field::PropertyBitField;
|
use properties::property_bit_field::PropertyBitField;
|
||||||
|
@ -157,7 +157,7 @@ pub mod longhands {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
seen.set_${property.ident}();
|
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 {
|
declared_value, &style.custom_properties, |value| match *value {
|
||||||
DeclaredValue::Value(ref specified_value) => {
|
DeclaredValue::Value(ref specified_value) => {
|
||||||
specified_value.to_computed_value(&context)
|
specified_value.to_computed_value(&context)
|
||||||
|
@ -193,29 +193,6 @@ pub mod longhands {
|
||||||
% endif
|
% endif
|
||||||
}
|
}
|
||||||
% if derived_from is None:
|
% 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)
|
pub fn parse_declared(context: &ParserContext, input: &mut Parser)
|
||||||
-> Result<DeclaredValue<SpecifiedValue>, ()> {
|
-> Result<DeclaredValue<SpecifiedValue>, ()> {
|
||||||
match input.try(CSSWideKeyword::parse) {
|
match input.try(CSSWideKeyword::parse) {
|
||||||
|
@ -227,13 +204,19 @@ pub mod longhands {
|
||||||
input.look_for_var_functions();
|
input.look_for_var_functions();
|
||||||
let start = input.position();
|
let start = input.position();
|
||||||
let specified = parse_specified(context, input);
|
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();
|
let var = input.seen_var_functions();
|
||||||
if specified.is_err() && var {
|
if specified.is_err() && var {
|
||||||
input.reset(start);
|
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 {
|
return Ok(DeclaredValue::WithVariables {
|
||||||
css: input.slice_from(start).to_owned(),
|
css: input.slice_from(start).to_owned(),
|
||||||
|
first_token_type: first_token_type,
|
||||||
base_url: context.base_url.clone(),
|
base_url: context.base_url.clone(),
|
||||||
|
from_shorthand: Shorthand::None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
specified
|
specified
|
||||||
|
@ -4881,7 +4864,7 @@ pub mod shorthands {
|
||||||
pub mod ${shorthand.ident} {
|
pub mod ${shorthand.ident} {
|
||||||
use cssparser::Parser;
|
use cssparser::Parser;
|
||||||
use parser::ParserContext;
|
use parser::ParserContext;
|
||||||
use properties::longhands;
|
use properties::{longhands, PropertyDeclaration, DeclaredValue, Shorthand};
|
||||||
|
|
||||||
pub struct Longhands {
|
pub struct Longhands {
|
||||||
% for sub_property in shorthand.sub_properties:
|
% for sub_property in shorthand.sub_properties:
|
||||||
|
@ -4890,8 +4873,46 @@ pub mod shorthands {
|
||||||
% endfor
|
% 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)]
|
#[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()}
|
${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.
|
/// Declarations are stored in reverse order.
|
||||||
/// Overridden declarations are skipped.
|
/// 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)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub enum DeclaredValue<T> {
|
pub enum DeclaredValue<T> {
|
||||||
Value(T),
|
Value(T),
|
||||||
WithVariables { css: String, base_url: Url },
|
WithVariables {
|
||||||
|
css: String,
|
||||||
|
first_token_type: TokenSerializationType,
|
||||||
|
base_url: Url,
|
||||||
|
from_shorthand: Shorthand
|
||||||
|
},
|
||||||
Initial,
|
Initial,
|
||||||
Inherit,
|
Inherit,
|
||||||
// There is no Unset variant here.
|
// There is no Unset variant here.
|
||||||
|
@ -5732,13 +5815,17 @@ pub enum DeclaredValue<T> {
|
||||||
// depending on whether the property is inherited.
|
// depending on whether the property is inherited.
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ToCss> DeclaredValue<T> {
|
impl<T: ToCss> ToCss for DeclaredValue<T> {
|
||||||
pub fn specified_value(&self) -> String {
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
match *self {
|
match *self {
|
||||||
DeclaredValue::Value(ref inner) => inner.to_css_string(),
|
DeclaredValue::Value(ref inner) => inner.to_css(dest),
|
||||||
DeclaredValue::WithVariables { ref css, .. } => css.clone(),
|
DeclaredValue::WithVariables { ref css, from_shorthand: Shorthand::None, .. } => {
|
||||||
DeclaredValue::Initial => "initial".to_owned(),
|
dest.write_str(css)
|
||||||
DeclaredValue::Inherit => "inherit".to_owned(),
|
}
|
||||||
|
// 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:
|
% for property in LONGHANDS:
|
||||||
${property.camel_case}(DeclaredValue<longhands::${property.ident}::SpecifiedValue>),
|
${property.camel_case}(DeclaredValue<longhands::${property.ident}::SpecifiedValue>),
|
||||||
% endfor
|
% 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,
|
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 {
|
impl PropertyDeclaration {
|
||||||
pub fn name(&self) -> &'static str {
|
pub fn name(&self) -> PropertyDeclarationName {
|
||||||
match *self {
|
match *self {
|
||||||
% for property in LONGHANDS:
|
% for property in LONGHANDS:
|
||||||
% if property.derived_from is None:
|
% if property.derived_from is None:
|
||||||
PropertyDeclaration::${property.camel_case}(..) => "${property.name}",
|
PropertyDeclaration::${property.camel_case}(..) => {
|
||||||
|
PropertyDeclarationName::Longhand("${property.name}")
|
||||||
|
}
|
||||||
% endif
|
% endif
|
||||||
% endfor
|
% endfor
|
||||||
_ => "",
|
PropertyDeclaration::Custom(ref name, _) => {
|
||||||
|
PropertyDeclarationName::Custom(name.clone())
|
||||||
|
}
|
||||||
|
_ => PropertyDeclarationName::Internal,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5777,10 +5901,11 @@ impl PropertyDeclaration {
|
||||||
% for property in LONGHANDS:
|
% for property in LONGHANDS:
|
||||||
% if property.derived_from is None:
|
% if property.derived_from is None:
|
||||||
PropertyDeclaration::${property.camel_case}(ref value) =>
|
PropertyDeclaration::${property.camel_case}(ref value) =>
|
||||||
value.specified_value(),
|
value.to_css_string(),
|
||||||
% endif
|
% endif
|
||||||
% endfor
|
% 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
|
% endif
|
||||||
% endfor
|
% endfor
|
||||||
|
PropertyDeclaration::Custom(ref declaration_name, _) => {
|
||||||
|
::custom_properties::parse_name(name) == Ok(&**declaration_name)
|
||||||
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5809,7 +5937,7 @@ impl PropertyDeclaration {
|
||||||
Err(()) => return PropertyDeclarationParseResult::InvalidValue,
|
Err(()) => return PropertyDeclarationParseResult::InvalidValue,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
result_list.push(PropertyDeclaration::Custom(name, value));
|
result_list.push(PropertyDeclaration::Custom(Atom::from_slice(name), value));
|
||||||
return PropertyDeclarationParseResult::ValidOrIgnoredDeclaration;
|
return PropertyDeclarationParseResult::ValidOrIgnoredDeclaration;
|
||||||
}
|
}
|
||||||
match_ignore_ascii_case! { name,
|
match_ignore_ascii_case! { name,
|
||||||
|
@ -5865,18 +5993,8 @@ impl PropertyDeclaration {
|
||||||
% endfor
|
% endfor
|
||||||
PropertyDeclarationParseResult::ValidOrIgnoredDeclaration
|
PropertyDeclarationParseResult::ValidOrIgnoredDeclaration
|
||||||
},
|
},
|
||||||
Err(()) => match shorthands::${shorthand.ident}::parse(context, input) {
|
Err(()) => match shorthands::${shorthand.ident}::parse(context, input, result_list) {
|
||||||
Ok(result) => {
|
Ok(()) => PropertyDeclarationParseResult::ValidOrIgnoredDeclaration,
|
||||||
% 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(()) => PropertyDeclarationParseResult::InvalidValue,
|
Err(()) => PropertyDeclarationParseResult::InvalidValue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5919,7 +6037,7 @@ pub struct ComputedValues {
|
||||||
% for style_struct in STYLE_STRUCTS:
|
% for style_struct in STYLE_STRUCTS:
|
||||||
${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
|
${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
|
||||||
% endfor
|
% endfor
|
||||||
custom_properties: Option<Arc<HashMap<::custom_properties::Name, String>>>,
|
custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>,
|
||||||
shareable: bool,
|
shareable: bool,
|
||||||
pub writing_mode: WritingMode,
|
pub writing_mode: WritingMode,
|
||||||
pub root_font_size: Au,
|
pub root_font_size: Au,
|
||||||
|
@ -6077,14 +6195,19 @@ impl ComputedValues {
|
||||||
}
|
}
|
||||||
% endfor
|
% 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 {
|
match name {
|
||||||
% for style_struct in STYLE_STRUCTS:
|
% for style_struct in STYLE_STRUCTS:
|
||||||
% for longhand in style_struct.longhands:
|
% 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
|
||||||
% 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,
|
shareable: bool,
|
||||||
parent_style: &ComputedValues,
|
parent_style: &ComputedValues,
|
||||||
cached_style: &ComputedValues,
|
cached_style: &ComputedValues,
|
||||||
custom_properties: Option<Arc<HashMap<Atom, String>>>,
|
custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>,
|
||||||
context: &computed::Context)
|
context: &computed::Context)
|
||||||
-> ComputedValues {
|
-> ComputedValues {
|
||||||
% for style_struct in STYLE_STRUCTS:
|
% for style_struct in STYLE_STRUCTS:
|
||||||
|
@ -6182,7 +6305,7 @@ fn cascade_with_cached_declarations(
|
||||||
}
|
}
|
||||||
seen.set_${property.ident}();
|
seen.set_${property.ident}();
|
||||||
let computed_value =
|
let computed_value =
|
||||||
longhands::${property.ident}::substitute_variables(
|
substitute_variables_${property.ident}(
|
||||||
declared_value, &custom_properties, |value| match *value {
|
declared_value, &custom_properties, |value| match *value {
|
||||||
DeclaredValue::Value(ref specified_value)
|
DeclaredValue::Value(ref specified_value)
|
||||||
=> specified_value.to_computed_value(context),
|
=> 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.
|
// This assumes that the computed and specified values have the same Rust type.
|
||||||
macro_rules! get_specified(
|
macro_rules! get_specified(
|
||||||
($style_struct_getter: ident, $property: ident, $declared_value: expr) => {
|
($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 {
|
$declared_value, &custom_properties, |value| match *value {
|
||||||
DeclaredValue::Value(specified_value) => specified_value,
|
DeclaredValue::Value(specified_value) => specified_value,
|
||||||
DeclaredValue::Initial => longhands::$property::get_initial_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() {
|
for declaration in sub_list.declarations.iter().rev() {
|
||||||
match *declaration {
|
match *declaration {
|
||||||
PropertyDeclaration::FontSize(ref value) => {
|
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 {
|
value, &custom_properties, |value| match *value {
|
||||||
DeclaredValue::Value(ref specified_value) => {
|
DeclaredValue::Value(ref specified_value) => {
|
||||||
match specified_value.0 {
|
match specified_value.0 {
|
||||||
|
@ -6395,7 +6518,7 @@ pub fn cascade(viewport_size: Size2D<Au>,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
PropertyDeclaration::Color(ref value) => {
|
PropertyDeclaration::Color(ref value) => {
|
||||||
context.color = longhands::color::substitute_variables(
|
context.color = substitute_variables_color(
|
||||||
value, &custom_properties, |value| match *value {
|
value, &custom_properties, |value| match *value {
|
||||||
DeclaredValue::Value(ref specified_value) => {
|
DeclaredValue::Value(ref specified_value) => {
|
||||||
specified_value.parsed
|
specified_value.parsed
|
||||||
|
@ -6700,7 +6823,7 @@ pub fn is_supported_property(property: &str) -> bool {
|
||||||
"${property.name}" => true,
|
"${property.name}" => true,
|
||||||
% endfor
|
% endfor
|
||||||
"${LONGHANDS[-1].name}" => true
|
"${LONGHANDS[-1].name}" => true
|
||||||
_ => false
|
_ => property.starts_with("--")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use azure::azure_hl::Color;
|
use azure::azure_hl::Color;
|
||||||
use cssparser::Color as CSSParserColor;
|
use cssparser::Color as CSSParserColor;
|
||||||
use cssparser::RGBA;
|
use cssparser::{RGBA, TokenSerializationType};
|
||||||
use cursor::Cursor;
|
use cursor::Cursor;
|
||||||
use euclid::length::Length;
|
use euclid::length::Length;
|
||||||
use euclid::scale_factor::ScaleFactor;
|
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, Length<T, U>, ScaleFactor<T, U, V>);
|
||||||
|
|
||||||
known_heap_size!(0, Au, WritingMode, CSSParserColor, Color, RGBA, Cursor, Matrix4, Atom, Namespace);
|
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);
|
known_heap_size!(0, PseudoElement, Combinator, str);
|
||||||
|
|
18
ports/cef/Cargo.lock
generated
18
ports/cef/Cargo.lock
generated
|
@ -129,7 +129,7 @@ version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"azure 0.1.0 (git+https://github.com/servo/rust-azure)",
|
"azure 0.1.0 (git+https://github.com/servo/rust-azure)",
|
||||||
"canvas_traits 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)",
|
||||||
"euclid 0.2.0 (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",
|
"gfx_traits 0.0.1",
|
||||||
"gleam 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"gleam 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -146,7 +146,7 @@ name = "canvas_traits"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"azure 0.1.0 (git+https://github.com/servo/rust-azure)",
|
"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)",
|
"euclid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"gfx_traits 0.0.1",
|
"gfx_traits 0.0.1",
|
||||||
"ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)",
|
"ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)",
|
||||||
|
@ -282,7 +282,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cssparser"
|
name = "cssparser"
|
||||||
version = "0.3.6"
|
version = "0.3.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"encoding 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
"encoding 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -880,7 +880,7 @@ dependencies = [
|
||||||
"canvas 0.0.1",
|
"canvas 0.0.1",
|
||||||
"canvas_traits 0.0.1",
|
"canvas_traits 0.0.1",
|
||||||
"clock_ticks 0.0.6 (git+https://github.com/tomaka/clock_ticks)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"canvas 0.0.1",
|
"canvas 0.0.1",
|
||||||
"canvas_traits 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",
|
"devtools_traits 0.0.1",
|
||||||
"encoding 0.2.32 (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)",
|
"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"
|
source = "git+https://github.com/servo/rust-selectors#572353b3209af040cd3e6261978b09c7f8122844"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"quickersort 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1581,7 +1581,7 @@ name = "style"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"fnv 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1606,7 +1606,7 @@ dependencies = [
|
||||||
name = "style_traits"
|
name = "style_traits"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
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)",
|
"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)",
|
"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)",
|
"log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1728,7 +1728,7 @@ version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"azure 0.1.0 (git+https://github.com/servo/rust-azure)",
|
"azure 0.1.0 (git+https://github.com/servo/rust-azure)",
|
||||||
"bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"html5ever 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
18
ports/gonk/Cargo.lock
generated
18
ports/gonk/Cargo.lock
generated
|
@ -110,7 +110,7 @@ version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"azure 0.1.0 (git+https://github.com/servo/rust-azure)",
|
"azure 0.1.0 (git+https://github.com/servo/rust-azure)",
|
||||||
"canvas_traits 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)",
|
||||||
"euclid 0.2.0 (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",
|
"gfx_traits 0.0.1",
|
||||||
"gleam 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"gleam 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -127,7 +127,7 @@ name = "canvas_traits"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"azure 0.1.0 (git+https://github.com/servo/rust-azure)",
|
"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)",
|
"euclid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"gfx_traits 0.0.1",
|
"gfx_traits 0.0.1",
|
||||||
"ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)",
|
"ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)",
|
||||||
|
@ -252,7 +252,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cssparser"
|
name = "cssparser"
|
||||||
version = "0.3.6"
|
version = "0.3.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"encoding 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
"encoding 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -764,7 +764,7 @@ dependencies = [
|
||||||
"canvas 0.0.1",
|
"canvas 0.0.1",
|
||||||
"canvas_traits 0.0.1",
|
"canvas_traits 0.0.1",
|
||||||
"clock_ticks 0.0.6 (git+https://github.com/tomaka/clock_ticks)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"canvas 0.0.1",
|
"canvas 0.0.1",
|
||||||
"canvas_traits 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",
|
"devtools_traits 0.0.1",
|
||||||
"encoding 0.2.32 (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)",
|
"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"
|
source = "git+https://github.com/servo/rust-selectors#572353b3209af040cd3e6261978b09c7f8122844"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"quickersort 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1427,7 +1427,7 @@ name = "style"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"fnv 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1452,7 +1452,7 @@ dependencies = [
|
||||||
name = "style_traits"
|
name = "style_traits"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
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)",
|
"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)",
|
"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)",
|
"log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1563,7 +1563,7 @@ version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"azure 0.1.0 (git+https://github.com/servo/rust-azure)",
|
"azure 0.1.0 (git+https://github.com/servo/rust-azure)",
|
||||||
"bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"html5ever 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
[css-vars-custom-property-inheritance.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[variable-declaration-08.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[variable-declaration-14.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[variable-declaration-20.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[variable-declaration-24.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[variable-declaration-26.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[variable-declaration-37.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[variable-declaration-53.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[variable-declaration-54.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[variable-declaration-55.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[variable-reference-03.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[variable-reference-04.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[variable-reference-13.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[variable-reference-14.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[variable-reference-15.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[variable-reference-18.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[variable-reference-19.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[variable-reference-20.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[variable-reference-26.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[variable-reference-27.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[variable-reference-36.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[variable-reference-38.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -281,6 +281,24 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"testharness": {
|
"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": [
|
"mozilla/DOMParser.html": [
|
||||||
{
|
{
|
||||||
"path": "mozilla/DOMParser.html",
|
"path": "mozilla/DOMParser.html",
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) \\<5C>` 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\\<5C>)` 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
|
||||||
|
|
119
tests/wpt/mozilla/tests/css/test_variable_legal_values.html
Normal file
119
tests/wpt/mozilla/tests/css/test_variable_legal_values.html
Normal file
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
Loading…
Add table
Add a link
Reference in a new issue