Bug 1411878 - Support Element.shadowRoot and Element.assignedSlot / TextNode.assignedSlot on closed shadow root
MozReview-Commit-ID: DSiGN7h5ErY
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -1149,16 +1149,35 @@ Element::SetSlot(const nsAString& aName,
}
void
Element::GetSlot(nsAString& aName)
{
GetAttr(kNameSpaceID_None, nsGkAtoms::slot, aName);
}
+// https://dom.spec.whatwg.org/#dom-element-shadowroot
+ShadowRoot*
+Element::GetShadowRootByMode() const
+{
+ /**
+ * 1. Let shadow be context object’s shadow root.
+ * 2. If shadow is null or its mode is "closed", then return null.
+ */
+ ShadowRoot* shadowRoot = GetShadowRoot();
+ if (!shadowRoot || shadowRoot->IsClosed()) {
+ return nullptr;
+ }
+
+ /**
+ * 3. Return shadow.
+ */
+ return shadowRoot;
+}
+
// https://dom.spec.whatwg.org/#dom-element-attachshadow
already_AddRefed<ShadowRoot>
Element::AttachShadow(const ShadowRootInit& aInit, ErrorResult& aError)
{
/**
* 1. If context object’s namespace is not the HTML namespace,
* then throw a "NotSupportedError" DOMException.
*/
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -1083,16 +1083,17 @@ public:
ErrorResult& aError);
already_AddRefed<DOMRectList> GetClientRects();
already_AddRefed<DOMRect> GetBoundingClientRect();
// Shadow DOM v1
already_AddRefed<ShadowRoot> AttachShadow(const ShadowRootInit& aInit,
ErrorResult& aError);
+ ShadowRoot* GetShadowRootByMode() const;
void SetSlot(const nsAString& aName, ErrorResult& aError);
void GetSlot(nsAString& aName);
// [deprecated] Shadow DOM v0
already_AddRefed<ShadowRoot> CreateShadowRoot(ErrorResult& aError);
already_AddRefed<DestinationInsertionPointList> GetDestinationInsertionPoints();
ShadowRoot *FastGetShadowRoot() const
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -150,16 +150,46 @@ nsIContent::FindFirstNonChromeOnlyAccess
// Oops, this function signature allows casting const to
// non-const. (Then again, so does GetChildAt(0)->GetParent().)
return const_cast<nsIContent*>(content);
}
}
return nullptr;
}
+// https://dom.spec.whatwg.org/#dom-slotable-assignedslot
+HTMLSlotElement*
+nsIContent::GetAssignedSlotByMode() const
+{
+ /**
+ * Get slotable's assigned slot for the result of
+ * find a slot with open flag UNSET [1].
+ *
+ * [1] https://dom.spec.whatwg.org/#assign-a-slot
+ */
+ HTMLSlotElement* slot = GetAssignedSlot();
+ if (!slot) {
+ return nullptr;
+ }
+
+ MOZ_ASSERT(GetParent());
+ MOZ_ASSERT(GetParent()->GetShadowRoot());
+
+ /**
+ * Additional check for open flag SET:
+ * If slotable’s parent’s shadow root's mode is not "open",
+ * then return null.
+ */
+ if (GetParent()->GetShadowRoot()->IsClosed()) {
+ return nullptr;
+ }
+
+ return slot;
+}
+
nsINode*
nsIContent::GetFlattenedTreeParentNodeInternal(FlattenedParentType aType) const
{
nsINode* parentNode = GetParentNode();
if (!parentNode || !parentNode->IsContent()) {
MOZ_ASSERT(!parentNode || parentNode == OwnerDoc());
return parentNode;
}
--- a/dom/base/ShadowRoot.h
+++ b/dom/base/ShadowRoot.h
@@ -46,16 +46,20 @@ public:
nsXBLPrototypeBinding* aProtoBinding);
// Shadow DOM v1
Element* Host();
ShadowRootMode Mode()
{
return mMode;
}
+ bool IsClosed()
+ {
+ return mMode == ShadowRootMode::Closed;
+ }
// [deprecated] Shadow DOM v0
void AddToIdTable(Element* aElement, nsAtom* aId);
void RemoveFromIdTable(Element* aElement, nsAtom* aId);
void InsertSheet(StyleSheet* aSheet, nsIContent* aLinkingContent);
void RemoveSheet(StyleSheet* aSheet);
bool ApplyAuthorStyles();
void SetApplyAuthorStyles(bool aApplyAuthorStyles);
--- a/dom/base/nsIContent.h
+++ b/dom/base/nsIContent.h
@@ -753,16 +753,25 @@ public:
/**
* Sets the assigned slot associated with this content.
*
* @param aSlot The assigned slot.
*/
virtual void SetAssignedSlot(mozilla::dom::HTMLSlotElement* aSlot) = 0;
+ /**
+ * Gets the assigned slot associated with this content based on parent's
+ * shadow root mode. Returns null if parent's shadow root is "closed".
+ * https://dom.spec.whatwg.org/#dom-slotable-assignedslot
+ *
+ * @return The assigned slot element or null.
+ */
+ mozilla::dom::HTMLSlotElement* GetAssignedSlotByMode() const;
+
nsIContent* GetXBLInsertionParent() const
{
nsIContent* ip = GetXBLInsertionPoint();
return ip ? ip->GetParent() : nullptr;
}
/**
* Gets the insertion parent element of the XBL binding.
--- a/dom/webidl/Element.webidl
+++ b/dom/webidl/Element.webidl
@@ -240,19 +240,19 @@ dictionary ShadowRootInit {
required ShadowRootMode mode;
};
// https://dom.spec.whatwg.org/#element
partial interface Element {
// Shadow DOM v1
[Throws, Pref="dom.webcomponents.enabled"]
ShadowRoot attachShadow(ShadowRootInit shadowRootInitDict);
- [Pref="dom.webcomponents.enabled"]
+ [BinaryName="shadowRootByMode", Pref="dom.webcomponents.enabled"]
readonly attribute ShadowRoot? shadowRoot;
- [Pref="dom.webcomponents.enabled"]
+ [BinaryName="assignedSlotByMode", Pref="dom.webcomponents.enabled"]
readonly attribute HTMLSlotElement? assignedSlot;
[CEReactions, Unscopable, SetterThrows, Pref="dom.webcomponents.enabled"]
attribute DOMString slot;
// [deprecated] Shadow DOM v0
[Throws, Pref="dom.webcomponents.enabled"]
ShadowRoot createShadowRoot();
[Pref="dom.webcomponents.enabled"]
--- a/dom/webidl/Text.webidl
+++ b/dom/webidl/Text.webidl
@@ -14,13 +14,13 @@
interface Text : CharacterData {
[Throws]
Text splitText(unsigned long offset);
[Throws]
readonly attribute DOMString wholeText;
};
partial interface Text {
- [Pref="dom.webcomponents.enabled"]
+ [BinaryName="assignedSlotByMode", Pref="dom.webcomponents.enabled"]
readonly attribute HTMLSlotElement? assignedSlot;
};
Text implements GeometryUtils;
deleted file mode 100644
--- a/testing/web-platform/meta/shadow-dom/Element-interface-shadowRoot-attribute.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[Element-interface-shadowRoot-attribute.html]
- type: testharness
- [shadowRoot attribute must return null if the shadow root attached to the element is closed]
- expected: FAIL
-