Look for relevant links while matching

Adjust the matching process to look for a "relevant link" while matching.  A
"relevant link" is the element being matched if it is a link or the nearest
ancestor link.

Matching for links now depends on the `VisitedHandlingMode`, which determines
whether all links match as if they are unvisited (the default) or if the
relevant link matches as visited (and all others remain unvisited).

If a relevant link is ever found for any selector, track this as part of the
`MatchingContext` object.  This is used in the next patch to determine if an
additional match and cascade should be performed to compute the styles when
visited.

MozReview-Commit-ID: 3xUbRo7vpuD
This commit is contained in:
J. Ryan Stinnett 2017-05-15 10:14:49 -05:00
parent 8ae546f7ea
commit e3a256803d
8 changed files with 197 additions and 55 deletions

View file

@ -65,7 +65,7 @@ use rule_tree::CascadeLevel as ServoCascadeLevel;
use selector_parser::ElementExt;
use selectors::Element;
use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator, CaseSensitivity, NamespaceConstraint};
use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode};
use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode, RelevantLinkStatus};
use shared_lock::Locked;
use sink::Push;
use std::cell::RefCell;
@ -1236,6 +1236,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
fn match_non_ts_pseudo_class<F>(&self,
pseudo_class: &NonTSPseudoClass,
context: &mut MatchingContext,
relevant_link: &RelevantLinkStatus,
flags_setter: &mut F)
-> bool
where F: FnMut(&Self, ElementSelectorFlags),
@ -1243,8 +1244,6 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
use selectors::matching::*;
match *pseudo_class {
NonTSPseudoClass::AnyLink |
NonTSPseudoClass::Link |
NonTSPseudoClass::Visited |
NonTSPseudoClass::Active |
NonTSPseudoClass::Focus |
NonTSPseudoClass::Hover |
@ -1293,6 +1292,8 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
// here, to handle `:any-link` correctly.
self.get_state().intersects(pseudo_class.state_flag())
},
NonTSPseudoClass::Link => relevant_link.is_unvisited(self, context),
NonTSPseudoClass::Visited => relevant_link.is_visited(self, context),
NonTSPseudoClass::MozFirstNode => {
flags_setter(self, HAS_EDGE_CHILD_SELECTOR);
let mut elem = self.as_node();
@ -1369,6 +1370,15 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
}
}
#[inline]
fn is_link(&self) -> bool {
let mut context = MatchingContext::new(MatchingMode::Normal, None);
self.match_non_ts_pseudo_class(&NonTSPseudoClass::AnyLink,
&mut context,
&RelevantLinkStatus::default(),
&mut |_, _| {})
}
fn get_id(&self) -> Option<Atom> {
if !self.has_id() {
return None;
@ -1420,14 +1430,6 @@ impl<'a> NamespaceConstraintHelpers for NamespaceConstraint<&'a Namespace> {
}
impl<'le> ElementExt for GeckoElement<'le> {
#[inline]
fn is_link(&self) -> bool {
let mut context = MatchingContext::new(MatchingMode::Normal, None);
self.match_non_ts_pseudo_class(&NonTSPseudoClass::AnyLink,
&mut context,
&mut |_, _| {})
}
#[inline]
fn matches_user_and_author_rules(&self) -> bool {
self.flags() & (NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE as u32) == 0