mirror of
https://github.com/servo/servo.git
synced 2025-08-14 01:45:33 +01:00
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:
parent
14bb57c08f
commit
fdf9093466
1 changed files with 66 additions and 5 deletions
|
@ -9,7 +9,7 @@ use Atom;
|
||||||
use context::SharedStyleContext;
|
use context::SharedStyleContext;
|
||||||
use data::ElementData;
|
use data::ElementData;
|
||||||
use dom::{TElement, TNode};
|
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::element_wrapper::{ElementSnapshot, ElementWrapper};
|
||||||
use invalidation::element::invalidation_map::*;
|
use invalidation::element::invalidation_map::*;
|
||||||
use invalidation::element::restyle_hints::*;
|
use invalidation::element::restyle_hints::*;
|
||||||
|
@ -105,6 +105,18 @@ impl<'a, 'b: 'a, E> TreeStyleInvalidator<'a, 'b, E>
|
||||||
return;
|
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_removed = SmallVec::<[Atom; 8]>::new();
|
||||||
let mut classes_added = SmallVec::<[Atom; 8]>::new();
|
let mut classes_added = SmallVec::<[Atom; 8]>::new();
|
||||||
if snapshot.class_changed() {
|
if snapshot.class_changed() {
|
||||||
|
@ -525,7 +537,10 @@ impl<'a, 'b: 'a, E> InvalidationCollector<'a, 'b, E>
|
||||||
self.removed_id,
|
self.removed_id,
|
||||||
self.classes_removed,
|
self.classes_removed,
|
||||||
&mut |dependency| {
|
&mut |dependency| {
|
||||||
self.scan_dependency(dependency);
|
self.scan_dependency(
|
||||||
|
dependency,
|
||||||
|
/* is_visited_dependent = */ false
|
||||||
|
);
|
||||||
true
|
true
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -544,13 +559,20 @@ impl<'a, 'b: 'a, E> InvalidationCollector<'a, 'b, E>
|
||||||
if !dependency.state.intersects(state_changes) {
|
if !dependency.state.intersects(state_changes) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
self.scan_dependency(&dependency.dep);
|
self.scan_dependency(
|
||||||
|
&dependency.dep,
|
||||||
|
dependency.state.intersects(IN_VISITED_OR_UNVISITED_STATE)
|
||||||
|
);
|
||||||
true
|
true
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scan_dependency(&mut self, dependency: &Dependency) {
|
fn scan_dependency(
|
||||||
|
&mut self,
|
||||||
|
dependency: &Dependency,
|
||||||
|
is_visited_dependent: bool
|
||||||
|
) {
|
||||||
debug!("TreeStyleInvalidator::scan_dependency({:?}, {:?}, {})",
|
debug!("TreeStyleInvalidator::scan_dependency({:?}, {:?}, {})",
|
||||||
self.element,
|
self.element,
|
||||||
dependency,
|
dependency,
|
||||||
|
@ -599,7 +621,46 @@ impl<'a, 'b: 'a, E> InvalidationCollector<'a, 'b, E>
|
||||||
// of whether a relevant link was found.
|
// of whether a relevant link was found.
|
||||||
if matched_then != matches_now ||
|
if matched_then != matches_now ||
|
||||||
then_context.relevant_link_found != now_context.relevant_link_found {
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue