WebCore:
authordarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 17 May 2009 16:47:09 +0000 (16:47 +0000)
committerdarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 17 May 2009 16:47:09 +0000 (16:47 +0000)
2009-05-17  Kai Brüning  <kai@granus.net>

        Reviewed by Darin Adler.

        bug 25822: DOM normalize does not remove empty text node between element nodes
        https://bugs.webkit.org/show_bug.cgi?id=25822

        Test: fast/dom/Node/normalize.html

        * dom/Node.cpp:
        (WebCore::Node::normalize): Changed to remove any empty text nodes.

LayoutTests:

2009-05-17  Kai Brüning  <kai@granus.net>

        Reviewed by Darin Adler.

        Test case for bug 25822: DOM normalize does not remove empty text node between element nodes
        https://bugs.webkit.org/show_bug.cgi?id=25822

        The test case strives to test the whole functionality of Node's normalize().

        * fast/dom/Node/normalize-expected.txt: Added.
        * fast/dom/Node/normalize.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@43809 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/fast/dom/Node/normalize-expected.txt [new file with mode: 0644]
LayoutTests/fast/dom/Node/normalize.html [new file with mode: 0644]
WebCore/ChangeLog
WebCore/dom/Node.cpp

index 1cabdbf..949fe46 100644 (file)
@@ -1,3 +1,15 @@
+2009-05-17  Kai Brüning  <kai@granus.net>
+
+        Reviewed by Darin Adler.
+        
+        Test case for bug 25822: DOM normalize does not remove empty text node between element nodes
+        https://bugs.webkit.org/show_bug.cgi?id=25822
+        
+        The test case strives to test the whole functionality of Node's normalize().
+
+        * fast/dom/Node/normalize-expected.txt: Added.
+        * fast/dom/Node/normalize.html: Added.
+
 2009-05-16  Dan Bernstein  <mitz@apple.com>
 
         Reviewed by Alexey Proskuryakov.
