Less cloning and dynamic dispatch.

This commit is contained in:
Simon Sapin 2016-04-04 21:14:57 +02:00
parent 7d7aac212b
commit dc829da07e
3 changed files with 63 additions and 40 deletions

View file

@ -13,6 +13,8 @@ use dom::element::{Element, StylePriority};
use dom::node::{Node, window_from_node}; use dom::node::{Node, window_from_node};
use dom::window::Window; use dom::window::Window;
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::cell::Ref;
use std::slice;
use string_cache::Atom; use string_cache::Atom;
use style::parser::ParserContextExtraData; use style::parser::ParserContextExtraData;
use style::properties::{PropertyDeclaration, Shorthand}; use style::properties::{PropertyDeclaration, Shorthand};
@ -140,14 +142,22 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
// Step 2.2.2 & 2.2.3 // Step 2.2.2 & 2.2.3
match declaration { match declaration {
Some(declaration) => list.push(declaration.clone()), Some(declaration) => list.push(declaration),
None => return DOMString::new(), None => return DOMString::new(),
} }
} }
// Step 2.3 // Step 2.3
let mut list = list.iter().map(|x| &*x); // Work around closures not being Clone
let serialized_value = shorthand.serialize_shorthand_to_string(&mut list); #[derive(Clone)]
struct Map<'a, 'b: 'a>(slice::Iter<'a, Ref<'b, PropertyDeclaration>>);
impl<'a, 'b> Iterator for Map<'a, 'b> {
type Item = &'a PropertyDeclaration;
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|r| &**r)
}
}
let serialized_value = shorthand.serialize_shorthand_to_string(Map(list.iter()));
return DOMString::from(serialized_value); return DOMString::from(serialized_value);
} }

View file

