mirror of
https://github.com/servo/servo.git
synced 2025-06-22 08:08:59 +01:00
Auto merge of #16567 - bholley:any_declarations, r=SimonSapin
Avoid pointer-chasing to check whether there are any declarations https://bugzilla.mozilla.org/show_bug.cgi?id=1358375 <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/16567) <!-- Reviewable:end -->
This commit is contained in:
commit
2d3a7b2001
2 changed files with 69 additions and 43 deletions
|
@ -324,12 +324,11 @@ impl Stylist {
|
||||||
self.element_map.borrow_for_origin(&stylesheet.origin)
|
self.element_map.borrow_for_origin(&stylesheet.origin)
|
||||||
};
|
};
|
||||||
|
|
||||||
map.insert(Rule {
|
map.insert(Rule::new(guard,
|
||||||
selector: selector.inner.clone(),
|
selector.inner.clone(),
|
||||||
style_rule: locked.clone(),
|
locked.clone(),
|
||||||
specificity: selector.specificity,
|
self.rules_source_order,
|
||||||
source_order: self.rules_source_order,
|
selector.specificity));
|
||||||
});
|
|
||||||
}
|
}
|
||||||
self.rules_source_order += 1;
|
self.rules_source_order += 1;
|
||||||
|
|
||||||
|
@ -661,7 +660,6 @@ impl Stylist {
|
||||||
// Step 1: Normal user-agent rules.
|
// Step 1: Normal user-agent rules.
|
||||||
map.user_agent.get_all_matching_rules(element,
|
map.user_agent.get_all_matching_rules(element,
|
||||||
parent_bf,
|
parent_bf,
|
||||||
guards.ua_or_user,
|
|
||||||
applicable_declarations,
|
applicable_declarations,
|
||||||
&mut relations,
|
&mut relations,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
|
@ -688,7 +686,6 @@ impl Stylist {
|
||||||
// Step 3: User and author normal rules.
|
// Step 3: User and author normal rules.
|
||||||
map.user.get_all_matching_rules(element,
|
map.user.get_all_matching_rules(element,
|
||||||
parent_bf,
|
parent_bf,
|
||||||
guards.ua_or_user,
|
|
||||||
applicable_declarations,
|
applicable_declarations,
|
||||||
&mut relations,
|
&mut relations,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
|
@ -696,7 +693,6 @@ impl Stylist {
|
||||||
debug!("user normal: {:?}", relations);
|
debug!("user normal: {:?}", relations);
|
||||||
map.author.get_all_matching_rules(element,
|
map.author.get_all_matching_rules(element,
|
||||||
parent_bf,
|
parent_bf,
|
||||||
guards.author,
|
|
||||||
applicable_declarations,
|
applicable_declarations,
|
||||||
&mut relations,
|
&mut relations,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
|
@ -731,7 +727,6 @@ impl Stylist {
|
||||||
// Step 6: Author-supplied `!important` rules.
|
// Step 6: Author-supplied `!important` rules.
|
||||||
map.author.get_all_matching_rules(element,
|
map.author.get_all_matching_rules(element,
|
||||||
parent_bf,
|
parent_bf,
|
||||||
guards.author,
|
|
||||||
applicable_declarations,
|
applicable_declarations,
|
||||||
&mut relations,
|
&mut relations,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
|
@ -755,7 +750,6 @@ impl Stylist {
|
||||||
// Step 8: User `!important` rules.
|
// Step 8: User `!important` rules.
|
||||||
map.user.get_all_matching_rules(element,
|
map.user.get_all_matching_rules(element,
|
||||||
parent_bf,
|
parent_bf,
|
||||||
guards.ua_or_user,
|
|
||||||
applicable_declarations,
|
applicable_declarations,
|
||||||
&mut relations,
|
&mut relations,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
|
@ -769,7 +763,6 @@ impl Stylist {
|
||||||
// Step 9: UA `!important` rules.
|
// Step 9: UA `!important` rules.
|
||||||
map.user_agent.get_all_matching_rules(element,
|
map.user_agent.get_all_matching_rules(element,
|
||||||
parent_bf,
|
parent_bf,
|
||||||
guards.ua_or_user,
|
|
||||||
applicable_declarations,
|
applicable_declarations,
|
||||||
&mut relations,
|
&mut relations,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
|
@ -990,7 +983,6 @@ impl SelectorMap {
|
||||||
pub fn get_all_matching_rules<E, V, F>(&self,
|
pub fn get_all_matching_rules<E, V, F>(&self,
|
||||||
element: &E,
|
element: &E,
|
||||||
parent_bf: Option<&BloomFilter>,
|
parent_bf: Option<&BloomFilter>,
|
||||||
guard: &SharedRwLockReadGuard,
|
|
||||||
matching_rules_list: &mut V,
|
matching_rules_list: &mut V,
|
||||||
relations: &mut StyleRelations,
|
relations: &mut StyleRelations,
|
||||||
flags_setter: &mut F,
|
flags_setter: &mut F,
|
||||||
|
@ -1010,7 +1002,6 @@ impl SelectorMap {
|
||||||
parent_bf,
|
parent_bf,
|
||||||
&self.id_hash,
|
&self.id_hash,
|
||||||
&id,
|
&id,
|
||||||
guard,
|
|
||||||
matching_rules_list,
|
matching_rules_list,
|
||||||
relations,
|
relations,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
|
@ -1022,7 +1013,6 @@ impl SelectorMap {
|
||||||
parent_bf,
|
parent_bf,
|
||||||
&self.class_hash,
|
&self.class_hash,
|
||||||
class,
|
class,
|
||||||
guard,
|
|
||||||
matching_rules_list,
|
matching_rules_list,
|
||||||
relations,
|
relations,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
|
@ -1038,7 +1028,6 @@ impl SelectorMap {
|
||||||
parent_bf,
|
parent_bf,
|
||||||
local_name_hash,
|
local_name_hash,
|
||||||
element.get_local_name(),
|
element.get_local_name(),
|
||||||
guard,
|
|
||||||
matching_rules_list,
|
matching_rules_list,
|
||||||
relations,
|
relations,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
|
@ -1047,7 +1036,6 @@ impl SelectorMap {
|
||||||
SelectorMap::get_matching_rules(element,
|
SelectorMap::get_matching_rules(element,
|
||||||
parent_bf,
|
parent_bf,
|
||||||
&self.other_rules,
|
&self.other_rules,
|
||||||
guard,
|
|
||||||
matching_rules_list,
|
matching_rules_list,
|
||||||
relations,
|
relations,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
|
@ -1107,7 +1095,6 @@ impl SelectorMap {
|
||||||
parent_bf: Option<&BloomFilter>,
|
parent_bf: Option<&BloomFilter>,
|
||||||
hash: &FnvHashMap<Str, Vec<Rule>>,
|
hash: &FnvHashMap<Str, Vec<Rule>>,
|
||||||
key: &BorrowedStr,
|
key: &BorrowedStr,
|
||||||
guard: &SharedRwLockReadGuard,
|
|
||||||
matching_rules: &mut Vector,
|
matching_rules: &mut Vector,
|
||||||
relations: &mut StyleRelations,
|
relations: &mut StyleRelations,
|
||||||
flags_setter: &mut F,
|
flags_setter: &mut F,
|
||||||
|
@ -1122,7 +1109,6 @@ impl SelectorMap {
|
||||||
SelectorMap::get_matching_rules(element,
|
SelectorMap::get_matching_rules(element,
|
||||||
parent_bf,
|
parent_bf,
|
||||||
rules,
|
rules,
|
||||||
guard,
|
|
||||||
matching_rules,
|
matching_rules,
|
||||||
relations,
|
relations,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
|
@ -1134,7 +1120,6 @@ impl SelectorMap {
|
||||||
fn get_matching_rules<E, V, F>(element: &E,
|
fn get_matching_rules<E, V, F>(element: &E,
|
||||||
parent_bf: Option<&BloomFilter>,
|
parent_bf: Option<&BloomFilter>,
|
||||||
rules: &[Rule],
|
rules: &[Rule],
|
||||||
guard: &SharedRwLockReadGuard,
|
|
||||||
matching_rules: &mut V,
|
matching_rules: &mut V,
|
||||||
relations: &mut StyleRelations,
|
relations: &mut StyleRelations,
|
||||||
flags_setter: &mut F,
|
flags_setter: &mut F,
|
||||||
|
@ -1144,12 +1129,10 @@ impl SelectorMap {
|
||||||
F: FnMut(&E, ElementSelectorFlags),
|
F: FnMut(&E, ElementSelectorFlags),
|
||||||
{
|
{
|
||||||
for rule in rules.iter() {
|
for rule in rules.iter() {
|
||||||
let style_rule = rule.style_rule.read_with(guard);
|
|
||||||
let block = style_rule.block.read_with(guard);
|
|
||||||
let any_declaration_for_importance = if cascade_level.is_important() {
|
let any_declaration_for_importance = if cascade_level.is_important() {
|
||||||
block.any_important()
|
rule.any_important_declarations()
|
||||||
} else {
|
} else {
|
||||||
block.any_normal()
|
rule.any_normal_declarations()
|
||||||
};
|
};
|
||||||
if any_declaration_for_importance &&
|
if any_declaration_for_importance &&
|
||||||
matches_selector(&rule.selector, element, parent_bf,
|
matches_selector(&rule.selector, element, parent_bf,
|
||||||
|
@ -1230,15 +1213,10 @@ impl SelectorMap {
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Rule {
|
pub struct Rule {
|
||||||
/// The selector this struct represents.
|
/// The selector this struct represents. We store this and the
|
||||||
/// This is an Arc because Rule will essentially be cloned for every element
|
/// any_{important,normal} booleans inline in the Rule to avoid
|
||||||
/// that it matches. Selector contains an owned vector (through
|
/// pointer-chasing when gathering applicable declarations, which
|
||||||
/// ComplexSelector) and we want to avoid the allocation.
|
/// can ruin performance when there are a lot of rules.
|
||||||
///
|
|
||||||
/// FIXME(emilio): We should be able to get rid of it and just use the style
|
|
||||||
/// rule? This predates the time where the rule was in `selectors`, and the
|
|
||||||
/// style rule was a generic parameter to it. It's not trivial though, due
|
|
||||||
/// to the specificity.
|
|
||||||
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
|
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
|
||||||
pub selector: SelectorInner<SelectorImpl>,
|
pub selector: SelectorInner<SelectorImpl>,
|
||||||
/// The actual style rule.
|
/// The actual style rule.
|
||||||
|
@ -1246,17 +1224,66 @@ pub struct Rule {
|
||||||
pub style_rule: Arc<Locked<StyleRule>>,
|
pub style_rule: Arc<Locked<StyleRule>>,
|
||||||
/// The source order this style rule appears in.
|
/// The source order this style rule appears in.
|
||||||
pub source_order: usize,
|
pub source_order: usize,
|
||||||
/// The specificity of the rule this selector represents.
|
/// Bottom 30 bits: The specificity of the rule this selector represents.
|
||||||
pub specificity: u32,
|
/// 31st bit: Whether the rule's declaration block has any important declarations.
|
||||||
|
/// 32nd bit: Whether the rule's declaration block has any normal declarations.
|
||||||
|
specificity_and_bits: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Masks for specificity_and_bits.
|
||||||
|
const SPECIFICITY_MASK: u32 = 0x3fffffff;
|
||||||
|
const ANY_IMPORTANT_DECLARATIONS_BIT: u32 = 1 << 30;
|
||||||
|
const ANY_NORMAL_DECLARATIONS_BIT: u32 = 1 << 31;
|
||||||
|
|
||||||
impl Rule {
|
impl Rule {
|
||||||
|
/// Returns the specificity of the rule.
|
||||||
|
pub fn specificity(&self) -> u32 {
|
||||||
|
self.specificity_and_bits & SPECIFICITY_MASK
|
||||||
|
}
|
||||||
|
|
||||||
|
fn any_important_declarations(&self) -> bool {
|
||||||
|
(self.specificity_and_bits & ANY_IMPORTANT_DECLARATIONS_BIT) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn any_normal_declarations(&self) -> bool {
|
||||||
|
(self.specificity_and_bits & ANY_NORMAL_DECLARATIONS_BIT) != 0
|
||||||
|
}
|
||||||
|
|
||||||
fn to_applicable_declaration_block(&self, level: CascadeLevel) -> ApplicableDeclarationBlock {
|
fn to_applicable_declaration_block(&self, level: CascadeLevel) -> ApplicableDeclarationBlock {
|
||||||
ApplicableDeclarationBlock {
|
ApplicableDeclarationBlock {
|
||||||
source: StyleSource::Style(self.style_rule.clone()),
|
source: StyleSource::Style(self.style_rule.clone()),
|
||||||
level: level,
|
level: level,
|
||||||
source_order: self.source_order,
|
source_order: self.source_order,
|
||||||
specificity: self.specificity,
|
specificity: self.specificity(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new Rule.
|
||||||
|
pub fn new(guard: &SharedRwLockReadGuard,
|
||||||
|
selector: SelectorInner<SelectorImpl>,
|
||||||
|
style_rule: Arc<Locked<StyleRule>>,
|
||||||
|
source_order: usize,
|
||||||
|
specificity: u32)
|
||||||
|
-> Self
|
||||||
|
{
|
||||||
|
let (any_important, any_normal) = {
|
||||||
|
let block = style_rule.read_with(guard).block.read_with(guard);
|
||||||
|
(block.any_important(), block.any_normal())
|
||||||
|
};
|
||||||
|
debug_assert!(specificity & (ANY_IMPORTANT_DECLARATIONS_BIT | ANY_NORMAL_DECLARATIONS_BIT) == 0);
|
||||||
|
let mut specificity_and_bits = specificity;
|
||||||
|
if any_important {
|
||||||
|
specificity_and_bits |= ANY_IMPORTANT_DECLARATIONS_BIT;
|
||||||
|
}
|
||||||
|
if any_normal {
|
||||||
|
specificity_and_bits |= ANY_NORMAL_DECLARATIONS_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rule {
|
||||||
|
selector: selector,
|
||||||
|
style_rule: style_rule,
|
||||||
|
source_order: source_order,
|
||||||
|
specificity_and_bits: specificity_and_bits,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,12 +34,11 @@ fn get_mock_rules(css_selectors: &[&str]) -> (Vec<Vec<Rule>>, SharedRwLock) {
|
||||||
let guard = shared_lock.read();
|
let guard = shared_lock.read();
|
||||||
let rule = locked.read_with(&guard);
|
let rule = locked.read_with(&guard);
|
||||||
rule.selectors.0.iter().map(|s| {
|
rule.selectors.0.iter().map(|s| {
|
||||||
Rule {
|
Rule::new(&guard,
|
||||||
selector: s.inner.clone(),
|
s.inner.clone(),
|
||||||
style_rule: locked.clone(),
|
locked.clone(),
|
||||||
specificity: s.specificity,
|
i,
|
||||||
source_order: i,
|
s.specificity)
|
||||||
}
|
|
||||||
}).collect()
|
}).collect()
|
||||||
}).collect(), shared_lock)
|
}).collect(), shared_lock)
|
||||||
}
|
}
|
||||||
|
@ -62,7 +61,7 @@ fn test_rule_ordering_same_specificity() {
|
||||||
let (rules_list, _) = get_mock_rules(&["a.intro", "img.sidebar"]);
|
let (rules_list, _) = get_mock_rules(&["a.intro", "img.sidebar"]);
|
||||||
let a = &rules_list[0][0];
|
let a = &rules_list[0][0];
|
||||||
let b = &rules_list[1][0];
|
let b = &rules_list[1][0];
|
||||||
assert!((a.specificity, a.source_order) < ((b.specificity, b.source_order)),
|
assert!((a.specificity(), a.source_order) < ((b.specificity(), b.source_order)),
|
||||||
"The rule that comes later should win.");
|
"The rule that comes later should win.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue