diff --git a/content/base/src/nsGenericElement.cpp b/content/base/src/nsGenericElement.cpp
index a1be153d4efd..1e5188ce9504 100644
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -1773,6 +1773,18 @@ nsGenericElement::Normalize()
switch (nodeType) {
case nsIDOMNode::TEXT_NODE:
+ // ensure that if the text node is empty, it is removed
+ if (0 == child->TextLength()) {
+ result = RemoveChildAt(index, PR_TRUE);
+ if (NS_FAILED(result)) {
+ return result;
+ }
+
+ count--;
+ index--;
+ break;
+ }
+
if (index+1 < count) {
// Get the sibling. If it's also a text node, then
// remove it from the tree and join the two text
diff --git a/content/test/unit/empty_document.xml b/content/test/unit/empty_document.xml
new file mode 100644
index 000000000000..ebd60b08c7b5
--- /dev/null
+++ b/content/test/unit/empty_document.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/content/test/unit/test_normalize.js b/content/test/unit/test_normalize.js
new file mode 100644
index 000000000000..6f5ce6ded60b
--- /dev/null
+++ b/content/test/unit/test_normalize.js
@@ -0,0 +1,141 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is DOM Node.normalize test code.
+ *
+ * The Initial Developer of the Original Code is
+ * Jeff Walden .
+ * Portions created by the Initial Developer are Copyright (C) 2006
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+function run_test()
+{
+ /*
+ * NOTE: [i] is not allowed in this test, since it's done via classinfo and
+ * we don't have that in xpcshell; the workaround is item(i). Suck.
+ */
+ init();
+
+ test_element();
+
+ // more tests would be nice here (such as for documents), but the primary
+ // uses of Node.normalize() are in test_element; stuff beyond this is either
+ // unimplemented or is unlikely to be used all that much within a browser
+ // DOM implementation
+}
+
+// TEST CODE
+
+var doc; // cache for use in all tests
+
+function init()
+{
+ doc = ParseFile("empty_document.xml");
+}
+
+function test_element()
+{
+ var x = doc.createElement("funk");
+
+ // one empty Text node
+ x.appendChild(doc.createTextNode(""));
+ do_check_eq(x.childNodes.length, 1);
+
+ x.normalize();
+ do_check_eq(x.childNodes.length, 0);
+
+
+ // multiple empty Text nodes
+ x.appendChild(doc.createTextNode(""));
+ x.appendChild(doc.createTextNode(""));
+ do_check_eq(x.childNodes.length, 2);
+
+ x.normalize();
+ do_check_eq(x.childNodes.length, 0);
+
+
+ // empty Text node followed by other Text node
+ x.appendChild(doc.createTextNode(""));
+ x.appendChild(doc.createTextNode("Guaraldi"));
+ do_check_eq(x.childNodes.length, 2);
+
+ x.normalize();
+ do_check_eq(x.childNodes.length, 1);
+ do_check_eq(x.childNodes.item(0).nodeValue, "Guaraldi");
+
+
+ // Text node followed by empty Text node
+ clearKids(x);
+ x.appendChild(doc.createTextNode("Guaraldi"));
+ x.appendChild(doc.createTextNode(""));
+ do_check_eq(x.childNodes.length, 2);
+
+ x.normalize();
+ do_check_eq(x.childNodes.item(0).nodeValue, "Guaraldi");
+
+
+ // Text node followed by empty Text node followed by other Node
+ clearKids(x);
+ x.appendChild(doc.createTextNode("Guaraldi"));
+ x.appendChild(doc.createTextNode(""));
+ x.appendChild(doc.createElement("jazzy"));
+ do_check_eq(x.childNodes.length, 3);
+
+ x.normalize();
+ do_check_eq(x.childNodes.length, 2);
+ do_check_eq(x.childNodes.item(0).nodeValue, "Guaraldi");
+ do_check_eq(x.childNodes.item(1).nodeName, "jazzy");
+
+
+ // Nodes are recursively normalized
+ clearKids(x);
+ var kid = doc.createElement("eit");
+ kid.appendChild(doc.createTextNode(""));
+
+ x.appendChild(doc.createTextNode("Guaraldi"));
+ x.appendChild(doc.createTextNode(""));
+ x.appendChild(kid);
+ do_check_eq(x.childNodes.length, 3);
+ do_check_eq(x.childNodes.item(2).childNodes.length, 1);
+
+ x.normalize();
+ do_check_eq(x.childNodes.length, 2);
+ do_check_eq(x.childNodes.item(0).nodeValue, "Guaraldi");
+ do_check_eq(x.childNodes.item(1).childNodes.length, 0);
+}
+
+
+// UTILITY FUNCTIONS
+
+function clearKids(node)
+{
+ while (node.hasChildNodes())
+ node.removeChild(node.childNodes.item(0));
+}