Make custom property substitution do less work.

When var() is substituted, record that result rather than re-compute it later.
This commit is contained in:
Simon Sapin 2015-07-23 02:15:34 +02:00
parent 1c1a9379a3
commit 4bf28417b4

View file

@ -210,37 +210,67 @@ 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>) -> HashMap<Atom, String> {
custom_properties.iter().filter_map(|(&name, value)| { let mut substituted_map = HashMap::new();
let mut substituted = String::new(); let mut invalid = HashSet::new();
if substitute_one(value, &mut substituted, &custom_properties).is_ok() { for (&name, value) in &custom_properties {
Some((name.clone(), substituted)) // If this value is invalid at computed time it wont be inserted in substituted_map.
} else { // Nothing else to do.
None let _ = substitute_one(
} name, value, &custom_properties, None, &mut substituted_map, &mut invalid);
}).collect() }
substituted_map
} }
fn substitute_one(value: &BorrowedValue, fn substitute_one(name: &Atom,
substituted: &mut String, value: &BorrowedValue,
custom_properties: &HashMap<&Atom, BorrowedValue>) custom_properties: &HashMap<&Atom, BorrowedValue>,
substituted: Option<&mut String>,
substituted_map: &mut HashMap<Atom, String>,
invalid: &mut HashSet<Atom>)
-> Result<(), ()> { -> Result<(), ()> {
if let Some(references) = value.references { if let Some(value) = substituted_map.get(name) {
if let Some(substituted) = substituted {
substituted.push_str(value)
}
return Ok(())
}
if invalid.contains(name) {
return Err(());
}
let value = if let Some(references) = value.references {
if !references.is_empty() { if !references.is_empty() {
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();
try!(substitute_block(&mut input, &mut start, substituted, &custom_properties)); if substitute_block(
custom_properties, &mut input, &mut start, &mut substituted,
substituted_map, invalid,
).is_err() {
invalid.insert(name.clone());
return Err(())
}
substituted.push_str(input.slice_from(start)); substituted.push_str(input.slice_from(start));
return Ok(()) substituted
} else {
value.value.to_owned()
} }
} else {
value.value.to_owned()
};
if let Some(substituted) = substituted {
substituted.push_str(&value)
} }
substituted.push_str(value.value); substituted_map.insert(name.clone(), value);
Ok(()) Ok(())
} }
fn substitute_block(input: &mut Parser, fn substitute_block(custom_properties: &HashMap<&Atom, BorrowedValue>,
input: &mut Parser,
start: &mut SourcePosition, start: &mut SourcePosition,
substituted: &mut String, substituted: &mut String,
custom_properties: &HashMap<&Atom, BorrowedValue>) substituted_map: &mut HashMap<Atom, String>,
invalid: &mut HashSet<Atom>)
-> Result<(), ()> { -> Result<(), ()> {
while let Ok(token) = input.next() { while let Ok(token) = input.next() {
match token { match token {
@ -252,12 +282,21 @@ fn substitute_block(input: &mut Parser,
let name = Atom::from_slice(&name[2..]); let name = Atom::from_slice(&name[2..]);
if let Some(value) = custom_properties.get(&name) { if let Some(value) = custom_properties.get(&name) {
return substitute_one(value, substituted, custom_properties) try!(substitute_one(
&name, value, custom_properties,
Some(substituted), substituted_map, invalid));
// Skip over the fallback, as `parse_nested_block` would return `Err`
// if we dont consume all of `input`.
// FIXME: Add a specialized method to cssparser to do this with less work.
while let Ok(_) = input.next() {}
} else {
try!(input.expect_comma());
let mut start = input.position();
try!(substitute_block(
custom_properties, input, &mut start, substituted,
substituted_map, invalid));
substituted.push_str(input.slice_from(start));
} }
try!(input.expect_comma());
let mut start = input.position();
try!(substitute_block(input, &mut start, substituted, custom_properties));
substituted.push_str(input.slice_from(start));
Ok(()) Ok(())
})); }));
*start = input.position(); *start = input.position();
@ -267,9 +306,8 @@ fn substitute_block(input: &mut Parser,
Token::ParenthesisBlock | Token::ParenthesisBlock |
Token::CurlyBracketBlock | Token::CurlyBracketBlock |
Token::SquareBracketBlock => { Token::SquareBracketBlock => {
try!(input.parse_nested_block(|input| { try!(input.parse_nested_block(|input| substitute_block(
substitute_block(input, start, substituted, custom_properties) custom_properties, input, start, substituted, substituted_map, invalid)));
}));
} }
_ => {} _ => {}