style: Add bindings for ShadowRoot.

This adds TShadowRoot to the `dom` module.

Right now it barely adds uses of it, but this is a prerequisite to fix a bunch
of Shadow DOM bugs and separate it from the XBL mess.
This commit is contained in:
Emilio Cobos Álvarez 2018-03-03 22:14:36 +01:00
parent df079286c2
commit 2f0df1b421
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
3 changed files with 118 additions and 38 deletions

View file

@ -21,7 +21,7 @@ use atomic_refcell::{AtomicRefCell, AtomicRefMut};
use author_styles::AuthorStyles;
use context::{QuirksMode, SharedStyleContext, PostAnimationTasks, UpdateAnimationsTasks};
use data::ElementData;
use dom::{LayoutIterator, NodeInfo, OpaqueNode, TElement, TDocument, TNode};
use dom::{LayoutIterator, NodeInfo, OpaqueNode, TElement, TDocument, TNode, TShadowRoot};
use element_state::{ElementState, DocumentState};
use font_metrics::{FontMetrics, FontMetricsProvider, FontMetricsQueryResult};
use gecko::data::GeckoStyleSheet;
@ -131,6 +131,24 @@ impl<'ld> TDocument for GeckoDocument<'ld> {
}
}
/// A simple wrapper over `ShadowRoot`.
#[derive(Clone, Copy)]
pub struct GeckoShadowRoot<'lr>(pub &'lr structs::ShadowRoot);
impl<'lr> TShadowRoot for GeckoShadowRoot<'lr> {
type ConcreteNode = GeckoNode<'lr>;
#[inline]
fn as_node(&self) -> Self::ConcreteNode {
GeckoNode(&self.0._base._base._base._base)
}
#[inline]
fn host(&self) -> GeckoElement<'lr> {
GeckoElement(unsafe { &*self.0._base.mHost.mRawPtr })
}
}
/// A simple wrapper over a non-null Gecko node (`nsINode`) pointer.
///
/// Important: We don't currently refcount the DOM, because the wrapper lifetime
@ -171,6 +189,11 @@ impl<'ln> GeckoNode<'ln> {
self.node_info().mInner.mNodeType == DOCUMENT_NODE
}
#[inline]
fn is_shadow_root(&self) -> bool {
self.is_in_shadow_tree() && self.parent_node().is_none()
}
#[inline]
fn from_content(content: &'ln nsIContent) -> Self {
GeckoNode(&content._base)
@ -205,6 +228,13 @@ impl<'ln> GeckoNode<'ln> {
self.bool_flags() & (1u32 << flag as u32) != 0
}
/// This logic is duplicate in Gecko's nsINode::IsInShadowTree().
#[inline]
fn is_in_shadow_tree(&self) -> bool {
use gecko_bindings::structs::NODE_IS_IN_SHADOW_TREE;
self.flags() & (NODE_IS_IN_SHADOW_TREE as u32) != 0
}
/// WARNING: This logic is duplicated in Gecko's FlattenedTreeParentIsParent.
/// Make sure to mirror any modifications in both places.
#[inline]
@ -275,6 +305,7 @@ impl<'ln> NodeInfo for GeckoNode<'ln> {
impl<'ln> TNode for GeckoNode<'ln> {
type ConcreteDocument = GeckoDocument<'ln>;
type ConcreteShadowRoot = GeckoShadowRoot<'ln>;
type ConcreteElement = GeckoElement<'ln>;
#[inline]
@ -329,20 +360,33 @@ impl<'ln> TNode for GeckoNode<'ln> {
#[inline]
fn as_element(&self) -> Option<GeckoElement<'ln>> {
if self.is_element() {
unsafe { Some(GeckoElement(&*(self.0 as *const _ as *const RawGeckoElement))) }
} else {
None
if !self.is_element() {
return None;
}
Some(GeckoElement(unsafe {
&*(self.0 as *const _ as *const RawGeckoElement)
}))
}
#[inline]
fn as_document(&self) -> Option<Self::ConcreteDocument> {
if self.is_document() {
Some(self.owner_doc())
} else {
None
if !self.is_document() {
return None;
}
Some(self.owner_doc())
}
#[inline]
fn as_shadow_root(&self) -> Option<Self::ConcreteShadowRoot> {
if !self.is_shadow_root() {
return None;
}
Some(GeckoShadowRoot(unsafe {
&*(self.0 as *const _ as *const structs::ShadowRoot)
}))
}
}
@ -488,11 +532,7 @@ impl<'le> GeckoElement<'le> {
#[inline]
fn flags(&self) -> u32 {
self.raw_node()._base._base_1.mFlags
}
fn raw_node(&self) -> &RawGeckoNode {
&(self.0)._base._base._base
self.as_node().flags()
}
// FIXME: We can implement this without OOL calls, but we can't easily given
@ -517,13 +557,6 @@ impl<'le> GeckoElement<'le> {
self.flags() & (NODE_NEEDS_FRAME as u32) != 0
}
/// Returns true if this element has a shadow root.
#[inline]
fn shadow_root(&self) -> Option<&structs::ShadowRoot> {
let slots = self.extended_slots()?;
unsafe { slots.mShadowRoot.mRawPtr.as_ref() }
}
/// Returns a reference to the DOM slots for this Element, if they exist.
fn dom_slots(&self) -> Option<&structs::FragmentOrElement_nsDOMSlots> {
let slots = self.as_node().0.mSlots as *const structs::FragmentOrElement_nsDOMSlots;
@ -732,18 +765,11 @@ impl<'le> GeckoElement<'le> {
self.flags() & (NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE as u32) != 0
}
/// This logic is duplicate in Gecko's nsIContent::IsInShadowTree().
#[inline]
fn is_in_shadow_tree(&self) -> bool {
use gecko_bindings::structs::NODE_IS_IN_SHADOW_TREE;
self.flags() & (NODE_IS_IN_SHADOW_TREE as u32) != 0
}
/// This logic is duplicated in Gecko's nsIContent::IsInAnonymousSubtree.
#[inline]
fn is_in_anonymous_subtree(&self) -> bool {
self.is_in_native_anonymous_subtree() ||
(!self.is_in_shadow_tree() && self.has_xbl_binding_parent())
(!self.as_node().is_in_shadow_tree() && self.has_xbl_binding_parent())
}
fn css_transitions_info(&self) -> FnvHashMap<LonghandId, Arc<AnimationValue>> {
@ -1011,7 +1037,7 @@ impl<'le> TElement for GeckoElement<'le> {
/// Return the list of slotted nodes of this node.
#[inline]
fn slotted_nodes(&self) -> &[Self::ConcreteNode] {
if !self.is_html_slot_element() || !self.is_in_shadow_tree() {
if !self.is_html_slot_element() || !self.as_node().is_in_shadow_tree() {
return &[];
}
@ -1036,6 +1062,12 @@ impl<'le> TElement for GeckoElement<'le> {
unsafe { mem::transmute(assigned_nodes) }
}
#[inline]
fn shadow_root(&self) -> Option<GeckoShadowRoot<'le>> {
let slots = self.extended_slots()?;
unsafe { slots.mShadowRoot.mRawPtr.as_ref().map(GeckoShadowRoot) }
}
/// Execute `f` for each anonymous content child element (apart from
/// ::before and ::after) whose originating element is `self`.
fn each_anonymous_content_child<F>(&self, mut f: F)
@ -1416,9 +1448,9 @@ impl<'le> TElement for GeckoElement<'le> {
// That will allow to clean up a bunch in
// push_applicable_declarations.
if let Some(shadow) = element.shadow_root() {
debug_assert!(!shadow.mServoStyles.mPtr.is_null());
debug_assert!(!shadow.0.mServoStyles.mPtr.is_null());
let author_styles = unsafe {
&*(shadow.mServoStyles.mPtr
&*(shadow.0.mServoStyles.mPtr
as *const structs::RawServoAuthorStyles
as *const bindings::RawServoAuthorStyles)
};