style: Allow passing an nth-index-cache to the invalidation code.

This commit is contained in:
Emilio Cobos Álvarez 2017-10-02 10:56:48 +02:00
parent e13f5a656a
commit aba1cf8cd5
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
4 changed files with 114 additions and 73 deletions

View file

@ -14,6 +14,7 @@ use properties::ComputedValues;
use properties::longhands::display::computed_value as display; use properties::longhands::display::computed_value as display;
use rule_tree::StrongRuleNode; use rule_tree::StrongRuleNode;
use selector_parser::{EAGER_PSEUDO_COUNT, PseudoElement, RestyleDamage}; use selector_parser::{EAGER_PSEUDO_COUNT, PseudoElement, RestyleDamage};
use selectors::NthIndexCache;
use servo_arc::Arc; use servo_arc::Arc;
use shared_lock::StylesheetGuards; use shared_lock::StylesheetGuards;
use std::fmt; use std::fmt;
@ -236,6 +237,7 @@ impl ElementData {
element: E, element: E,
shared_context: &SharedStyleContext, shared_context: &SharedStyleContext,
stack_limit_checker: Option<&StackLimitChecker>, stack_limit_checker: Option<&StackLimitChecker>,
nth_index_cache: Option<&mut NthIndexCache>,
) -> InvalidationResult { ) -> InvalidationResult {
// In animation-only restyle we shouldn't touch snapshot at all. // In animation-only restyle we shouldn't touch snapshot at all.
if shared_context.traversal_flags.for_animation_only() { if shared_context.traversal_flags.for_animation_only() {
@ -261,7 +263,9 @@ impl ElementData {
Some(self), Some(self),
shared_context, shared_context,
stack_limit_checker, stack_limit_checker,
nth_index_cache,
); );
let result = invalidator.invalidate(); let result = invalidator.invalidate();
unsafe { element.set_handled_snapshot() } unsafe { element.set_handled_snapshot() }
debug_assert!(element.handled_snapshot()); debug_assert!(element.handled_snapshot());

View file

@ -15,6 +15,7 @@ use invalidation::element::invalidation_map::*;
use invalidation::element::restyle_hints::*; use invalidation::element::restyle_hints::*;
use selector_map::SelectorMap; use selector_map::SelectorMap;
use selector_parser::{SelectorImpl, Snapshot}; use selector_parser::{SelectorImpl, Snapshot};
use selectors::NthIndexCache;
use selectors::attr::CaseSensitivity; use selectors::attr::CaseSensitivity;
use selectors::matching::{MatchingContext, MatchingMode, VisitedHandlingMode}; use selectors::matching::{MatchingContext, MatchingMode, VisitedHandlingMode};
use selectors::matching::{matches_selector, matches_compound_selector}; use selectors::matching::{matches_selector, matches_compound_selector};
@ -47,6 +48,7 @@ pub struct TreeStyleInvalidator<'a, 'b: 'a, E>
data: Option<&'a mut ElementData>, data: Option<&'a mut ElementData>,
shared_context: &'a SharedStyleContext<'b>, shared_context: &'a SharedStyleContext<'b>,
stack_limit_checker: Option<&'a StackLimitChecker>, stack_limit_checker: Option<&'a StackLimitChecker>,
nth_index_cache: Option<&'a mut NthIndexCache>,
} }
type InvalidationVector = SmallVec<[Invalidation; 10]>; type InvalidationVector = SmallVec<[Invalidation; 10]>;
@ -174,12 +176,14 @@ impl<'a, 'b: 'a, E> TreeStyleInvalidator<'a, 'b, E>
data: Option<&'a mut ElementData>, data: Option<&'a mut ElementData>,
shared_context: &'a SharedStyleContext<'b>, shared_context: &'a SharedStyleContext<'b>,
stack_limit_checker: Option<&'a StackLimitChecker>, stack_limit_checker: Option<&'a StackLimitChecker>,
nth_index_cache: Option<&'a mut NthIndexCache>,
) -> Self { ) -> Self {
Self { Self {
element, element,
data, data,
shared_context, shared_context,
stack_limit_checker, stack_limit_checker,
nth_index_cache,
} }
} }
@ -252,16 +256,17 @@ impl<'a, 'b: 'a, E> TreeStyleInvalidator<'a, 'b, E>
let mut sibling_invalidations = InvalidationVector::new(); let mut sibling_invalidations = InvalidationVector::new();
let invalidated_self = { let invalidated_self = {
let mut collector = InvalidationCollector { let mut collector = InvalidationCollector {
wrapper: wrapper, wrapper,
lookup_element,
nth_index_cache: self.nth_index_cache.as_mut().map(|c| &mut **c),
state_changes,
element: self.element, element: self.element,
snapshot: &snapshot, snapshot: &snapshot,
shared_context: self.shared_context, shared_context: self.shared_context,
lookup_element: lookup_element,
removed_id: id_removed.as_ref(), removed_id: id_removed.as_ref(),
added_id: id_added.as_ref(), added_id: id_added.as_ref(),
classes_removed: &classes_removed, classes_removed: &classes_removed,
classes_added: &classes_added, classes_added: &classes_added,
state_changes: state_changes,
descendant_invalidations: &mut descendant_invalidations, descendant_invalidations: &mut descendant_invalidations,
sibling_invalidations: &mut sibling_invalidations, sibling_invalidations: &mut sibling_invalidations,
invalidates_self: false, invalidates_self: false,
@ -325,6 +330,7 @@ impl<'a, 'b: 'a, E> TreeStyleInvalidator<'a, 'b, E>
sibling_data, sibling_data,
self.shared_context, self.shared_context,
self.stack_limit_checker, self.stack_limit_checker,
self.nth_index_cache.as_mut().map(|c| &mut **c),
); );
let mut invalidations_for_descendants = InvalidationVector::new(); let mut invalidations_for_descendants = InvalidationVector::new();
@ -388,6 +394,7 @@ impl<'a, 'b: 'a, E> TreeStyleInvalidator<'a, 'b, E>
child_data, child_data,
self.shared_context, self.shared_context,
self.stack_limit_checker, self.stack_limit_checker,
self.nth_index_cache.as_mut().map(|c| &mut **c),
); );
let mut invalidations_for_descendants = InvalidationVector::new(); let mut invalidations_for_descendants = InvalidationVector::new();
@ -633,22 +640,22 @@ impl<'a, 'b: 'a, E> TreeStyleInvalidator<'a, 'b, E>
debug!("TreeStyleInvalidator::process_invalidation({:?}, {:?}, {:?})", debug!("TreeStyleInvalidator::process_invalidation({:?}, {:?}, {:?})",
self.element, invalidation, invalidation_kind); self.element, invalidation, invalidation_kind);
// FIXME(bholley): Consider passing an nth-index cache here. let matching_result = {
let mut context = let mut context = MatchingContext::new_for_visited(
MatchingContext::new_for_visited(
MatchingMode::Normal, MatchingMode::Normal,
None, None,
None, self.nth_index_cache.as_mut().map(|c| &mut **c),
VisitedHandlingMode::AllLinksVisitedAndUnvisited, VisitedHandlingMode::AllLinksVisitedAndUnvisited,
self.shared_context.quirks_mode(), self.shared_context.quirks_mode(),
); );
let matching_result = matches_compound_selector( matches_compound_selector(
&invalidation.selector, &invalidation.selector,
invalidation.offset, invalidation.offset,
&mut context, &mut context,
&self.element &self.element
); )
};
let mut invalidated_self = false; let mut invalidated_self = false;
let mut matched = false; let mut matched = false;
@ -814,6 +821,7 @@ struct InvalidationCollector<'a, 'b: 'a, E>
{ {
element: E, element: E,
wrapper: ElementWrapper<'b, E>, wrapper: ElementWrapper<'b, E>,
nth_index_cache: Option<&'a mut NthIndexCache>,
snapshot: &'a Snapshot, snapshot: &'a Snapshot,
shared_context: &'a SharedStyleContext<'b>, shared_context: &'a SharedStyleContext<'b>,
lookup_element: E, lookup_element: E,
@ -923,6 +931,64 @@ impl<'a, 'b: 'a, E> InvalidationCollector<'a, 'b, E>
); );
} }
/// Check whether a dependency should be taken into account, using a given
/// visited handling mode.
fn check_dependency(
&mut self,
visited_handling_mode: VisitedHandlingMode,
dependency: &Dependency,
relevant_link_found: &mut bool,
) -> bool {
let (matches_now, relevant_link_found_now) = {
let mut context = MatchingContext::new_for_visited(
MatchingMode::Normal,
None,
self.nth_index_cache.as_mut().map(|c| &mut **c),
visited_handling_mode,
self.shared_context.quirks_mode(),
);
let matches_now = matches_selector(
&dependency.selector,
dependency.selector_offset,
None,
&self.element,
&mut context,
&mut |_, _| {},
);
(matches_now, context.relevant_link_found)
};
let (matched_then, relevant_link_found_then) = {
let mut context = MatchingContext::new_for_visited(
MatchingMode::Normal,
None,
self.nth_index_cache.as_mut().map(|c| &mut **c),
visited_handling_mode,
self.shared_context.quirks_mode(),
);
let matched_then = matches_selector(
&dependency.selector,
dependency.selector_offset,
None,
&self.wrapper,
&mut context,
&mut |_, _| {},
);
(matched_then, context.relevant_link_found)
};
*relevant_link_found = relevant_link_found_now;
// Check for mismatches in both the match result and also the status
// of whether a relevant link was found.
matched_then != matches_now ||
relevant_link_found_now != relevant_link_found_then
}
fn scan_dependency( fn scan_dependency(
&mut self, &mut self,
dependency: &Dependency, dependency: &Dependency,
@ -937,47 +1003,15 @@ impl<'a, 'b: 'a, E> InvalidationCollector<'a, 'b, E>
return; return;
} }
// TODO(emilio): Add a bloom filter here? let mut relevant_link_found = false;
//
// If we decide to do so, we can't use the bloom filter for snapshots,
// given that arbitrary elements in the parent chain may have mutated
// their id's/classes, which means that they won't be in the filter, and
// as such we may fast-reject selectors incorrectly.
//
// We may be able to improve this if we record as we go down the tree
// whether any parent had a snapshot, and whether those snapshots were
// taken due to an element class/id change, but it's not clear it'd be
// worth it.
//
// FIXME(bholley): Consider passing an nth-index cache here.
let mut now_context =
MatchingContext::new_for_visited(MatchingMode::Normal, None, None,
VisitedHandlingMode::AllLinksUnvisited,
self.shared_context.quirks_mode());
let mut then_context =
MatchingContext::new_for_visited(MatchingMode::Normal, None, None,
VisitedHandlingMode::AllLinksUnvisited,
self.shared_context.quirks_mode());
let matched_then = let should_account_for_dependency = self.check_dependency(
matches_selector(&dependency.selector, VisitedHandlingMode::AllLinksUnvisited,
dependency.selector_offset, dependency,
None, &mut relevant_link_found,
&self.wrapper, );
&mut then_context,
&mut |_, _| {});
let matches_now =
matches_selector(&dependency.selector,
dependency.selector_offset,
None,
&self.element,
&mut now_context,
&mut |_, _| {});
// Check for mismatches in both the match result and also the status if should_account_for_dependency {
// of whether a relevant link was found.
if matched_then != matches_now ||
then_context.relevant_link_found != now_context.relevant_link_found {
return self.note_dependency(dependency); return self.note_dependency(dependency);
} }
@ -997,25 +1031,14 @@ impl<'a, 'b: 'a, E> InvalidationCollector<'a, 'b, E>
// //
// NOTE: This thing is actually untested because testing it is flaky, // NOTE: This thing is actually untested because testing it is flaky,
// see the tests that were added and then backed out in bug 1328509. // see the tests that were added and then backed out in bug 1328509.
if is_visited_dependent == VisitedDependent::Yes && now_context.relevant_link_found { if is_visited_dependent == VisitedDependent::Yes && relevant_link_found {
then_context.visited_handling = VisitedHandlingMode::RelevantLinkVisited; let should_account_for_dependency = self.check_dependency(
let matched_then = VisitedHandlingMode::RelevantLinkVisited,
matches_selector(&dependency.selector, dependency,
dependency.selector_offset, &mut false,
None, );
&self.wrapper,
&mut then_context,
&mut |_, _| {});
now_context.visited_handling = VisitedHandlingMode::RelevantLinkVisited; if should_account_for_dependency {
let matches_now =
matches_selector(&dependency.selector,
dependency.selector_offset,
None,
&self.element,
&mut now_context,
&mut |_, _| {});
if matched_then != matches_now {
return self.note_dependency(dependency); return self.note_dependency(dependency);
} }
} }

