Auto merge of #19024 - emilio:document, r=KiChjang

Introduce style::dom::TDocument.

The secret plan is introducing a `get_elements_with_id` for use by `querySelector` / `querySelectorAll`.

But this allows also to make some code look a bit nicer.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/19024)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-10-26 07:51:21 -05:00 committed by GitHub
commit ee4e371c73
6 changed files with 117 additions and 47 deletions

View file

@ -51,7 +51,7 @@ use script_layout_interface::{OpaqueStyleAndLayoutData, StyleData};
use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, GetLayoutData, LayoutNode}; use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, GetLayoutData, LayoutNode};
use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode}; use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
use selectors::attr::{AttrSelectorOperation, NamespaceConstraint, CaseSensitivity}; use selectors::attr::{AttrSelectorOperation, NamespaceConstraint, CaseSensitivity};
use selectors::matching::{ElementSelectorFlags, MatchingContext, RelevantLinkStatus}; use selectors::matching::{ElementSelectorFlags, MatchingContext, QuirksMode, RelevantLinkStatus};
use selectors::matching::VisitedHandlingMode; use selectors::matching::VisitedHandlingMode;
use selectors::sink::Push; use selectors::sink::Push;
use servo_arc::{Arc, ArcBorrow}; use servo_arc::{Arc, ArcBorrow};
@ -69,7 +69,7 @@ use style::computed_values::display;
use style::context::SharedStyleContext; use style::context::SharedStyleContext;
use style::data::ElementData; use style::data::ElementData;
use style::dom::{DomChildren, LayoutIterator, NodeInfo, OpaqueNode}; use style::dom::{DomChildren, LayoutIterator, NodeInfo, OpaqueNode};
use style::dom::{TElement, TNode}; use style::dom::{TDocument, TElement, TNode};
use style::element_state::*; use style::element_state::*;
use style::font_metrics::ServoMetricsProvider; use style::font_metrics::ServoMetricsProvider;
use style::properties::{ComputedValues, PropertyDeclarationBlock}; use style::properties::{ComputedValues, PropertyDeclarationBlock};
@ -139,10 +139,6 @@ impl<'ln> ServoLayoutNode<'ln> {
self.node.type_id_for_layout() self.node.type_id_for_layout()
} }
} }
pub fn as_document(&self) -> Option<ServoLayoutDocument<'ln>> {
self.node.downcast().map(ServoLayoutDocument::from_layout_js)
}
} }
impl<'ln> NodeInfo for ServoLayoutNode<'ln> { impl<'ln> NodeInfo for ServoLayoutNode<'ln> {
@ -158,6 +154,7 @@ impl<'ln> NodeInfo for ServoLayoutNode<'ln> {
} }
impl<'ln> TNode for ServoLayoutNode<'ln> { impl<'ln> TNode for ServoLayoutNode<'ln> {
type ConcreteDocument = ServoLayoutDocument<'ln>;
type ConcreteElement = ServoLayoutElement<'ln>; type ConcreteElement = ServoLayoutElement<'ln>;
fn parent_node(&self) -> Option<Self> { fn parent_node(&self) -> Option<Self> {
@ -190,6 +187,10 @@ impl<'ln> TNode for ServoLayoutNode<'ln> {
} }
} }
fn owner_doc(&self) -> Self::ConcreteDocument {
ServoLayoutDocument::from_layout_js(unsafe { self.node.owner_doc_for_layout() })
}
fn traversal_parent(&self) -> Option<ServoLayoutElement<'ln>> { fn traversal_parent(&self) -> Option<ServoLayoutElement<'ln>> {
self.parent_element() self.parent_element()
} }
@ -206,6 +207,10 @@ impl<'ln> TNode for ServoLayoutNode<'ln> {
as_element(self.node) as_element(self.node)
} }
fn as_document(&self) -> Option<ServoLayoutDocument<'ln>> {
self.node.downcast().map(ServoLayoutDocument::from_layout_js)
}
fn can_be_fragmented(&self) -> bool { fn can_be_fragmented(&self) -> bool {
unsafe { self.node.get_flag(CAN_BE_FRAGMENTED) } unsafe { self.node.get_flag(CAN_BE_FRAGMENTED) }
} }
@ -287,11 +292,23 @@ pub struct ServoLayoutDocument<'ld> {
chain: PhantomData<&'ld ()>, chain: PhantomData<&'ld ()>,
} }
impl<'ld> ServoLayoutDocument<'ld> { impl<'ld> TDocument for ServoLayoutDocument<'ld> {
fn as_node(&self) -> ServoLayoutNode<'ld> { type ConcreteNode = ServoLayoutNode<'ld>;
fn as_node(&self) -> Self::ConcreteNode {
ServoLayoutNode::from_layout_js(self.document.upcast()) ServoLayoutNode::from_layout_js(self.document.upcast())
} }
fn quirks_mode(&self) -> QuirksMode {
unsafe { self.document.quirks_mode() }
}
fn is_html_document(&self) -> bool {
unsafe { self.document.is_html_document_for_layout() }
}
}
impl<'ld> ServoLayoutDocument<'ld> {
pub fn root_element(&self) -> Option<ServoLayoutElement<'ld>> { pub fn root_element(&self) -> Option<ServoLayoutElement<'ld>> {
self.as_node().dom_children().flat_map(|n| n.as_element()).next() self.as_node().dom_children().flat_map(|n| n.as_element()).next()
} }
@ -773,8 +790,12 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
fn is_html_element_in_html_document(&self) -> bool { fn is_html_element_in_html_document(&self) -> bool {
unsafe { unsafe {
self.element.html_element_in_html_document_for_layout() if !self.element.is_html_element() {
return false;
}
} }
self.as_node().owner_doc().is_html_document()
} }
} }

