mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
Invalid at computed-value time customp properties get their inherited value.
This commit is contained in:
parent
a18a1a8d79
commit
1d47857be9
1 changed files with 39 additions and 27 deletions
|
@ -25,6 +25,8 @@ pub struct BorrowedValue<'a> {
|
||||||
pub fn parse(input: &mut Parser) -> Result<Value, ()> {
|
pub fn parse(input: &mut Parser) -> Result<Value, ()> {
|
||||||
let start = input.position();
|
let start = input.position();
|
||||||
let mut references = HashSet::new();
|
let mut references = HashSet::new();
|
||||||
|
// FIXME: don’t consume a top-level `!` as that would prevent parsing `!important`.
|
||||||
|
// Maybe using Parser::parse_until_before?
|
||||||
try!(parse_declaration_value(input, &mut references));
|
try!(parse_declaration_value(input, &mut references));
|
||||||
Ok(Value {
|
Ok(Value {
|
||||||
value: input.slice_from(start).to_owned(),
|
value: input.slice_from(start).to_owned(),
|
||||||
|
@ -127,7 +129,7 @@ fn parse_var_function<'i, 't>(input: &mut Parser<'i, 't>, references: &mut HashS
|
||||||
/// 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 Atom, BorrowedValue<'a>>>,
|
pub fn cascade<'a>(custom_properties: &mut Option<HashMap<&'a Atom, BorrowedValue<'a>>>,
|
||||||
inherited_custom_properties: &'a Option<Arc<HashMap<Atom, String>>>,
|
inherited: &'a Option<Arc<HashMap<Atom, String>>>,
|
||||||
seen: &mut HashSet<&'a Atom>,
|
seen: &mut HashSet<&'a Atom>,
|
||||||
name: &'a Atom,
|
name: &'a Atom,
|
||||||
value: &'a DeclaredValue<Value>) {
|
value: &'a DeclaredValue<Value>) {
|
||||||
|
@ -136,7 +138,7 @@ pub fn cascade<'a>(custom_properties: &mut Option<HashMap<&'a Atom, BorrowedValu
|
||||||
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 {
|
*custom_properties = Some(match *inherited {
|
||||||
Some(ref inherited) => inherited.iter().map(|(key, value)| {
|
Some(ref inherited) => inherited.iter().map(|(key, value)| {
|
||||||
(key, BorrowedValue { value: &value, references: None })
|
(key, BorrowedValue { value: &value, references: None })
|
||||||
}).collect(),
|
}).collect(),
|
||||||
|
@ -161,17 +163,18 @@ pub fn cascade<'a>(custom_properties: &mut Option<HashMap<&'a Atom, BorrowedValu
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn finish_cascade(custom_properties: Option<HashMap<&Atom, BorrowedValue>>,
|
pub fn finish_cascade(custom_properties: Option<HashMap<&Atom, BorrowedValue>>,
|
||||||
inherited_custom_properties: &Option<Arc<HashMap<Atom, String>>>)
|
inherited: &Option<Arc<HashMap<Atom, String>>>)
|
||||||
-> Option<Arc<HashMap<Atom, String>>> {
|
-> Option<Arc<HashMap<Atom, String>>> {
|
||||||
if let Some(mut map) = custom_properties {
|
if let Some(mut map) = custom_properties {
|
||||||
remove_cycles(&mut map);
|
remove_cycles(&mut map);
|
||||||
Some(Arc::new(substitute_all(map)))
|
Some(Arc::new(substitute_all(map, inherited)))
|
||||||
} else {
|
} else {
|
||||||
inherited_custom_properties.clone()
|
inherited.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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.
|
||||||
fn remove_cycles(map: &mut HashMap<&Atom, BorrowedValue>) {
|
fn remove_cycles(map: &mut HashMap<&Atom, BorrowedValue>) {
|
||||||
let mut to_remove = HashSet::new();
|
let mut to_remove = HashSet::new();
|
||||||
{
|
{
|
||||||
|
@ -195,8 +198,8 @@ fn remove_cycles(map: &mut HashMap<&Atom, BorrowedValue>) {
|
||||||
for next in references {
|
for next in references {
|
||||||
if let Some(position) = stack.position_elem(&next) {
|
if let Some(position) = stack.position_elem(&next) {
|
||||||
// Found a cycle
|
// Found a cycle
|
||||||
for in_cycle in &stack[position..] {
|
for &in_cycle in &stack[position..] {
|
||||||
to_remove.insert((**in_cycle).clone());
|
to_remove.insert(in_cycle.clone());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
walk(map, next, stack, visited, to_remove);
|
walk(map, next, stack, visited, to_remove);
|
||||||
|
@ -213,14 +216,16 @@ fn remove_cycles(map: &mut HashMap<&Atom, BorrowedValue>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn substitute_all(custom_properties: HashMap<&Atom, BorrowedValue>) -> HashMap<Atom, String> {
|
fn substitute_all(custom_properties: HashMap<&Atom, BorrowedValue>,
|
||||||
|
inherited: &Option<Arc<HashMap<Atom, String>>>)
|
||||||
|
-> HashMap<Atom, String> {
|
||||||
let mut substituted_map = HashMap::new();
|
let mut substituted_map = HashMap::new();
|
||||||
let mut invalid = HashSet::new();
|
let mut invalid = HashSet::new();
|
||||||
for (&name, value) in &custom_properties {
|
for (&name, value) in &custom_properties {
|
||||||
// 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 substituted_map.
|
||||||
// Nothing else to do.
|
// Nothing else to do.
|
||||||
let _ = substitute_one(
|
let _ = substitute_one(
|
||||||
name, value, &custom_properties, None, &mut substituted_map, &mut invalid);
|
name, value, &custom_properties, inherited, None, &mut substituted_map, &mut invalid);
|
||||||
}
|
}
|
||||||
substituted_map
|
substituted_map
|
||||||
}
|
}
|
||||||
|
@ -228,6 +233,7 @@ fn substitute_all(custom_properties: HashMap<&Atom, BorrowedValue>) -> HashMap<A
|
||||||
fn substitute_one(name: &Atom,
|
fn substitute_one(name: &Atom,
|
||||||
value: &BorrowedValue,
|
value: &BorrowedValue,
|
||||||
custom_properties: &HashMap<&Atom, BorrowedValue>,
|
custom_properties: &HashMap<&Atom, BorrowedValue>,
|
||||||
|
inherited: &Option<Arc<HashMap<Atom, String>>>,
|
||||||
substituted: Option<&mut String>,
|
substituted: Option<&mut String>,
|
||||||
substituted_map: &mut HashMap<Atom, String>,
|
substituted_map: &mut HashMap<Atom, String>,
|
||||||
invalid: &mut HashSet<Atom>)
|
invalid: &mut HashSet<Atom>)
|
||||||
|
@ -242,22 +248,26 @@ fn substitute_one(name: &Atom,
|
||||||
if invalid.contains(name) {
|
if invalid.contains(name) {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
let value = if let Some(references) = value.references {
|
let value = if value.references.map(|set| set.is_empty()) == Some(false) {
|
||||||
if !references.is_empty() {
|
let mut substituted = String::new();
|
||||||
let mut substituted = String::new();
|
let mut input = Parser::new(&value.value);
|
||||||
let mut input = Parser::new(&value.value);
|
let mut start = input.position();
|
||||||
let mut start = input.position();
|
if substitute_block(
|
||||||
if substitute_block(
|
custom_properties, inherited, &mut input, &mut start, &mut substituted,
|
||||||
custom_properties, &mut input, &mut start, &mut substituted,
|
substituted_map, invalid,
|
||||||
substituted_map, invalid,
|
).is_ok() {
|
||||||
).is_err() {
|
|
||||||
invalid.insert(name.clone());
|
|
||||||
return Err(())
|
|
||||||
}
|
|
||||||
substituted.push_str(input.slice_from(start));
|
substituted.push_str(input.slice_from(start));
|
||||||
substituted
|
substituted
|
||||||
} else {
|
} else {
|
||||||
value.value.to_owned()
|
// Invalid at computed-value time. Use the inherited value.
|
||||||
|
// FIXME: Should it be the inital value instead?
|
||||||
|
// See https://lists.w3.org/Archives/Public/www-style/2015Jul/0354.html
|
||||||
|
if let Some(value) = inherited.as_ref().and_then(|i| i.get(name)) {
|
||||||
|
value.clone()
|
||||||
|
} else {
|
||||||
|
invalid.insert(name.clone());
|
||||||
|
return Err(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
value.value.to_owned()
|
value.value.to_owned()
|
||||||
|
@ -270,6 +280,7 @@ fn substitute_one(name: &Atom,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn substitute_block(custom_properties: &HashMap<&Atom, BorrowedValue>,
|
fn substitute_block(custom_properties: &HashMap<&Atom, BorrowedValue>,
|
||||||
|
inherited: &Option<Arc<HashMap<Atom, String>>>,
|
||||||
input: &mut Parser,
|
input: &mut Parser,
|
||||||
start: &mut SourcePosition,
|
start: &mut SourcePosition,
|
||||||
substituted: &mut String,
|
substituted: &mut String,
|
||||||
|
@ -287,7 +298,7 @@ fn substitute_block(custom_properties: &HashMap<&Atom, BorrowedValue>,
|
||||||
|
|
||||||
if let Some(value) = custom_properties.get(&name) {
|
if let Some(value) = custom_properties.get(&name) {
|
||||||
try!(substitute_one(
|
try!(substitute_one(
|
||||||
&name, value, custom_properties,
|
&name, value, custom_properties, inherited,
|
||||||
Some(substituted), substituted_map, invalid));
|
Some(substituted), substituted_map, invalid));
|
||||||
// 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`.
|
||||||
|
@ -297,8 +308,8 @@ fn substitute_block(custom_properties: &HashMap<&Atom, BorrowedValue>,
|
||||||
try!(input.expect_comma());
|
try!(input.expect_comma());
|
||||||
let mut start = input.position();
|
let mut start = input.position();
|
||||||
try!(substitute_block(
|
try!(substitute_block(
|
||||||
custom_properties, input, &mut start, substituted,
|
custom_properties, inherited, input,
|
||||||
substituted_map, invalid));
|
&mut start, substituted, substituted_map, invalid));
|
||||||
substituted.push_str(input.slice_from(start));
|
substituted.push_str(input.slice_from(start));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -311,7 +322,8 @@ fn substitute_block(custom_properties: &HashMap<&Atom, BorrowedValue>,
|
||||||
Token::CurlyBracketBlock |
|
Token::CurlyBracketBlock |
|
||||||
Token::SquareBracketBlock => {
|
Token::SquareBracketBlock => {
|
||||||
try!(input.parse_nested_block(|input| substitute_block(
|
try!(input.parse_nested_block(|input| substitute_block(
|
||||||
custom_properties, input, start, substituted, substituted_map, invalid)));
|
custom_properties, inherited, input,
|
||||||
|
start, substituted, substituted_map, invalid)));
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue