mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
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:
parent
8ae546f7ea
commit
e3a256803d
8 changed files with 197 additions and 55 deletions
|
@ -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
|
||||
|
|
|
@ -20,7 +20,7 @@ use selector_map::{SelectorMap, SelectorMapEntry};
|
|||
use selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl, Snapshot, SnapshotMap, AttrValue};
|
||||
use selectors::Element;
|
||||
use selectors::attr::{AttrSelectorOperation, NamespaceConstraint};
|
||||
use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode};
|
||||
use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode, RelevantLinkStatus};
|
||||
use selectors::matching::matches_selector;
|
||||
use selectors::parser::{Combinator, Component, Selector, SelectorInner, SelectorMethods};
|
||||
use selectors::visitor::SelectorVisitor;
|
||||
|
@ -535,6 +535,7 @@ impl<'a, E> Element for ElementWrapper<'a, E>
|
|||
fn match_non_ts_pseudo_class<F>(&self,
|
||||
pseudo_class: &NonTSPseudoClass,
|
||||
context: &mut MatchingContext,
|
||||
relevant_link: &RelevantLinkStatus,
|
||||
_setter: &mut F)
|
||||
-> bool
|
||||
where F: FnMut(&Self, ElementSelectorFlags),
|
||||
|
@ -580,6 +581,7 @@ impl<'a, E> Element for ElementWrapper<'a, E>
|
|||
if flag.is_empty() {
|
||||
return self.element.match_non_ts_pseudo_class(pseudo_class,
|
||||
context,
|
||||
relevant_link,
|
||||
&mut |_, _| {})
|
||||
}
|
||||
match self.snapshot().and_then(|s| s.state()) {
|
||||
|
@ -587,6 +589,7 @@ impl<'a, E> Element for ElementWrapper<'a, E>
|
|||
None => {
|
||||
self.element.match_non_ts_pseudo_class(pseudo_class,
|
||||
context,
|
||||
relevant_link,
|
||||
&mut |_, _| {})
|
||||
}
|
||||
}
|
||||
|
@ -600,6 +603,14 @@ impl<'a, E> Element for ElementWrapper<'a, E>
|
|||
self.element.match_pseudo_element(pseudo_element, context)
|
||||
}
|
||||
|
||||
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 parent_element(&self) -> Option<Self> {
|
||||
self.element.parent_element()
|
||||
.map(|e| ElementWrapper::new(e, self.snapshot_map))
|
||||
|
|
|
@ -103,9 +103,6 @@ pub enum PseudoElementCascadeType {
|
|||
|
||||
/// An extension to rust-selector's `Element` trait.
|
||||
pub trait ElementExt: Element<Impl=SelectorImpl> + Debug {
|
||||
/// Whether this element is a `link`.
|
||||
fn is_link(&self) -> bool;
|
||||
|
||||
/// Whether this element should match user and author rules.
|
||||
///
|
||||
/// We use this for Native Anonymous Content in Gecko.
|
||||
|
|
|
@ -16,7 +16,6 @@ use restyle_hints::ElementSnapshot;
|
|||
use selector_parser::{ElementExt, PseudoElementCascadeType, SelectorParser};
|
||||
use selectors::Element;
|
||||
use selectors::attr::{AttrSelectorOperation, NamespaceConstraint};
|
||||
use selectors::matching::{MatchingContext, MatchingMode};
|
||||
use selectors::parser::SelectorMethods;
|
||||
use selectors::visitor::SelectorVisitor;
|
||||
use std::borrow::Cow;
|
||||
|
@ -601,13 +600,6 @@ impl ServoElementSnapshot {
|
|||
}
|
||||
|
||||
impl<E: Element<Impl=SelectorImpl> + Debug> ElementExt for E {
|
||||
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 {
|
||||
true
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue