style: Add missing visitedness check while invalidating elements.

This is needed for the omta test to pass. This is pretty much the equivalent to
the old restyle hints code.

Bug: 1368240
MozReview-Commit-ID: BLUfw5Wxpxd
This commit is contained in:
Emilio Cobos Álvarez 2017-06-09 16:18:03 +02:00
parent 14bb57c08f
commit fdf9093466
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C

View file

@ -9,7 +9,7 @@ use Atom;
use context::SharedStyleContext;
use data::ElementData;
use dom::{TElement, TNode};
use element_state::ElementState;
use element_state::{ElementState, IN_VISITED_OR_UNVISITED_STATE};
use invalidation::element::element_wrapper::{ElementSnapshot, ElementWrapper};
use invalidation::element::invalidation_map::*;
use invalidation::element::restyle_hints::*;
@ -105,6 +105,18 @@ impl<'a, 'b: 'a, E> TreeStyleInvalidator<'a, 'b, E>
return;
}
// If we are sensitive to visitedness and the visited state changed, we
// force a restyle here. Matching doesn't depend on the actual visited
// state at all, so we can't look at matching results to decide what to
// do for this case.
if state_changes.intersects(IN_VISITED_OR_UNVISITED_STATE) {
trace!(" > visitedness change, force subtree restyle");
// We can't just return here because there may also be attribute
// changes as well that imply additional hints.
let mut data = self.data.as_mut().unwrap();
data.ensure_restyle().hint.insert(RestyleHint::restyle_subtree().into());
}
let mut classes_removed = SmallVec::<[Atom; 8]>::new();
let mut classes_added = SmallVec::<[Atom; 8]>::new();
if snapshot.class_changed() {
@ -525,7 +537,10 @@ impl<'a, 'b: 'a, E> InvalidationCollector<'a, 'b, E>
self.removed_id,
self.classes_removed,
&mut |dependency| {
self.scan_dependency(dependency);
self.scan_dependency(
dependency,
/* is_visited_dependent = */ false
);
true
},
);
@ -544,13 +559,20 @@ impl<'a, 'b: 'a, E> InvalidationCollector<'a, 'b, E>
if !dependency.state.intersects(state_changes) {
return true;
}
self.scan_dependency(&dependency.dep);
self.scan_dependency(
&dependency.dep,
dependency.state.intersects(IN_VISITED_OR_UNVISITED_STATE)
);
true
},
);
}
fn scan_dependency(&mut self, dependency: &Dependency) {
fn scan_dependency(
&mut self,
dependency: &Dependency,
is_visited_dependent: bool
) {
debug!("TreeStyleInvalidator::scan_dependency({:?}, {:?}, {})",
self.element,
dependency,
@ -599,7 +621,46 @@ impl<'a, 'b: 'a, E> InvalidationCollector<'a, 'b, E>
// of whether a relevant link was found.
if matched_then != matches_now ||
then_context.relevant_link_found != now_context.relevant_link_found {
self.note_dependency(dependency);
return self.note_dependency(dependency);
}
// If there is a relevant link, then we also matched in visited
// mode.
//
// Match again in this mode to ensure this also matches.
//
// Note that we never actually match directly against the element's true
// visited state at all, since that would expose us to timing attacks.
//
// The matching process only considers the relevant link state and
// visited handling mode when deciding if visited matches. Instead, we
// are rematching here in case there is some :visited selector whose
// matching result changed for some other state or attribute change of
// this element (for example, for things like [foo]:visited).
//
// NOTE: This thing is actually untested because testing it is flaky,
// see the tests that were added and then backed out in bug 1328509.
if is_visited_dependent && now_context.relevant_link_found {
then_context.visited_handling = VisitedHandlingMode::RelevantLinkVisited;
let matched_then =
matches_selector(&dependency.selector,
dependency.selector_offset,
&dependency.hashes,
&self.wrapper,
&mut then_context,
&mut |_, _| {});
now_context.visited_handling = VisitedHandlingMode::RelevantLinkVisited;
let matches_now =
matches_selector(&dependency.selector,
dependency.selector_offset,
&dependency.hashes,
&self.element,
&mut now_context,
&mut |_, _| {});
if matched_then != matches_now {
return self.note_dependency(dependency);
}
}
}