Bug 265894 - Part 15. (Stylo) Fix counterpart of Part 8 and Part 9 in stylo. draft
authorcku <cku@mozilla.com>
Thu, 15 Jun 2017 00:45:49 +0800
changeset 597095 2f5b82accc83a54037719cc06fb7f00c7f39941a
parent 597094 240b453e62a3db3ce8f0e9123a68110091ddc6c0
child 634134 b69cd2a401de626a9f1fbaa3f3c01fbb49aa266c
push id64828
push userbmo:cku@mozilla.com
push dateTue, 20 Jun 2017 04:17:06 +0000
bugs265894
milestone56.0a1
Bug 265894 - Part 15. (Stylo) Fix counterpart of Part 8 and Part 9 in stylo. MozReview-Commit-ID: 95ObxsatgbM
servo/components/selectors/matching.rs
servo/components/selectors/tree.rs
servo/components/style/gecko/non_ts_pseudo_class_list.rs
servo/components/style/gecko/wrapper.rs
--- a/servo/components/selectors/matching.rs
+++ b/servo/components/selectors/matching.rs
@@ -527,18 +527,22 @@ fn matches_complex_selector_internal<E, 
                 Combinator::NextSibling | Combinator::LaterSibling => {
                     // Only ancestor combinators are allowed while looking for
                     // relevant links, so switch to not looking.
                     *relevant_link = RelevantLinkStatus::NotLooking;
                     (element.prev_sibling_element(),
                      SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant)
                 }
                 Combinator::Child | Combinator::Descendant => {
-                    (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(),
                      SelectorMatchingResult::NotMatchedGlobally)
                 }
             };
 
             loop {
--- a/servo/components/selectors/tree.rs
+++ b/servo/components/selectors/tree.rs
@@ -80,9 +80,16 @@ pub trait Element: Sized + Debug {
     fn is_empty(&self) -> bool;
 
     /// Returns whether this element matches `:root`,
     /// i.e. whether it is the root element of a document.
     ///
     /// 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
+    }
 }
--- a/servo/components/style/gecko/non_ts_pseudo_class_list.rs
+++ b/servo/components/style/gecko/non_ts_pseudo_class_list.rs
@@ -102,16 +102,17 @@ macro_rules! apply_non_ts_list {
                 ("-moz-meter-sub-sub-optimum", MozMeterSubSubOptimum, mozMeterSubSubOptimum, IN_SUB_SUB_OPTIMUM_STATE, _),
 
                 ("-moz-user-disabled", MozUserDisabled, mozUserDisabled, IN_USER_DISABLED_STATE, PSEUDO_CLASS_INTERNAL),
 
                 ("-moz-first-node", MozFirstNode, firstNode, _, _),
                 ("-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, _, _),
             ],
             string: [
                 ("-moz-system-metric", MozSystemMetric, mozSystemMetric, _, PSEUDO_CLASS_INTERNAL),
                 ("-moz-empty-except-children-with-localname", MozEmptyExceptChildrenWithLocalname,
                  mozEmptyExceptChildrenWithLocalname, _, PSEUDO_CLASS_INTERNAL),
                 ("lang", Lang, lang, _, _),
--- a/servo/components/style/gecko/wrapper.rs
+++ b/servo/components/style/gecko/wrapper.rs
@@ -1558,17 +1558,18 @@ impl<'le> ::selectors::Element for Gecko
                 flags_setter(self, HAS_EMPTY_SELECTOR);
                 if self.as_node().dom_children().any(|c| c.contains_non_whitespace_content()) {
                     return false
                 }
                 true
             }
             NonTSPseudoClass::MozTableBorderNonzero |
             NonTSPseudoClass::MozBrowserFrame |
-            NonTSPseudoClass::MozNativeAnonymous => unsafe {
+            NonTSPseudoClass::MozNativeAnonymous |
+            NonTSPseudoClass::MozUseShadowTreeRoot => unsafe {
                 Gecko_MatchesElement(pseudo_class.to_gecko_pseudoclasstype().unwrap(), self.0)
             },
             NonTSPseudoClass::MozIsHTML => {
                 self.is_html_element_in_html_document()
             }
             NonTSPseudoClass::MozPlaceholder => false,
             NonTSPseudoClass::MozAny(ref sels) => {
                 let old_value = context.hover_active_quirk_disabled;
@@ -1647,16 +1648,34 @@ impl<'le> ::selectors::Element for Gecko
     }
 
     fn is_html_element_in_html_document(&self) -> bool {
         let node = self.as_node();
         let node_info = node.node_info();
         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.
 pub trait NamespaceConstraintHelpers {
     /// Returns the namespace of the selector, or null otherwise.
     fn atom_or_null(&self) -> *mut nsIAtom;
 }