aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/script/dom/element.rs61
-rw-r--r--components/style/properties/properties.mako.rs64
-rw-r--r--components/style/selector_matching.rs12
-rw-r--r--tests/unit/style/properties/serialization.rs12
-rw-r--r--tests/unit/style/stylesheets.rs28
5 files changed, 107 insertions, 70 deletions
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index f6f8661689c..26ad3eaee40 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -762,12 +762,21 @@ impl Element {
fn remove(element: &Element, property: &str) {
let mut inline_declarations = element.style_attribute.borrow_mut();
if let &mut Some(ref mut declarations) = &mut *inline_declarations {
- let index = declarations.declarations
- .iter()
- .position(|&(ref decl, _)| decl.matches(property));
+ let mut importance = None;
+ let index = declarations.declarations.iter().position(|&(ref decl, i)| {
+ let matching = decl.matches(property);
+ if matching {
+ importance = Some(i)
+ }
+ matching
+ });
if let Some(index) = index {
Arc::make_mut(&mut declarations.declarations).remove(index);
- declarations.recalc_any();
+ if importance.unwrap().important() {
+ declarations.important_count -= 1;
+ } else {
+ declarations.normal_count -= 1;
+ }
}
}
}
@@ -791,21 +800,42 @@ impl Element {
'outer: for incoming_declaration in declarations {
for existing_declaration in &mut *existing_declarations {
if existing_declaration.0.name() == incoming_declaration.name() {
+ match (existing_declaration.1, importance) {
+ (Importance::Normal, Importance::Important) => {
+ declaration_block.normal_count -= 1;
+ declaration_block.important_count += 1;
+ }
+ (Importance::Important, Importance::Normal) => {
+ declaration_block.normal_count += 1;
+ declaration_block.important_count -= 1;
+ }
+ _ => {}
+ }
*existing_declaration = (incoming_declaration, importance);
continue 'outer;
}
}
existing_declarations.push((incoming_declaration, importance));
+ if importance.important() {
+ declaration_block.important_count += 1;
+ } else {
+ declaration_block.normal_count += 1;
+ }
}
}
- declaration_block.recalc_any();
return;
}
+ let (normal_count, important_count) = if importance.important() {
+ (0, declarations.len() as u32)
+ } else {
+ (declarations.len() as u32, 0)
+ };
+
*inline_declarations = Some(PropertyDeclarationBlock {
declarations: Arc::new(declarations.into_iter().map(|d| (d, importance)).collect()),
- any_important: importance.important(),
- any_normal: !importance.important(),
+ normal_count: normal_count,
+ important_count: important_count,
});
}
@@ -818,13 +848,24 @@ impl Element {
new_importance: Importance) {
{
let mut inline_declarations = self.style_attribute().borrow_mut();
- if let &mut Some(ref mut declarations) = &mut *inline_declarations {
+ if let &mut Some(ref mut block) = &mut *inline_declarations {
// Usually, the reference counts of `from` and `to` will be 1 here. But transitions
// could make them greater than that.
- let declarations = Arc::make_mut(&mut declarations.declarations);
+ let declarations = Arc::make_mut(&mut block.declarations);
for &mut (ref declaration, ref mut importance) in declarations {
if properties.iter().any(|p| declaration.name() == **p) {
- *importance = new_importance
+ match (*importance, new_importance) {
+ (Importance::Normal, Importance::Important) => {
+ block.normal_count -= 1;
+ block.important_count += 1;
+ }
+ (Importance::Important, Importance::Normal) => {
+ block.normal_count += 1;
+ block.important_count -= 1;
+ }
+ _ => {}
+ }
+ *importance = new_importance;
}
}
}
diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs
index 539e03253c4..b0c92710a06 100644
--- a/components/style/properties/properties.mako.rs
+++ b/components/style/properties/properties.mako.rs
@@ -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]
diff --git a/components/style/selector_matching.rs b/components/style/selector_matching.rs
index d04aa322924..781f2298c4a 100644
--- a/components/style/selector_matching.rs
+++ b/components/style/selector_matching.rs
@@ -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,
diff --git a/tests/unit/style/properties/serialization.rs b/tests/unit/style/properties/serialization.rs
index d22043b237b..f47b5303a0f 100644
--- a/tests/unit/style/properties/serialization.rs
+++ b/tests/unit/style/properties/serialization.rs
@@ -46,8 +46,10 @@ fn property_declaration_block_should_serialize_correctly() {
let block = PropertyDeclarationBlock {
declarations: Arc::new(declarations),
- any_important: true,
- any_normal: true,
+
+ // Incorrect, but not used here:
+ normal_count: 0,
+ important_count: 0,
};
let css_string = block.to_css_string();
@@ -64,8 +66,10 @@ mod shorthand_serialization {
pub fn shorthand_properties_to_string(properties: Vec<PropertyDeclaration>) -> String {
let block = PropertyDeclarationBlock {
declarations: Arc::new(properties.into_iter().map(|d| (d, Importance::Normal)).collect()),
- any_important: false,
- any_normal: true,
+
+ // Incorrect, but not used here:
+ normal_count: 0,
+ important_count: 0,
};
block.to_css_string()
diff --git a/tests/unit/style/stylesheets.rs b/tests/unit/style/stylesheets.rs
index 28b795d440e..a73f43b51ba 100644
--- a/tests/unit/style/stylesheets.rs
+++ b/tests/unit/style/stylesheets.rs
@@ -24,8 +24,18 @@ fn test_parse_stylesheet() {
let css = r"
@namespace url(http://www.w3.org/1999/xhtml);
/* FIXME: only if scripting is enabled */
- input[type=hidden i] { display: none !important; }
- html , body /**/ { display: block; }
+ input[type=hidden i] {
+ display: block !important;
+ display: none !important;
+ display: inline;
+ --a: b !important;
+ --a: inherit !important;
+ --a: c;
+ }
+ html , body /**/ {
+ display: none;
+ display: block;
+ }
#d1 > .ok { background: blue; }
@keyframes foo {
from { width: 0% }
@@ -92,9 +102,11 @@ fn test_parse_stylesheet() {
(PropertyDeclaration::Display(DeclaredValue::Value(
longhands::display::SpecifiedValue::none)),
Importance::Important),
+ (PropertyDeclaration::Custom(Atom::from("a"), DeclaredValue::Inherit),
+ Importance::Important),
]),
- any_normal: false,
- any_important: true,
+ normal_count: 0,
+ important_count: 2,
},
}),
CSSRule::Style(StyleRule {
@@ -140,8 +152,8 @@ fn test_parse_stylesheet() {
longhands::display::SpecifiedValue::block)),
Importance::Normal),
]),
- any_normal: true,
- any_important: false,
+ normal_count: 1,
+ important_count: 0,
},
}),
CSSRule::Style(StyleRule {
@@ -196,8 +208,8 @@ fn test_parse_stylesheet() {
(PropertyDeclaration::BackgroundClip(DeclaredValue::Initial),
Importance::Normal),
]),
- any_normal: true,
- any_important: false,
+ normal_count: 8,
+ important_count: 0,
},
}),
CSSRule::Keyframes(KeyframesRule {