View file

@ -169,8 +169,11 @@ pub trait DomTraversal<E: TElement> : Sync {
if !traversal_flags.for_animation_only() { if !traversal_flags.for_animation_only() {
// Invalidate our style, and that of our siblings and // Invalidate our style, and that of our siblings and
// descendants as needed. // descendants as needed.
//
// FIXME(emilio): an nth-index cache could be worth here, even
// if temporary?
let invalidation_result = let invalidation_result =
data.invalidate_style_if_needed(root, shared_context, None); data.invalidate_style_if_needed(root, shared_context, None, None);
if invalidation_result.has_invalidated_siblings() { if invalidation_result.has_invalidated_siblings() {
let actual_root = let actual_root =
@ -895,7 +898,8 @@ where
child_data.invalidate_style_if_needed( child_data.invalidate_style_if_needed(
child, child,
&context.shared, &context.shared,
Some(&context.thread_local.stack_limit_checker) Some(&context.thread_local.stack_limit_checker),
Some(&mut context.thread_local.nth_index_cache)
); );
} }

View file

@ -4058,7 +4058,17 @@ pub extern "C" fn Servo_ProcessInvalidations(set: RawServoStyleSetBorrowed,
let mut data = data.as_mut().map(|d| &mut **d); let mut data = data.as_mut().map(|d| &mut **d);
if let Some(ref mut data) = data { if let Some(ref mut data) = data {
let result = data.invalidate_style_if_needed(element, &shared_style_context, None); // FIXME(emilio): an nth-index cache could be worth here, even
// if temporary?
//
// Also, ideally we could share them across all the elements?
let result = data.invalidate_style_if_needed(
element,
&shared_style_context,
None,
None,
);
if result.has_invalidated_siblings() { if result.has_invalidated_siblings() {
let parent = element.traversal_parent().expect("How could we invalidate siblings without a common parent?"); let parent = element.traversal_parent().expect("How could we invalidate siblings without a common parent?");
unsafe { unsafe {