Keep track of the number of important and normal declarations in a block

… instead of the presence (`bool` flags) of each.

This allows removing `recalc_any` which iterated over the `Vec`.
This commit is contained in:
Simon Sapin 2016-08-21 03:20:29 +02:00
parent 5e4bdac2bd
commit f9150af936
5 changed files with 107 additions and 70 deletions

View file

@ -288,27 +288,11 @@ pub struct PropertyDeclarationBlock {
#[cfg_attr(feature = "servo", ignore_heap_size_of = "#7038")]
pub declarations: Arc<Vec<(PropertyDeclaration, Importance)>>,
/// Whether `self.declaration` contains at least one declaration with `Importance::Normal`
pub any_normal: bool,
/// The number of entries in `self.declaration` with `Importance::Normal`
pub normal_count: u32,
/// Whether `self.declaration` contains at least one declaration with `Importance::Important`
pub any_important: bool,
}
impl PropertyDeclarationBlock {
pub fn recalc_any(&mut self) {
let mut any_normal = false;
let mut any_important = false;
for &(_, importance) in &*self.declarations {
if importance.important() {
any_important = true
} else {
any_normal = true
}
}
self.any_normal = any_normal;
self.any_important = any_important;
}
/// The number of entries in `self.declaration` with `Importance::Important`
pub important_count: u32,
}
impl ToCss for PropertyDeclarationBlock {
@ -564,8 +548,8 @@ impl<'a, 'b> DeclarationParser for PropertyDeclarationParser<'a, 'b> {
pub fn parse_property_declaration_list(context: &ParserContext, input: &mut Parser)
-> PropertyDeclarationBlock {
let mut declarations = Vec::new();
let mut any_normal = false;
let mut any_important = false;
let mut normal_count = 0;
let mut important_count = 0;
let parser = PropertyDeclarationParser {
context: context,
};
@ -574,9 +558,9 @@ pub fn parse_property_declaration_list(context: &ParserContext, input: &mut Pars
match declaration {
Ok((results, importance)) => {
if importance.important() {
any_important = true
important_count += results.len() as u32;
} else {
any_normal = true
normal_count += results.len() as u32;
}
declarations.extend(results.into_iter().map(|d| (d, importance)))
}
@ -588,50 +572,46 @@ pub fn parse_property_declaration_list(context: &ParserContext, input: &mut Pars
}
}
}
let (declarations, removed_any) = deduplicate_property_declarations(declarations);
let mut block = PropertyDeclarationBlock {
declarations: Arc::new(declarations),
any_normal: any_normal,
any_important: any_important,
normal_count: normal_count,
important_count: important_count,
};
if removed_any {
block.recalc_any();
}
deduplicate_property_declarations(&mut block);
block
}
/// Only keep the "winning" declaration for any given property, by importance then source order.
/// The input and output are in source order
fn deduplicate_property_declarations(declarations: Vec<(PropertyDeclaration, Importance)>)
-> (Vec<(PropertyDeclaration, Importance)>, bool) {
let mut removed_any = false;
fn deduplicate_property_declarations(block: &mut PropertyDeclarationBlock) {
let mut deduplicated = Vec::new();
let mut seen_normal = PropertyBitField::new();
let mut seen_important = PropertyBitField::new();
let mut seen_custom_normal = Vec::new();
let mut seen_custom_important = Vec::new();
for (declaration, importance) in declarations.into_iter().rev() {
let declarations = Arc::get_mut(&mut block.declarations).unwrap();
for (declaration, importance) in declarations.drain(..).rev() {
match declaration {
% for property in data.longhands:
PropertyDeclaration::${property.camel_case}(..) => {
% if not property.derived_from:
if importance.important() {
if seen_important.get_${property.ident}() {
removed_any = true;
block.important_count -= 1;
continue
}
if seen_normal.get_${property.ident}() {
remove_one(&mut deduplicated, |d| {
matches!(d, &(PropertyDeclaration::${property.camel_case}(..), _))
});
removed_any = true;
block.normal_count -= 1;
}
seen_important.set_${property.ident}()
} else {
if seen_normal.get_${property.ident}() ||
seen_important.get_${property.ident}() {
removed_any = true;
block.normal_count -= 1;
continue
}
seen_normal.set_${property.ident}()
@ -644,20 +624,20 @@ fn deduplicate_property_declarations(declarations: Vec<(PropertyDeclaration, Imp
PropertyDeclaration::Custom(ref name, _) => {
if importance.important() {
if seen_custom_important.contains(name) {
removed_any = true;
block.important_count -= 1;
continue
}
if seen_custom_normal.contains(name) {
remove_one(&mut deduplicated, |d| {
matches!(d, &(PropertyDeclaration::Custom(ref n, _), _) if n == name)
});
removed_any = true;
block.normal_count -= 1;
}
seen_custom_important.push(name.clone())
} else {
if seen_custom_normal.contains(name) ||
seen_custom_important.contains(name) {
removed_any = true;
block.normal_count -= 1;
continue
}
seen_custom_normal.push(name.clone())
@ -667,7 +647,7 @@ fn deduplicate_property_declarations(declarations: Vec<(PropertyDeclaration, Imp
deduplicated.push((declaration, importance))
}
deduplicated.reverse();
(deduplicated, removed_any)
*declarations = deduplicated;
}
#[inline]

View file

@ -162,8 +162,8 @@ impl Stylist {
// Take apart the StyleRule into individual Rules and insert
// them into the SelectorMap of that priority.
macro_rules! append(
($style_rule: ident, $priority: ident, $importance: expr, $any: ident) => {
if $style_rule.declarations.$any {
($style_rule: ident, $priority: ident, $importance: expr, $count: ident) => {
if $style_rule.declarations.$count > 0 {
for selector in &$style_rule.selectors {
let map = if let Some(ref pseudo) = selector.pseudo_element {
self.pseudos_map
@ -191,8 +191,8 @@ impl Stylist {
for rule in stylesheet.effective_rules(&self.device) {
match *rule {
CSSRule::Style(ref style_rule) => {
append!(style_rule, normal, Importance::Normal, any_normal);
append!(style_rule, important, Importance::Important, any_important);
append!(style_rule, normal, Importance::Normal, normal_count);
append!(style_rule, important, Importance::Important, important_count);
rules_source_order += 1;
for selector in &style_rule.selectors {
@ -394,7 +394,7 @@ impl Stylist {
// Step 4: Normal style attributes.
if let Some(ref sa) = style_attribute {
if sa.any_normal {
if sa.normal_count > 0 {
relations |= AFFECTED_BY_STYLE_ATTRIBUTE;
Push::push(
applicable_declarations,
@ -416,7 +416,7 @@ impl Stylist {
// Step 6: `!important` style attributes.
if let Some(ref sa) = style_attribute {
if sa.any_important {
if sa.important_count > 0 {
relations |= AFFECTED_BY_STYLE_ATTRIBUTE;
Push::push(
applicable_declarations,