diff --git a/LayoutTests/fast/dom/Node/normalize-expected.txt b/LayoutTests/fast/dom/Node/normalize-expected.txt
new file mode 100644 (file)
index 0000000..31f1ff9
--- /dev/null
@@ -0,0 +1,12 @@
+Several tests of the DOM normalize() function.
+test1 (two non-empty text nodes): PASSED
+test2 (three non-empty text nodes): PASSED
+test3 (non-empty text nodes mixed with elements): PASSED
+test4 (single empty text node): PASSED
+test5 (empty text node between elements): PASSED
+test6 (empty text nodes before non-empty node): PASSED
+test7 (empty text nodes after non-empty node): PASSED
+test8 (empty text nodes between non-empty nodes): PASSED
+test9 (empty and non-empty text nodes mixed with elements): PASSED
+test10 (mixed cases including deeper nested text nodes): PASSED
+
diff --git a/LayoutTests/fast/dom/Node/normalize.html b/LayoutTests/fast/dom/Node/normalize.html
new file mode 100644 (file)
index 0000000..a8b61cb
--- /dev/null
@@ -0,0 +1,213 @@
+<html>
+
+<head>
+
+<title>Test of DOM Node.normalize()</title>
+
+<script>
+
+function logLine(message)
+{
+    var console = document.getElementById("console");
+    console.appendChild(document.createTextNode(message));
+    console.appendChild(document.createElement('br'));
+}
+
+function log(message)
+{
+    var console = document.getElementById("console");
+    console.appendChild(document.createTextNode(message));
+}
+
+
+function prepare_test1(testDiv)
+{
+    testDiv.firstChild.splitText(4);
+    return testDiv.childNodes.length == 2;
+}
+function check_test1(testDiv)
+{
+    return testDiv.childNodes.length == 1;
+}
+
+function prepare_test2(testDiv)
+{
+    testDiv.firstChild.splitText(9);
+    testDiv.firstChild.splitText(4);
+    return testDiv.childNodes.length == 3;
+}
+function check_test2(testDiv)
+{
+    return testDiv.childNodes.length == 1;
+}
+
+function prepare_test3(testDiv)
+{
+    testDiv.childNodes[1].splitText(4);
+    testDiv.childNodes[4].splitText(3);
+    return testDiv.childNodes.length == 6;
+}
+function check_test3(testDiv)
+{
+    return testDiv.childNodes.length == 4;
+}
+
+function prepare_test4(testDiv)
+{
+    testDiv.childNodes[0].data = "";
+    return testDiv.childNodes.length == 1;
+}
+function check_test4(testDiv)
+{
+    return testDiv.childNodes.length == 0;
+}
+
+function prepare_test5(testDiv)
+{
+    testDiv.childNodes[1].data = "";
+    return testDiv.childNodes.length == 3;
+}
+function check_test5(testDiv)
+{
+    return testDiv.childNodes.length == 2;
+}
+
+function prepare_test6(testDiv)
+{
+    testDiv.childNodes[0].splitText(0);
+    testDiv.childNodes[0].splitText(0);
+    return testDiv.childNodes.length == 3;
+}
+function check_test6(testDiv)
+{
+    return testDiv.childNodes.length == 1;
+}
+
+function prepare_test7(testDiv)
+{
+    testDiv.childNodes[0].splitText(4);
+    testDiv.childNodes[0].splitText(4);
+    testDiv.childNodes[0].splitText(4);
+    return testDiv.childNodes.length == 4;
+}
+function check_test7(testDiv)
+{
+    return testDiv.childNodes.length == 1;
+}
+
+function prepare_test8(testDiv)
+{
+    testDiv.childNodes[0].splitText(4);
+    testDiv.childNodes[0].splitText(4);
+    return testDiv.childNodes.length == 3;
+}
+function check_test8(testDiv)
+{
+    return testDiv.childNodes.length == 1;
+}
+
+function prepare_test9(testDiv)
+{
+    testDiv.childNodes[1].splitText(4);
+    testDiv.childNodes[1].splitText(0);    // empty text node before other text nodes
+    testDiv.childNodes[5].splitText(3);
+    testDiv.childNodes[5].splitText(3);    // empty text node between other text nodes
+    testDiv.childNodes[7].splitText(2);    // empty text node after other text nodes
+    return testDiv.childNodes.length == 9;
+}
+function check_test9(testDiv)
+{
+    return testDiv.childNodes.length == 4;
+}
+
+function prepare_test10(testDiv)
+{
+    testDiv.childNodes[0].childNodes[0].splitText(2);
+    testDiv.childNodes[1].splitText(4);
+    testDiv.childNodes[3].childNodes[0].data = "";    // empty first text node of the second bold node
+    testDiv.childNodes[3].childNodes[1].childNodes[0].data = "";    // empty text node of the italic node
+    testDiv.childNodes[4].splitText(1);
+    return testDiv.childNodes.length == 6;
+}
+function check_test10(testDiv)
+{
+    return testDiv.childNodes.length == 4
+        && testDiv.childNodes[0].childNodes.length == 1        // first bold node must have single text node child
+        && testDiv.childNodes[2].childNodes.length == 1        // first bold node must have single italic node child
+        && testDiv.childNodes[2].childNodes[0].childNodes.length == 0;    // italic node must be empty
+}
+
+function runTest(testDiv, testName)
+{
+    if (self["prepare_"+testName](testDiv)) {
+        var oldHTML = testDiv.innerHTML;
+        testDiv.normalize();
+        if (testDiv.innerHTML != oldHTML) {
+            log("FAILED: innerHTML changed from \"" + oldHTML + "\" to \"" + testDiv.innerHTML + "\"");
+        } else {
+            if (self["check_"+testName](testDiv))
+                log("PASSED");
+            else
+                log("FAILED");
+        }        
+    } else {
+        log("FAILED in test preparation");
+    }
+}
+
+function runTests()
+{
+    if (window.layoutTestController)
+        layoutTestController.dumpAsText();
+
+    try {
+        var tests = document.getElementById("tests").childNodes;
+        for (i = 0; i < tests.length; i++) {
+            var testDiv = tests[i];
+            // Skip formatting text nodes
+            if (testDiv.nodeType == Node.ELEMENT_NODE) {
+                var testName = testDiv.getAttribute("name");
+                
+                log(testName + " (" + testDiv.getAttribute("description") + "): ");
+                
+                try {
+                    runTest(testDiv, testName);
+                } catch(e) {
+                    log("FAILED with exception: " + e);
+                }
+                
+                logLine("")
+            }
+        }
+
+    } catch(e) {
+        logLine("FAILED, exception thrown during tests: " + e);
+    }
+}
+
+</script>
+
+</head>
+
+<body onload="runTests()">
+
+<div id="description">Several tests of the DOM normalize() function.</div>
+
+<div id="tests" style="display:none">
+    <div name="test1" description="two non-empty text nodes">some text</div>
+    <div name="test2" description="three non-empty text nodes">some more text</div>
+    <div name="test3" description="non-empty text nodes mixed with elements"><b></b>some more<b></b> text</div>
+    <div name="test4" description="single empty text node">text</div>
+    <div name="test5" description="empty text node between elements"><b></b>text<i></i></div>
+    <div name="test6" description="empty text nodes before non-empty node">text</div>
+    <div name="test7" description="empty text nodes after non-empty node">text</div>
+    <div name="test8" description="empty text nodes between non-empty nodes">some text</div>
+    <div name="test9" description="empty and non-empty text nodes mixed with elements"><b></b>some more<b></b> text</div>
+    <div name="test10" description="mixed cases including deeper nested text nodes"><b>text</b>text <b>text<i>text</i></b> text</div>
+</div>
+
+<div id="console"></div>
+
+</body>
+
+</html>
index 5533328..6667cb7 100644 (file)
@@ -1,3 +1,15 @@
+2009-05-17  Kai Brüning  <kai@granus.net>
+
+        Reviewed by Darin Adler.
+
+        bug 25822: DOM normalize does not remove empty text node between element nodes
+        https://bugs.webkit.org/show_bug.cgi?id=25822
+
+        Test: fast/dom/Node/normalize.html
+
+        * dom/Node.cpp:
+        (WebCore::Node::normalize): Changed to remove any empty text nodes.
+
 2009-05-16  Dave Moore  <davemoore@google.com>
 
         Reviewed by Darin Adler.
