Use a bitmap to optimize adding to a PropertyDeclarationBlock.

This commit is contained in:
Simon Sapin 2017-03-07 20:12:06 +01:00
parent f70a49974a
commit 60f454d7c4
3 changed files with 61 additions and 18 deletions

View file

@ -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
}

View file

@ -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) {

View file

@ -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::<PropertyDeclarationBlock>::as_arc(&a).read() == *RwLock::<PropertyDeclarationBlock>::as_arc(&b).read()
*RwLock::<PropertyDeclarationBlock>::as_arc(&a).read().declarations() ==
*RwLock::<PropertyDeclarationBlock>::as_arc(&b).read().declarations()
}
#[no_mangle]