diff --git a/components/style/rule_tree/mod.rs b/components/style/rule_tree/mod.rs index ceb94aa15f6..5353816a9df 100644 --- a/components/style/rule_tree/mod.rs +++ b/components/style/rule_tree/mod.rs @@ -193,10 +193,11 @@ impl RuleTree { for (source, level) in iter { debug_assert!(last_level <= level, "Not really ordered"); debug_assert!(!level.is_important(), "Important levels handled internally"); - let (any_normal, any_important) = { + let any_important = { let pdb = source.read(level.guard(guards)); - (pdb.any_normal(), pdb.any_important()) + pdb.any_important() }; + if any_important { found_important = true; match level { @@ -210,19 +211,25 @@ impl RuleTree { _ => {}, }; } - // We really want to ensure empty rule nodes appear in the rule tree for - // devtools, this condition ensures that if we find an empty rule node, we - // insert it at the normal level. - if any_normal || !any_important { - if matches!(level, Transitions) && found_important { - // There can be at most one transition, and it will come at - // the end of the iterator. Stash it and apply it after - // !important rules. - debug_assert!(transition.is_none()); - transition = Some(source); - } else { - current = current.ensure_child(self.root.downgrade(), source, level); - } + + // We don't optimize out empty rules, even though we could. + // + // Inspector relies on every rule being inserted in the normal level + // at least once, in order to return the rules with the correct + // specificity order. + // + // TODO(emilio): If we want to apply these optimizations without + // breaking inspector's expectations, we'd need to run + // selector-matching again at the inspector's request. That may or + // may not be a better trade-off. + if matches!(level, Transitions) && found_important { + // There can be at most one transition, and it will come at + // the end of the iterator. Stash it and apply it after + // !important rules. + debug_assert!(transition.is_none()); + transition = Some(source); + } else { + current = current.ensure_child(self.root.downgrade(), source, level); } last_level = level; } diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index a35be024a33..30f80e0dd61 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -1916,9 +1916,6 @@ pub extern "C" fn Servo_ComputedValues_GetStyleRuleList(values: ServoStyleContex None => return, }; - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - // TODO(emilio): Will benefit from SmallVec. let mut result = vec![]; for node in rule_node.self_and_ancestors() { @@ -1927,13 +1924,12 @@ pub extern "C" fn Servo_ComputedValues_GetStyleRuleList(values: ServoStyleContex _ => continue, }; + // For the rules with any important declaration, we insert them into + // rule tree twice, one for normal level and another for important + // level. So, we skip the important one to keep the specificity order of + // rules. if node.importance().important() { - let block = style_rule.read_with(&guard).block.read_with(&guard); - if block.any_normal() { - // We'll append it when we find the normal rules in our - // parent chain. - continue; - } + continue; } result.push(style_rule);