diff options
-rw-r--r-- | components/layout_thread/dom_wrapper.rs | 39 | ||||
-rw-r--r-- | components/style/dom.rs | 21 | ||||
-rw-r--r-- | components/style/gecko/wrapper.rs | 96 |
3 files changed, 118 insertions, 38 deletions
diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index 1eaf74e4e9d..b9baea95b0e 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -66,7 +66,7 @@ use style::attr::AttrValue; use style::context::SharedStyleContext; use style::data::ElementData; use style::dom::{DomChildren, LayoutIterator, NodeInfo, OpaqueNode}; -use style::dom::{TDocument, TElement, TNode}; +use style::dom::{TDocument, TElement, TNode, TShadowRoot}; use style::element_state::*; use style::font_metrics::ServoMetricsProvider; use style::properties::{ComputedValues, PropertyDeclarationBlock}; @@ -150,9 +150,28 @@ impl<'ln> NodeInfo for ServoLayoutNode<'ln> { } } +#[derive(Clone, Copy)] +enum Impossible { } + +#[derive(Clone, Copy)] +pub struct ShadowRoot<'lr>(Impossible, PhantomData<&'lr ()>); + +impl<'lr> TShadowRoot for ShadowRoot<'lr> { + type ConcreteNode = ServoLayoutNode<'lr>; + + fn as_node(&self) -> Self::ConcreteNode { + match self.0 { } + } + + fn host(&self) -> ServoLayoutElement<'lr> { + match self.0 { } + } +} + impl<'ln> TNode for ServoLayoutNode<'ln> { type ConcreteDocument = ServoLayoutDocument<'ln>; type ConcreteElement = ServoLayoutElement<'ln>; + type ConcreteShadowRoot = ShadowRoot<'ln>; fn parent_node(&self) -> Option<Self> { unsafe { @@ -208,6 +227,10 @@ impl<'ln> TNode for ServoLayoutNode<'ln> { self.node.downcast().map(ServoLayoutDocument::from_layout_js) } + fn as_shadow_root(&self) -> Option<ShadowRoot<'ln>> { + None + } + fn is_in_document(&self) -> bool { unsafe { self.node.get_flag(NodeFlags::IS_IN_DOC) } } @@ -489,11 +512,11 @@ impl<'le> TElement for ServoLayoutElement<'le> { .map(|v| String::from(v as &str)) } - fn match_element_lang(&self, - override_lang: Option<Option<SelectorAttrValue>>, - value: &PseudoClassStringArg) - -> bool - { + fn match_element_lang( + &self, + override_lang: Option<Option<SelectorAttrValue>>, + value: &PseudoClassStringArg, + ) -> bool { // Servo supports :lang() from CSS Selectors 4, which can take a comma- // separated list of language tags in the pseudo-class, and which // performs RFC 4647 extended filtering matching on them. @@ -535,6 +558,10 @@ impl<'le> TElement for ServoLayoutElement<'le> { self.element.synthesize_presentational_hints_for_legacy_attributes(hints); } } + + fn shadow_root(&self) -> Option<ShadowRoot<'le>> { + None + } } impl<'le> PartialEq for ServoLayoutElement<'le> { diff --git a/components/style/dom.rs b/components/style/dom.rs index 087e56ac6c1..69a4a9a4432 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -154,6 +154,9 @@ pub trait TNode : Sized + Copy + Clone + Debug + NodeInfo + PartialEq { /// The concrete `TDocument` type. type ConcreteDocument: TDocument<ConcreteNode = Self>; + /// The concrete `TShadowRoot` type. + type ConcreteShadowRoot: TShadowRoot<ConcreteNode = Self>; + /// Get this node's parent node. fn parent_node(&self) -> Option<Self>; @@ -235,6 +238,9 @@ pub trait TNode : Sized + Copy + Clone + Debug + NodeInfo + PartialEq { /// Get this node as a document, if it's one. fn as_document(&self) -> Option<Self::ConcreteDocument>; + + /// Get this node as a ShadowRoot, if it's one. + fn as_shadow_root(&self) -> Option<Self::ConcreteShadowRoot>; } /// Wrapper to output the subtree rather than the single node when formatting @@ -314,6 +320,18 @@ fn fmt_subtree<F, N: TNode>(f: &mut fmt::Formatter, stringify: &F, n: N, indent: Ok(()) } +/// The ShadowRoot trait. +pub trait TShadowRoot : Sized + Copy + Clone { + /// The concrete node type. + type ConcreteNode: TNode<ConcreteShadowRoot = Self>; + + /// Get this ShadowRoot as a node. + fn as_node(&self) -> Self::ConcreteNode; + + /// Get the shadow host that hosts this ShadowRoot. + fn host(&self) -> <Self::ConcreteNode as TNode>::ConcreteElement; +} + /// The element trait, the main abstraction the style crate acts over. pub trait TElement : Eq @@ -719,6 +737,9 @@ pub trait TElement None } + /// The shadow root this element is a host of. + fn shadow_root(&self) -> Option<<Self::ConcreteNode as TNode>::ConcreteShadowRoot>; + /// Return the element which we can use to look up rules in the selector /// maps. /// diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 35520d9a2a5..0475651340e 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -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 @@ -172,6 +190,11 @@ impl<'ln> GeckoNode<'ln> { } #[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) }; |