index c27e24d..d5381cb 100644 (file)
@@ -561,43 +561,57 @@ void Node::remove(ExceptionCode& ec)
 void Node::normalize()
 {
     // Go through the subtree beneath us, normalizing all nodes. This means that
-    // any two adjacent text nodes are merged together.
+    // any two adjacent text nodes are merged and any empty text nodes are removed.
 
     RefPtr<Node> node = this;
     while (Node* firstChild = node->firstChild())
         node = firstChild;
-    for (; node; node = node->traverseNextNodePostOrder()) {
+    while (node) {
         NodeType type = node->nodeType();
         if (type == ELEMENT_NODE)
             static_cast<Element*>(node.get())->normalizeAttributes();
 
-        Node* firstChild = node->firstChild();
-        if (firstChild && !firstChild->nextSibling() && firstChild->isTextNode()) {
-            Text* text = static_cast<Text*>(firstChild);
-            if (!text->length()) {
-                ExceptionCode ec;
-                text->remove(ec);
-            }
-        }
-
         if (node == this)
             break;
 
-        if (type == TEXT_NODE) {
-            while (1) {
-                Node* nextSibling = node->nextSibling();
-                if (!nextSibling || !nextSibling->isTextNode())
-                    break;
-                // Current child and the next one are both text nodes. Merge them.
-                Text* text = static_cast<Text*>(node.get());
-                RefPtr<Text> nextText = static_cast<Text*>(nextSibling);
-                unsigned offset = text->length();
+        if (type != TEXT_NODE) {
+            node = node->traverseNextNodePostOrder();
+            continue;
+        }
+
+        Text* text = static_cast<Text*>(node.get());
+
+        // Remove empty text nodes.
+        if (!text->length()) {
+            // Care must be taken to get the next node before removing the current node.
+            node = node->traverseNextNodePostOrder();
+            ExceptionCode ec;
+            text->remove(ec);
+            continue;
+        }
+
+        // Merge text nodes.
+        while (Node* nextSibling = node->nextSibling()) {
+            if (!nextSibling->isTextNode())
+                break;
+            RefPtr<Text> nextText = static_cast<Text*>(nextSibling);
+
+            // Remove empty text nodes.
+            if (!nextText->length()) {
                 ExceptionCode ec;
-                text->appendData(nextText->data(), ec);
-                document()->textNodesMerged(nextText.get(), offset);
                 nextText->remove(ec);
+                continue;
             }
+
+            // Both non-empty text nodes. Merge them.
+            unsigned offset = text->length();
+            ExceptionCode ec;
+            text->appendData(nextText->data(), ec);
+            document()->textNodesMerged(nextText.get(), offset);
+            nextText->remove(ec);
         }
+
+        node = node->traverseNextNodePostOrder();
     }
 }