diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 32e9fc3545e..ee5682b561a 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -2217,26 +2217,18 @@ impl ElementMethods for Element { // https://dom.spec.whatwg.org/#dom-element-closest fn Closest(&self, selectors: DOMString) -> Fallible>> { - match SelectorParser::parse_author_origin_no_namespace(&selectors) { - Err(_) => Err(Error::Syntax), - Ok(selectors) => { - let self_root = DomRoot::from_ref(self); - let root = self.upcast::(); - for element in root.inclusive_ancestors() { - if let Some(element) = DomRoot::downcast::(element) { - let quirks_mode = document_from_node(self).quirks_mode(); - // FIXME(bholley): Consider an nth-index cache here. - let mut ctx = MatchingContext::new(MatchingMode::Normal, None, None, - quirks_mode); - ctx.scope_element = Some(self_root.opaque()); - if matches_selector_list(&selectors, &element, &mut ctx) { - return Ok(Some(element)); - } - } - } - Ok(None) - } - } + let selectors = + match SelectorParser::parse_author_origin_no_namespace(&selectors) { + Err(_) => return Err(Error::Syntax), + Ok(selectors) => selectors, + }; + + let quirks_mode = document_from_node(self).quirks_mode(); + Ok(dom_apis::element_closest( + DomRoot::from_ref(self), + &selectors, + quirks_mode, + )) } // https://dom.spec.whatwg.org/#dom-element-insertadjacentelement diff --git a/components/style/dom_apis.rs b/components/style/dom_apis.rs index 056f5dd2a12..dcdd201c754 100644 --- a/components/style/dom_apis.rs +++ b/components/style/dom_apis.rs @@ -6,7 +6,7 @@ //! and Gecko. use context::QuirksMode; -use selectors::{Element, SelectorList}; +use selectors::{Element, NthIndexCache, SelectorList}; use selectors::matching::{self, MatchingContext, MatchingMode}; /// https://dom.spec.whatwg.org/#dom-element-matches @@ -27,3 +27,33 @@ where context.scope_element = Some(element.opaque()); matching::matches_selector_list(selector_list, element, &mut context) } + +/// https://dom.spec.whatwg.org/#dom-element-closest +pub fn element_closest( + element: E, + selector_list: &SelectorList, + quirks_mode: QuirksMode, +) -> Option +where + E: Element, +{ + let mut nth_index_cache = NthIndexCache::default(); + + let mut context = MatchingContext::new( + MatchingMode::Normal, + None, + Some(&mut nth_index_cache), + quirks_mode, + ); + context.scope_element = Some(element.opaque()); + + let mut current = Some(element); + while let Some(element) = current.take() { + if matching::matches_selector_list(selector_list, &element, &mut context) { + return Some(element); + } + current = element.parent_element(); + } + + return None; +} diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 53d65991e70..c6b0e36e7a6 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -6,7 +6,7 @@ use cssparser::{Parser, ParserInput}; use cssparser::ToCss as ParserToCss; use env_logger::LogBuilder; use malloc_size_of::MallocSizeOfOps; -use selectors::{self, Element, NthIndexCache}; +use selectors::Element; use selectors::matching::{MatchingContext, MatchingMode, matches_selector}; use servo_arc::{Arc, ArcBorrow, RawOffsetArc}; use std::cell::RefCell; @@ -1526,28 +1526,13 @@ pub unsafe extern "C" fn Servo_SelectorList_Closest<'a>( selectors: RawServoSelectorListBorrowed, ) -> RawGeckoElementBorrowedOrNull<'a> { use std::borrow::Borrow; - - let mut nth_index_cache = NthIndexCache::default(); + use style::dom_apis; let element = GeckoElement(element); - let mut context = MatchingContext::new( - MatchingMode::Normal, - None, - Some(&mut nth_index_cache), - element.owner_document_quirks_mode(), - ); - context.scope_element = Some(element.opaque()); - let selectors = ::selectors::SelectorList::from_ffi(selectors).borrow(); - let mut current = Some(element); - while let Some(element) = current.take() { - if selectors::matching::matches_selector_list(&selectors, &element, &mut context) { - return Some(element.0); - } - current = element.parent_element(); - } - return None; + dom_apis::element_closest(element, &selectors, element.owner_document_quirks_mode()) + .map(|e| e.0) } #[no_mangle]