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
% 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)
#[derive(Debug, PartialEq, HeapSizeOf)]
@ -267,6 +268,19 @@ pub struct PropertyDeclarationBlock {
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 {
// https://drafts.csswg.org/cssom/#serialize-a-css-declaration-block
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();
// Step 3
// restore order of declarations since PropertyDeclarationBlock is stored in reverse order
for declaration in self.important.iter().chain(self.normal.iter()).rev() {
for (declaration, important) in self.declarations() {
// Step 3.1
let property = declaration.name();
@ -293,8 +306,8 @@ impl ToCss for PropertyDeclarationBlock {
if !shorthands.is_empty() {
// Step 3.3.1
let mut longhands = self.important.iter().chain(self.normal.iter()).rev()
.filter(|d| !already_serialized.contains(&d.name()))
let mut longhands = self.declarations()
.filter(|d| !already_serialized.contains(&d.0.name()))
.collect::<Vec<_>>();
// Step 3.3.2
@ -303,24 +316,27 @@ impl ToCss for PropertyDeclarationBlock {
// Substep 2 & 3
let mut current_longhands = Vec::new();
let mut important_count = 0;
for longhand in longhands.iter() {
let longhand_name = longhand.name();
let longhand_name = longhand.0.name();
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
/* 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() {
continue;
}
// Substep 4
let important_count = current_longhands.iter()
.filter(|l| self.important.contains(l))
.count();
let is_important = important_count > 0;
if is_important && important_count != current_longhands.len() {
continue;
@ -340,7 +356,7 @@ impl ToCss for PropertyDeclarationBlock {
for current_longhand in current_longhands {
// Substep 9
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 {
// Substep 10
longhands.remove(index);
@ -355,11 +371,10 @@ impl ToCss for PropertyDeclarationBlock {
}
// Steps 3.3.5, 3.3.6 & 3.3.7
let append_important = self.important.contains(declaration);
try!(append_serialization(dest,
&property.to_string(),
AppendableValue::Declaration(declaration),
append_important,
important,
&mut is_first_serialization));
// Step 3.3.8
@ -380,7 +395,7 @@ fn append_serialization<W>(dest: &mut W,
property_name: &str,
appendable_value: AppendableValue,
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
if !*is_first_serialization {