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
--- 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.