aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/layout_thread/dom_wrapper.rs39
-rw-r--r--components/style/dom.rs21
-rw-r--r--components/style/gecko/wrapper.rs96
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)
};