style: Skip matching :nth-child if element is the root of anonymous subtree draft
authorTing-Yu Lin <tlin@mozilla.com>
Tue, 15 Aug 2017 20:35:08 +0800
changeset 646590 2e1b7774807c6bad782ed1c0c048033d821d4b8a
parent 646498 564e82f0f289af976da01c2d50507017bbc152b5
child 646591 ea8aa9e1e3fb6e10b661bfca30b56ce06529230b
push id74182
push userbmo:tlin@mozilla.com
push dateTue, 15 Aug 2017 14:40:10 +0000
milestone57.0a1
style: Skip matching :nth-child if element is the root of anonymous subtree This implement the logic in Gecko's nsNthIndexCache::GetNthIndex(). MozReview-Commit-ID: 8lzK9iIbfzo
servo/components/selectors/matching.rs
servo/components/selectors/tree.rs
servo/components/style/gecko/wrapper.rs
--- a/servo/components/selectors/matching.rs
+++ b/servo/components/selectors/matching.rs
@@ -771,16 +771,20 @@ fn matches_generic_nth_child<E, F>(eleme
                                    b: i32,
                                    is_of_type: bool,
                                    is_from_end: bool,
                                    flags_setter: &mut F)
                                    -> bool
     where E: Element,
           F: FnMut(&E, ElementSelectorFlags),
 {
+    if element.is_root_of_anonymous_subtree() {
+        return false;
+    }
+
     flags_setter(element, if is_from_end {
         HAS_SLOW_SELECTOR
     } else {
         HAS_SLOW_SELECTOR_LATER_SIBLINGS
     });
 
     let mut index: i32 = 1;
     let mut next_sibling = if is_from_end {
--- a/servo/components/selectors/tree.rs
+++ b/servo/components/selectors/tree.rs
@@ -81,15 +81,21 @@ pub trait Element: Sized + Debug {
 
     /// 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;
 
+    /// Returns true if this element is the root of anonymous subtree (only
+    /// Gecko has anonymous elements).
+    fn is_root_of_anonymous_subtree(&self) -> bool {
+        false
+    }
+
     /// 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/wrapper.rs
+++ b/servo/components/style/gecko/wrapper.rs
@@ -1954,19 +1954,24 @@ 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 {
+    /// This logic is duplicated in Gecko's nsIContent::IsRootOfAnonymousSubtree.
+    fn is_root_of_anonymous_subtree(&self) -> bool {
         use gecko_bindings::structs::NODE_IS_ANONYMOUS_ROOT;
-        if self.flags() & (NODE_IS_ANONYMOUS_ROOT as u32) == 0 {
+        self.flags() & (NODE_IS_ANONYMOUS_ROOT as u32) != 0
+    }
+
+    fn blocks_ancestor_combinators(&self) -> bool {
+        if !self.is_root_of_anonymous_subtree() {
             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.