--- a/servo/components/style/dom_apis.rs
+++ b/servo/components/style/dom_apis.rs
@@ -4,16 +4,17 @@
//! Generic implementations of some DOM APIs so they can be shared between Servo
//! and Gecko.
use context::QuirksMode;
use dom::{TDocument, TElement, TNode};
use invalidation::element::invalidator::{Invalidation, InvalidationProcessor, InvalidationVector};
use selectors::{Element, NthIndexCache, SelectorList};
+use selectors::attr::CaseSensitivity;
use selectors::matching::{self, MatchingContext, MatchingMode};
use selectors::parser::{Component, LocalName};
use smallvec::SmallVec;
use std::borrow::Borrow;
/// <https://dom.spec.whatwg.org/#dom-element-matches>
pub fn element_matches<E>(
element: &E,
@@ -215,16 +216,33 @@ where
Q::append_element(results, element);
if Q::should_stop_after_first_match() {
return;
}
}
}
+/// Returns whether a given element is descendant of a given `root` node.
+///
+/// NOTE(emilio): if root == element, this returns false.
+fn element_is_descendant_of<E>(element: E, root: E::ConcreteNode) -> bool
+where
+ E: TElement,
+{
+ let mut current = element.as_node().parent_node();
+ while let Some(n) = current.take() {
+ if n == root {
+ return true;
+ }
+
+ current = n.parent_node();
+ }
+ false
+}
/// Fast paths for querySelector with a single simple selector.
fn query_selector_single_query<E, Q>(
root: E::ConcreteNode,
component: &Component<E::Impl>,
results: &mut Q::Output,
quirks_mode: QuirksMode,
) -> Result<(), ()>
@@ -232,18 +250,46 @@ where
E: TElement,
Q: SelectorQuery<E>,
{
match *component {
Component::ExplicitUniversalType => {
collect_all_elements::<E, Q, _>(root, results, |_| true)
}
Component::ID(ref id) => {
- // TODO(emilio): We may want to reuse Gecko's document ID table.
let case_sensitivity = quirks_mode.classes_and_ids_case_sensitivity();
+
+ if case_sensitivity == CaseSensitivity::CaseSensitive &&
+ root.is_in_document()
+ {
+ let doc = root.owner_doc();
+ if let Ok(elements) = doc.elements_with_id(id) {
+ if root == doc.as_node() {
+ for element in elements {
+ Q::append_element(results, *element);
+ if Q::should_stop_after_first_match() {
+ break;
+ }
+ }
+ } else {
+ for element in elements {
+ if !element_is_descendant_of(*element, root) {
+ continue;
+ }
+
+ Q::append_element(results, *element);
+ if Q::should_stop_after_first_match() {
+ break;
+ }
+ }
+ }
+ return Ok(())
+ }
+ }
+
collect_all_elements::<E, Q, _>(root, results, |element| {
element.has_id(id, case_sensitivity)
})
}
Component::Class(ref class) => {
let case_sensitivity = quirks_mode.classes_and_ids_case_sensitivity();
collect_all_elements::<E, Q, _>(root, results, |element| {
element.has_class(class, case_sensitivity)