style: Add an AllLinksVisitedAndUnvisited for invalidation.

Otherwise, tests like the following fail, given we always match as unvisited,
and we'd never mark the link as needing invalidation.

<!doctype html>
<style>
a {
  color: red !important;
}

.foo :visited {
  color: green !important;
}
</style>
<div>
  <a href="https://google.es">visit me</a>
  <button onclick="this.parentNode.className = 'foo'">Then click me</button>
</div>

Bug: 1368240
MozReview-Commit-ID: LDv6S28c4ju
This commit is contained in:
Emilio Cobos Álvarez 2017-06-09 17:11:19 +02:00
parent fdf9093466
commit 4434509088
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
6 changed files with 42 additions and 2 deletions

View file

@ -48,6 +48,12 @@ pub enum MatchingMode {
pub enum VisitedHandlingMode {
/// All links are matched as if they are unvisted.
AllLinksUnvisited,
/// All links are matched as if they are visited and unvisited (both :link
/// and :visited match).
///
/// This is intended to be used from invalidation code, to be conservative
/// about whether we need to restyle a link.
AllLinksVisitedAndUnvisited,
/// A element's "relevant link" is the element being matched if it is a link
/// or the nearest ancestor link. The relevant link is matched as though it
/// is visited, and all other links are matched as if they are unvisited.

View file

@ -253,6 +253,10 @@ impl RelevantLinkStatus {
return false
}
if context.visited_handling == VisitedHandlingMode::AllLinksVisitedAndUnvisited {
return true;
}
// Non-relevant links are always unvisited.
if *self != RelevantLinkStatus::Found {
return false
@ -274,6 +278,10 @@ impl RelevantLinkStatus {
return false
}
if context.visited_handling == VisitedHandlingMode::AllLinksVisitedAndUnvisited {
return true;
}
// Non-relevant links are always unvisited.
if *self != RelevantLinkStatus::Found {
return true

View file

@ -268,6 +268,10 @@ impl EagerPseudoStyles {
rules: StrongRuleNode)
-> bool {
match visited_handling {
VisitedHandlingMode::AllLinksVisitedAndUnvisited => {
unreachable!("We should never try to selector match with \
AllLinksVisitedAndUnvisited");
},
VisitedHandlingMode::AllLinksUnvisited => {
self.add_unvisited_rules(&pseudo, rules)
},
@ -286,6 +290,10 @@ impl EagerPseudoStyles {
visited_handling: VisitedHandlingMode)
-> bool {
match visited_handling {
VisitedHandlingMode::AllLinksVisitedAndUnvisited => {
unreachable!("We should never try to selector match with \
AllLinksVisitedAndUnvisited");
},
VisitedHandlingMode::AllLinksUnvisited => {
self.remove_unvisited_rules(&pseudo)
},

View file

@ -1258,6 +1258,10 @@ impl<'le> PresentationalHintsSynthesizer for GeckoElement<'le> {
// Unvisited vs. visited styles are computed up-front based on the
// visited mode (not the element's actual state).
let declarations = match visited_handling {
VisitedHandlingMode::AllLinksVisitedAndUnvisited => {
unreachable!("We should never try to selector match with \
AllLinksVisitedAndUnvisited");
},
VisitedHandlingMode::AllLinksUnvisited => unsafe {
Gecko_GetUnvisitedLinkAttrDeclarationBlock(self.0)
},

View file

@ -420,8 +420,14 @@ impl<'a, 'b: 'a, E> TreeStyleInvalidator<'a, 'b, E>
debug!("TreeStyleInvalidator::process_invalidation({:?}, {:?})",
self.element, invalidation);
let mut context = MatchingContext::new(MatchingMode::Normal, None,
self.shared_context.quirks_mode);
let mut context =
MatchingContext::new_for_visited(
MatchingMode::Normal,
None,
VisitedHandlingMode::AllLinksVisitedAndUnvisited,
self.shared_context.quirks_mode,
);
let matching_result = matches_compound_selector(
&invalidation.selector,
invalidation.offset,

View file

@ -991,6 +991,10 @@ pub trait MatchMethods : TElement {
&context.shared.guards);
let rules_changed = match visited_handling {
VisitedHandlingMode::AllLinksVisitedAndUnvisited => {
unreachable!("We should never try to selector match with \
AllLinksVisitedAndUnvisited");
},
VisitedHandlingMode::AllLinksUnvisited => {
data.set_primary_rules(rules)
},
@ -1070,6 +1074,10 @@ pub trait MatchMethods : TElement {
);
let rules_changed = match visited_handling {
VisitedHandlingMode::AllLinksVisitedAndUnvisited => {
unreachable!("We should never try to selector match with \
AllLinksVisitedAndUnvisited");
},
VisitedHandlingMode::AllLinksUnvisited => {
data.set_primary_rules(primary_rule_node)
},