selectors: Simplify :visited by only using the "is inside link" information.

Right now we go through a lot of hoops to see if we ever see a relevant link.

However, that information is not needed: if the element is a link, we'll always
need to compute its visited style because its its own relevant link.

If the element inherits from a link, we need to also compute the visited style
anyway.

So the "has a relevant link been found" is pretty useless when we know what are
we inheriting from.

The branches at the beginning of matches_complex_selector_internal were
affecting performance, and there are no good reasons to keep them.

I've verified that this passes all the visited tests in mozilla central, and
that the test-cases too-flaky to be landed still pass.
This commit is contained in:
Emilio Cobos Álvarez 2017-12-08 04:48:03 +01:00
parent e4bb3a102e
commit 3119db724a
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
10 changed files with 128 additions and 208 deletions

View file

@ -406,9 +406,8 @@ where
&mut self,
visited_handling_mode: VisitedHandlingMode,
dependency: &Dependency,
relevant_link_found: &mut bool,
) -> bool {
let (matches_now, relevant_link_found_now) = {
let matches_now = {
let mut context = MatchingContext::new_for_visited(
MatchingMode::Normal,
None,
@ -426,10 +425,10 @@ where
&mut |_, _| {},
);
(matches_now, context.relevant_link_found)
matches_now
};
let (matched_then, relevant_link_found_then) = {
let matched_then = {
let mut context = MatchingContext::new_for_visited(
MatchingMode::Normal,
None,
@ -447,15 +446,12 @@ where
&mut |_, _| {},
);
(matched_then, context.relevant_link_found)
matched_then
};
*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
matched_then != matches_now
}
fn scan_dependency(
@ -464,20 +460,18 @@ where
is_visited_dependent: VisitedDependent,
) {
debug!("TreeStyleInvalidator::scan_dependency({:?}, {:?}, {:?})",
self.element,
dependency,
is_visited_dependent);
self.element,
dependency,
is_visited_dependent,
);
if !self.dependency_may_be_relevant(dependency) {
return;
}
let mut relevant_link_found = false;
let should_account_for_dependency = self.check_dependency(
VisitedHandlingMode::AllLinksUnvisited,
VisitedHandlingMode::AllLinksVisitedAndUnvisited,
dependency,
&mut relevant_link_found,
);
if should_account_for_dependency {
@ -500,11 +494,12 @@ where
//
// 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 == VisitedDependent::Yes && relevant_link_found {
if is_visited_dependent == VisitedDependent::Yes &&
self.element.is_link()
{
let should_account_for_dependency = self.check_dependency(
VisitedHandlingMode::RelevantLinkVisited,
dependency,
&mut false,
);
if should_account_for_dependency {

View file

@ -11,8 +11,8 @@ use element_state::ElementState;
use selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl, Snapshot, SnapshotMap, AttrValue};
use selectors::{Element, OpaqueElement};
use selectors::attr::{AttrSelectorOperation, CaseSensitivity, NamespaceConstraint};
use selectors::context::VisitedHandlingMode;
use selectors::matching::{ElementSelectorFlags, MatchingContext};
use selectors::matching::RelevantLinkStatus;
use std::cell::Cell;
use std::fmt;
@ -153,7 +153,7 @@ impl<'a, E> Element for ElementWrapper<'a, E>
&self,
pseudo_class: &NonTSPseudoClass,
context: &mut MatchingContext<Self::Impl>,
relevant_link: &RelevantLinkStatus,
visited_handling: VisitedHandlingMode,
_setter: &mut F,
) -> bool
where
@ -196,14 +196,16 @@ impl<'a, E> Element for ElementWrapper<'a, E>
return state.contains(selector_flag);
}
// For :link and :visited, we don't actually want to test the element
// state directly. Instead, we use the `relevant_link` to determine if
// they match.
// For :link and :visited, we don't actually want to test the
// element state directly.
//
// Instead, we use the `visited_handling` to determine if they
// match.
NonTSPseudoClass::Link => {
return relevant_link.is_unvisited(self, context);
return self.is_link() && visited_handling.matches_unvisited()
}
NonTSPseudoClass::Visited => {
return relevant_link.is_visited(self, context);
return self.is_link() && visited_handling.matches_visited()
}
#[cfg(feature = "gecko")]
@ -238,7 +240,7 @@ impl<'a, E> Element for ElementWrapper<'a, E>
return self.element.match_non_ts_pseudo_class(
pseudo_class,
context,
relevant_link,
visited_handling,
&mut |_, _| {},
)
}
@ -248,7 +250,7 @@ impl<'a, E> Element for ElementWrapper<'a, E>
self.element.match_non_ts_pseudo_class(
pseudo_class,
context,
relevant_link,
visited_handling,
&mut |_, _| {},
)
}