Bug 1276438 part 3. Align the .body setter with the spec a bit better. r=mystor
authorBoris Zbarsky <bzbarsky@mit.edu>
Fri, 26 Jan 2018 00:52:40 -0500
changeset 748747 82958e09a8c6d376e17a0dce0b1379f86e61f747
parent 748746 7f8a7edd37851786280250d8c2e30efcc91930bf
child 748748 d6b890b102b7197415317b0966e6a5c636fd5f57
push id97228
push usersfraser@mozilla.com
push dateTue, 30 Jan 2018 10:21:04 +0000
reviewersmystor
bugs1276438, 366200
milestone60.0a1
Bug 1276438 part 3. Align the .body setter with the spec a bit better. r=mystor There are two changes here: 1) We allow setting .body even if the root element is not an <html:html>. This is what the spec says to do, and what we used to do before the changes in bug 366200. No tests for this yet, pending https://github.com/whatwg/html/issues/3403 getting resolved. 2) We use GetBody(), not GetBodyElement(), to look for an existing thing to replace. This matters if there are <frameset>s involved. MozReview-Commit-ID: JCaQGHKgzE7
dom/base/nsDocument.cpp
testing/web-platform/tests/html/dom/documents/dom-tree-accessors/Document.body.html
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -6821,28 +6821,26 @@ nsIDocument::GetBody()
 }
 
 void
 nsIDocument::SetBody(nsGenericHTMLElement* newBody, ErrorResult& rv)
 {
   nsCOMPtr<Element> root = GetRootElement();
 
   // The body element must be either a body tag or a frameset tag. And we must
-  // have a html root tag, otherwise GetBody will not return the newly set
-  // body.
+  // have a root element to be able to add kids to it.
   if (!newBody ||
       !newBody->IsAnyOfHTMLElements(nsGkAtoms::body, nsGkAtoms::frameset) ||
-      !root || !root->IsHTMLElement() ||
-      !root->IsHTMLElement(nsGkAtoms::html)) {
+      !root) {
     rv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
     return;
   }
 
   // Use DOM methods so that we pass through the appropriate security checks.
-  nsCOMPtr<Element> currentBody = GetBodyElement();
+  nsCOMPtr<Element> currentBody = GetBody();
   if (currentBody) {
     root->ReplaceChild(*newBody, *currentBody, rv);
   } else {
     root->AppendChild(*newBody, rv);
   }
 }
 
 Element*
--- a/testing/web-platform/tests/html/dom/documents/dom-tree-accessors/Document.body.html
+++ b/testing/web-platform/tests/html/dom/documents/dom-tree-accessors/Document.body.html
@@ -161,9 +161,59 @@ test(function() {
 
   var new_frameset = doc.createElement("frameset");
   assert_true(new_frameset instanceof HTMLFrameSetElement, "should be HTMLFrameSetElement");
   assert_equals(new_frameset.tagName, "FRAMESET");
 
   doc.body = new_frameset;
   assert_equals(doc.body, new_frameset, "test6-3, append frameset to a new document");
 }, "Setting document.body to a new frameset element.");
+
+test(function() {
+  var doc = createDocument();
+  var html = doc.appendChild(doc.createElement("html"));
+  var f =
+    html.appendChild(doc.createElement("frameset"));
+  assert_equals(doc.body, f);
+
+  var b = doc.createElement("body");
+  doc.body = b;
+
+  assert_equals(f.parentNode, null,
+                "Frameset should have been removed from the tree");
+  assert_equals(doc.body, b, "Body should be the new doc.body");
+}, "Setting document.body to a body will replace an existing frameset if there is one.");
+
+test(function() {
+  var doc = createDocument();
+  var html = doc.appendChild(doc.createElement("html"));
+  var b =
+    html.appendChild(doc.createElement("body"));
+  assert_equals(doc.body, b);
+
+  var f = doc.createElement("frameset");
+  doc.body = f;
+
+  assert_equals(b.parentNode, null,
+                "Body should have been removed from the tree");
+  assert_equals(doc.body, f, "Frameset should be the new doc.body");
+}, "Setting document.body to a frameset will replace an existing body if there is one.");
+
+test(function() {
+  var doc = createDocument();
+  var html = doc.appendChild(doc.createElement("html"));
+  var b =
+    html.appendChild(doc.createElement("body"));
+  var f1 = html.appendChild(doc.createElement("frameset"));
+  assert_equals(doc.body, b);
+
+  var f2 = doc.createElement("frameset");
+  doc.body = f2;
+
+  assert_equals(b.parentNode, null,
+                "Body should have been removed from the tree");
+  assert_equals(f1.parentNode, html,
+                "Frameset following body should still be in the tree.");
+  assert_equals(doc.body, f2, "New frameset should be the new doc.body");
+  assert_equals(f2.nextSibling, f1, "New frameset should have replaced the body");
+}, "Setting document.body to a frameset will replace the first existing body/frameset.");
+
 </script>