From 60f454d7c4ca2249bf914b9f6180e53df9ebe4a4 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 7 Mar 2017 20:12:06 +0100 Subject: [PATCH] Use a bitmap to optimize adding to a PropertyDeclarationBlock. --- .../style/properties/declaration_block.rs | 68 ++++++++++++++----- .../style/properties/properties.mako.rs | 8 +++ ports/geckolib/glue.rs | 3 +- 3 files changed, 61 insertions(+), 18 deletions(-) diff --git a/components/style/properties/declaration_block.rs b/components/style/properties/declaration_block.rs index 0ddf73a62d5..2cb5cba4874 100644 --- a/components/style/properties/declaration_block.rs +++ b/components/style/properties/declaration_block.rs @@ -41,7 +41,7 @@ impl Importance { } /// Overridden declarations are skipped. -#[derive(Debug, PartialEq, Clone)] +#[derive(Clone)] pub struct PropertyDeclarationBlock { /// The group of declarations, along with their importance. /// @@ -50,6 +50,14 @@ pub struct PropertyDeclarationBlock { /// The number of entries in `self.declaration` with `Importance::Important` important_count: usize, + + longhands: LonghandIdSet, +} + +impl fmt::Debug for PropertyDeclarationBlock { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.declarations.fmt(f) + } } impl PropertyDeclarationBlock { @@ -58,14 +66,20 @@ impl PropertyDeclarationBlock { PropertyDeclarationBlock { declarations: Vec::new(), important_count: 0, + longhands: LonghandIdSet::new(), } } /// Create a block with a single declaration pub fn with_one(declaration: PropertyDeclaration, importance: Importance) -> Self { + let mut longhands = LonghandIdSet::new(); + if let PropertyDeclarationId::Longhand(id) = declaration.id() { + longhands.insert(id); + } PropertyDeclarationBlock { declarations: vec![(declaration, importance)], important_count: if importance.important() { 1 } else { 0 }, + longhands: longhands, } } @@ -198,28 +212,39 @@ impl PropertyDeclarationBlock { fn push_common(&mut self, declaration: PropertyDeclaration, importance: Importance, overwrite_more_important: bool) -> bool { - for slot in &mut *self.declarations { - if slot.0.id() == declaration.id() { - match (slot.1, importance) { - (Importance::Normal, Importance::Important) => { - self.important_count += 1; - } - (Importance::Important, Importance::Normal) => { - if overwrite_more_important { - self.important_count -= 1; - } else { - return false + let definitely_new = if let PropertyDeclarationId::Longhand(id) = declaration.id() { + !self.longhands.contains(id) + } else { + false // For custom properties, always scan + }; + + if !definitely_new { + for slot in &mut *self.declarations { + if slot.0.id() == declaration.id() { + match (slot.1, importance) { + (Importance::Normal, Importance::Important) => { + self.important_count += 1; + } + (Importance::Important, Importance::Normal) => { + if overwrite_more_important { + self.important_count -= 1; + } else { + return false + } + } + _ => if slot.0 == declaration { + return false; } } - _ => if slot.0 == declaration { - return false; - } + *slot = (declaration, importance); + return true } - *slot = (declaration, importance); - return true; } } + if let PropertyDeclarationId::Longhand(id) = declaration.id() { + self.longhands.insert(id); + } self.declarations.push((declaration, importance)); if importance.important() { self.important_count += 1; @@ -256,6 +281,11 @@ impl PropertyDeclarationBlock { /// /// Returns whether any declaration was actually removed. pub fn remove_property(&mut self, property: &PropertyId) -> bool { + if let PropertyId::Longhand(id) = *property { + if !self.longhands.contains(id) { + return false + } + } let important_count = &mut self.important_count; let mut removed_at_least_one = false; self.declarations.retain(|&(ref declaration, importance)| { @@ -269,6 +299,10 @@ impl PropertyDeclarationBlock { !remove }); + if let PropertyId::Longhand(id) = *property { + debug_assert!(removed_at_least_one); + self.longhands.remove(id); + } removed_at_least_one } diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 849cb74e965..5eb133601fe 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -177,6 +177,7 @@ pub mod animated_properties { } /// A set of longhand properties +#[derive(Clone)] pub struct LonghandIdSet { storage: [u32; (${len(data.longhands)} - 1 + 32) / 32] } @@ -202,6 +203,13 @@ impl LonghandIdSet { self.storage[bit / 32] |= 1 << (bit % 32); } + /// Remove the given property from the set + #[inline] + pub fn remove(&mut self, id: LonghandId) { + let bit = id as usize; + self.storage[bit / 32] &= !(1 << (bit % 32)); + } + /// Set the corresponding bit of TransitionProperty. /// This function will panic if TransitionProperty::All is given. pub fn set_transition_property_bit(&mut self, property: &TransitionProperty) { diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 509e7efe316..06f3c0f3de8 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -738,7 +738,8 @@ pub extern "C" fn Servo_DeclarationBlock_Clone(declarations: RawServoDeclaration pub extern "C" fn Servo_DeclarationBlock_Equals(a: RawServoDeclarationBlockBorrowed, b: RawServoDeclarationBlockBorrowed) -> bool { - *RwLock::::as_arc(&a).read() == *RwLock::::as_arc(&b).read() + *RwLock::::as_arc(&a).read().declarations() == + *RwLock::::as_arc(&b).read().declarations() } #[no_mangle]