Adding more efficient way of determining if PropertyDeclaration is important

This commit is contained in:
David Raifaizen 2016-04-02 12:20:25 -04:00 committed by Simon Sapin
parent 51e642e875
commit be2f70393f

View file

@ -254,9 +254,10 @@ mod property_bit_field {
% endif % endif
% endfor % endfor
/// Declarations are stored in reverse order.
/// Overridden declarations are skipped.
use std::iter::{Iterator, Chain, Zip, Rev, Repeat, repeat};
use std::slice;
/// Overridden declarations are skipped.
// FIXME (https://github.com/servo/servo/issues/3426) // FIXME (https://github.com/servo/servo/issues/3426)
#[derive(Debug, PartialEq, HeapSizeOf)] #[derive(Debug, PartialEq, HeapSizeOf)]
@ -267,6 +268,19 @@ pub struct PropertyDeclarationBlock {
pub normal: Arc<Vec<PropertyDeclaration>>, pub normal: Arc<Vec<PropertyDeclaration>>,
} }
impl PropertyDeclarationBlock {
/// Provides an iterator of all declarations, with indication of !important value
pub fn declarations(&self) -> Chain<
Zip<Rev<slice::Iter<PropertyDeclaration>>, Repeat<bool>>,
Zip<Rev<slice::Iter<PropertyDeclaration>>, Repeat<bool>>
> {
// Declarations are stored in reverse order.
let normal = self.normal.iter().rev().zip(repeat(false));
let important = self.important.iter().rev().zip(repeat(true));
normal.chain(important)
}
}
impl ToCss for PropertyDeclarationBlock { impl ToCss for PropertyDeclarationBlock {
// https://drafts.csswg.org/cssom/#serialize-a-css-declaration-block // https://drafts.csswg.org/cssom/#serialize-a-css-declaration-block
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
@ -278,8 +292,7 @@ impl ToCss for PropertyDeclarationBlock {
let mut already_serialized = Vec::new(); let mut already_serialized = Vec::new();
// Step 3 // Step 3
// restore order of declarations since PropertyDeclarationBlock is stored in reverse order for (declaration, important) in self.declarations() {
for declaration in self.important.iter().chain(self.normal.iter()).rev() {
// Step 3.1 // Step 3.1
let property = declaration.name(); let property = declaration.name();
@ -293,8 +306,8 @@ impl ToCss for PropertyDeclarationBlock {
if !shorthands.is_empty() { if !shorthands.is_empty() {
// Step 3.3.1 // Step 3.3.1
let mut longhands = self.important.iter().chain(self.normal.iter()).rev() let mut longhands = self.declarations()
.filter(|d| !already_serialized.contains(&d.name())) .filter(|d| !already_serialized.contains(&d.0.name()))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
// Step 3.3.2 // Step 3.3.2
@ -303,24 +316,27 @@ impl ToCss for PropertyDeclarationBlock {
// Substep 2 & 3 // Substep 2 & 3
let mut current_longhands = Vec::new(); let mut current_longhands = Vec::new();
let mut important_count = 0;
for longhand in longhands.iter() { for longhand in longhands.iter() {
let longhand_name = longhand.name(); let longhand_name = longhand.0.name();
if properties.iter().any(|p| &longhand_name == *p) { if properties.iter().any(|p| &longhand_name == *p) {
current_longhands.push(*longhand); current_longhands.push(longhand.0);
if longhand.1 == true {
important_count += 1;
}
} }
} }
// Substep 1 // Substep 1
/* Assuming that the PropertyDeclarationBlock contains no duplicate entries,
if the current_longhands length is equal to the properties length, it means
that the properties that map to shorthand are present in longhands */
if current_longhands.is_empty() || current_longhands.len() != properties.len() { if current_longhands.is_empty() || current_longhands.len() != properties.len() {
continue; continue;
} }
// Substep 4 // Substep 4
let important_count = current_longhands.iter()
.filter(|l| self.important.contains(l))
.count();
let is_important = important_count > 0; let is_important = important_count > 0;
if is_important && important_count != current_longhands.len() { if is_important && important_count != current_longhands.len() {
continue; continue;
@ -340,7 +356,7 @@ impl ToCss for PropertyDeclarationBlock {
for current_longhand in current_longhands { for current_longhand in current_longhands {
// Substep 9 // Substep 9
already_serialized.push(current_longhand.name()); already_serialized.push(current_longhand.name());
let index_to_remove = longhands.iter().position(|l| l == &current_longhand); let index_to_remove = longhands.iter().position(|l| l.0 == current_longhand);
if let Some(index) = index_to_remove { if let Some(index) = index_to_remove {
// Substep 10 // Substep 10
longhands.remove(index); longhands.remove(index);
@ -355,11 +371,10 @@ impl ToCss for PropertyDeclarationBlock {
} }
// Steps 3.3.5, 3.3.6 & 3.3.7 // Steps 3.3.5, 3.3.6 & 3.3.7
let append_important = self.important.contains(declaration);
try!(append_serialization(dest, try!(append_serialization(dest,
&property.to_string(), &property.to_string(),
AppendableValue::Declaration(declaration), AppendableValue::Declaration(declaration),
append_important, important,
&mut is_first_serialization)); &mut is_first_serialization));
// Step 3.3.8 // Step 3.3.8
@ -380,7 +395,7 @@ fn append_serialization<W>(dest: &mut W,
property_name: &str, property_name: &str,
appendable_value: AppendableValue, appendable_value: AppendableValue,
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 {
// 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 {