summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dom/base/nsINode.cpp25
-rw-r--r--dom/base/nsINode.h10
-rw-r--r--dom/tests/mochitest/webcomponents/mochitest.ini1
-rw-r--r--dom/tests/mochitest/webcomponents/test_bug1269155.html89
-rw-r--r--dom/webidl/Node.webidl9
-rw-r--r--modules/libpref/init/all.js7
-rw-r--r--testing/web-platform/meta/dom/historical.html.ini4
-rw-r--r--testing/web-platform/meta/dom/interfaces.html.ini57
-rw-r--r--testing/web-platform/meta/dom/nodes/rootNode.html.ini15
9 files changed, 128 insertions, 89 deletions
diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp
index d0cbdb454..da30bed5c 100644
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -107,6 +107,7 @@
#include "GeometryUtils.h"
#include "nsIAnimationObserver.h"
#include "nsChildContentList.h"
+#include "mozilla/dom/NodeBinding.h"
#ifdef ACCESSIBILITY
#include "mozilla/dom/AccessibleNode.h"
@@ -250,6 +251,30 @@ nsINode::GetTextEditorRootContent(nsIEditor** aEditor)
return nullptr;
}
+nsINode* nsINode::GetRootNode(const GetRootNodeOptions& aOptions)
+{
+ if (aOptions.mComposed) {
+ if (IsInComposedDoc() && GetComposedDoc()) {
+ return OwnerDoc();
+ }
+
+ nsINode* node = this;
+ ShadowRoot* shadowRootParent = nullptr;
+ while(node) {
+ node = node->SubtreeRoot();
+ shadowRootParent = ShadowRoot::FromNode(node);
+ if (!shadowRootParent) {
+ break;
+ }
+ node = shadowRootParent->GetHost();
+ }
+
+ return node;
+ }
+
+ return SubtreeRoot();
+}
+
nsINode*
nsINode::SubtreeRoot() const
{
diff --git a/dom/base/nsINode.h b/dom/base/nsINode.h
index 7fb535701..5ae3a1da9 100644
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -84,6 +84,7 @@ template<typename> class Sequence;
class Text;
class TextOrElementOrDocument;
struct DOMPointInit;
+struct GetRootNodeOptions;
} // namespace dom
} // namespace mozilla
@@ -982,10 +983,11 @@ public:
*/
nsINode* SubtreeRoot() const;
- nsINode* RootNode() const
- {
- return SubtreeRoot();
- }
+ /*
+ * Get context object's shadow-including root if options's composed is true,
+ * and context object's root otherwise.
+ */
+ nsINode* GetRootNode(const mozilla::dom::GetRootNodeOptions& aOptions);
/**
* See nsIDOMEventTarget
diff --git a/dom/tests/mochitest/webcomponents/mochitest.ini b/dom/tests/mochitest/webcomponents/mochitest.ini
index 428cc0e73..7b6ec9724 100644
--- a/dom/tests/mochitest/webcomponents/mochitest.ini
+++ b/dom/tests/mochitest/webcomponents/mochitest.ini
@@ -40,3 +40,4 @@ skip-if = true # disabled - See bug 1390396
[test_shadowroot_style_order.html]
[test_style_fallback_content.html]
[test_link_prefetch.html]
+[test_bug1269155.html]
diff --git a/dom/tests/mochitest/webcomponents/test_bug1269155.html b/dom/tests/mochitest/webcomponents/test_bug1269155.html
new file mode 100644
index 000000000..f280ae1d2
--- /dev/null
+++ b/dom/tests/mochitest/webcomponents/test_bug1269155.html
@@ -0,0 +1,89 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1269155
+-->
+<head>
+ <title>Test for Bug 1269155</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=1269155">Mozilla Bug 1269155</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 1269155 **/
+var host = document.querySelector('#content');
+ var root = host.createShadowRoot();
+
+ var header1 = document.createElement('h1');
+ header1.textContent = 'Shadow Header1';
+
+ var paragraph1 = document.createElement('p');
+ paragraph1.textContent = 'shadow text paragraph1';
+
+ root.appendChild(header1);
+ root.appendChild(paragraph1);
+
+var root2 = paragraph1.createShadowRoot();
+var header2 = document.createElement('h2');
+header2.textContent = 'Shadow Header2';
+
+var paragraph2 = document.createElement('p');
+paragraph2.textContent = 'shadow text paragraph2';
+root2.appendChild(header2);
+root2.appendChild(paragraph2);
+
+
+var frag = document.createDocumentFragment();
+var paragraph3 = document.createElement('p');
+paragraph3.textContent = 'fragment paragraph3';
+frag.appendChild(paragraph3);
+
+var root3 = paragraph3.createShadowRoot();
+var header4 = document.createElement('h2');
+header4.textContent = 'Shadow Header3';
+
+var paragraph4 = document.createElement('p');
+paragraph4.textContent = 'shadow text paragraph4';
+
+root3.appendChild(header4);
+root3.appendChild(paragraph4);
+
+//shadow dom without compose
+is(root.getRootNode(), root, "root.getRootNode() should be root.");
+is(root2.getRootNode(), root2, "root2.getRootNode() should be root.");
+is(root3.getRootNode(), root3, "root3.getRootNode() should be root.");
+is(header1.getRootNode(), root, "header1.getRootNode() should be root.");
+is(header2.getRootNode(), root2, "header1.getRootNode() should be root2.");
+is(header4.getRootNode(), root3, "header1.getRootNode() should be root3.");
+//shadow dom with compose
+is(root.getRootNode({ composed: true }), document, "root.getRootNode() with composed flag should be document.");
+is(root2.getRootNode({ composed: true }), document, "root2.getRootNode() with composed flag should be document.");
+is(root3.getRootNode({ composed: true }), frag, "root3.getRootNode() with composed flag should be frag.");
+is(header1.getRootNode({ composed: true }) , document, "header1.getRootNode() with composed flag should be document.");
+is(header2.getRootNode({ composed: true }) , document, "header2.getRootNode() with composed flag should be document.");
+is(header4.getRootNode({ composed: true }) , frag, "head4.getRootNode() with composed flag should be frag.");
+//dom without compose
+is(host.getRootNode(), document, "host.getRootNode() should be document.");
+is(header1.getRootNode(), root, "header1.getRootNode() should be root.");
+is(paragraph1.getRootNode(), root, "paragraph1.getRootNode() should be root.");
+is(frag.getRootNode(), frag, "frag.getRootNode() should be frag.");
+//dom with compose
+is(host.getRootNode({ composed: true }) , document, "host.getRootNode() with composed flag should be document.");
+is(header1.getRootNode({ composed: true }) , document, "header1.getRootNode() with composed flag should be document.");
+is(paragraph1.getRootNode({ composed: true }) , document, "paragraph1.getRootNode() with composed flag should be document.");
+is(frag.getRootNode({ composed: true }) , frag, "frag.getRootNode() with composed flag should be frag.");
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/webidl/Node.webidl b/dom/webidl/Node.webidl
index 8b6dca788..c9fb7e77e 100644
--- a/dom/webidl/Node.webidl
+++ b/dom/webidl/Node.webidl
@@ -38,8 +38,8 @@ interface Node : EventTarget {
readonly attribute boolean isConnected;
[Pure]
readonly attribute Document? ownerDocument;
- [Pure, Pref="dom.node.rootNode.enabled"]
- readonly attribute Node rootNode;
+ [Pure]
+ Node getRootNode(optional GetRootNodeOptions options);
[Pure]
readonly attribute Node? parentNode;
[Pure]
@@ -113,3 +113,8 @@ interface Node : EventTarget {
readonly attribute AccessibleNode? accessibleNode;
#endif
};
+
+dictionary GetRootNodeOptions {
+ boolean composed = false;
+};
+
diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js
index 9e2513011..b5b112020 100644
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -5377,13 +5377,6 @@ pref("layout.css.color-adjust.enabled", true);
pref("dom.audiochannel.audioCompeting", false);
pref("dom.audiochannel.audioCompeting.allAgents", false);
-// Disable Node.rootNode in release builds.
-#ifdef RELEASE_OR_BETA
-pref("dom.node.rootNode.enabled", false);
-#else
-pref("dom.node.rootNode.enabled", true);
-#endif
-
// Default media volume
pref("media.default_volume", "1.0");
diff --git a/testing/web-platform/meta/dom/historical.html.ini b/testing/web-platform/meta/dom/historical.html.ini
index 6894d4868..42c737606 100644
--- a/testing/web-platform/meta/dom/historical.html.ini
+++ b/testing/web-platform/meta/dom/historical.html.ini
@@ -12,7 +12,3 @@
expected: FAIL
bug: 660660
- [Node member must be nuked: rootNode]
- disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1303802
- bug: 1269155
-
diff --git a/testing/web-platform/meta/dom/interfaces.html.ini b/testing/web-platform/meta/dom/interfaces.html.ini
index 988efdf97..a9aa4a34e 100644
--- a/testing/web-platform/meta/dom/interfaces.html.ini
+++ b/testing/web-platform/meta/dom/interfaces.html.ini
@@ -1,6 +1,5 @@
[interfaces.html]
type: testharness
- prefs: [dom.node.rootNode.enabled:true]
[Document interface: attribute origin]
expected: FAIL
@@ -42,60 +41,4 @@
[Text interface: document.createTextNode("abc") must inherit property "assignedSlot" with the proper type (2)]
expected: FAIL
- [Node interface: operation getRootNode(GetRootNodeOptions)]
- expected: FAIL
-
- [Node interface: new Document() must inherit property "getRootNode" with the proper type (17)]
- expected: FAIL
-
- [Node interface: calling getRootNode(GetRootNodeOptions) on new Document() with too few arguments must throw TypeError]
- expected: FAIL
-
- [Node interface: xmlDoc must inherit property "getRootNode" with the proper type (17)]
- expected: FAIL
-
- [Node interface: calling getRootNode(GetRootNodeOptions) on xmlDoc with too few arguments must throw TypeError]
- expected: FAIL
-
- [Node interface: document.doctype must inherit property "getRootNode" with the proper type (17)]
- expected: FAIL
-
- [Node interface: calling getRootNode(GetRootNodeOptions) on document.doctype with too few arguments must throw TypeError]
- expected: FAIL
-
- [Node interface: document.createDocumentFragment() must inherit property "getRootNode" with the proper type (17)]
- expected: FAIL
-
- [Node interface: calling getRootNode(GetRootNodeOptions) on document.createDocumentFragment() with too few arguments must throw TypeError]
- expected: FAIL
-
- [Node interface: element must inherit property "getRootNode" with the proper type (17)]
- expected: FAIL
-
- [Node interface: calling getRootNode(GetRootNodeOptions) on element with too few arguments must throw TypeError]
- expected: FAIL
-
- [Node interface: document.querySelector("[id\]").attributes[0\] must inherit property "getRootNode" with the proper type (17)]
- expected: FAIL
-
- [Node interface: calling getRootNode(GetRootNodeOptions) on document.querySelector("[id\]").attributes[0\] with too few arguments must throw TypeError]
- expected: FAIL
-
- [Node interface: document.createTextNode("abc") must inherit property "getRootNode" with the proper type (17)]
- expected: FAIL
-
- [Node interface: calling getRootNode(GetRootNodeOptions) on document.createTextNode("abc") with too few arguments must throw TypeError]
- expected: FAIL
-
- [Node interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "getRootNode" with the proper type (17)]
- expected: FAIL
-
- [Node interface: calling getRootNode(GetRootNodeOptions) on xmlDoc.createProcessingInstruction("abc", "def") with too few arguments must throw TypeError]
- expected: FAIL
-
- [Node interface: document.createComment("abc") must inherit property "getRootNode" with the proper type (17)]
- expected: FAIL
-
- [Node interface: calling getRootNode(GetRootNodeOptions) on document.createComment("abc") with too few arguments must throw TypeError]
- expected: FAIL
diff --git a/testing/web-platform/meta/dom/nodes/rootNode.html.ini b/testing/web-platform/meta/dom/nodes/rootNode.html.ini
deleted file mode 100644
index 59533aebb..000000000
--- a/testing/web-platform/meta/dom/nodes/rootNode.html.ini
+++ /dev/null
@@ -1,15 +0,0 @@
-[rootNode.html]
- type: testharness
- prefs: [dom.node.rootNode.enabled:true]
- [getRootNode() must return the context object when it does not have any parent]
- expected: FAIL
-
- [getRootNode() must return the parent node of the context object when the context object has a single ancestor not in a document]
- expected: FAIL
-
- [getRootNode() must return the document when a node is in document]
- expected: FAIL
-
- [getRootNode() must return a document fragment when a node is in the fragment]
- expected: FAIL
-