@ -699,10 +699,11 @@ impl Element {
} }
fn sync_property_with_attrs_style(&self) { fn sync_property_with_attrs_style(&self) {
let mut style_str = String::new(); let style_str = if let &Some(ref declarations) = &*self.style_attribute().borrow() {
if let &Some(ref declarations) = &*self.style_attribute().borrow() { declarations.to_css_string()
declarations.to_css(&mut style_str).unwrap(); } else {
} String::new()
};
let new_style = AttrValue::String(style_str); let new_style = AttrValue::String(style_str);

View file

@ -318,11 +318,11 @@ impl ToCss for PropertyDeclarationBlock {
let mut current_longhands = Vec::new(); let mut current_longhands = Vec::new();
let mut important_count = 0; let mut important_count = 0;
for longhand in longhands.iter() { for &(longhand, longhand_important) in longhands.iter() {
let longhand_name = longhand.0.name(); let longhand_name = longhand.name();
if properties.iter().any(|p| &longhand_name == *p) { if properties.iter().any(|p| &longhand_name == *p) {
current_longhands.push(longhand.0); current_longhands.push(longhand);
if longhand.1 == true { if longhand_important {
important_count += 1; important_count += 1;
} }
} }
@ -348,7 +348,7 @@ impl ToCss for PropertyDeclarationBlock {
try!( try!(
shorthand.serialize_shorthand_to_buffer( shorthand.serialize_shorthand_to_buffer(
dest, dest,
&mut current_longhands.iter().cloned(), current_longhands.iter().cloned(),
&mut is_first_serialization &mut is_first_serialization
) )
); );
@ -376,12 +376,20 @@ impl ToCss for PropertyDeclarationBlock {
continue; continue;
} }
use std::iter::Cloned;
use std::slice;
// Steps 3.3.5, 3.3.6 & 3.3.7 // Steps 3.3.5, 3.3.6 & 3.3.7
try!(append_serialization(dest, // Need to specify an iterator type here even though its unused to work around
&property.to_string(), // "error: unable to infer enough type information about `_`;
AppendableValue::Declaration(declaration), // type annotations or generic parameter binding required [E0282]"
important, // Use the same type as earlier call to reuse generated code.
&mut is_first_serialization)); try!(append_serialization::<W, Cloned<slice::Iter< &PropertyDeclaration>>>(
dest,
&property.to_string(),
AppendableValue::Declaration(declaration),
important,
&mut is_first_serialization));
// Step 3.3.8 // Step 3.3.8
already_serialized.push(property); already_serialized.push(property);
@ -392,17 +400,20 @@ impl ToCss for PropertyDeclarationBlock {
} }
} }
enum AppendableValue<'a> { enum AppendableValue<'a, I>
where I: Iterator<Item=&'a PropertyDeclaration> {
Declaration(&'a PropertyDeclaration), Declaration(&'a PropertyDeclaration),
DeclarationsForShorthand(&'a mut Iterator<Item=&'a PropertyDeclaration>), DeclarationsForShorthand(I),
Css(&'a str) Css(&'a str)
} }
fn append_serialization<W>(dest: &mut W, fn append_serialization<'a, W, I>(dest: &mut W,
property_name: &str, property_name: &str,
appendable_value: AppendableValue, appendable_value: AppendableValue<'a, I>,
is_important: bool, is_important: bool,
is_first_serialization: &mut bool) -> fmt::Result where W: fmt::Write { is_first_serialization: &mut bool)
-> fmt::Result
where W: fmt::Write, I: Iterator<Item=&'a PropertyDeclaration> {
// after first serialization(key: value;) add whitespace between the pairs // after first serialization(key: value;) add whitespace between the pairs
if !*is_first_serialization { if !*is_first_serialization {
@ -611,7 +622,8 @@ impl Shorthand {
} }
/// Serializes possible shorthand value to String. /// Serializes possible shorthand value to String.
pub fn serialize_shorthand_to_string(self, declarations: &mut Iterator<Item=&PropertyDeclaration>) -> String { pub fn serialize_shorthand_to_string<'a, I>(self, declarations: I) -> String
where I: Iterator<Item=&'a PropertyDeclaration> + Clone {
let mut result = String::new(); let mut result = String::new();
self.serialize_shorthand_to_buffer(&mut result, declarations, &mut true).unwrap(); self.serialize_shorthand_to_buffer(&mut result, declarations, &mut true).unwrap();
result result
@ -620,28 +632,28 @@ impl Shorthand {
/// Serializes possible shorthand value to input buffer given a list of longhand declarations. /// Serializes possible shorthand value to input buffer given a list of longhand declarations.
/// On success, returns true if shorthand value is written and false if no shorthand value is present. /// On success, returns true if shorthand value is written and false if no shorthand value is present.
pub fn serialize_shorthand_to_buffer<W>(self, pub fn serialize_shorthand_to_buffer<'a, W, I>(self,
dest: &mut W, dest: &mut W,
declarations: &mut Iterator<Item=&PropertyDeclaration>, declarations: I,
is_first_serialization: &mut bool) is_first_serialization: &mut bool)
-> Result<bool, fmt::Error> where W: Write { -> Result<bool, fmt::Error>
where W: Write, I: Iterator<Item=&'a PropertyDeclaration> + Clone {
// FIXME: I know that creating this list here is wrong, but I couldn't get it to compile otherwise // Only cloning iterators (a few pointers each) not declarations.
// using plain iterators, need advice! let mut declarations2 = declarations.clone();
let declaration_list: Vec<_> = declarations.cloned().collect(); let mut declarations3 = declarations.clone();
let mut declarations = declaration_list.iter();
let first_declaration = match declarations.next() { let first_declaration = match declarations2.next() {
Some(declaration) => declaration, Some(declaration) => declaration,
None => return Ok(false) None => return Ok(false)
}; };
let property_name = &self.name(); let property_name = self.name();
// https://drafts.csswg.org/css-variables/#variables-in-shorthands // https://drafts.csswg.org/css-variables/#variables-in-shorthands
if let Some(css) = first_declaration.with_variables_from_shorthand(self) { if let Some(css) = first_declaration.with_variables_from_shorthand(self) {
if declarations.all(|d| d.with_variables_from_shorthand(self) == Some(css)) { if declarations2.all(|d| d.with_variables_from_shorthand(self) == Some(css)) {
return append_serialization( return append_serialization::<W, I>(
dest, property_name, AppendableValue::Css(css), false, is_first_serialization dest, property_name, AppendableValue::Css(css), false, is_first_serialization
).and_then(|_| Ok(true)); ).and_then(|_| Ok(true));
} }
@ -650,12 +662,12 @@ impl Shorthand {
} }
} }
if !declaration_list.iter().any(|d| d.with_variables()) { if !declarations3.any(|d| d.with_variables()) {
try!( try!(
append_serialization( append_serialization(
dest, dest,
property_name, property_name,
AppendableValue::DeclarationsForShorthand(&mut declaration_list.iter()), AppendableValue::DeclarationsForShorthand(declarations),
false, false,
is_first_serialization is_first_serialization
) )