diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index a87e561f912..ee5682b561a 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -107,6 +107,7 @@ use style::CaseSensitivityExt; use style::applicable_declarations::ApplicableDeclarationBlock; use style::attr::{AttrValue, LengthOrPercentageOrAuto}; use style::context::QuirksMode; +use style::dom_apis; use style::element_state::*; use style::invalidation::element::restyle_hints::RESTYLE_SELF; use style::properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock, parse_style_attribute}; @@ -2197,18 +2198,16 @@ impl ElementMethods for Element { // https://dom.spec.whatwg.org/#dom-element-matches fn Matches(&self, selectors: DOMString) -> Fallible { - match SelectorParser::parse_author_origin_no_namespace(&selectors) { - Err(_) => Err(Error::Syntax), - Ok(selectors) => { - let quirks_mode = document_from_node(self).quirks_mode(); - let root = DomRoot::from_ref(self); - // FIXME(bholley): Consider an nth-index cache here. - let mut ctx = MatchingContext::new(MatchingMode::Normal, None, None, - quirks_mode); - ctx.scope_element = Some(root.opaque()); - Ok(matches_selector_list(&selectors, &root, &mut ctx)) - } - } + 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(); + let element = DomRoot::from_ref(self); + + Ok(dom_apis::element_matches(&element, &selectors, quirks_mode)) } // https://dom.spec.whatwg.org/#dom-element-webkitmatchesselector @@ -2218,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 new file mode 100644 index 00000000000..dcdd201c754 --- /dev/null +++ b/components/style/dom_apis.rs @@ -0,0 +1,59 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! Generic implementations of some DOM APIs so they can be shared between Servo +//! and Gecko. + +use context::QuirksMode; +use selectors::{Element, NthIndexCache, SelectorList}; +use selectors::matching::{self, MatchingContext, MatchingMode}; + +/// https://dom.spec.whatwg.org/#dom-element-matches +pub fn element_matches( + element: &E, + selector_list: &SelectorList, + quirks_mode: QuirksMode, +) -> bool +where + E: Element, +{ + let mut context = MatchingContext::new( + MatchingMode::Normal, + None, + None, + quirks_mode, + ); + 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/components/style/lib.rs b/components/style/lib.rs index 997efddb026..b4b40cf56db 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -107,6 +107,7 @@ pub mod counter_style; pub mod custom_properties; pub mod data; pub mod dom; +pub mod dom_apis; pub mod driver; pub mod element_state; #[cfg(feature = "servo")] mod encoding_support; diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index f7a1357549b..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] @@ -1556,18 +1541,15 @@ pub unsafe extern "C" fn Servo_SelectorList_Matches( selectors: RawServoSelectorListBorrowed, ) -> bool { use std::borrow::Borrow; + use style::dom_apis; let element = GeckoElement(element); - let mut context = MatchingContext::new( - MatchingMode::Normal, - None, - None, - element.owner_document_quirks_mode(), - ); - context.scope_element = Some(element.opaque()); - let selectors = ::selectors::SelectorList::from_ffi(selectors).borrow(); - selectors::matching::matches_selector_list(&selectors, &element, &mut context) + dom_apis::element_matches( + &element, + &selectors, + element.owner_document_quirks_mode(), + ) } #[no_mangle]