Skip to content

Commit d98abe1

Browse files
author
bors-servo
authored
Auto merge of servo#16943 - emilio:bloom-restyle-hints, r=bholley
style: Make a bloom filter arrive to restyle hint computation. <!-- 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/16943) <!-- Reviewable:end -->
2 parents 323760f + a12996f commit d98abe1

File tree

5 files changed

+115
-43
lines changed

5 files changed

+115
-43
lines changed

components/style/bloom.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
use dom::{SendElement, TElement};
1111
use selectors::bloom::BloomFilter;
12+
use smallvec::SmallVec;
1213

1314
/// A struct that allows us to fast-reject deep descendant selectors avoiding
1415
/// selector-matching.
@@ -223,7 +224,7 @@ impl<E: TElement> StyleBloom<E> {
223224

224225
// Let's collect the parents we are going to need to insert once we've
225226
// found the common one.
226-
let mut parents_to_insert = vec![];
227+
let mut parents_to_insert = SmallVec::<[E; 8]>::new();
227228

228229
// If the bloom filter still doesn't have enough elements, the common
229230
// parent is up in the dom.
@@ -245,10 +246,12 @@ impl<E: TElement> StyleBloom<E> {
245246
// Not-so-happy case: Parent's don't match, so we need to keep going up
246247
// until we find a common ancestor.
247248
//
248-
// Gecko currently models native anonymous content that conceptually hangs
249-
// off the document (such as scrollbars) as a separate subtree from the
250-
// document root. Thus it's possible with Gecko that we do not find any
251-
// common ancestor.
249+
// Gecko currently models native anonymous content that conceptually
250+
// hangs off the document (such as scrollbars) as a separate subtree
251+
// from the document root.
252+
//
253+
// Thus it's possible with Gecko that we do not find any common
254+
// ancestor.
252255
while **self.elements.last().unwrap() != common_parent {
253256
parents_to_insert.push(common_parent);
254257
self.pop().unwrap();

components/style/data.rs

+10-7
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,11 @@
44

55
//! Per-node data used in style calculation.
66
7-
#![deny(missing_docs)]
8-
97
use context::SharedStyleContext;
108
use dom::TElement;
119
use properties::ComputedValues;
1210
use properties::longhands::display::computed_value as display;
13-
use restyle_hints::{RestyleReplacements, RestyleHint};
11+
use restyle_hints::{HintComputationContext, RestyleReplacements, RestyleHint};
1412
use rule_tree::StrongRuleNode;
1513
use selector_parser::{EAGER_PSEUDO_COUNT, PseudoElement, RestyleDamage};
1614
use shared_lock::StylesheetGuards;
@@ -372,15 +370,16 @@ impl ElementData {
372370
/// explicit sibling restyle hints from the stored restyle hint.
373371
///
374372
/// Returns true if later siblings must be restyled.
375-
pub fn compute_final_hint<E: TElement>(
373+
pub fn compute_final_hint<'a, E: TElement>(
376374
&mut self,
377375
element: E,
378-
context: &SharedStyleContext)
376+
shared_context: &SharedStyleContext,
377+
hint_context: HintComputationContext<'a, E>)
379378
-> bool
380379
{
381380
debug!("compute_final_hint: {:?}, {:?}",
382381
element,
383-
context.traversal_flags);
382+
shared_context.traversal_flags);
384383

385384
let mut hint = match self.get_restyle() {
386385
Some(r) => r.hint.0.clone(),
@@ -395,7 +394,11 @@ impl ElementData {
395394
element.implemented_pseudo_element());
396395

397396
if element.has_snapshot() && !element.handled_snapshot() {
398-
hint.insert(context.stylist.compute_restyle_hint(&element, context.snapshot_map));
397+
let snapshot_hint =
398+
shared_context.stylist.compute_restyle_hint(&element,
399+
shared_context,
400+
hint_context);
401+
hint.insert(snapshot_hint);
399402
unsafe { element.set_handled_snapshot() }
400403
debug_assert!(element.handled_snapshot());
401404
}

components/style/restyle_hints.rs

+61-8
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Atom;
1010
use LocalName;
1111
use Namespace;
12+
use context::{SharedStyleContext, ThreadLocalStyleContext};
1213
use dom::TElement;
1314
use element_state::*;
1415
#[cfg(feature = "gecko")]
@@ -825,6 +826,35 @@ pub struct DependencySet {
825826
dependencies: SelectorMap<Dependency>,
826827
}
827828

829+
/// The data that we need to compute a given restyle hint.
830+
pub enum HintComputationContext<'a, E: 'a>
831+
where E: TElement,
832+
{
833+
/// The data we need to compute a restyle hint for the root of the
834+
/// traversal.
835+
///
836+
/// We don't bother with the bloom filter there for multiple reasons:
837+
///
838+
/// * The root of the traversal uses to be the root of the document, so we
839+
/// don't gain much using a bloom filter.
840+
///
841+
/// * The chances that a non-root-element root of the traversal has a
842+
/// snapshot is quite low.
843+
Root,
844+
845+
/// The data we need to compute a restyle hint for a child.
846+
///
847+
/// This needs a full-blown style context in order to get the selector
848+
/// filters up-to-date, and the dom depth in order to insert into the filter
849+
/// properly if needed.
850+
Child {
851+
/// The thread-local context, that holds the bloom filter alive.
852+
local_context: &'a mut ThreadLocalStyleContext<E>,
853+
/// The dom depth of this element.
854+
dom_depth: usize,
855+
}
856+
}
857+
828858
impl DependencySet {
829859
/// Adds a selector to this `DependencySet`.
830860
pub fn note_selector(&mut self, selector: &Selector<SelectorImpl>) {
@@ -921,16 +951,17 @@ impl DependencySet {
921951

922952
/// Compute a restyle hint given an element and a snapshot, per the rules
923953
/// explained in the rest of the documentation.
924-
pub fn compute_hint<E>(
954+
pub fn compute_hint<'a, E>(
925955
&self,
926956
el: &E,
927-
snapshots: &SnapshotMap)
957+
shared_context: &SharedStyleContext,
958+
hint_context: HintComputationContext<'a, E>)
928959
-> RestyleHint
929960
where E: TElement,
930961
{
931962
debug_assert!(el.has_snapshot(), "Shouldn't be here!");
932-
933-
let snapshot_el = ElementWrapper::new(el.clone(), snapshots);
963+
let snapshot_el =
964+
ElementWrapper::new(*el, shared_context.snapshot_map);
934965
let snapshot =
935966
snapshot_el.snapshot().expect("has_snapshot lied so badly");
936967

@@ -960,8 +991,30 @@ impl DependencySet {
960991
});
961992
}
962993

963-
// FIXME(emilio): A bloom filter here would be neat.
964-
let mut matching_context =
994+
let bloom_filter = match hint_context {
995+
HintComputationContext::Root => None,
996+
HintComputationContext::Child { mut local_context, dom_depth } => {
997+
local_context
998+
.bloom_filter
999+
.insert_parents_recovering(*el, dom_depth);
1000+
local_context.bloom_filter.assert_complete(*el);
1001+
Some(local_context.bloom_filter.filter())
1002+
}
1003+
};
1004+
1005+
let mut element_matching_context =
1006+
MatchingContext::new(MatchingMode::Normal, bloom_filter);
1007+
1008+
// NOTE(emilio): We can't use the bloom filter for snapshots, given that
1009+
// arbitrary elements in the parent chain may have mutated their
1010+
// id's/classes, which means that they won't be in the filter, and as
1011+
// such we may fast-reject selectors incorrectly.
1012+
//
1013+
// We may be able to improve this if we record as we go down the tree
1014+
// whether any parent had a snapshot, and whether those snapshots were
1015+
// taken due to an element class/id change, but it's not clear we _need_
1016+
// it right now.
1017+
let mut snapshot_matching_context =
9651018
MatchingContext::new(MatchingMode::Normal, None);
9661019

9671020
let lookup_element = if el.implemented_pseudo_element().is_some() {
@@ -989,11 +1042,11 @@ impl DependencySet {
9891042
// change its matching behavior here.
9901043
let matched_then =
9911044
matches_selector(&dep.selector, &snapshot_el,
992-
&mut matching_context,
1045+
&mut snapshot_matching_context,
9931046
&mut |_, _| {});
9941047
let matches_now =
9951048
matches_selector(&dep.selector, el,
996-
&mut matching_context,
1049+
&mut element_matching_context,
9971050
&mut |_, _| {});
9981051
if matched_then != matches_now {
9991052
hint.insert_from(&dep.hint);

components/style/stylist.rs

+9-10
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,9 @@
44

55
//! Selector matching.
66
7-
#![deny(missing_docs)]
8-
97
use {Atom, LocalName, Namespace};
108
use bit_vec::BitVec;
11-
use context::QuirksMode;
9+
use context::{QuirksMode, SharedStyleContext};
1210
use data::ComputedStyle;
1311
use dom::{AnimationRules, TElement};
1412
use element_state::ElementState;
@@ -23,9 +21,9 @@ use properties::{self, CascadeFlags, ComputedValues};
2321
#[cfg(feature = "servo")]
2422
use properties::INHERIT_ALL;
2523
use properties::PropertyDeclarationBlock;
26-
use restyle_hints::{RestyleHint, DependencySet};
24+
use restyle_hints::{HintComputationContext, DependencySet, RestyleHint};
2725
use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
28-
use selector_parser::{SelectorImpl, PseudoElement, SnapshotMap};
26+
use selector_parser::{SelectorImpl, PseudoElement};
2927
use selectors::attr::NamespaceConstraint;
3028
use selectors::bloom::BloomFilter;
3129
use selectors::matching::{AFFECTED_BY_STYLE_ATTRIBUTE, AFFECTED_BY_PRESENTATIONAL_HINTS};
@@ -1029,13 +1027,14 @@ impl Stylist {
10291027
/// Given an element, and a snapshot table that represents a previous state
10301028
/// of the tree, compute the appropriate restyle hint, that is, the kind of
10311029
/// restyle we need to do.
1032-
pub fn compute_restyle_hint<E>(&self,
1033-
element: &E,
1034-
snapshots: &SnapshotMap)
1035-
-> RestyleHint
1030+
pub fn compute_restyle_hint<'a, E>(&self,
1031+
element: &E,
1032+
shared_context: &SharedStyleContext,
1033+
context: HintComputationContext<'a, E>)
1034+
-> RestyleHint
10361035
where E: TElement,
10371036
{
1038-
self.dependencies.compute_hint(element, snapshots)
1037+
self.dependencies.compute_hint(element, shared_context, context)
10391038
}
10401039

10411040
/// Computes styles for a given declaration with parent_style.

components/style/traversal.rs

+27-13
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use context::{SharedStyleContext, StyleContext, ThreadLocalStyleContext};
99
use data::{ElementData, ElementStyles, StoredRestyleHint};
1010
use dom::{DirtyDescendants, NodeInfo, OpaqueNode, TElement, TNode};
1111
use matching::{ChildCascadeRequirement, MatchMethods, StyleSharingBehavior};
12-
use restyle_hints::RestyleHint;
12+
use restyle_hints::{HintComputationContext, RestyleHint};
1313
use selector_parser::RestyleDamage;
1414
#[cfg(feature = "servo")] use servo_config::opts;
1515
use std::borrow::BorrowMut;
@@ -123,7 +123,8 @@ pub trait DomTraversal<E: TElement> : Sync {
123123
type ThreadLocalContext: Send + BorrowMut<ThreadLocalStyleContext<E>>;
124124

125125
/// Process `node` on the way down, before its children have been processed.
126-
fn process_preorder(&self, data: &PerLevelTraversalData,
126+
fn process_preorder(&self,
127+
data: &PerLevelTraversalData,
127128
thread_local: &mut Self::ThreadLocalContext,
128129
node: E::ConcreteNode);
129130

@@ -227,7 +228,10 @@ pub trait DomTraversal<E: TElement> : Sync {
227228
// Expanding snapshots here may create a LATER_SIBLINGS restyle hint, which
228229
// we propagate to the next sibling element.
229230
if let Some(mut data) = root.mutate_data() {
230-
let later_siblings = data.compute_final_hint(root, shared_context);
231+
let later_siblings =
232+
data.compute_final_hint(root,
233+
shared_context,
234+
HintComputationContext::Root);
231235
if later_siblings {
232236
if let Some(next) = root.next_sibling_element() {
233237
if let Some(mut next_data) = next.mutate_data() {
@@ -669,11 +673,12 @@ pub fn recalc_style_at<E, D>(traversal: &D,
669673
r.damage_handled() | r.damage.handled_for_descendants()
670674
});
671675

672-
preprocess_children(traversal,
673-
element,
674-
propagated_hint,
675-
damage_handled,
676-
inherited_style_changed);
676+
preprocess_children::<E, D>(context,
677+
traversal_data,
678+
element,
679+
propagated_hint,
680+
damage_handled,
681+
inherited_style_changed);
677682
}
678683

679684
// If we are in a restyle for reconstruction, drop the existing restyle
@@ -740,7 +745,8 @@ fn compute_style<E, D>(_traversal: &D,
740745
MatchAndCascade => {
741746
// Ensure the bloom filter is up to date.
742747
context.thread_local.bloom_filter
743-
.insert_parents_recovering(element, traversal_data.current_dom_depth);
748+
.insert_parents_recovering(element,
749+
traversal_data.current_dom_depth);
744750

745751
context.thread_local.bloom_filter.assert_complete(element);
746752
context.thread_local.statistics.elements_matched += 1;
@@ -770,15 +776,17 @@ fn compute_style<E, D>(_traversal: &D,
770776
}
771777
}
772778

773-
fn preprocess_children<E, D>(traversal: &D,
779+
fn preprocess_children<E, D>(context: &mut StyleContext<E>,
780+
parent_traversal_data: &PerLevelTraversalData,
774781
element: E,
775782
mut propagated_hint: StoredRestyleHint,
776783
damage_handled: RestyleDamage,
777784
parent_inherited_style_changed: bool)
778785
where E: TElement,
779-
D: DomTraversal<E>
786+
D: DomTraversal<E>,
780787
{
781788
trace!("preprocess_children: {:?}", element);
789+
782790
// Loop over all the children.
783791
for child in element.as_node().children() {
784792
// FIXME(bholley): Add TElement::element_children instead of this.
@@ -787,7 +795,8 @@ fn preprocess_children<E, D>(traversal: &D,
787795
None => continue,
788796
};
789797

790-
let mut child_data = unsafe { D::ensure_element_data(&child).borrow_mut() };
798+
let mut child_data =
799+
unsafe { D::ensure_element_data(&child).borrow_mut() };
791800

792801
// If the child is unstyled, we don't need to set up any restyling.
793802
if !child_data.has_styles() {
@@ -798,7 +807,12 @@ fn preprocess_children<E, D>(traversal: &D,
798807
//
799808
// NB: This will be a no-op if there's no restyle data and no snapshot.
800809
let later_siblings =
801-
child_data.compute_final_hint(child, traversal.shared_context());
810+
child_data.compute_final_hint(child,
811+
&context.shared,
812+
HintComputationContext::Child {
813+
local_context: &mut context.thread_local,
814+
dom_depth: parent_traversal_data.current_dom_depth + 1,
815+
});
802816

803817
trace!(" > {:?} -> {:?} + {:?}, pseudo: {:?}, later_siblings: {:?}",
804818
child,

0 commit comments

Comments
 (0)