mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
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:
parent
fdf9093466
commit
4434509088
6 changed files with 42 additions and 2 deletions
|
@ -48,6 +48,12 @@ pub enum MatchingMode {
|
||||||
pub enum VisitedHandlingMode {
|
pub enum VisitedHandlingMode {
|
||||||
/// All links are matched as if they are unvisted.
|
/// All links are matched as if they are unvisted.
|
||||||
AllLinksUnvisited,
|
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
|
/// 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
|
/// 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.
|
/// is visited, and all other links are matched as if they are unvisited.
|
||||||
|
|
|
@ -253,6 +253,10 @@ impl RelevantLinkStatus {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if context.visited_handling == VisitedHandlingMode::AllLinksVisitedAndUnvisited {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Non-relevant links are always unvisited.
|
// Non-relevant links are always unvisited.
|
||||||
if *self != RelevantLinkStatus::Found {
|
if *self != RelevantLinkStatus::Found {
|
||||||
return false
|
return false
|
||||||
|
@ -274,6 +278,10 @@ impl RelevantLinkStatus {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if context.visited_handling == VisitedHandlingMode::AllLinksVisitedAndUnvisited {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Non-relevant links are always unvisited.
|
// Non-relevant links are always unvisited.
|
||||||
if *self != RelevantLinkStatus::Found {
|
if *self != RelevantLinkStatus::Found {
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -268,6 +268,10 @@ impl EagerPseudoStyles {
|
||||||
rules: StrongRuleNode)
|
rules: StrongRuleNode)
|
||||||
-> bool {
|
-> bool {
|
||||||
match visited_handling {
|
match visited_handling {
|
||||||
|
VisitedHandlingMode::AllLinksVisitedAndUnvisited => {
|
||||||
|
unreachable!("We should never try to selector match with \
|
||||||
|
AllLinksVisitedAndUnvisited");
|
||||||
|
},
|
||||||
VisitedHandlingMode::AllLinksUnvisited => {
|
VisitedHandlingMode::AllLinksUnvisited => {
|
||||||
self.add_unvisited_rules(&pseudo, rules)
|
self.add_unvisited_rules(&pseudo, rules)
|
||||||
},
|
},
|
||||||
|
@ -286,6 +290,10 @@ impl EagerPseudoStyles {
|
||||||
visited_handling: VisitedHandlingMode)
|
visited_handling: VisitedHandlingMode)
|
||||||
-> bool {
|
-> bool {
|
||||||
match visited_handling {
|
match visited_handling {
|
||||||
|
VisitedHandlingMode::AllLinksVisitedAndUnvisited => {
|
||||||
|
unreachable!("We should never try to selector match with \
|
||||||
|
AllLinksVisitedAndUnvisited");
|
||||||
|
},
|
||||||
VisitedHandlingMode::AllLinksUnvisited => {
|
VisitedHandlingMode::AllLinksUnvisited => {
|
||||||
self.remove_unvisited_rules(&pseudo)
|
self.remove_unvisited_rules(&pseudo)
|
||||||
},
|
},
|
||||||
|
|
|
@ -1258,6 +1258,10 @@ impl<'le> PresentationalHintsSynthesizer for GeckoElement<'le> {
|
||||||
// Unvisited vs. visited styles are computed up-front based on the
|
// Unvisited vs. visited styles are computed up-front based on the
|
||||||
// visited mode (not the element's actual state).
|
// visited mode (not the element's actual state).
|
||||||
let declarations = match visited_handling {
|
let declarations = match visited_handling {
|
||||||
|
VisitedHandlingMode::AllLinksVisitedAndUnvisited => {
|
||||||
|
unreachable!("We should never try to selector match with \
|
||||||
|
AllLinksVisitedAndUnvisited");
|
||||||
|
},
|
||||||
VisitedHandlingMode::AllLinksUnvisited => unsafe {
|
VisitedHandlingMode::AllLinksUnvisited => unsafe {
|
||||||
Gecko_GetUnvisitedLinkAttrDeclarationBlock(self.0)
|
Gecko_GetUnvisitedLinkAttrDeclarationBlock(self.0)
|
||||||
},
|
},
|
||||||
|
|
|
@ -420,8 +420,14 @@ impl<'a, 'b: 'a, E> TreeStyleInvalidator<'a, 'b, E>
|
||||||
debug!("TreeStyleInvalidator::process_invalidation({:?}, {:?})",
|
debug!("TreeStyleInvalidator::process_invalidation({:?}, {:?})",
|
||||||
self.element, invalidation);
|
self.element, invalidation);
|
||||||
|
|
||||||
let mut context = MatchingContext::new(MatchingMode::Normal, None,
|
let mut context =
|
||||||
self.shared_context.quirks_mode);
|
MatchingContext::new_for_visited(
|
||||||
|
MatchingMode::Normal,
|
||||||
|
None,
|
||||||
|
VisitedHandlingMode::AllLinksVisitedAndUnvisited,
|
||||||
|
self.shared_context.quirks_mode,
|
||||||
|
);
|
||||||
|
|
||||||
let matching_result = matches_compound_selector(
|
let matching_result = matches_compound_selector(
|
||||||
&invalidation.selector,
|
&invalidation.selector,
|
||||||
invalidation.offset,
|
invalidation.offset,
|
||||||
|
|
|
@ -991,6 +991,10 @@ pub trait MatchMethods : TElement {
|
||||||
&context.shared.guards);
|
&context.shared.guards);
|
||||||
|
|
||||||
let rules_changed = match visited_handling {
|
let rules_changed = match visited_handling {
|
||||||
|
VisitedHandlingMode::AllLinksVisitedAndUnvisited => {
|
||||||
|
unreachable!("We should never try to selector match with \
|
||||||
|
AllLinksVisitedAndUnvisited");
|
||||||
|
},
|
||||||
VisitedHandlingMode::AllLinksUnvisited => {
|
VisitedHandlingMode::AllLinksUnvisited => {
|
||||||
data.set_primary_rules(rules)
|
data.set_primary_rules(rules)
|
||||||
},
|
},
|
||||||
|
@ -1070,6 +1074,10 @@ pub trait MatchMethods : TElement {
|
||||||
);
|
);
|
||||||
|
|
||||||
let rules_changed = match visited_handling {
|
let rules_changed = match visited_handling {
|
||||||
|
VisitedHandlingMode::AllLinksVisitedAndUnvisited => {
|
||||||
|
unreachable!("We should never try to selector match with \
|
||||||
|
AllLinksVisitedAndUnvisited");
|
||||||
|
},
|
||||||
VisitedHandlingMode::AllLinksUnvisited => {
|
VisitedHandlingMode::AllLinksUnvisited => {
|
||||||
data.set_primary_rules(primary_rule_node)
|
data.set_primary_rules(primary_rule_node)
|
||||||
},
|
},
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue