mirror of
https://github.com/servo/servo.git
synced 2025-06-24 00:54:32 +01:00
Bug 1336646 - Use the bloom filter for manual style resolves and pass a mutable StyleContext into match_element. r=emilio
We need to do something here to avoid a double-borrow when passing a mutable StyleContext to match_element. After some discussion on IRC, we decided that building the bloom filter for this case is probably worthwhile.
This commit is contained in:
parent
8aec1ccdd2
commit
e7a8f5ec30
3 changed files with 35 additions and 15 deletions
|
@ -66,7 +66,7 @@ impl<E: TElement> StyleBloom<E> {
|
||||||
|
|
||||||
/// Push an element to the bloom filter, knowing that it's a child of the
|
/// Push an element to the bloom filter, knowing that it's a child of the
|
||||||
/// last element parent.
|
/// last element parent.
|
||||||
fn push(&mut self, element: E) {
|
pub fn push(&mut self, element: E) {
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
if self.elements.is_empty() {
|
if self.elements.is_empty() {
|
||||||
assert!(element.parent_element().is_none());
|
assert!(element.parent_element().is_none());
|
||||||
|
@ -86,12 +86,20 @@ impl<E: TElement> StyleBloom<E> {
|
||||||
popped
|
popped
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear(&mut self) {
|
/// Returns true if the bloom filter is empty.
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.elements.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Clears the bloom filter.
|
||||||
|
pub fn clear(&mut self) {
|
||||||
self.filter.clear();
|
self.filter.clear();
|
||||||
self.elements.clear();
|
self.elements.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rebuild(&mut self, mut element: E) -> usize {
|
/// Rebuilds the bloom filter up to the parent of the given element.
|
||||||
|
pub fn rebuild(&mut self, mut element: E) -> usize {
|
||||||
self.clear();
|
self.clear();
|
||||||
|
|
||||||
while let Some(parent) = element.parent_element() {
|
while let Some(parent) = element.parent_element() {
|
||||||
|
|
|
@ -577,8 +577,7 @@ impl<E: TElement> PrivateMatchMethods for E {}
|
||||||
pub trait MatchMethods : TElement {
|
pub trait MatchMethods : TElement {
|
||||||
/// Runs selector matching of this element, and returns the result.
|
/// Runs selector matching of this element, and returns the result.
|
||||||
fn match_element(&self,
|
fn match_element(&self,
|
||||||
context: &StyleContext<Self>,
|
context: &mut StyleContext<Self>)
|
||||||
parent_bf: Option<&BloomFilter>)
|
|
||||||
-> MatchResults
|
-> MatchResults
|
||||||
{
|
{
|
||||||
let mut applicable_declarations =
|
let mut applicable_declarations =
|
||||||
|
@ -591,7 +590,7 @@ pub trait MatchMethods : TElement {
|
||||||
// Compute the primary rule node.
|
// Compute the primary rule node.
|
||||||
let mut primary_relations =
|
let mut primary_relations =
|
||||||
stylist.push_applicable_declarations(self,
|
stylist.push_applicable_declarations(self,
|
||||||
parent_bf,
|
Some(context.thread_local.bloom_filter.filter()),
|
||||||
style_attribute,
|
style_attribute,
|
||||||
animation_rules,
|
animation_rules,
|
||||||
None,
|
None,
|
||||||
|
@ -604,8 +603,9 @@ pub trait MatchMethods : TElement {
|
||||||
SelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| {
|
SelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| {
|
||||||
debug_assert!(applicable_declarations.is_empty());
|
debug_assert!(applicable_declarations.is_empty());
|
||||||
let pseudo_animation_rules = self.get_animation_rules(Some(&pseudo));
|
let pseudo_animation_rules = self.get_animation_rules(Some(&pseudo));
|
||||||
stylist.push_applicable_declarations(self, parent_bf, None,
|
stylist.push_applicable_declarations(self,
|
||||||
pseudo_animation_rules,
|
Some(context.thread_local.bloom_filter.filter()),
|
||||||
|
None, pseudo_animation_rules,
|
||||||
Some(&pseudo),
|
Some(&pseudo),
|
||||||
&mut applicable_declarations,
|
&mut applicable_declarations,
|
||||||
MatchingReason::ForStyling);
|
MatchingReason::ForStyling);
|
||||||
|
|
|
@ -312,7 +312,7 @@ pub trait DomTraversal<E: TElement> : Sync {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper for the function below.
|
/// Helper for the function below.
|
||||||
fn resolve_style_internal<E, F>(context: &StyleContext<E>, element: E, ensure_data: &F)
|
fn resolve_style_internal<E, F>(context: &mut StyleContext<E>, element: E, ensure_data: &F)
|
||||||
-> Option<E>
|
-> Option<E>
|
||||||
where E: TElement,
|
where E: TElement,
|
||||||
F: Fn(E),
|
F: Fn(E),
|
||||||
|
@ -324,12 +324,22 @@ fn resolve_style_internal<E, F>(context: &StyleContext<E>, element: E, ensure_da
|
||||||
// If the Element isn't styled, we need to compute its style.
|
// If the Element isn't styled, we need to compute its style.
|
||||||
if data.get_styles().is_none() {
|
if data.get_styles().is_none() {
|
||||||
// Compute the parent style if necessary.
|
// Compute the parent style if necessary.
|
||||||
if let Some(parent) = element.parent_element() {
|
let parent = element.parent_element();
|
||||||
display_none_root = resolve_style_internal(context, parent, ensure_data);
|
if let Some(p) = parent {
|
||||||
|
display_none_root = resolve_style_internal(context, p, ensure_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maintain the bloom filter. If it doesn't exist, we need to build it
|
||||||
|
// from scratch. Otherwise we just need to push the parent.
|
||||||
|
if context.thread_local.bloom_filter.is_empty() {
|
||||||
|
context.thread_local.bloom_filter.rebuild(element);
|
||||||
|
} else {
|
||||||
|
context.thread_local.bloom_filter.push(parent.unwrap());
|
||||||
|
context.thread_local.bloom_filter.assert_complete(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute our style.
|
// Compute our style.
|
||||||
let match_results = element.match_element(context, None);
|
let match_results = element.match_element(context);
|
||||||
let shareable = match_results.primary_is_shareable();
|
let shareable = match_results.primary_is_shareable();
|
||||||
element.cascade_node(context, &mut data, element.parent_element(),
|
element.cascade_node(context, &mut data, element.parent_element(),
|
||||||
match_results.primary,
|
match_results.primary,
|
||||||
|
@ -355,13 +365,16 @@ fn resolve_style_internal<E, F>(context: &StyleContext<E>, element: E, ensure_da
|
||||||
/// first styled Element, ignoring pending restyles. The resolved style is
|
/// first styled Element, ignoring pending restyles. The resolved style is
|
||||||
/// made available via a callback, and can be dropped by the time this function
|
/// made available via a callback, and can be dropped by the time this function
|
||||||
/// returns in the display:none subtree case.
|
/// returns in the display:none subtree case.
|
||||||
pub fn resolve_style<E, F, G, H>(context: &StyleContext<E>, element: E,
|
pub fn resolve_style<E, F, G, H>(context: &mut StyleContext<E>, element: E,
|
||||||
ensure_data: &F, clear_data: &G, callback: H)
|
ensure_data: &F, clear_data: &G, callback: H)
|
||||||
where E: TElement,
|
where E: TElement,
|
||||||
F: Fn(E),
|
F: Fn(E),
|
||||||
G: Fn(E),
|
G: Fn(E),
|
||||||
H: FnOnce(&ElementStyles)
|
H: FnOnce(&ElementStyles)
|
||||||
{
|
{
|
||||||
|
// Clear the bloom filter, just in case the caller is reusing TLS.
|
||||||
|
context.thread_local.bloom_filter.clear();
|
||||||
|
|
||||||
// Resolve styles up the tree.
|
// Resolve styles up the tree.
|
||||||
let display_none_root = resolve_style_internal(context, element, ensure_data);
|
let display_none_root = resolve_style_internal(context, element, ensure_data);
|
||||||
|
|
||||||
|
@ -499,8 +512,7 @@ fn compute_style<E, D>(_traversal: &D,
|
||||||
// Perform the CSS selector matching.
|
// Perform the CSS selector matching.
|
||||||
context.thread_local.statistics.elements_matched += 1;
|
context.thread_local.statistics.elements_matched += 1;
|
||||||
|
|
||||||
let filter = context.thread_local.bloom_filter.filter();
|
Some(element.match_element(context))
|
||||||
Some(element.match_element(context, Some(filter)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue