mirror of
https://github.com/servo/servo.git
synced 2025-07-23 15:23:42 +01:00
stylo: Support :hover and :active quirk
This commit is contained in:
parent
ff17af064b
commit
15fe48f3f6
15 changed files with 229 additions and 73 deletions
|
@ -209,6 +209,7 @@ pub struct Document {
|
||||||
is_html_document: bool,
|
is_html_document: bool,
|
||||||
activity: Cell<DocumentActivity>,
|
activity: Cell<DocumentActivity>,
|
||||||
url: DOMRefCell<ServoUrl>,
|
url: DOMRefCell<ServoUrl>,
|
||||||
|
#[ignore_heap_size_of = "defined in selectors"]
|
||||||
quirks_mode: Cell<QuirksMode>,
|
quirks_mode: Cell<QuirksMode>,
|
||||||
/// Caches for the getElement methods
|
/// Caches for the getElement methods
|
||||||
id_map: DOMRefCell<HashMap<Atom, Vec<JS<Element>>>>,
|
id_map: DOMRefCell<HashMap<Atom, Vec<JS<Element>>>>,
|
||||||
|
|
|
@ -86,7 +86,7 @@ use ref_filter_map::ref_filter_map;
|
||||||
use script_layout_interface::message::ReflowQueryType;
|
use script_layout_interface::message::ReflowQueryType;
|
||||||
use script_thread::Runnable;
|
use script_thread::Runnable;
|
||||||
use selectors::attr::{AttrSelectorOperation, NamespaceConstraint};
|
use selectors::attr::{AttrSelectorOperation, NamespaceConstraint};
|
||||||
use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode};
|
use selectors::matching::{ElementSelectorFlags, LocalMatchingContext, MatchingContext, MatchingMode};
|
||||||
use selectors::matching::{HAS_EDGE_CHILD_SELECTOR, HAS_SLOW_SELECTOR, HAS_SLOW_SELECTOR_LATER_SIBLINGS};
|
use selectors::matching::{HAS_EDGE_CHILD_SELECTOR, HAS_SLOW_SELECTOR, HAS_SLOW_SELECTOR_LATER_SIBLINGS};
|
||||||
use selectors::matching::{RelevantLinkStatus, matches_selector_list};
|
use selectors::matching::{RelevantLinkStatus, matches_selector_list};
|
||||||
use servo_atoms::Atom;
|
use servo_atoms::Atom;
|
||||||
|
@ -2063,7 +2063,9 @@ impl ElementMethods for Element {
|
||||||
match SelectorParser::parse_author_origin_no_namespace(&selectors) {
|
match SelectorParser::parse_author_origin_no_namespace(&selectors) {
|
||||||
Err(_) => Err(Error::Syntax),
|
Err(_) => Err(Error::Syntax),
|
||||||
Ok(selectors) => {
|
Ok(selectors) => {
|
||||||
let mut ctx = MatchingContext::new(MatchingMode::Normal, None);
|
let quirks_mode = document_from_node(self).quirks_mode();
|
||||||
|
let mut ctx = MatchingContext::new(MatchingMode::Normal, None,
|
||||||
|
quirks_mode);
|
||||||
Ok(matches_selector_list(&selectors, &Root::from_ref(self), &mut ctx))
|
Ok(matches_selector_list(&selectors, &Root::from_ref(self), &mut ctx))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2082,7 +2084,9 @@ impl ElementMethods for Element {
|
||||||
let root = self.upcast::<Node>();
|
let root = self.upcast::<Node>();
|
||||||
for element in root.inclusive_ancestors() {
|
for element in root.inclusive_ancestors() {
|
||||||
if let Some(element) = Root::downcast::<Element>(element) {
|
if let Some(element) = Root::downcast::<Element>(element) {
|
||||||
let mut ctx = MatchingContext::new(MatchingMode::Normal, None);
|
let quirks_mode = document_from_node(self).quirks_mode();
|
||||||
|
let mut ctx = MatchingContext::new(MatchingMode::Normal, None,
|
||||||
|
quirks_mode);
|
||||||
if matches_selector_list(&selectors, &element, &mut ctx) {
|
if matches_selector_list(&selectors, &element, &mut ctx) {
|
||||||
return Ok(Some(element));
|
return Ok(Some(element));
|
||||||
}
|
}
|
||||||
|
@ -2432,7 +2436,7 @@ impl<'a> ::selectors::Element for Root<Element> {
|
||||||
|
|
||||||
fn match_non_ts_pseudo_class<F>(&self,
|
fn match_non_ts_pseudo_class<F>(&self,
|
||||||
pseudo_class: &NonTSPseudoClass,
|
pseudo_class: &NonTSPseudoClass,
|
||||||
_: &mut MatchingContext,
|
_: &mut LocalMatchingContext<Self::Impl>,
|
||||||
_: &RelevantLinkStatus,
|
_: &RelevantLinkStatus,
|
||||||
_: &mut F)
|
_: &mut F)
|
||||||
-> bool
|
-> bool
|
||||||
|
|
|
@ -347,11 +347,11 @@ impl<'a> Iterator for QuerySelectorIterator {
|
||||||
fn next(&mut self) -> Option<Root<Node>> {
|
fn next(&mut self) -> Option<Root<Node>> {
|
||||||
let selectors = &self.selectors;
|
let selectors = &self.selectors;
|
||||||
|
|
||||||
// TODO(cgaebel): Is it worth it to build a bloom filter here
|
|
||||||
// (instead of passing `None`)? Probably.
|
|
||||||
let mut ctx = MatchingContext::new(MatchingMode::Normal, None);
|
|
||||||
|
|
||||||
self.iterator.by_ref().filter_map(|node| {
|
self.iterator.by_ref().filter_map(|node| {
|
||||||
|
// TODO(cgaebel): Is it worth it to build a bloom filter here
|
||||||
|
// (instead of passing `None`)? Probably.
|
||||||
|
let mut ctx = MatchingContext::new(MatchingMode::Normal, None,
|
||||||
|
node.owner_doc().quirks_mode());
|
||||||
if let Some(element) = Root::downcast(node) {
|
if let Some(element) = Root::downcast(node) {
|
||||||
if matches_selector_list(selectors, &element, &mut ctx) {
|
if matches_selector_list(selectors, &element, &mut ctx) {
|
||||||
return Some(Root::upcast(element));
|
return Some(Root::upcast(element));
|
||||||
|
@ -720,7 +720,8 @@ impl Node {
|
||||||
Err(_) => Err(Error::Syntax),
|
Err(_) => Err(Error::Syntax),
|
||||||
// Step 3.
|
// Step 3.
|
||||||
Ok(selectors) => {
|
Ok(selectors) => {
|
||||||
let mut ctx = MatchingContext::new(MatchingMode::Normal, None);
|
let mut ctx = MatchingContext::new(MatchingMode::Normal, None,
|
||||||
|
self.owner_doc().quirks_mode());
|
||||||
Ok(self.traverse_preorder().filter_map(Root::downcast).find(|element| {
|
Ok(self.traverse_preorder().filter_map(Root::downcast).find(|element| {
|
||||||
matches_selector_list(&selectors, element, &mut ctx)
|
matches_selector_list(&selectors, element, &mut ctx)
|
||||||
}))
|
}))
|
||||||
|
|
|
@ -50,7 +50,8 @@ use script_layout_interface::{OpaqueStyleAndLayoutData, StyleData};
|
||||||
use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, GetLayoutData, LayoutNode};
|
use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, GetLayoutData, LayoutNode};
|
||||||
use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
|
use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
|
||||||
use selectors::attr::{AttrSelectorOperation, NamespaceConstraint};
|
use selectors::attr::{AttrSelectorOperation, NamespaceConstraint};
|
||||||
use selectors::matching::{ElementSelectorFlags, MatchingContext, RelevantLinkStatus, VisitedHandlingMode};
|
use selectors::matching::{ElementSelectorFlags, LocalMatchingContext, MatchingContext, RelevantLinkStatus};
|
||||||
|
use selectors::matching::VisitedHandlingMode;
|
||||||
use servo_atoms::Atom;
|
use servo_atoms::Atom;
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -721,7 +722,7 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
|
||||||
|
|
||||||
fn match_non_ts_pseudo_class<F>(&self,
|
fn match_non_ts_pseudo_class<F>(&self,
|
||||||
pseudo_class: &NonTSPseudoClass,
|
pseudo_class: &NonTSPseudoClass,
|
||||||
_: &mut MatchingContext,
|
_: &mut LocalMatchingContext<Self::Impl>,
|
||||||
_: &RelevantLinkStatus,
|
_: &RelevantLinkStatus,
|
||||||
_: &mut F)
|
_: &mut F)
|
||||||
-> bool
|
-> bool
|
||||||
|
@ -1232,7 +1233,7 @@ impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
|
||||||
|
|
||||||
fn match_non_ts_pseudo_class<F>(&self,
|
fn match_non_ts_pseudo_class<F>(&self,
|
||||||
_: &NonTSPseudoClass,
|
_: &NonTSPseudoClass,
|
||||||
_: &mut MatchingContext,
|
_: &mut LocalMatchingContext<Self::Impl>,
|
||||||
_: &RelevantLinkStatus,
|
_: &RelevantLinkStatus,
|
||||||
_: &mut F)
|
_: &mut F)
|
||||||
-> bool
|
-> bool
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
use attr::{ParsedAttrSelectorOperation, AttrSelectorOperation, NamespaceConstraint};
|
use attr::{ParsedAttrSelectorOperation, AttrSelectorOperation, NamespaceConstraint};
|
||||||
use bloom::BloomFilter;
|
use bloom::BloomFilter;
|
||||||
use parser::{AncestorHashes, Combinator, Component, LocalName};
|
use parser::{AncestorHashes, Combinator, Component, LocalName};
|
||||||
use parser::{Selector, SelectorIter, SelectorList};
|
use parser::{Selector, SelectorImpl, SelectorIter, SelectorList};
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use tree::Element;
|
use tree::Element;
|
||||||
|
|
||||||
|
@ -100,6 +100,19 @@ pub enum VisitedHandlingMode {
|
||||||
RelevantLinkVisited,
|
RelevantLinkVisited,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Which quirks mode is this document in.
|
||||||
|
///
|
||||||
|
/// See: https://quirks.spec.whatwg.org/
|
||||||
|
#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)]
|
||||||
|
pub enum QuirksMode {
|
||||||
|
/// Quirks mode.
|
||||||
|
Quirks,
|
||||||
|
/// Limited quirks mode.
|
||||||
|
LimitedQuirks,
|
||||||
|
/// No quirks mode.
|
||||||
|
NoQuirks,
|
||||||
|
}
|
||||||
|
|
||||||
/// Data associated with the matching process for a element. This context is
|
/// Data associated with the matching process for a element. This context is
|
||||||
/// used across many selectors for an element, so it's not appropriate for
|
/// used across many selectors for an element, so it's not appropriate for
|
||||||
/// transient data that applies to only a single selector.
|
/// transient data that applies to only a single selector.
|
||||||
|
@ -119,12 +132,15 @@ pub struct MatchingContext<'a> {
|
||||||
/// `RelevantLinkStatus` which tracks the status for the _current_ selector
|
/// `RelevantLinkStatus` which tracks the status for the _current_ selector
|
||||||
/// only.)
|
/// only.)
|
||||||
pub relevant_link_found: bool,
|
pub relevant_link_found: bool,
|
||||||
|
/// The quirks mode of the document.
|
||||||
|
pub quirks_mode: QuirksMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> MatchingContext<'a> {
|
impl<'a> MatchingContext<'a> {
|
||||||
/// Constructs a new `MatchingContext`.
|
/// Constructs a new `MatchingContext`.
|
||||||
pub fn new(matching_mode: MatchingMode,
|
pub fn new(matching_mode: MatchingMode,
|
||||||
bloom_filter: Option<&'a BloomFilter>)
|
bloom_filter: Option<&'a BloomFilter>,
|
||||||
|
quirks_mode: QuirksMode)
|
||||||
-> Self
|
-> Self
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
|
@ -133,13 +149,15 @@ impl<'a> MatchingContext<'a> {
|
||||||
bloom_filter: bloom_filter,
|
bloom_filter: bloom_filter,
|
||||||
visited_handling: VisitedHandlingMode::AllLinksUnvisited,
|
visited_handling: VisitedHandlingMode::AllLinksUnvisited,
|
||||||
relevant_link_found: false,
|
relevant_link_found: false,
|
||||||
|
quirks_mode: quirks_mode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a new `MatchingContext` for use in visited matching.
|
/// Constructs a new `MatchingContext` for use in visited matching.
|
||||||
pub fn new_for_visited(matching_mode: MatchingMode,
|
pub fn new_for_visited(matching_mode: MatchingMode,
|
||||||
bloom_filter: Option<&'a BloomFilter>,
|
bloom_filter: Option<&'a BloomFilter>,
|
||||||
visited_handling: VisitedHandlingMode)
|
visited_handling: VisitedHandlingMode,
|
||||||
|
quirks_mode: QuirksMode)
|
||||||
-> Self
|
-> Self
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
|
@ -148,10 +166,97 @@ impl<'a> MatchingContext<'a> {
|
||||||
bloom_filter: bloom_filter,
|
bloom_filter: bloom_filter,
|
||||||
visited_handling: visited_handling,
|
visited_handling: visited_handling,
|
||||||
relevant_link_found: false,
|
relevant_link_found: false,
|
||||||
|
quirks_mode: quirks_mode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Holds per-element data alongside a pointer to MatchingContext.
|
||||||
|
pub struct LocalMatchingContext<'a, 'b: 'a, Impl: SelectorImpl> {
|
||||||
|
/// Shared `MatchingContext`.
|
||||||
|
pub shared: &'a mut MatchingContext<'b>,
|
||||||
|
/// A reference to the base selector we're matching against.
|
||||||
|
pub selector: &'a Selector<Impl>,
|
||||||
|
/// The offset of the current compound selector being matched, kept up to date by
|
||||||
|
/// the callees when the iterator is advanced. This, in conjunction with the selector
|
||||||
|
/// reference above, allows callees to synthesize an iterator for the current compound
|
||||||
|
/// selector on-demand. This is necessary because the primary iterator may already have
|
||||||
|
/// been advanced partway through the current compound selector, and the callee may need
|
||||||
|
/// the whole thing.
|
||||||
|
offset: usize,
|
||||||
|
/// Holds a bool flag to see if LocalMatchingContext is within a functional
|
||||||
|
/// pseudo class argument. This is used for pseudo classes like
|
||||||
|
/// `:-moz-any` or `:not`. If this flag is true, :active and :hover
|
||||||
|
/// quirk shouldn't match.
|
||||||
|
pub within_functional_pseudo_class_argument: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b, Impl> LocalMatchingContext<'a, 'b, Impl>
|
||||||
|
where Impl: SelectorImpl
|
||||||
|
{
|
||||||
|
/// Constructs a new `LocalMatchingContext`.
|
||||||
|
pub fn new(shared: &'a mut MatchingContext<'b>,
|
||||||
|
selector: &'a Selector<Impl>) -> Self {
|
||||||
|
Self {
|
||||||
|
shared: shared,
|
||||||
|
selector: selector,
|
||||||
|
offset: 0,
|
||||||
|
within_functional_pseudo_class_argument: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates offset of Selector to show new compound selector.
|
||||||
|
/// To be able to correctly re-synthesize main SelectorIter.
|
||||||
|
pub fn note_next_sequence(&mut self, selector_iter: &SelectorIter<Impl>) {
|
||||||
|
if let QuirksMode::Quirks = self.shared.quirks_mode {
|
||||||
|
self.offset = self.selector.len() - selector_iter.selector_length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if current compound selector matches :active and :hover quirk.
|
||||||
|
/// https://quirks.spec.whatwg.org/#the-active-and-hover-quirk
|
||||||
|
pub fn active_hover_quirk_matches(&mut self) -> bool {
|
||||||
|
if self.shared.quirks_mode != QuirksMode::Quirks ||
|
||||||
|
self.within_functional_pseudo_class_argument {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut iter = if self.offset == 0 {
|
||||||
|
self.selector.iter()
|
||||||
|
} else {
|
||||||
|
self.selector.iter_from(self.offset)
|
||||||
|
};
|
||||||
|
|
||||||
|
return iter.all(|simple| {
|
||||||
|
match *simple {
|
||||||
|
Component::LocalName(_) |
|
||||||
|
Component::AttributeInNoNamespaceExists { .. } |
|
||||||
|
Component::AttributeInNoNamespace { .. } |
|
||||||
|
Component::AttributeOther(_) |
|
||||||
|
Component::ID(_) |
|
||||||
|
Component::Class(_) |
|
||||||
|
Component::PseudoElement(_) |
|
||||||
|
Component::Negation(_) |
|
||||||
|
Component::FirstChild |
|
||||||
|
Component::LastChild |
|
||||||
|
Component::OnlyChild |
|
||||||
|
Component::Empty |
|
||||||
|
Component::NthChild(_, _) |
|
||||||
|
Component::NthLastChild(_, _) |
|
||||||
|
Component::NthOfType(_, _) |
|
||||||
|
Component::NthLastOfType(_, _) |
|
||||||
|
Component::FirstOfType |
|
||||||
|
Component::LastOfType |
|
||||||
|
Component::OnlyOfType => false,
|
||||||
|
Component::NonTSPseudoClass(ref pseudo_class) => {
|
||||||
|
Impl::is_active_or_hover(pseudo_class)
|
||||||
|
},
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn matches_selector_list<E>(selector_list: &SelectorList<E::Impl>,
|
pub fn matches_selector_list<E>(selector_list: &SelectorList<E::Impl>,
|
||||||
element: &E,
|
element: &E,
|
||||||
context: &mut MatchingContext)
|
context: &mut MatchingContext)
|
||||||
|
@ -361,14 +466,15 @@ pub fn matches_selector<E, F>(selector: &Selector<E::Impl>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
matches_complex_selector(selector, offset, element, context, flags_setter)
|
let mut local_context = LocalMatchingContext::new(context, selector);
|
||||||
|
matches_complex_selector(&selector, offset, element, &mut local_context, flags_setter)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Matches a complex selector.
|
/// Matches a complex selector.
|
||||||
pub fn matches_complex_selector<E, F>(complex_selector: &Selector<E::Impl>,
|
pub fn matches_complex_selector<E, F>(complex_selector: &Selector<E::Impl>,
|
||||||
offset: usize,
|
offset: usize,
|
||||||
element: &E,
|
element: &E,
|
||||||
context: &mut MatchingContext,
|
mut context: &mut LocalMatchingContext<E::Impl>,
|
||||||
flags_setter: &mut F)
|
flags_setter: &mut F)
|
||||||
-> bool
|
-> bool
|
||||||
where E: Element,
|
where E: Element,
|
||||||
|
@ -381,14 +487,14 @@ pub fn matches_complex_selector<E, F>(complex_selector: &Selector<E::Impl>,
|
||||||
};
|
};
|
||||||
|
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
if context.matching_mode == MatchingMode::ForStatelessPseudoElement {
|
if context.shared.matching_mode == MatchingMode::ForStatelessPseudoElement {
|
||||||
assert!(iter.clone().any(|c| {
|
assert!(iter.clone().any(|c| {
|
||||||
matches!(*c, Component::PseudoElement(..))
|
matches!(*c, Component::PseudoElement(..))
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if context.matching_mode == MatchingMode::ForStatelessPseudoElement {
|
if context.shared.matching_mode == MatchingMode::ForStatelessPseudoElement {
|
||||||
match *iter.next().unwrap() {
|
match *iter.next().unwrap() {
|
||||||
// Stateful pseudo, just don't match.
|
// Stateful pseudo, just don't match.
|
||||||
Component::NonTSPseudoClass(..) => return false,
|
Component::NonTSPseudoClass(..) => return false,
|
||||||
|
@ -401,6 +507,8 @@ pub fn matches_complex_selector<E, F>(complex_selector: &Selector<E::Impl>,
|
||||||
if iter.next_sequence().is_none() {
|
if iter.next_sequence().is_none() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
// Inform the context that the we've advanced to the next compound selector.
|
||||||
|
context.note_next_sequence(&mut iter);
|
||||||
}
|
}
|
||||||
_ => panic!("Used MatchingMode::ForStatelessPseudoElement in a non-pseudo selector"),
|
_ => panic!("Used MatchingMode::ForStatelessPseudoElement in a non-pseudo selector"),
|
||||||
}
|
}
|
||||||
|
@ -418,14 +526,14 @@ pub fn matches_complex_selector<E, F>(complex_selector: &Selector<E::Impl>,
|
||||||
|
|
||||||
fn matches_complex_selector_internal<E, F>(mut selector_iter: SelectorIter<E::Impl>,
|
fn matches_complex_selector_internal<E, F>(mut selector_iter: SelectorIter<E::Impl>,
|
||||||
element: &E,
|
element: &E,
|
||||||
context: &mut MatchingContext,
|
context: &mut LocalMatchingContext<E::Impl>,
|
||||||
relevant_link: &mut RelevantLinkStatus,
|
relevant_link: &mut RelevantLinkStatus,
|
||||||
flags_setter: &mut F)
|
flags_setter: &mut F)
|
||||||
-> SelectorMatchingResult
|
-> SelectorMatchingResult
|
||||||
where E: Element,
|
where E: Element,
|
||||||
F: FnMut(&E, ElementSelectorFlags),
|
F: FnMut(&E, ElementSelectorFlags),
|
||||||
{
|
{
|
||||||
*relevant_link = relevant_link.examine_potential_link(element, context);
|
*relevant_link = relevant_link.examine_potential_link(element, &mut context.shared);
|
||||||
|
|
||||||
let matches_all_simple_selectors = selector_iter.all(|simple| {
|
let matches_all_simple_selectors = selector_iter.all(|simple| {
|
||||||
matches_simple_selector(simple, element, context, &relevant_link, flags_setter)
|
matches_simple_selector(simple, element, context, &relevant_link, flags_setter)
|
||||||
|
@ -435,6 +543,8 @@ fn matches_complex_selector_internal<E, F>(mut selector_iter: SelectorIter<E::Im
|
||||||
element, selector_iter, relevant_link);
|
element, selector_iter, relevant_link);
|
||||||
|
|
||||||
let combinator = selector_iter.next_sequence();
|
let combinator = selector_iter.next_sequence();
|
||||||
|
// Inform the context that the we've advanced to the next compound selector.
|
||||||
|
context.note_next_sequence(&mut selector_iter);
|
||||||
let siblings = combinator.map_or(false, |c| c.is_sibling());
|
let siblings = combinator.map_or(false, |c| c.is_sibling());
|
||||||
if siblings {
|
if siblings {
|
||||||
flags_setter(element, HAS_SLOW_SELECTOR_LATER_SIBLINGS);
|
flags_setter(element, HAS_SLOW_SELECTOR_LATER_SIBLINGS);
|
||||||
|
@ -517,7 +627,7 @@ fn matches_complex_selector_internal<E, F>(mut selector_iter: SelectorIter<E::Im
|
||||||
fn matches_simple_selector<E, F>(
|
fn matches_simple_selector<E, F>(
|
||||||
selector: &Component<E::Impl>,
|
selector: &Component<E::Impl>,
|
||||||
element: &E,
|
element: &E,
|
||||||
context: &mut MatchingContext,
|
context: &mut LocalMatchingContext<E::Impl>,
|
||||||
relevant_link: &RelevantLinkStatus,
|
relevant_link: &RelevantLinkStatus,
|
||||||
flags_setter: &mut F)
|
flags_setter: &mut F)
|
||||||
-> bool
|
-> bool
|
||||||
|
@ -527,7 +637,7 @@ fn matches_simple_selector<E, F>(
|
||||||
match *selector {
|
match *selector {
|
||||||
Component::Combinator(_) => unreachable!(),
|
Component::Combinator(_) => unreachable!(),
|
||||||
Component::PseudoElement(ref pseudo) => {
|
Component::PseudoElement(ref pseudo) => {
|
||||||
element.match_pseudo_element(pseudo, context)
|
element.match_pseudo_element(pseudo, context.shared)
|
||||||
}
|
}
|
||||||
Component::LocalName(LocalName { ref name, ref lower_name }) => {
|
Component::LocalName(LocalName { ref name, ref lower_name }) => {
|
||||||
let is_html = element.is_html_element_in_html_document();
|
let is_html = element.is_html_element_in_html_document();
|
||||||
|
@ -651,7 +761,14 @@ fn matches_simple_selector<E, F>(
|
||||||
matches_generic_nth_child(element, 0, 1, true, true, flags_setter)
|
matches_generic_nth_child(element, 0, 1, true, true, flags_setter)
|
||||||
}
|
}
|
||||||
Component::Negation(ref negated) => {
|
Component::Negation(ref negated) => {
|
||||||
!negated.iter().all(|ss| matches_simple_selector(ss, element, context, relevant_link, flags_setter))
|
let old_value = context.within_functional_pseudo_class_argument;
|
||||||
|
context.within_functional_pseudo_class_argument = true;
|
||||||
|
let result = !negated.iter().all(|ss| {
|
||||||
|
matches_simple_selector(ss, element, context,
|
||||||
|
relevant_link, flags_setter)
|
||||||
|
});
|
||||||
|
context.within_functional_pseudo_class_argument = old_value;
|
||||||
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,6 +103,10 @@ macro_rules! with_all_bounds {
|
||||||
|
|
||||||
/// pseudo-elements
|
/// pseudo-elements
|
||||||
type PseudoElement: $($CommonBounds)* + PseudoElement<Impl = Self>;
|
type PseudoElement: $($CommonBounds)* + PseudoElement<Impl = Self>;
|
||||||
|
|
||||||
|
/// Returns whether the given pseudo class is :active or :hover.
|
||||||
|
#[inline]
|
||||||
|
fn is_active_or_hover(pseudo_class: &Self::NonTSPseudoClass) -> bool;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -427,7 +431,7 @@ impl<Impl: SelectorImpl> Selector<Impl> {
|
||||||
|
|
||||||
pub fn iter_from(&self, offset: usize) -> SelectorIter<Impl> {
|
pub fn iter_from(&self, offset: usize) -> SelectorIter<Impl> {
|
||||||
// Note: selectors are stored left-to-right but logical order is right-to-left.
|
// Note: selectors are stored left-to-right but logical order is right-to-left.
|
||||||
let iter = self.0.slice[..(self.0.slice.len() - offset)].iter().rev();
|
let iter = self.0.slice[..(self.len() - offset)].iter().rev();
|
||||||
SelectorIter {
|
SelectorIter {
|
||||||
iter: iter,
|
iter: iter,
|
||||||
next_combinator: None,
|
next_combinator: None,
|
||||||
|
@ -451,6 +455,11 @@ impl<Impl: SelectorImpl> Selector<Impl> {
|
||||||
let header = HeaderWithLength::new(SpecificityAndFlags(specificity_and_flags), vec.len());
|
let header = HeaderWithLength::new(SpecificityAndFlags(specificity_and_flags), vec.len());
|
||||||
Selector(Arc::into_thin(Arc::from_header_and_iter(header, vec.into_iter())))
|
Selector(Arc::into_thin(Arc::from_header_and_iter(header, vec.into_iter())))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns count of simple selectors and combinators in the Selector.
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.0.slice.len()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -465,6 +474,11 @@ impl<'a, Impl: 'a + SelectorImpl> SelectorIter<'a, Impl> {
|
||||||
pub fn next_sequence(&mut self) -> Option<Combinator> {
|
pub fn next_sequence(&mut self) -> Option<Combinator> {
|
||||||
self.next_combinator.take()
|
self.next_combinator.take()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns remaining count of the simple selectors and combinators in the Selector.
|
||||||
|
pub fn selector_length(&self) -> usize {
|
||||||
|
self.iter.len()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Impl: SelectorImpl> Iterator for SelectorIter<'a, Impl> {
|
impl<'a, Impl: SelectorImpl> Iterator for SelectorIter<'a, Impl> {
|
||||||
|
@ -1711,6 +1725,12 @@ pub mod tests {
|
||||||
type BorrowedNamespaceUrl = DummyAtom;
|
type BorrowedNamespaceUrl = DummyAtom;
|
||||||
type NonTSPseudoClass = PseudoClass;
|
type NonTSPseudoClass = PseudoClass;
|
||||||
type PseudoElement = PseudoElement;
|
type PseudoElement = PseudoElement;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_active_or_hover(pseudo_class: &Self::NonTSPseudoClass) -> bool {
|
||||||
|
matches!(*pseudo_class, PseudoClass::Active |
|
||||||
|
PseudoClass::Hover)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
|
|
@ -34,6 +34,11 @@ impl SelectorImpl for Impl {
|
||||||
type BorrowedNamespaceUrl = Atom;
|
type BorrowedNamespaceUrl = Atom;
|
||||||
type NonTSPseudoClass = PseudoClass;
|
type NonTSPseudoClass = PseudoClass;
|
||||||
type PseudoElement = gecko_like_types::PseudoElement;
|
type PseudoElement = gecko_like_types::PseudoElement;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_active_or_hover(_pseudo_class: &Self::NonTSPseudoClass) -> bool {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SelectorMethods for PseudoClass {
|
impl SelectorMethods for PseudoClass {
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
//! between layout and style.
|
//! between layout and style.
|
||||||
|
|
||||||
use attr::{AttrSelectorOperation, NamespaceConstraint};
|
use attr::{AttrSelectorOperation, NamespaceConstraint};
|
||||||
use matching::{ElementSelectorFlags, MatchingContext, RelevantLinkStatus};
|
use matching::{ElementSelectorFlags, LocalMatchingContext, MatchingContext, RelevantLinkStatus};
|
||||||
use parser::SelectorImpl;
|
use parser::SelectorImpl;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ pub trait Element: Sized + Debug {
|
||||||
|
|
||||||
fn match_non_ts_pseudo_class<F>(&self,
|
fn match_non_ts_pseudo_class<F>(&self,
|
||||||
pc: &<Self::Impl as SelectorImpl>::NonTSPseudoClass,
|
pc: &<Self::Impl as SelectorImpl>::NonTSPseudoClass,
|
||||||
context: &mut MatchingContext,
|
context: &mut LocalMatchingContext<Self::Impl>,
|
||||||
relevant_link: &RelevantLinkStatus,
|
relevant_link: &RelevantLinkStatus,
|
||||||
flags_setter: &mut F) -> bool
|
flags_setter: &mut F) -> bool
|
||||||
where F: FnMut(&Self, ElementSelectorFlags);
|
where F: FnMut(&Self, ElementSelectorFlags);
|
||||||
|
|
|
@ -33,6 +33,8 @@ use time;
|
||||||
use timer::Timer;
|
use timer::Timer;
|
||||||
use traversal::{DomTraversal, TraversalFlags};
|
use traversal::{DomTraversal, TraversalFlags};
|
||||||
|
|
||||||
|
pub use selectors::matching::QuirksMode;
|
||||||
|
|
||||||
/// This structure is used to create a local style context from a shared one.
|
/// This structure is used to create a local style context from a shared one.
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
pub struct ThreadLocalStyleContextCreationInfo {
|
pub struct ThreadLocalStyleContextCreationInfo {
|
||||||
|
@ -49,20 +51,6 @@ impl ThreadLocalStyleContextCreationInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Which quirks mode is this document in.
|
|
||||||
///
|
|
||||||
/// See: https://quirks.spec.whatwg.org/
|
|
||||||
#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
|
||||||
pub enum QuirksMode {
|
|
||||||
/// Quirks mode.
|
|
||||||
Quirks,
|
|
||||||
/// Limited quirks mode.
|
|
||||||
LimitedQuirks,
|
|
||||||
/// No quirks mode.
|
|
||||||
NoQuirks,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A global options structure for the style system. We use this instead of
|
/// A global options structure for the style system. We use this instead of
|
||||||
/// opts to abstract across Gecko and Servo.
|
/// opts to abstract across Gecko and Servo.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
|
@ -237,6 +237,12 @@ impl ::selectors::SelectorImpl for SelectorImpl {
|
||||||
|
|
||||||
type PseudoElement = PseudoElement;
|
type PseudoElement = PseudoElement;
|
||||||
type NonTSPseudoClass = NonTSPseudoClass;
|
type NonTSPseudoClass = NonTSPseudoClass;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_active_or_hover(pseudo_class: &Self::NonTSPseudoClass) -> bool {
|
||||||
|
matches!(*pseudo_class, NonTSPseudoClass::Active |
|
||||||
|
NonTSPseudoClass::Hover)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
|
impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
|
||||||
|
|
|
@ -72,7 +72,7 @@ use rule_tree::CascadeLevel as ServoCascadeLevel;
|
||||||
use selector_parser::{AttrValue, ElementExt, PseudoClassStringArg};
|
use selector_parser::{AttrValue, ElementExt, PseudoClassStringArg};
|
||||||
use selectors::Element;
|
use selectors::Element;
|
||||||
use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator, CaseSensitivity, NamespaceConstraint};
|
use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator, CaseSensitivity, NamespaceConstraint};
|
||||||
use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode};
|
use selectors::matching::{ElementSelectorFlags, LocalMatchingContext, MatchingContext};
|
||||||
use selectors::matching::{RelevantLinkStatus, VisitedHandlingMode};
|
use selectors::matching::{RelevantLinkStatus, VisitedHandlingMode};
|
||||||
use shared_lock::Locked;
|
use shared_lock::Locked;
|
||||||
use sink::Push;
|
use sink::Push;
|
||||||
|
@ -1424,7 +1424,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
|
|
||||||
fn match_non_ts_pseudo_class<F>(&self,
|
fn match_non_ts_pseudo_class<F>(&self,
|
||||||
pseudo_class: &NonTSPseudoClass,
|
pseudo_class: &NonTSPseudoClass,
|
||||||
context: &mut MatchingContext,
|
context: &mut LocalMatchingContext<Self::Impl>,
|
||||||
relevant_link: &RelevantLinkStatus,
|
relevant_link: &RelevantLinkStatus,
|
||||||
flags_setter: &mut F)
|
flags_setter: &mut F)
|
||||||
-> bool
|
-> bool
|
||||||
|
@ -1432,10 +1432,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
{
|
{
|
||||||
use selectors::matching::*;
|
use selectors::matching::*;
|
||||||
match *pseudo_class {
|
match *pseudo_class {
|
||||||
NonTSPseudoClass::AnyLink |
|
|
||||||
NonTSPseudoClass::Active |
|
|
||||||
NonTSPseudoClass::Focus |
|
NonTSPseudoClass::Focus |
|
||||||
NonTSPseudoClass::Hover |
|
|
||||||
NonTSPseudoClass::Enabled |
|
NonTSPseudoClass::Enabled |
|
||||||
NonTSPseudoClass::Disabled |
|
NonTSPseudoClass::Disabled |
|
||||||
NonTSPseudoClass::Checked |
|
NonTSPseudoClass::Checked |
|
||||||
|
@ -1477,12 +1474,19 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
NonTSPseudoClass::MozMeterSubSubOptimum |
|
NonTSPseudoClass::MozMeterSubSubOptimum |
|
||||||
NonTSPseudoClass::MozAutofill |
|
NonTSPseudoClass::MozAutofill |
|
||||||
NonTSPseudoClass::MozAutofillPreview => {
|
NonTSPseudoClass::MozAutofillPreview => {
|
||||||
// NB: It's important to use `intersect` instead of `contains`
|
|
||||||
// here, to handle `:any-link` correctly.
|
|
||||||
self.get_state().intersects(pseudo_class.state_flag())
|
self.get_state().intersects(pseudo_class.state_flag())
|
||||||
},
|
},
|
||||||
NonTSPseudoClass::Link => relevant_link.is_unvisited(self, context),
|
NonTSPseudoClass::AnyLink => self.is_link(),
|
||||||
NonTSPseudoClass::Visited => relevant_link.is_visited(self, context),
|
NonTSPseudoClass::Link => relevant_link.is_unvisited(self, context.shared),
|
||||||
|
NonTSPseudoClass::Visited => relevant_link.is_visited(self, context.shared),
|
||||||
|
NonTSPseudoClass::Active |
|
||||||
|
NonTSPseudoClass::Hover => {
|
||||||
|
if context.active_hover_quirk_matches() && !self.is_link() {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
self.get_state().contains(pseudo_class.state_flag())
|
||||||
|
}
|
||||||
|
},
|
||||||
NonTSPseudoClass::MozFirstNode => {
|
NonTSPseudoClass::MozFirstNode => {
|
||||||
flags_setter(self, HAS_EDGE_CHILD_SELECTOR);
|
flags_setter(self, HAS_EDGE_CHILD_SELECTOR);
|
||||||
let mut elem = self.as_node();
|
let mut elem = self.as_node();
|
||||||
|
@ -1522,9 +1526,13 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
NonTSPseudoClass::MozPlaceholder => false,
|
NonTSPseudoClass::MozPlaceholder => false,
|
||||||
NonTSPseudoClass::MozAny(ref sels) => {
|
NonTSPseudoClass::MozAny(ref sels) => {
|
||||||
sels.iter().any(|s| {
|
let old_value = context.within_functional_pseudo_class_argument;
|
||||||
|
context.within_functional_pseudo_class_argument = true;
|
||||||
|
let result = sels.iter().any(|s| {
|
||||||
matches_complex_selector(s, 0, self, context, flags_setter)
|
matches_complex_selector(s, 0, self, context, flags_setter)
|
||||||
})
|
});
|
||||||
|
context.within_functional_pseudo_class_argument = old_value;
|
||||||
|
result
|
||||||
}
|
}
|
||||||
NonTSPseudoClass::Lang(ref lang_arg) => {
|
NonTSPseudoClass::Lang(ref lang_arg) => {
|
||||||
self.match_element_lang(None, lang_arg)
|
self.match_element_lang(None, lang_arg)
|
||||||
|
@ -1563,11 +1571,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_link(&self) -> bool {
|
fn is_link(&self) -> bool {
|
||||||
let mut context = MatchingContext::new(MatchingMode::Normal, None);
|
self.get_state().intersects(NonTSPseudoClass::AnyLink.state_flag())
|
||||||
self.match_non_ts_pseudo_class(&NonTSPseudoClass::AnyLink,
|
|
||||||
&mut context,
|
|
||||||
&RelevantLinkStatus::default(),
|
|
||||||
&mut |_, _| {})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_id(&self) -> Option<Atom> {
|
fn get_id(&self) -> Option<Atom> {
|
||||||
|
|
|
@ -1021,7 +1021,8 @@ pub trait MatchMethods : TElement {
|
||||||
let mut matching_context =
|
let mut matching_context =
|
||||||
MatchingContext::new_for_visited(MatchingMode::Normal,
|
MatchingContext::new_for_visited(MatchingMode::Normal,
|
||||||
Some(bloom_filter),
|
Some(bloom_filter),
|
||||||
visited_handling);
|
visited_handling,
|
||||||
|
context.shared.quirks_mode);
|
||||||
|
|
||||||
{
|
{
|
||||||
let smil_override = data.get_smil_override();
|
let smil_override = data.get_smil_override();
|
||||||
|
@ -1117,7 +1118,8 @@ pub trait MatchMethods : TElement {
|
||||||
let mut matching_context =
|
let mut matching_context =
|
||||||
MatchingContext::new_for_visited(MatchingMode::ForStatelessPseudoElement,
|
MatchingContext::new_for_visited(MatchingMode::ForStatelessPseudoElement,
|
||||||
Some(bloom_filter),
|
Some(bloom_filter),
|
||||||
visited_handling);
|
visited_handling,
|
||||||
|
context.shared.quirks_mode);
|
||||||
|
|
||||||
// Compute rule nodes for eagerly-cascaded pseudo-elements.
|
// Compute rule nodes for eagerly-cascaded pseudo-elements.
|
||||||
let mut matches_different_pseudos = false;
|
let mut matches_different_pseudos = false;
|
||||||
|
|
|
@ -20,7 +20,7 @@ use selector_map::{SelectorMap, SelectorMapEntry};
|
||||||
use selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl, Snapshot, SnapshotMap, AttrValue};
|
use selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl, Snapshot, SnapshotMap, AttrValue};
|
||||||
use selectors::Element;
|
use selectors::Element;
|
||||||
use selectors::attr::{AttrSelectorOperation, NamespaceConstraint};
|
use selectors::attr::{AttrSelectorOperation, NamespaceConstraint};
|
||||||
use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode};
|
use selectors::matching::{ElementSelectorFlags, LocalMatchingContext, MatchingContext, MatchingMode};
|
||||||
use selectors::matching::{RelevantLinkStatus, VisitedHandlingMode, matches_selector};
|
use selectors::matching::{RelevantLinkStatus, VisitedHandlingMode, matches_selector};
|
||||||
use selectors::parser::{AncestorHashes, Combinator, Component};
|
use selectors::parser::{AncestorHashes, Combinator, Component};
|
||||||
use selectors::parser::{Selector, SelectorAndHashes, SelectorIter, SelectorMethods};
|
use selectors::parser::{Selector, SelectorAndHashes, SelectorIter, SelectorMethods};
|
||||||
|
@ -664,7 +664,7 @@ impl<'a, E> Element for ElementWrapper<'a, E>
|
||||||
|
|
||||||
fn match_non_ts_pseudo_class<F>(&self,
|
fn match_non_ts_pseudo_class<F>(&self,
|
||||||
pseudo_class: &NonTSPseudoClass,
|
pseudo_class: &NonTSPseudoClass,
|
||||||
context: &mut MatchingContext,
|
context: &mut LocalMatchingContext<Self::Impl>,
|
||||||
relevant_link: &RelevantLinkStatus,
|
relevant_link: &RelevantLinkStatus,
|
||||||
_setter: &mut F)
|
_setter: &mut F)
|
||||||
-> bool
|
-> bool
|
||||||
|
@ -707,10 +707,10 @@ impl<'a, E> Element for ElementWrapper<'a, E>
|
||||||
// state directly. Instead, we use the `relevant_link` to determine if
|
// state directly. Instead, we use the `relevant_link` to determine if
|
||||||
// they match.
|
// they match.
|
||||||
NonTSPseudoClass::Link => {
|
NonTSPseudoClass::Link => {
|
||||||
return relevant_link.is_unvisited(self, context);
|
return relevant_link.is_unvisited(self, context.shared);
|
||||||
}
|
}
|
||||||
NonTSPseudoClass::Visited => {
|
NonTSPseudoClass::Visited => {
|
||||||
return relevant_link.is_visited(self, context);
|
return relevant_link.is_visited(self, context.shared);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
|
@ -767,11 +767,7 @@ impl<'a, E> Element for ElementWrapper<'a, E>
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_link(&self) -> bool {
|
fn is_link(&self) -> bool {
|
||||||
let mut context = MatchingContext::new(MatchingMode::Normal, None);
|
self.element.is_link()
|
||||||
self.match_non_ts_pseudo_class(&NonTSPseudoClass::AnyLink,
|
|
||||||
&mut context,
|
|
||||||
&RelevantLinkStatus::default(),
|
|
||||||
&mut |_, _| {})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parent_element(&self) -> Option<Self> {
|
fn parent_element(&self) -> Option<Self> {
|
||||||
|
@ -1202,7 +1198,8 @@ impl DependencySet {
|
||||||
// not clear we _need_ it right now.
|
// not clear we _need_ it right now.
|
||||||
let mut then_context =
|
let mut then_context =
|
||||||
MatchingContext::new_for_visited(MatchingMode::Normal, None,
|
MatchingContext::new_for_visited(MatchingMode::Normal, None,
|
||||||
VisitedHandlingMode::AllLinksUnvisited);
|
VisitedHandlingMode::AllLinksUnvisited,
|
||||||
|
shared_context.quirks_mode);
|
||||||
let matched_then =
|
let matched_then =
|
||||||
matches_selector(&dep.selector,
|
matches_selector(&dep.selector,
|
||||||
dep.selector_offset,
|
dep.selector_offset,
|
||||||
|
@ -1212,7 +1209,8 @@ impl DependencySet {
|
||||||
&mut |_, _| {});
|
&mut |_, _| {});
|
||||||
let mut now_context =
|
let mut now_context =
|
||||||
MatchingContext::new_for_visited(MatchingMode::Normal, bloom_filter,
|
MatchingContext::new_for_visited(MatchingMode::Normal, bloom_filter,
|
||||||
VisitedHandlingMode::AllLinksUnvisited);
|
VisitedHandlingMode::AllLinksUnvisited,
|
||||||
|
shared_context.quirks_mode);
|
||||||
let matches_now =
|
let matches_now =
|
||||||
matches_selector(&dep.selector,
|
matches_selector(&dep.selector,
|
||||||
dep.selector_offset,
|
dep.selector_offset,
|
||||||
|
|
|
@ -299,6 +299,12 @@ impl ::selectors::SelectorImpl for SelectorImpl {
|
||||||
type NamespaceUrl = Namespace;
|
type NamespaceUrl = Namespace;
|
||||||
type BorrowedLocalName = LocalName;
|
type BorrowedLocalName = LocalName;
|
||||||
type BorrowedNamespaceUrl = Namespace;
|
type BorrowedNamespaceUrl = Namespace;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_active_or_hover(pseudo_class: &Self::NonTSPseudoClass) -> bool {
|
||||||
|
matches!(*pseudo_class, NonTSPseudoClass::Active |
|
||||||
|
NonTSPseudoClass::Hover)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
|
impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
|
||||||
|
|
|
@ -88,6 +88,7 @@ pub struct Stylist {
|
||||||
effective_media_query_results: EffectiveMediaQueryResults,
|
effective_media_query_results: EffectiveMediaQueryResults,
|
||||||
|
|
||||||
/// If true, the quirks-mode stylesheet is applied.
|
/// If true, the quirks-mode stylesheet is applied.
|
||||||
|
#[cfg_attr(feature = "servo", ignore_heap_size_of = "defined in selectors")]
|
||||||
quirks_mode: QuirksMode,
|
quirks_mode: QuirksMode,
|
||||||
|
|
||||||
/// If true, the device has changed, and the stylist needs to be updated.
|
/// If true, the device has changed, and the stylist needs to be updated.
|
||||||
|
@ -735,7 +736,9 @@ impl Stylist {
|
||||||
// Bug 1364242: We need to add visited support for lazy pseudos
|
// Bug 1364242: We need to add visited support for lazy pseudos
|
||||||
let mut declarations = ApplicableDeclarationList::new();
|
let mut declarations = ApplicableDeclarationList::new();
|
||||||
let mut matching_context =
|
let mut matching_context =
|
||||||
MatchingContext::new(MatchingMode::ForStatelessPseudoElement, None);
|
MatchingContext::new(MatchingMode::ForStatelessPseudoElement,
|
||||||
|
None,
|
||||||
|
self.quirks_mode);
|
||||||
self.push_applicable_declarations(element,
|
self.push_applicable_declarations(element,
|
||||||
Some(&pseudo),
|
Some(&pseudo),
|
||||||
None,
|
None,
|
||||||
|
@ -927,7 +930,7 @@ impl Stylist {
|
||||||
V: Push<ApplicableDeclarationBlock> + VecLike<ApplicableDeclarationBlock>,
|
V: Push<ApplicableDeclarationBlock> + VecLike<ApplicableDeclarationBlock>,
|
||||||
{
|
{
|
||||||
let mut matching_context =
|
let mut matching_context =
|
||||||
MatchingContext::new(MatchingMode::Normal, None);
|
MatchingContext::new(MatchingMode::Normal, None, self.quirks_mode);
|
||||||
let mut dummy_flag_setter = |_: &E, _: ElementSelectorFlags| {};
|
let mut dummy_flag_setter = |_: &E, _: ElementSelectorFlags| {};
|
||||||
|
|
||||||
self.element_map.author.get_all_matching_rules(element,
|
self.element_map.author.get_all_matching_rules(element,
|
||||||
|
@ -1156,7 +1159,7 @@ impl Stylist {
|
||||||
// NB: `MatchingMode` doesn't really matter, given we don't share style
|
// NB: `MatchingMode` doesn't really matter, given we don't share style
|
||||||
// between pseudos.
|
// between pseudos.
|
||||||
let mut matching_context =
|
let mut matching_context =
|
||||||
MatchingContext::new(MatchingMode::Normal, bloom);
|
MatchingContext::new(MatchingMode::Normal, bloom, self.quirks_mode);
|
||||||
|
|
||||||
// Note that, by the time we're revalidating, we're guaranteed that the
|
// Note that, by the time we're revalidating, we're guaranteed that the
|
||||||
// candidate and the entry have the same id, classes, and local name.
|
// candidate and the entry have the same id, classes, and local name.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue