Bug 1408341 - Implement assignedSlot on Element and Text. r=smaug
authorJessica Jong <jjong@mozilla.com>
Thu, 19 Oct 2017 14:31:36 +0800
changeset 440352 c5ee99a2c4c83edf6d19294618102b763b96c4a5
parent 440351 64cecfd341a1ff9375316d3b3565124def78f257
child 440353 87e3813e79396f88e63fc6cfd7f07c3dbb415195
child 440383 3d6e6c4772ec5449016d93116ebd6b865219f634
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1408341
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1408341 - Implement assignedSlot on Element and Text. r=smaug
dom/base/FragmentOrElement.cpp
dom/base/FragmentOrElement.h
dom/base/nsGenericDOMDataNode.cpp
dom/base/nsGenericDOMDataNode.h
dom/base/nsIContent.h
dom/webidl/Element.webidl
dom/webidl/Text.webidl
testing/web-platform/meta/dom/interfaces.html.ini
testing/web-platform/meta/payment-request/interfaces.https.html.ini
testing/web-platform/meta/shadow-dom/Slotable-interface.html.ini
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -120,16 +120,17 @@
 #include "nsCycleCollector.h"
 #include "xpcpublic.h"
 #include "nsIScriptError.h"
 #include "mozilla/Telemetry.h"
 
 #include "mozilla/CORSMode.h"
 
 #include "mozilla/dom/ShadowRoot.h"
+#include "mozilla/dom/HTMLSlotElement.h"
 #include "mozilla/dom/HTMLTemplateElement.h"
 #include "mozilla/dom/SVGUseElement.h"
 
 #include "nsStyledElement.h"
 #include "nsIContentInlines.h"
 #include "nsChildContentList.h"
 
 using namespace mozilla;
@@ -693,16 +694,19 @@ FragmentOrElement::nsDOMSlots::Traverse(
   cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMNodeList*,mExtendedSlots-> mLabelsList));
 
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mShadowRoot");
   cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mExtendedSlots->mShadowRoot));
 
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mContainingShadow");
   cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mExtendedSlots->mContainingShadow));
 
+  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mAssignedSlot");
+  cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mExtendedSlots->mAssignedSlot.get()));
+
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mXBLBinding");
   cb.NoteNativeChild(mExtendedSlots->mXBLBinding,
                      NS_CYCLE_COLLECTION_PARTICIPANT(nsXBLBinding));
 
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mXBLInsertionParent");
   cb.NoteXPCOMChild(mExtendedSlots->mXBLInsertionParent.get());
 
   if (mExtendedSlots->mCustomElementData) {
@@ -740,16 +744,17 @@ FragmentOrElement::nsDOMSlots::Unlink()
     return;
   }
 
   mExtendedSlots->mSMILOverrideStyle = nullptr;
   mExtendedSlots->mControllers = nullptr;
   mExtendedSlots->mLabelsList = nullptr;
   mExtendedSlots->mShadowRoot = nullptr;
   mExtendedSlots->mContainingShadow = nullptr;
+  mExtendedSlots->mAssignedSlot = nullptr;
   MOZ_ASSERT(!(mExtendedSlots->mXBLBinding));
   mExtendedSlots->mXBLInsertionParent = nullptr;
   if (mExtendedSlots->mCustomElementData) {
     if (mExtendedSlots->mCustomElementData->mCustomElementDefinition) {
       mExtendedSlots->mCustomElementData->mCustomElementDefinition = nullptr;
     }
     mExtendedSlots->mCustomElementData = nullptr;
   }
@@ -1210,16 +1215,30 @@ FragmentOrElement::GetExistingDestInsert
 {
   nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
   if (slots) {
     return &slots->mDestInsertionPoints;
   }
   return nullptr;
 }
 
+HTMLSlotElement*
+FragmentOrElement::GetAssignedSlot() const
+{
+  nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
+  return slots ? slots->mAssignedSlot.get() : nullptr;
+}
+
+void
+FragmentOrElement::SetAssignedSlot(HTMLSlotElement* aSlot)
+{
+  nsExtendedDOMSlots* slots = ExtendedDOMSlots();
+  slots->mAssignedSlot = aSlot;
+}
+
 void
 FragmentOrElement::SetXBLInsertionParent(nsIContent* aContent)
 {
   nsCOMPtr<nsIContent> oldInsertionParent = nullptr;
   if (aContent) {
     nsExtendedDOMSlots* slots = ExtendedDOMSlots();
     SetFlags(NODE_MAY_BE_IN_BINDING_MNGR);
     oldInsertionParent = slots->mXBLInsertionParent.forget();
--- a/dom/base/FragmentOrElement.h
+++ b/dom/base/FragmentOrElement.h
@@ -150,16 +150,18 @@ public:
   virtual nsIContent *GetBindingParent() const override;
   virtual nsXBLBinding *GetXBLBinding() const override;
   virtual void SetXBLBinding(nsXBLBinding* aBinding,
                              nsBindingManager* aOldBindingManager = nullptr) override;
   virtual ShadowRoot *GetContainingShadow() const override;
   virtual nsTArray<nsIContent*> &DestInsertionPoints() override;
   virtual nsTArray<nsIContent*> *GetExistingDestInsertionPoints() const override;
   virtual void SetShadowRoot(ShadowRoot* aBinding) override;
+  virtual mozilla::dom::HTMLSlotElement* GetAssignedSlot() const override;
+  virtual void SetAssignedSlot(mozilla::dom::HTMLSlotElement* aSlot) override;
   virtual nsIContent *GetXBLInsertionParent() const override;
   virtual void SetXBLInsertionParent(nsIContent* aContent) override;
   virtual bool IsLink(nsIURI** aURI) const override;
 
   virtual void DestroyContent() override;
   virtual void SaveSubtreeState() override;
 
   NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) override;
@@ -293,16 +295,21 @@ public:
 
     /**
      * An array of web component insertion points to which this element
      * is distributed.
      */
     nsTArray<nsIContent*> mDestInsertionPoints;
 
     /**
+     * The assigned slot associated with this element.
+     */
+    RefPtr<mozilla::dom::HTMLSlotElement> mAssignedSlot;
+
+    /**
      * XBL binding installed on the element.
      */
     RefPtr<nsXBLBinding> mXBLBinding;
 
     /**
      * XBL binding installed on the lement.
      */
     nsCOMPtr<nsIContent> mXBLInsertionParent;
--- a/dom/base/nsGenericDOMDataNode.cpp
+++ b/dom/base/nsGenericDOMDataNode.cpp
@@ -10,16 +10,17 @@
  */
 
 #include "mozilla/DebugOnly.h"
 
 #include "nsGenericDOMDataNode.h"
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/Element.h"
+#include "mozilla/dom/HTMLSlotElement.h"
 #include "mozilla/dom/ShadowRoot.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsReadableUtils.h"
 #include "mozilla/InternalMutationEvent.h"
 #include "nsIURI.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMText.h"
@@ -734,16 +735,30 @@ nsGenericDOMDataNode::GetExistingDestIns
 {
   nsDataSlots *slots = GetExistingDataSlots();
   if (slots) {
     return &slots->mDestInsertionPoints;
   }
   return nullptr;
 }
 
+HTMLSlotElement*
+nsGenericDOMDataNode::GetAssignedSlot() const
+{
+  nsDataSlots *slots = GetExistingDataSlots();
+  return slots ? slots->mAssignedSlot.get() : nullptr;
+}
+
+void
+nsGenericDOMDataNode::SetAssignedSlot(HTMLSlotElement* aSlot)
+{
+  nsDataSlots *slots = DataSlots();
+  slots->mAssignedSlot = aSlot;
+}
+
 nsXBLBinding *
 nsGenericDOMDataNode::GetXBLBinding() const
 {
   return nullptr;
 }
 
 void
 nsGenericDOMDataNode::SetXBLBinding(nsXBLBinding* aBinding,
@@ -824,23 +839,27 @@ nsGenericDOMDataNode::nsDataSlots::nsDat
 void
 nsGenericDOMDataNode::nsDataSlots::Traverse(nsCycleCollectionTraversalCallback &cb)
 {
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mXBLInsertionParent");
   cb.NoteXPCOMChild(mXBLInsertionParent.get());
 
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mContainingShadow");
   cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mContainingShadow));
+
+  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mAssignedSlot");
+  cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mAssignedSlot.get()));
 }
 
 void
 nsGenericDOMDataNode::nsDataSlots::Unlink()
 {
   mXBLInsertionParent = nullptr;
   mContainingShadow = nullptr;
+  mAssignedSlot = nullptr;
 }
 
 //----------------------------------------------------------------------
 
 // Implementation of the nsIDOMText interface
 
 nsresult
 nsGenericDOMDataNode::SplitData(uint32_t aOffset, nsIContent** aReturn,
--- a/dom/base/nsGenericDOMDataNode.h
+++ b/dom/base/nsGenericDOMDataNode.h
@@ -21,16 +21,22 @@
 #include "nsCycleCollectionParticipant.h"
 
 #include "nsISMILAttr.h"
 #include "mozilla/dom/ShadowRoot.h"
 
 class nsIDocument;
 class nsIDOMText;
 
+namespace mozilla {
+namespace dom {
+class HTMLSlotElement;
+} // namespace dom
+} // namespace mozilla
+
 #define DATA_NODE_FLAG_BIT(n_) NODE_FLAG_BIT(NODE_TYPE_SPECIFIC_BITS_OFFSET + (n_))
 
 // Data node specific flags
 enum {
   // This bit is set to indicate that if the text node changes to
   // non-whitespace, we may need to create a frame for it. This bit must
   // not be set on nodes that already have a frame.
   NS_CREATE_FRAME_IF_NON_WHITESPACE =     DATA_NODE_FLAG_BIT(0),
@@ -165,16 +171,18 @@ public:
   virtual nsIContent *GetBindingParent() const override;
   virtual nsXBLBinding *GetXBLBinding() const override;
   virtual void SetXBLBinding(nsXBLBinding* aBinding,
                              nsBindingManager* aOldBindingManager = nullptr) override;
   virtual mozilla::dom::ShadowRoot *GetContainingShadow() const override;
   virtual nsTArray<nsIContent*> &DestInsertionPoints() override;
   virtual nsTArray<nsIContent*> *GetExistingDestInsertionPoints() const override;
   virtual void SetShadowRoot(mozilla::dom::ShadowRoot* aShadowRoot) override;
+  virtual mozilla::dom::HTMLSlotElement* GetAssignedSlot() const override;
+  virtual void SetAssignedSlot(mozilla::dom::HTMLSlotElement* aSlot) override;
   virtual nsIContent *GetXBLInsertionParent() const override;
   virtual void SetXBLInsertionParent(nsIContent* aContent) override;
   virtual bool IsNodeOfType(uint32_t aFlags) const override;
   virtual bool IsLink(nsIURI** aURI) const override;
 
   NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const;
   virtual nsChangeHint GetAttributeChangeHint(const nsAtom* aAttribute,
@@ -278,16 +286,21 @@ protected:
      * @see nsIContent::GetContainingShadow
      */
     RefPtr<mozilla::dom::ShadowRoot> mContainingShadow;
 
     /**
      * @see nsIContent::GetDestInsertionPoints
      */
     nsTArray<nsIContent*> mDestInsertionPoints;
+
+    /**
+     * @see nsIContent::GetAssignedSlot
+     */
+    RefPtr<mozilla::dom::HTMLSlotElement> mAssignedSlot;
   };
 
   // Override from nsINode
   virtual nsINode::nsSlots* CreateSlots() override;
 
   nsDataSlots* DataSlots()
   {
     return static_cast<nsDataSlots*>(Slots());
--- a/dom/base/nsIContent.h
+++ b/dom/base/nsIContent.h
@@ -23,16 +23,17 @@ class nsIFrame;
 class nsXBLBinding;
 class nsITextControlElement;
 
 namespace mozilla {
 class EventChainPreVisitor;
 struct URLExtraData;
 namespace dom {
 class ShadowRoot;
+class HTMLSlotElement;
 } // namespace dom
 namespace widget {
 struct IMEState;
 } // namespace widget
 } // namespace mozilla
 
 enum nsLinkState {
   eLinkState_Unvisited  = 1,
@@ -739,16 +740,30 @@ public:
   /**
    * Same as DestInsertionPoints except that this method will return
    * null if the array of destination insertion points does not already
    * exist.
    */
   virtual nsTArray<nsIContent*> *GetExistingDestInsertionPoints() const = 0;
 
   /**
+   * Gets the assigned slot associated with this content.
+   *
+   * @return The assigned slot element or null.
+   */
+  virtual mozilla::dom::HTMLSlotElement* GetAssignedSlot() const = 0;
+
+  /**
+   * Sets the assigned slot associated with this content.
+   *
+   * @param aSlot The assigned slot.
+   */
+  virtual void SetAssignedSlot(mozilla::dom::HTMLSlotElement* aSlot) = 0;
+
+  /**
    * Gets the insertion parent element of the XBL binding.
    * The insertion parent is our one true parent in the transformed DOM.
    *
    * @return the insertion parent element.
    */
   virtual nsIContent *GetXBLInsertionParent() const = 0;
 
   /**
--- a/dom/webidl/Element.webidl
+++ b/dom/webidl/Element.webidl
@@ -238,16 +238,18 @@ partial interface Element {
 // http://w3c.github.io/webcomponents/spec/shadow/#extensions-to-element-interface
 partial interface Element {
   [Throws,Pref="dom.webcomponents.enabled"]
   ShadowRoot createShadowRoot();
   [Pref="dom.webcomponents.enabled"]
   NodeList getDestinationInsertionPoints();
   [Pref="dom.webcomponents.enabled"]
   readonly attribute ShadowRoot? shadowRoot;
+  [Pref="dom.webcomponents.enabled"]
+  readonly attribute HTMLSlotElement? assignedSlot;
 };
 
 Element implements ChildNode;
 Element implements NonDocumentTypeChildNode;
 Element implements ParentNode;
 Element implements Animatable;
 Element implements GeometryUtils;
 
--- a/dom/webidl/Text.webidl
+++ b/dom/webidl/Text.webidl
@@ -13,9 +13,14 @@
 [Constructor(optional DOMString data = "")]
 interface Text : CharacterData {
   [Throws]
   Text splitText(unsigned long offset);
   [Throws]
   readonly attribute DOMString wholeText;
 };
 
+partial interface Text {
+  [Pref="dom.webcomponents.enabled"]
+  readonly attribute HTMLSlotElement? assignedSlot;
+};
+
 Text implements GeometryUtils;
--- a/testing/web-platform/meta/dom/interfaces.html.ini
+++ b/testing/web-platform/meta/dom/interfaces.html.ini
@@ -1,10 +1,11 @@
 [interfaces.html]
   type: testharness
+  prefs: [dom.webcomponents.enabled:true]
   [Document interface: attribute origin]
     expected: FAIL
     bug: 931884
 
   [Document interface: xmlDoc must inherit property "origin" with the proper type (3)]
     expected: FAIL
     bug: 931884
 
@@ -19,34 +20,28 @@
     expected: FAIL
 
   [Element interface: attribute slot]
     expected: FAIL
 
   [Element interface: operation attachShadow(ShadowRootInit)]
     expected: FAIL
 
-  [Element interface: attribute assignedSlot]
-    expected: FAIL
-
   [Element interface: element must inherit property "slot" with the proper type (7)]
     expected: FAIL
 
   [Element interface: element must inherit property "attachShadow" with the proper type (24)]
     expected: FAIL
 
   [Element interface: calling attachShadow(ShadowRootInit) on element with too few arguments must throw TypeError]
     expected: FAIL
 
   [Element interface: element must inherit property "assignedSlot" with the proper type (48)]
     expected: FAIL
 
-  [Text interface: attribute assignedSlot]
-    expected: FAIL
-
   [Text interface: document.createTextNode("abc") must inherit property "assignedSlot" with the proper type (2)]
     expected: FAIL
 
   [EventTarget must be primary interface of new EventTarget()]
     expected: FAIL
 
   [Stringification of new EventTarget()]
     expected: FAIL
@@ -97,14 +92,8 @@
     expected: FAIL
 
   [Element interface: element must inherit property "slot" with the proper type]
     expected: FAIL
 
   [Element interface: element must inherit property "attachShadow(ShadowRootInit)" with the proper type]
     expected: FAIL
 
-  [Element interface: element must inherit property "assignedSlot" with the proper type]
-    expected: FAIL
-
-  [Text interface: document.createTextNode("abc") must inherit property "assignedSlot" with the proper type]
-    expected: FAIL
-
--- a/testing/web-platform/meta/payment-request/interfaces.https.html.ini
+++ b/testing/web-platform/meta/payment-request/interfaces.https.html.ini
@@ -1,10 +1,11 @@
 [interfaces.https.html]
   type: testharness
+  prefs: [dom.webcomponents.enabled:true]
   [PaymentRequest interface: existence and properties of interface object]
     expected: FAIL
 
   [PaymentRequest interface object length]
     expected: FAIL
 
   [PaymentRequest interface object name]
     expected: FAIL
@@ -271,22 +272,16 @@
     expected: FAIL
 
   [Element interface: attribute slot]
     expected: FAIL
 
   [Element interface: operation attachShadow(ShadowRootInit)]
     expected: FAIL
 
-  [Element interface: attribute assignedSlot]
-    expected: FAIL
-
-  [Text interface: attribute assignedSlot]
-    expected: FAIL
-
   [PaymentRequest must be primary interface of new PaymentRequest([{supportedMethods: 'foo'}\], {total: {label: 'bar', amount: {currency: 'USD', value: '0'}} })]
     expected: FAIL
 
   [Stringification of new PaymentRequest([{supportedMethods: 'foo'}\], {total: {label: 'bar', amount: {currency: 'USD', value: '0'}} })]
     expected: FAIL
 
   [PaymentRequest interface: new PaymentRequest([{supportedMethods: 'foo'}\], {total: {label: 'bar', amount: {currency: 'USD', value: '0'}} }) must inherit property "show()" with the proper type]
     expected: FAIL
--- a/testing/web-platform/meta/shadow-dom/Slotable-interface.html.ini
+++ b/testing/web-platform/meta/shadow-dom/Slotable-interface.html.ini
@@ -1,13 +1,11 @@
 [Slotable-interface.html]
   type: testharness
-  [assignedSlot attribute must be defined on Element and Text interfaces]
-    expected: FAIL
-
+  prefs: [dom.webcomponents.enabled:true]
   [assignedSlot must return null when the node does not have an assigned node]
     expected: FAIL
 
   [assignedSlot must return the assigned slot]
     expected: FAIL
 
   [assignedSlot must return null when the assigned slot element is inside a closed shadow tree]
     expected: FAIL