From 8b53ea8a2cd8b02095da0986df428d45d6a76152 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 6 May 2014 16:56:37 +0100 Subject: [PATCH] Cascade declarations in reverse order, skipping those already seen Previously we processed them in forward order, latter dcelarations for the same property overriding any earlier one, making the work of converting the earlier ones to a computed value redundant. Maintaining a bit field of "seen" properties will also help fixing #2288. --- src/components/style/properties.rs.mako | 68 +++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 5 deletions(-) diff --git a/src/components/style/properties.rs.mako b/src/components/style/properties.rs.mako index 4f6b8830ff0..eecb4fde494 100644 --- a/src/components/style/properties.rs.mako +++ b/src/components/style/properties.rs.mako @@ -7,6 +7,7 @@ #![allow(non_camel_case_types, uppercase_variables)] pub use std::ascii::StrAsciiExt; +use serialize::{Encodable, Encoder}; pub use servo_util::url::parse_url; use sync::Arc; @@ -21,10 +22,11 @@ pub use parsing_utils::*; pub use self::common_types::*; use selector_matching::MatchedProperty; -use serialize::{Encodable, Encoder}; +pub use self::property_bit_field::PropertyBitField; pub mod common_types; + <%! def to_rust_ident(name): @@ -1331,6 +1333,52 @@ pub mod shorthands { } +// TODO(SimonSapin): Convert this to a syntax extension rather than a Mako template. +// Maybe submit for inclusion in libstd? +mod property_bit_field { + use std::uint; + use std::mem; + + pub struct PropertyBitField { + storage: [uint, ..(${len(LONGHANDS)} - 1 + uint::BITS) / uint::BITS] + } + + impl PropertyBitField { + #[inline] + pub fn new() -> PropertyBitField { + PropertyBitField { storage: unsafe { mem::init() } } + } + + #[inline] + fn get(&self, bit: uint) -> bool { + (self.storage[bit / uint::BITS] & (1 << (bit % uint::BITS))) != 0 + } + #[inline] + fn set(&mut self, bit: uint) { + self.storage[bit / uint::BITS] |= 1 << (bit % uint::BITS) + } + #[inline] + fn clear(&mut self, bit: uint) { + self.storage[bit / uint::BITS] &= !(1 << (bit % uint::BITS)) + } + % for i, property in enumerate(LONGHANDS): + #[inline] + pub fn get_${property.ident}(&self) -> bool { + self.get(${i}) + } + #[inline] + pub fn set_${property.ident}(&mut self) { + self.set(${i}) + } + #[inline] + pub fn clear_${property.ident}(&mut self) { + self.clear(${i}) + } + % endfor + } +} + + pub struct PropertyDeclarationBlock { pub important: Arc>, pub normal: Arc>, @@ -1539,14 +1587,19 @@ fn cascade_with_cached_declarations(applicable_declarations: &[MatchedProperty], % endif % endfor - for sub_list in applicable_declarations.iter() { - for declaration in sub_list.declarations.iter() { + let mut seen = PropertyBitField::new(); + for sub_list in applicable_declarations.iter().rev() { + for declaration in sub_list.declarations.iter().rev() { match *declaration { % for style_struct in STYLE_STRUCTS: % if style_struct.inherited: % for property in style_struct.longhands: % if property.derived_from is None: ${property.ident}_declaration(ref declared_value) => { + if seen.get_${property.ident}() { + continue + } + seen.set_${property.ident}(); let computed_value = match *declared_value { SpecifiedValue(ref specified_value) => longhands::${property.ident}::to_computed_value( @@ -1734,13 +1787,18 @@ pub fn cascade(applicable_declarations: &[MatchedProperty], .${style_struct.name}.clone(); % endfor let mut cacheable = true; - for sub_list in applicable_declarations.iter() { - for declaration in sub_list.declarations.iter() { + let mut seen = PropertyBitField::new(); + for sub_list in applicable_declarations.iter().rev() { + for declaration in sub_list.declarations.iter().rev() { match *declaration { % for style_struct in STYLE_STRUCTS: % for property in style_struct.longhands: % if property.derived_from is None: ${property.ident}_declaration(ref declared_value) => { + if seen.get_${property.ident}() { + continue + } + seen.set_${property.ident}(); let computed_value = match *declared_value { SpecifiedValue(ref specified_value) => longhands::${property.ident}::to_computed_value(