style: Avoid extra allocations in serialization of a property declaration block.

Concretely we avoid allocating and scanning a temporary vector of longhands not
yet serialized for each shorthand.

This doesn't save a lot of time in Linux, but I bet it's somewhat important on
OSX.
This commit is contained in:
Emilio Cobos Álvarez 2017-06-14 12:53:49 +02:00
parent 8b20d7a982
commit 6e85601858
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C

View file

@ -14,6 +14,7 @@ use parser::{ParserContext, log_css_error};
use properties::animated_properties::AnimationValue; use properties::animated_properties::AnimationValue;
use selectors::parser::SelectorParseError; use selectors::parser::SelectorParseError;
use shared_lock::Locked; use shared_lock::Locked;
use smallvec::SmallVec;
use std::fmt; use std::fmt;
use std::slice::Iter; use std::slice::Iter;
use style_traits::{PARSING_MODE_DEFAULT, ToCss, ParseError, ParsingMode, StyleParseError}; use style_traits::{PARSING_MODE_DEFAULT, ToCss, ParseError, ParsingMode, StyleParseError};
@ -605,24 +606,31 @@ impl ToCss for PropertyDeclarationBlock {
// Step 3.3 // Step 3.3
let shorthands = declaration.shorthands(); let shorthands = declaration.shorthands();
if !shorthands.is_empty() { if !shorthands.is_empty() {
// Step 3.3.1 // Step 3.3.1 is done by checking already_serialized while
// // iterating below.
// FIXME(emilio): All this looks terribly inefficient...
let mut longhands = self.declarations.iter()
.filter(|d| !already_serialized.contains(d.0.id()))
.collect::<Vec<_>>();
// Step 3.3.2 // Step 3.3.2
for &shorthand in shorthands { for &shorthand in shorthands {
let properties = shorthand.longhands(); let properties = shorthand.longhands();
// Substep 2 & 3 // Substep 2 & 3
let mut current_longhands = Vec::new(); let mut current_longhands = SmallVec::<[_; 10]>::new();
let mut important_count = 0; let mut important_count = 0;
let mut found_system = None; let mut found_system = None;
if shorthand == ShorthandId::Font && longhands.iter().any(|&&(ref l, _)| l.get_system().is_some()) { let is_system_font =
for &&(ref longhand, longhand_importance) in longhands.iter() { shorthand == ShorthandId::Font &&
self.declarations.iter().any(|&(ref l, _)| {
!already_serialized.contains(l.id()) &&
l.get_system().is_some()
});
if is_system_font {
for &(ref longhand, longhand_importance) in &self.declarations {
if already_serialized.contains(longhand.id()) {
continue;
}
if longhand.get_system().is_some() || longhand.is_default_line_height() { if longhand.get_system().is_some() || longhand.is_default_line_height() {
current_longhands.push(longhand); current_longhands.push(longhand);
if found_system.is_none() { if found_system.is_none() {
@ -634,7 +642,11 @@ impl ToCss for PropertyDeclarationBlock {
} }
} }
} else { } else {
for &&(ref longhand, longhand_importance) in longhands.iter() { for &(ref longhand, longhand_importance) in &self.declarations {
if already_serialized.contains(longhand.id()) {
continue;
}
if longhand.id().is_longhand_of(shorthand) { if longhand.id().is_longhand_of(shorthand) {
current_longhands.push(longhand); current_longhands.push(longhand);
if longhand_importance.important() { if longhand_importance.important() {
@ -728,11 +740,6 @@ impl ToCss for PropertyDeclarationBlock {
for current_longhand in &current_longhands { for current_longhand in &current_longhands {
// Substep 9 // Substep 9
already_serialized.insert(current_longhand.id()); already_serialized.insert(current_longhand.id());
let index_to_remove = longhands.iter().position(|l| l.0 == **current_longhand);
if let Some(index) = index_to_remove {
// Substep 10
longhands.remove(index);
}
} }
} }
} }