View file

@ -446,7 +446,7 @@ pub trait LayoutElementHelpers {
#[allow(unsafe_code)] #[allow(unsafe_code)]
unsafe fn get_rowspan(self) -> u32; unsafe fn get_rowspan(self) -> u32;
#[allow(unsafe_code)] #[allow(unsafe_code)]
unsafe fn html_element_in_html_document_for_layout(&self) -> bool; unsafe fn is_html_element(&self) -> bool;
fn id_attribute(&self) -> *const Option<Atom>; fn id_attribute(&self) -> *const Option<Atom>;
fn style_attribute(&self) -> *const Option<Arc<Locked<PropertyDeclarationBlock>>>; fn style_attribute(&self) -> *const Option<Arc<Locked<PropertyDeclarationBlock>>>;
fn local_name(&self) -> &LocalName; fn local_name(&self) -> &LocalName;
@ -781,11 +781,8 @@ impl LayoutElementHelpers for LayoutDom<Element> {
#[inline] #[inline]
#[allow(unsafe_code)] #[allow(unsafe_code)]
unsafe fn html_element_in_html_document_for_layout(&self) -> bool { unsafe fn is_html_element(&self) -> bool {
if (*self.unsafe_get()).namespace != ns!(html) { (*self.unsafe_get()).namespace == ns!(html)
return false;
}
self.upcast::<Node>().owner_doc_for_layout().is_html_document_for_layout()
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]

View file

@ -22,7 +22,7 @@ use properties::{AnimationRules, ComputedValues, PropertyDeclarationBlock};
use rule_tree::CascadeLevel; use rule_tree::CascadeLevel;
use selector_parser::{AttrValue, PseudoClassStringArg, PseudoElement, SelectorImpl}; use selector_parser::{AttrValue, PseudoClassStringArg, PseudoElement, SelectorImpl};
use selectors::Element as SelectorsElement; use selectors::Element as SelectorsElement;
use selectors::matching::{ElementSelectorFlags, VisitedHandlingMode}; use selectors::matching::{ElementSelectorFlags, QuirksMode, VisitedHandlingMode};
use selectors::sink::Push; use selectors::sink::Push;
use servo_arc::{Arc, ArcBorrow}; use servo_arc::{Arc, ArcBorrow};
use shared_lock::Locked; use shared_lock::Locked;
@ -133,12 +133,30 @@ where
} }
} }
/// The `TDocument` trait, to represent a document node.
pub trait TDocument : Sized + Copy + Clone {
/// The concrete `TNode` type.
type ConcreteNode: TNode<ConcreteDocument = Self>;
/// Get this document as a `TNode`.
fn as_node(&self) -> Self::ConcreteNode;
/// Returns whether this document is an HTML document.
fn is_html_document(&self) -> bool;
/// Returns the quirks mode of this document.
fn quirks_mode(&self) -> QuirksMode;
}
/// The `TNode` trait. This is the main generic trait over which the style /// The `TNode` trait. This is the main generic trait over which the style
/// system can be implemented. /// system can be implemented.
pub trait TNode : Sized + Copy + Clone + Debug + NodeInfo + PartialEq { pub trait TNode : Sized + Copy + Clone + Debug + NodeInfo + PartialEq {
/// The concrete `TElement` type. /// The concrete `TElement` type.
type ConcreteElement: TElement<ConcreteNode = Self>; type ConcreteElement: TElement<ConcreteNode = Self>;
/// The concrete `TDocument` type.
type ConcreteDocument: TDocument<ConcreteNode = Self>;
/// Get this node's parent node. /// Get this node's parent node.
fn parent_node(&self) -> Option<Self>; fn parent_node(&self) -> Option<Self>;
@ -154,6 +172,9 @@ pub trait TNode : Sized + Copy + Clone + Debug + NodeInfo + PartialEq {
/// Get this node's next sibling. /// Get this node's next sibling.
fn next_sibling(&self) -> Option<Self>; fn next_sibling(&self) -> Option<Self>;
/// Get the owner document of this node.
fn owner_doc(&self) -> Self::ConcreteDocument;
/// Iterate over the DOM children of a node. /// Iterate over the DOM children of a node.
fn dom_children(&self) -> DomChildren<Self> { fn dom_children(&self) -> DomChildren<Self> {
DomChildren(self.first_child()) DomChildren(self.first_child())
@ -211,6 +232,9 @@ pub trait TNode : Sized + Copy + Clone + Debug + NodeInfo + PartialEq {
/// Get this node as an element, if it's one. /// Get this node as an element, if it's one.
fn as_element(&self) -> Option<Self::ConcreteElement>; fn as_element(&self) -> Option<Self::ConcreteElement>;
/// Get this node as a document, if it's one.
fn as_document(&self) -> Option<Self::ConcreteDocument>;
/// Whether this node can be fragmented. This is used for multicol, and only /// Whether this node can be fragmented. This is used for multicol, and only
/// for Servo. /// for Servo.
fn can_be_fragmented(&self) -> bool; fn can_be_fragmented(&self) -> bool;

View file

@ -6,7 +6,7 @@
//! and Gecko. //! and Gecko.
use context::QuirksMode; use context::QuirksMode;
use dom::{TElement, TNode}; use dom::{TDocument, TElement, TNode};
use invalidation::element::invalidator::{Invalidation, InvalidationProcessor, InvalidationVector}; use invalidation::element::invalidator::{Invalidation, InvalidationProcessor, InvalidationVector};
use selectors::{Element, NthIndexCache, SelectorList}; use selectors::{Element, NthIndexCache, SelectorList};
use selectors::matching::{self, MatchingContext, MatchingMode}; use selectors::matching::{self, MatchingContext, MatchingMode};
@ -308,7 +308,6 @@ pub fn query_selector<E, Q>(
root: E::ConcreteNode, root: E::ConcreteNode,
selector_list: &SelectorList<E::Impl>, selector_list: &SelectorList<E::Impl>,
results: &mut Q::Output, results: &mut Q::Output,
quirks_mode: QuirksMode,
) )
where where
E: TElement, E: TElement,
@ -316,6 +315,7 @@ where
{ {
use invalidation::element::invalidator::TreeStyleInvalidator; use invalidation::element::invalidator::TreeStyleInvalidator;
let quirks_mode = root.owner_doc().quirks_mode();
let fast_result = query_selector_fast::<E, Q>( let fast_result = query_selector_fast::<E, Q>(
root, root,
selector_list, selector_list,

View file

@ -20,7 +20,7 @@ use applicable_declarations::ApplicableDeclarationBlock;
use atomic_refcell::{AtomicRefCell, AtomicRef, AtomicRefMut}; use atomic_refcell::{AtomicRefCell, AtomicRef, AtomicRefMut};
use context::{QuirksMode, SharedStyleContext, PostAnimationTasks, UpdateAnimationsTasks}; use context::{QuirksMode, SharedStyleContext, PostAnimationTasks, UpdateAnimationsTasks};
use data::ElementData; use data::ElementData;
use dom::{LayoutIterator, NodeInfo, OpaqueNode, TElement, TNode}; use dom::{LayoutIterator, NodeInfo, OpaqueNode, TElement, TDocument, TNode};
use element_state::{ElementState, DocumentState, NS_DOCUMENT_STATE_WINDOW_INACTIVE}; use element_state::{ElementState, DocumentState, NS_DOCUMENT_STATE_WINDOW_INACTIVE};
use error_reporting::ParseErrorReporter; use error_reporting::ParseErrorReporter;
use font_metrics::{FontMetrics, FontMetricsProvider, FontMetricsQueryResult}; use font_metrics::{FontMetrics, FontMetricsProvider, FontMetricsQueryResult};
@ -92,6 +92,26 @@ use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
use stylesheets::UrlExtraData; use stylesheets::UrlExtraData;
use stylist::Stylist; use stylist::Stylist;
/// A simple wrapper over `nsIDocument`.
#[derive(Clone, Copy)]
pub struct GeckoDocument<'ld>(pub &'ld structs::nsIDocument);
impl<'ld> TDocument for GeckoDocument<'ld> {
type ConcreteNode = GeckoNode<'ld>;
fn as_node(&self) -> Self::ConcreteNode {
GeckoNode(&self.0._base)
}
fn is_html_document(&self) -> bool {
self.0.mType == structs::root::nsIDocument_Type::eHTML
}
fn quirks_mode(&self) -> QuirksMode {
self.0.mCompatMode.into()
}
}
/// A simple wrapper over a non-null Gecko node (`nsINode`) pointer. /// A simple wrapper over a non-null Gecko node (`nsINode`) pointer.
/// ///
/// Important: We don't currently refcount the DOM, because the wrapper lifetime /// Important: We don't currently refcount the DOM, because the wrapper lifetime
@ -124,6 +144,13 @@ impl<'ln> fmt::Debug for GeckoNode<'ln> {
} }
impl<'ln> GeckoNode<'ln> { impl<'ln> GeckoNode<'ln> {
#[inline]
fn is_document(&self) -> bool {
// This is a DOM constant that isn't going to change.
const DOCUMENT_NODE: u16 = 9;
self.node_info().mInner.mNodeType == DOCUMENT_NODE
}
#[inline] #[inline]
fn from_content(content: &'ln nsIContent) -> Self { fn from_content(content: &'ln nsIContent) -> Self {
GeckoNode(&content._base) GeckoNode(&content._base)
@ -153,22 +180,11 @@ impl<'ln> GeckoNode<'ln> {
(self.0).mBoolFlags (self.0).mBoolFlags
} }
/// Owner document quirks mode getter.
#[inline]
pub fn owner_document_quirks_mode(&self) -> QuirksMode {
self.owner_doc().mCompatMode.into()
}
#[inline] #[inline]
fn get_bool_flag(&self, flag: nsINode_BooleanFlag) -> bool { fn get_bool_flag(&self, flag: nsINode_BooleanFlag) -> bool {
self.bool_flags() & (1u32 << flag as u32) != 0 self.bool_flags() & (1u32 << flag as u32) != 0
} }
fn owner_doc(&self) -> &structs::nsIDocument {
debug_assert!(!self.node_info().mDocument.is_null());
unsafe { &*self.node_info().mDocument }
}
/// WARNING: This logic is duplicated in Gecko's FlattenedTreeParentIsParent. /// WARNING: This logic is duplicated in Gecko's FlattenedTreeParentIsParent.
/// Make sure to mirror any modifications in both places. /// Make sure to mirror any modifications in both places.
fn flattened_tree_parent_is_parent(&self) -> bool { fn flattened_tree_parent_is_parent(&self) -> bool {
@ -223,6 +239,7 @@ impl<'ln> NodeInfo for GeckoNode<'ln> {
} }
impl<'ln> TNode for GeckoNode<'ln> { impl<'ln> TNode for GeckoNode<'ln> {
type ConcreteDocument = GeckoDocument<'ln>;
type ConcreteElement = GeckoElement<'ln>; type ConcreteElement = GeckoElement<'ln>;
fn parent_node(&self) -> Option<Self> { fn parent_node(&self) -> Option<Self> {
@ -249,6 +266,12 @@ impl<'ln> TNode for GeckoNode<'ln> {
unsafe { self.0.mNextSibling.as_ref().map(GeckoNode::from_content) } unsafe { self.0.mNextSibling.as_ref().map(GeckoNode::from_content) }
} }
#[inline]
fn owner_doc(&self) -> Self::ConcreteDocument {
debug_assert!(!self.node_info().mDocument.is_null());
GeckoDocument(unsafe { &*self.node_info().mDocument })
}
fn traversal_parent(&self) -> Option<GeckoElement<'ln>> { fn traversal_parent(&self) -> Option<GeckoElement<'ln>> {
self.flattened_tree_parent().and_then(|n| n.as_element()) self.flattened_tree_parent().and_then(|n| n.as_element())
} }
@ -271,6 +294,15 @@ impl<'ln> TNode for GeckoNode<'ln> {
} }
} }
#[inline]
fn as_document(&self) -> Option<Self::ConcreteDocument> {
if self.is_document() {
Some(self.owner_doc())
} else {
None
}
}
fn can_be_fragmented(&self) -> bool { fn can_be_fragmented(&self) -> bool {
// FIXME(SimonSapin): Servo uses this to implement CSS multicol / fragmentation // FIXME(SimonSapin): Servo uses this to implement CSS multicol / fragmentation
// Maybe this isnt useful for Gecko? // Maybe this isnt useful for Gecko?
@ -596,7 +628,7 @@ impl<'le> GeckoElement<'le> {
fn document_state(&self) -> DocumentState { fn document_state(&self) -> DocumentState {
let node = self.as_node(); let node = self.as_node();
unsafe { unsafe {
let states = Gecko_DocumentState(node.owner_doc()); let states = Gecko_DocumentState(node.owner_doc().0);
DocumentState::from_bits_truncate(states) DocumentState::from_bits_truncate(states)
} }
} }
@ -632,13 +664,7 @@ impl<'le> GeckoElement<'le> {
#[inline] #[inline]
fn get_document_theme(&self) -> DocumentTheme { fn get_document_theme(&self) -> DocumentTheme {
let node = self.as_node(); let node = self.as_node();
unsafe { Gecko_GetDocumentLWTheme(node.owner_doc()) } unsafe { Gecko_GetDocumentLWTheme(node.owner_doc().0) }
}
/// Owner document quirks mode getter.
#[inline]
pub fn owner_document_quirks_mode(&self) -> QuirksMode {
self.as_node().owner_document_quirks_mode()
} }
/// Only safe to call on the main thread, with exclusive access to the element and /// Only safe to call on the main thread, with exclusive access to the element and
@ -949,7 +975,7 @@ impl<'le> TElement for GeckoElement<'le> {
} }
fn owner_doc_matches_for_testing(&self, device: &Device) -> bool { fn owner_doc_matches_for_testing(&self, device: &Device) -> bool {
self.as_node().owner_doc() as *const structs::nsIDocument == self.as_node().owner_doc().0 as *const structs::nsIDocument ==
device.pres_context().mDocument.raw::<structs::nsIDocument>() device.pres_context().mDocument.raw::<structs::nsIDocument>()
} }
@ -1584,7 +1610,7 @@ impl<'le> TElement for GeckoElement<'le> {
if self.get_local_name().as_ptr() == atom!("th").as_ptr() { if self.get_local_name().as_ptr() == atom!("th").as_ptr() {
hints.push(TH_RULE.clone()); hints.push(TH_RULE.clone());
} else if self.get_local_name().as_ptr() == atom!("table").as_ptr() && } else if self.get_local_name().as_ptr() == atom!("table").as_ptr() &&
self.as_node().owner_doc().mCompatMode == structs::nsCompatibility::eCompatibility_NavQuirks { self.as_node().owner_doc().quirks_mode() == QuirksMode::Quirks {
hints.push(TABLE_COLOR_RULE.clone()); hints.push(TABLE_COLOR_RULE.clone());
} }
} }
@ -2031,7 +2057,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
fn is_html_element_in_html_document(&self) -> bool { fn is_html_element_in_html_document(&self) -> bool {
self.is_html_element() && self.is_html_element() &&
self.as_node().owner_doc().mType == structs::root::nsIDocument_Type::eHTML self.as_node().owner_doc().is_html_document()
} }
fn ignores_nth_child_selectors(&self) -> bool { fn ignores_nth_child_selectors(&self) -> bool {

View file

@ -19,7 +19,7 @@ use style::applicable_declarations::ApplicableDeclarationBlock;
use style::context::{CascadeInputs, QuirksMode, SharedStyleContext, StyleContext}; use style::context::{CascadeInputs, QuirksMode, SharedStyleContext, StyleContext};
use style::context::ThreadLocalStyleContext; use style::context::ThreadLocalStyleContext;
use style::data::{ElementStyles, self}; use style::data::{ElementStyles, self};
use style::dom::{ShowSubtreeData, TElement, TNode}; use style::dom::{ShowSubtreeData, TDocument, TElement, TNode};
use style::driver; use style::driver;
use style::element_state::{DocumentState, ElementState}; use style::element_state::{DocumentState, ElementState};
use style::error_reporting::{NullReporter, ParseErrorReporter}; use style::error_reporting::{NullReporter, ParseErrorReporter};
@ -1577,7 +1577,9 @@ pub extern "C" fn Servo_StyleRule_SelectorMatchesElement(rule: RawServoStyleRule
}; };
let element = GeckoElement(element); let element = GeckoElement(element);
let mut ctx = MatchingContext::new(matching_mode, None, None, element.owner_document_quirks_mode()); let quirks_mode = element.as_node().owner_doc().quirks_mode();
let mut ctx =
MatchingContext::new(matching_mode, None, None, quirks_mode);
matches_selector(selector, 0, None, &element, &mut ctx, &mut |_, _| {}) matches_selector(selector, 0, None, &element, &mut ctx, &mut |_, _| {})
}) })
} }
@ -1591,9 +1593,10 @@ pub unsafe extern "C" fn Servo_SelectorList_Closest(
use style::dom_apis; use style::dom_apis;
let element = GeckoElement(element); let element = GeckoElement(element);
let quirks_mode = element.as_node().owner_doc().quirks_mode();
let selectors = ::selectors::SelectorList::from_ffi(selectors).borrow(); let selectors = ::selectors::SelectorList::from_ffi(selectors).borrow();
dom_apis::element_closest(element, &selectors, element.owner_document_quirks_mode()) dom_apis::element_closest(element, &selectors, quirks_mode)
.map_or(ptr::null(), |e| e.0) .map_or(ptr::null(), |e| e.0)
} }
@ -1606,11 +1609,12 @@ pub unsafe extern "C" fn Servo_SelectorList_Matches(
use style::dom_apis; use style::dom_apis;
let element = GeckoElement(element); let element = GeckoElement(element);
let quirks_mode = element.as_node().owner_doc().quirks_mode();
let selectors = ::selectors::SelectorList::from_ffi(selectors).borrow(); let selectors = ::selectors::SelectorList::from_ffi(selectors).borrow();
dom_apis::element_matches( dom_apis::element_matches(
&element, &element,
&selectors, &selectors,
element.owner_document_quirks_mode(), quirks_mode,
) )
} }
@ -1629,7 +1633,6 @@ pub unsafe extern "C" fn Servo_SelectorList_QueryFirst(
node, node,
&selectors, &selectors,
&mut result, &mut result,
node.owner_document_quirks_mode(),
); );
result.map_or(ptr::null(), |e| e.0) result.map_or(ptr::null(), |e| e.0)
@ -1653,7 +1656,6 @@ pub unsafe extern "C" fn Servo_SelectorList_QueryAll(
node, node,
&selectors, &selectors,
&mut result, &mut result,
node.owner_document_quirks_mode(),
); );
if !result.is_empty() { if !result.is_empty() {