diff --git a/components/style/dom.rs b/components/style/dom.rs index b4e70498d46..91e7324afd4 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -332,6 +332,23 @@ pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone + self.parent_element() } + /// The ::before pseudo-element of this element, if it exists. + fn before_pseudo_element(&self) -> Option { + None + } + + /// The ::after pseudo-element of this element, if it exists. + fn after_pseudo_element(&self) -> Option { + None + } + + /// Execute `f` for each anonymous content child (apart from ::before and + /// ::after) whose originating element is `self`. + fn each_anonymous_content_child(&self, _f: F) + where + F: FnMut(Self), + {} + /// For a given NAC element, return the closest non-NAC ancestor, which is /// guaranteed to exist. fn closest_non_native_anonymous_ancestor(&self) -> Option { diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index e997486b1d3..9d17f442edf 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -557,6 +557,25 @@ impl<'le> GeckoElement<'le> { self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementMayHaveClass) } + #[inline] + fn has_properties(&self) -> bool { + use gecko_bindings::structs::NODE_HAS_PROPERTIES; + + (self.flags() & NODE_HAS_PROPERTIES as u32) != 0 + } + + #[inline] + fn get_before_or_after_pseudo(&self, is_before: bool) -> Option { + if !self.has_properties() { + return None; + } + + unsafe { + bindings::Gecko_GetBeforeOrAfterPseudo(self.0, is_before) + .map(GeckoElement) + } + } + #[inline] fn may_have_style_attribute(&self) -> bool { self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementMayHaveStyle) @@ -689,6 +708,40 @@ impl<'le> TElement for GeckoElement<'le> { } } + fn before_pseudo_element(&self) -> Option { + self.get_before_or_after_pseudo(/* is_before = */ true) + } + + fn after_pseudo_element(&self) -> Option { + self.get_before_or_after_pseudo(/* is_before = */ false) + } + + /// Execute `f` for each anonymous content child element (apart from + /// ::before and ::after) whose originating element is `self`. + fn each_anonymous_content_child(&self, mut f: F) + where + F: FnMut(Self), + { + let array: *mut structs::nsTArray<*mut nsIContent> = + unsafe { bindings::Gecko_GetAnonymousContentForElement(self.0) }; + + if array.is_null() { + return; + } + + for content in unsafe { &**array } { + let node = GeckoNode::from_content(unsafe { &**content }); + let element = match node.as_element() { + Some(e) => e, + None => continue, + }; + + f(element); + } + + unsafe { bindings::Gecko_DestroyAnonymousContentList(array) }; + } + fn closest_non_native_anonymous_ancestor(&self) -> Option { debug_assert!(self.is_native_anonymous()); let mut parent = match self.parent_element() { @@ -868,6 +921,10 @@ impl<'le> TElement for GeckoElement<'le> { return None; } + if !self.has_properties() { + return None; + } + let pseudo_type = unsafe { bindings::Gecko_GetImplementedPseudo(self.0) }; PseudoElement::from_pseudo_type(pseudo_type)