diff --git a/components/selectors/matching.rs b/components/selectors/matching.rs index 62cd7ee5448..252a1c11d10 100644 --- a/components/selectors/matching.rs +++ b/components/selectors/matching.rs @@ -532,8 +532,12 @@ fn matches_complex_selector_internal(mut selector_iter: SelectorIter { - (element.parent_element(), - SelectorMatchingResult::NotMatchedGlobally) + if element.blocks_ancestor_combinators() { + (None, SelectorMatchingResult::NotMatchedGlobally) + } else { + (element.parent_element(), + SelectorMatchingResult::NotMatchedGlobally) + } } Combinator::PseudoElement => { (element.pseudo_element_originating_element(), diff --git a/components/selectors/tree.rs b/components/selectors/tree.rs index 99c07c6bf3b..7827dc6bbe6 100644 --- a/components/selectors/tree.rs +++ b/components/selectors/tree.rs @@ -85,4 +85,11 @@ pub trait Element: Sized + Debug { /// Note: this can be false even if `.parent_element()` is `None` /// if the parent node is a `DocumentFragment`. fn is_root(&self) -> bool; + + /// Return true if we want to stop lookup ancestor of the current + /// element while matching complex selectors with descendant/child + /// combinator. + fn blocks_ancestor_combinators(&self) -> bool { + false + } } diff --git a/components/style/gecko/non_ts_pseudo_class_list.rs b/components/style/gecko/non_ts_pseudo_class_list.rs index a6c3549bafa..8beb8c98493 100644 --- a/components/style/gecko/non_ts_pseudo_class_list.rs +++ b/components/style/gecko/non_ts_pseudo_class_list.rs @@ -111,6 +111,7 @@ macro_rules! apply_non_ts_list { ("-moz-last-node", MozLastNode, lastNode, _, _), ("-moz-only-whitespace", MozOnlyWhitespace, mozOnlyWhitespace, _, _), ("-moz-native-anonymous", MozNativeAnonymous, mozNativeAnonymous, _, PSEUDO_CLASS_INTERNAL), + ("-moz-use-shadow-tree-root", MozUseShadowTreeRoot, mozUseShadowTreeRoot, _, PSEUDO_CLASS_INTERNAL), ("-moz-is-html", MozIsHTML, mozIsHTML, _, _), ("-moz-placeholder", MozPlaceholder, mozPlaceholder, _, _), ], diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 355863d94ba..937d1422e1d 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -1645,7 +1645,8 @@ impl<'le> ::selectors::Element for GeckoElement<'le> { } NonTSPseudoClass::MozTableBorderNonzero | NonTSPseudoClass::MozBrowserFrame | - NonTSPseudoClass::MozNativeAnonymous => unsafe { + NonTSPseudoClass::MozNativeAnonymous | + NonTSPseudoClass::MozUseShadowTreeRoot => unsafe { Gecko_MatchesElement(pseudo_class.to_gecko_pseudoclasstype().unwrap(), self.0) }, NonTSPseudoClass::MozIsHTML => { @@ -1734,6 +1735,24 @@ impl<'le> ::selectors::Element for GeckoElement<'le> { node_info.mInner.mNamespaceID == (structs::root::kNameSpaceID_XHTML as i32) && node.owner_doc().mType == structs::root::nsIDocument_Type::eHTML } + + fn blocks_ancestor_combinators(&self) -> bool { + use gecko_bindings::structs::NODE_IS_ANONYMOUS_ROOT; + if self.flags() & (NODE_IS_ANONYMOUS_ROOT as u32) == 0 { + return false + } + + match self.parent_element() { + Some(e) => { + // If this element is the shadow root of an use-element shadow + // tree, according to the spec, we should not match rules + // cross the shadow DOM boundary. + e.get_local_name().as_ptr() == atom!("use").as_ptr() && + e.get_namespace() == &*Namespace(atom!("http://www.w3.org/2000/svg")) + }, + None => false, + } + } } /// A few helpers to help with attribute selectors and snapshotting.