Bug 1411878 - Support Element.shadowRoot and Element.assignedSlot / TextNode.assignedSlot on closed shadow root draft
authorbtian <btian@mozilla.com>
Thu, 02 Nov 2017 16:53:44 +0800
changeset 691895 4cc9c3974fa4463b4368c905b446b95f283d59b7
parent 691808 a0334f789772302ba5cfb6fd61290408842c7432
child 738626 52f0a37dd22b3b3d497ab153ef5f575a358fedb4
push id87356
push userbmo:btian@mozilla.com
push dateThu, 02 Nov 2017 08:54:01 +0000
bugs1411878
milestone58.0a1
Bug 1411878 - Support Element.shadowRoot and Element.assignedSlot / TextNode.assignedSlot on closed shadow root MozReview-Commit-ID: DSiGN7h5ErY
dom/base/Element.cpp
dom/base/Element.h
dom/base/FragmentOrElement.cpp
dom/base/ShadowRoot.h
dom/base/nsIContent.h
dom/webidl/Element.webidl
dom/webidl/Text.webidl
testing/web-platform/meta/shadow-dom/Element-interface-shadowRoot-attribute.html.ini
--- 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
-