aboutsummaryrefslogtreecommitdiffstats
path: root/components/selectors/matching.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/selectors/matching.rs')
-rw-r--r--components/selectors/matching.rs50
1 files changed, 44 insertions, 6 deletions
diff --git a/components/selectors/matching.rs b/components/selectors/matching.rs
index 6cb9acf59fe..7244868285b 100644
--- a/components/selectors/matching.rs
+++ b/components/selectors/matching.rs
@@ -6,7 +6,7 @@ use attr::{ParsedAttrSelectorOperation, AttrSelectorOperation, NamespaceConstrai
use bloom::{BLOOM_HASH_MASK, BloomFilter};
use nth_index_cache::NthIndexCacheInner;
use parser::{AncestorHashes, Combinator, Component, LocalName};
-use parser::{Selector, SelectorImpl, SelectorIter, SelectorList};
+use parser::{Selector, SelectorImpl, SelectorIter, SelectorList, NonTSPseudoClass};
use std::borrow::Borrow;
use std::iter;
use tree::Element;
@@ -404,7 +404,7 @@ fn matches_hover_and_active_quirk<Impl: SelectorImpl>(
Component::LastOfType |
Component::OnlyOfType => false,
Component::NonTSPseudoClass(ref pseudo_class) => {
- Impl::is_active_or_hover(pseudo_class)
+ pseudo_class.is_active_or_hover()
},
_ => true,
}
@@ -427,6 +427,7 @@ enum Rightmost {
fn next_element_for_combinator<E>(
element: &E,
combinator: Combinator,
+ selector: &SelectorIter<E::Impl>,
) -> Option<E>
where
E: Element,
@@ -442,7 +443,42 @@ where
return None;
}
- element.parent_element()
+ match element.parent_element() {
+ Some(e) => return Some(e),
+ None => {}
+ }
+
+ if !element.parent_node_is_shadow_root() {
+ return None;
+ }
+
+ // https://drafts.csswg.org/css-scoping/#host-element-in-tree:
+ //
+ // For the purpose of Selectors, a shadow host also appears in
+ // its shadow tree, with the contents of the shadow tree treated
+ // as its children. (In other words, the shadow host is treated as
+ // replacing the shadow root node.)
+ //
+ // and also:
+ //
+ // When considered within its own shadow trees, the shadow host is
+ // featureless. Only the :host, :host(), and :host-context()
+ // pseudo-classes are allowed to match it.
+ //
+ // Since we know that the parent is a shadow root, we necessarily
+ // are in a shadow tree of the host.
+ let all_selectors_could_match = selector.clone().all(|component| {
+ match *component {
+ Component::NonTSPseudoClass(ref pc) => pc.is_host(),
+ _ => false,
+ }
+ });
+
+ if !all_selectors_could_match {
+ return None;
+ }
+
+ element.containing_shadow_host()
}
Combinator::SlotAssignment => {
debug_assert!(element.assigned_slot().map_or(true, |s| s.is_html_slot_element()));
@@ -502,7 +538,8 @@ where
}
};
- let mut next_element = next_element_for_combinator(element, combinator);
+ let mut next_element =
+ next_element_for_combinator(element, combinator, &selector_iter);
// Stop matching :visited as soon as we find a link, or a combinator for
// something that isn't an ancestor.
@@ -565,7 +602,8 @@ where
visited_handling = VisitedHandlingMode::AllLinksUnvisited;
}
- next_element = next_element_for_combinator(&element, combinator);
+ next_element =
+ next_element_for_combinator(&element, combinator, &selector_iter);
}
}
@@ -753,7 +791,7 @@ where
Component::NonTSPseudoClass(ref pc) => {
if context.matches_hover_and_active_quirk == MatchesHoverAndActiveQuirk::Yes &&
!context.shared.is_nested() &&
- E::Impl::is_active_or_hover(pc) &&
+ pc.is_active_or_hover() &&
!element.is_link()
{
return false;