Title: [105058] trunk
Revision
105058
Author
[email protected]
Date
2012-01-16 05:35:04 -0800 (Mon, 16 Jan 2012)

Log Message

Web Inspector: editing body multiplies head
https://bugs.webkit.org/show_bug.cgi?id=62272

Patch by Pavel Feldman <[email protected]> on 2012-01-15
Reviewed by Yury Semikhatsky.

Source/WebCore:

Test: inspector/elements/set-outer-html-body.html

* inspector/DOMEditor.cpp:
(WebCore::DOMEditor::patchDocument):
(WebCore::DOMEditor::patchNode):
(WebCore::DOMEditor::innerPatchChildren):
(WebCore::DOMEditor::insertBefore):
* inspector/DOMEditor.h:
* inspector/InspectorDOMAgent.cpp:
(WebCore::InspectorDOMAgent::setOuterHTML):

LayoutTests:

* inspector/elements/resources/set-outer-html-body-iframe.html: Added.
* inspector/elements/set-outer-html-body-expected.txt: Added.
* inspector/elements/set-outer-html-body.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (105057 => 105058)


--- trunk/LayoutTests/ChangeLog	2012-01-16 13:08:29 UTC (rev 105057)
+++ trunk/LayoutTests/ChangeLog	2012-01-16 13:35:04 UTC (rev 105058)
@@ -1,3 +1,14 @@
+2012-01-15  Pavel Feldman  <[email protected]>
+
+        Web Inspector: editing body multiplies head
+        https://bugs.webkit.org/show_bug.cgi?id=62272
+
+        Reviewed by Yury Semikhatsky.
+
+        * inspector/elements/resources/set-outer-html-body-iframe.html: Added.
+        * inspector/elements/set-outer-html-body-expected.txt: Added.
+        * inspector/elements/set-outer-html-body.html: Added.
+
 2012-01-16  Alexander Pavlov  <[email protected]>
 
         [Chromium] Unreviewed, mark two inspector/debugger tests as SLOW on Linux Debug.

Added: trunk/LayoutTests/inspector/elements/resources/set-outer-html-body-iframe.html (0 => 105058)


--- trunk/LayoutTests/inspector/elements/resources/set-outer-html-body-iframe.html	                        (rev 0)
+++ trunk/LayoutTests/inspector/elements/resources/set-outer-html-body-iframe.html	2012-01-16 13:35:04 UTC (rev 105058)
@@ -0,0 +1,9 @@
+<html id="html">
+<head id="head">
+<script>
+</script>
+</head>
+<body id="body">
+<div>Foo</div>
+</body>
+</html>
Property changes on: trunk/LayoutTests/inspector/elements/resources/set-outer-html-body-iframe.html
___________________________________________________________________

Added: svn:eol-style

Added: trunk/LayoutTests/inspector/elements/set-outer-html-body-expected.txt (0 => 105058)


--- trunk/LayoutTests/inspector/elements/set-outer-html-body-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/inspector/elements/set-outer-html-body-expected.txt	2012-01-16 13:35:04 UTC (rev 105058)
@@ -0,0 +1,26 @@
+Tests DOMAgent.setOuterHTML invoked on body tag. See https://bugs.webkit.org/show_bug.cgi?id=62272. 
+
+
+Running: testSetUp
+
+Running: testSetBody
+<html id="html"><head id="head">
+<script>
+</script>
+</head>
+<body>New body content</body></html>
+
+Running: testInsertComments
+<html id="html"><head id="head">
+<script>
+</script>
+</head>
+<!-- new comment between head and body --><body>New body content</body></html>
+
+Running: testSetHead
+<html id="html"><head><!-- new head content --></head>
+<!-- new comment between head and body --><body>New body content</body></html>
+
+Running: testSetHTML
+<html><head><!-- new head content --></head><body>Setting body as a part of HTML.</body></html>
+
Property changes on: trunk/LayoutTests/inspector/elements/set-outer-html-body-expected.txt
___________________________________________________________________

Added: svn:eol-style

Added: trunk/LayoutTests/inspector/elements/set-outer-html-body.html (0 => 105058)


--- trunk/LayoutTests/inspector/elements/set-outer-html-body.html	                        (rev 0)
+++ trunk/LayoutTests/inspector/elements/set-outer-html-body.html	2012-01-16 13:35:04 UTC (rev 105058)
@@ -0,0 +1,72 @@
+<html>
+<head>
+
+<script src=""
+<script src=""
+<script>
+
+function test()
+{
+    var htmlNode;
+    var bodyNode;
+    var headNode;
+
+    InspectorTest.runTestSuite([
+        function testSetUp(next)
+        {
+            InspectorTest.expandElementsTree(step1);
+            function step1()
+            {
+                htmlNode = InspectorTest.expandedNodeWithId("html");
+                headNode = InspectorTest.expandedNodeWithId("head");
+                bodyNode = InspectorTest.expandedNodeWithId("body");
+                next();
+            }
+        },
+
+        function testSetBody(next)
+        {
+            DOMAgent.setOuterHTML(bodyNode.id, "<body>New body content</body>", dumpHTML(next));
+        },
+
+        function testInsertComments(next)
+        {
+            DOMAgent.setOuterHTML(bodyNode.id, "<!-- new comment between head and body --><body>New body content</body>", dumpHTML(next));
+        },
+
+        function testSetHead(next)
+        {
+            DOMAgent.setOuterHTML(headNode.id, "<head><!-- new head content --></head>", dumpHTML(next));
+        },
+
+         function testSetHTML(next)
+        {
+            DOMAgent.setOuterHTML(htmlNode.id, "<html><head><!-- new head content --></head><body>Setting body as a part of HTML.</body></html>", dumpHTML(next));
+        }
+    ]);
+
+    function dumpHTML(next)
+    {
+        function dump()
+        {
+            // User console.log for output since body has been overwritten.
+            DOMAgent.getOuterHTML(htmlNode.id, callback);
+            function callback(error, text)
+            {
+                InspectorTest.addResult(error ? error : text);
+                next();
+            }
+        }
+        return dump;
+    }
+}
+</script>
+</head>
+
+<body>
+<p>
+Tests DOMAgent.setOuterHTML invoked on body tag. See https://bugs.webkit.org/show_bug.cgi?id=62272.
+<iframe src="" _onload_="runTest()"></iframe>
+</p>
+</body>
+</html>
Property changes on: trunk/LayoutTests/inspector/elements/set-outer-html-body.html
___________________________________________________________________

Added: svn:eol-style

Modified: trunk/Source/WebCore/ChangeLog (105057 => 105058)


--- trunk/Source/WebCore/ChangeLog	2012-01-16 13:08:29 UTC (rev 105057)
+++ trunk/Source/WebCore/ChangeLog	2012-01-16 13:35:04 UTC (rev 105058)
@@ -1,3 +1,21 @@
+2012-01-15  Pavel Feldman  <[email protected]>
+
+        Web Inspector: editing body multiplies head
+        https://bugs.webkit.org/show_bug.cgi?id=62272
+
+        Reviewed by Yury Semikhatsky.
+
+        Test: inspector/elements/set-outer-html-body.html
+
+        * inspector/DOMEditor.cpp:
+        (WebCore::DOMEditor::patchDocument):
+        (WebCore::DOMEditor::patchNode):
+        (WebCore::DOMEditor::innerPatchChildren):
+        (WebCore::DOMEditor::insertBefore):
+        * inspector/DOMEditor.h:
+        * inspector/InspectorDOMAgent.cpp:
+        (WebCore::InspectorDOMAgent::setOuterHTML):
+
 2012-01-16  Nikolas Zimmermann  <[email protected]>
 
         Large SVG text layout performance regression in r81168

Modified: trunk/Source/WebCore/inspector/DOMEditor.cpp (105057 => 105058)


--- trunk/Source/WebCore/inspector/DOMEditor.cpp	2012-01-16 13:08:29 UTC (rev 105057)
+++ trunk/Source/WebCore/inspector/DOMEditor.cpp	2012-01-16 13:35:04 UTC (rev 105058)
@@ -41,6 +41,7 @@
 #include "HTMLDocumentParser.h"
 #include "HTMLElement.h"
 #include "HTMLHeadElement.h"
+#include "HTMLNames.h"
 #include "Node.h"
 
 #include <wtf/Deque.h>
@@ -52,6 +53,10 @@
 
 namespace WebCore {
 
+using HTMLNames::bodyTag;
+using HTMLNames::headTag;
+using HTMLNames::htmlTag;
+
 struct DOMEditor::Digest {
     explicit Digest(Node* node) : m_node(node) { }
 
@@ -74,9 +79,9 @@
     parser->detach();
 
     ExceptionCode ec = 0;
-    innerPatchHTMLElement(m_document->head(), newDocument->head(), ec);
-    if (!ec)
-        innerPatchHTMLElement(m_document->body(), newDocument->body(), ec);
+    OwnPtr<Digest> oldInfo = createDigest(m_document->documentElement(), 0);
+    OwnPtr<Digest> newInfo = createDigest(newDocument->documentElement(), &m_unusedNodesMap);
+    innerPatchNode(oldInfo.get(), newInfo.get(), ec);
 
     if (ec) {
         // Fall back to rewrite.
@@ -87,53 +92,49 @@
 
 Node* DOMEditor::patchNode(Node* node, const String& markup, ExceptionCode& ec)
 {
-    Element* parentElement = node->parentElement();
+    // Don't parse <html> as a fragment.
+    if (node == node->ownerDocument()->documentElement()) {
+        patchDocument(markup);
+        return 0;
+    }
+
     Node* previousSibling = node->previousSibling();
     RefPtr<DocumentFragment> fragment = DocumentFragment::create(m_document);
-    fragment->parseHTML(markup, parentElement);
+    fragment->parseHTML(markup, node->parentElement() ? node->parentElement() : m_document->documentElement());
 
     // Compose the old list.
+    ContainerNode* parentNode = node->parentNode();
     Vector<OwnPtr<Digest> > oldList;
-    for (Node* child = parentElement->firstChild(); child; child = child->nextSibling())
+    for (Node* child = parentNode->firstChild(); child; child = child->nextSibling())
         oldList.append(createDigest(child, 0));
 
     // Compose the new list.
+    String markupCopy = markup;
+    markupCopy.makeLower();
     Vector<OwnPtr<Digest> > newList;
-    for (Node* child = parentElement->firstChild(); child != node; child = child->nextSibling())
+    for (Node* child = parentNode->firstChild(); child != node; child = child->nextSibling())
         newList.append(createDigest(child, 0));
-    for (Node* child = fragment->firstChild(); child; child = child->nextSibling())
+    for (Node* child = fragment->firstChild(); child; child = child->nextSibling()) {
+        if (child->hasTagName(headTag) && !child->firstChild() && markupCopy.find("</head>") == notFound)
+            continue; // HTML5 parser inserts empty <head> tag whenever it parses <body>
+        if (child->hasTagName(bodyTag) && !child->firstChild() && markupCopy.find("</body>") == notFound)
+            continue; // HTML5 parser inserts empty <body> tag whenever it parses </head>
         newList.append(createDigest(child, &m_unusedNodesMap));
+    }
     for (Node* child = node->nextSibling(); child; child = child->nextSibling())
         newList.append(createDigest(child, 0));
 
-    innerPatchChildren(parentElement, oldList, newList, ec);
+    innerPatchChildren(parentNode, oldList, newList, ec);
     if (ec) {
         // Fall back to total replace.
         ec = 0;
-        parentElement->replaceChild(fragment.release(), node, ec);
+        parentNode->replaceChild(fragment.release(), node, ec);
         if (ec)
             return 0;
     }
-    return previousSibling ? previousSibling->nextSibling() : parentElement->firstChild();
+    return previousSibling ? previousSibling->nextSibling() : parentNode->firstChild();
 }
 
-void DOMEditor::innerPatchHTMLElement(HTMLElement* oldElement, HTMLElement* newElement, ExceptionCode& ec)
-{
-    if (oldElement)  {
-        if (newElement) {
-            OwnPtr<Digest> oldInfo = createDigest(oldElement, 0);
-            OwnPtr<Digest> newInfo = createDigest(newElement, &m_unusedNodesMap);
-            innerPatchNode(oldInfo.get(), newInfo.get(), ec);
-            if (ec)
-                return;
-        }
-        oldElement->removeAllChildren();
-        return;
-    }
-    if (newElement)
-        m_document->documentElement()->appendChild(newElement, ec);
-}
-
 void DOMEditor::innerPatchNode(Digest* oldDigest, Digest* newDigest, ExceptionCode& ec)
 {
     if (oldDigest->m_sha1 == newDigest->m_sha1)
@@ -261,18 +262,32 @@
     return make_pair(oldMap, newMap);
 }
 
-void DOMEditor::innerPatchChildren(Element* element, const Vector<OwnPtr<Digest> >& oldList, const Vector<OwnPtr<Digest> >& newList, ExceptionCode& ec)
+void DOMEditor::innerPatchChildren(ContainerNode* parentNode, const Vector<OwnPtr<Digest> >& oldList, const Vector<OwnPtr<Digest> >& newList, ExceptionCode& ec)
 {
     pair<ResultMap, ResultMap> resultMaps = diff(oldList, newList);
     ResultMap& oldMap = resultMaps.first;
     ResultMap& newMap = resultMaps.second;
 
+    Digest* oldHead = 0;
+    Digest* oldBody = 0;
+
     // 1. First strip everything except for the nodes that retain. Collect pending merges.
     HashMap<Digest*, Digest*> merges;
     for (size_t i = 0; i < oldList.size(); ++i) {
         if (oldMap[i].first)
             continue;
 
+        // Always match <head> and <body> tags with each other - we can't remove them from the DOM
+        // upon patching.
+        if (oldList[i]->m_node->hasTagName(headTag)) {
+            oldHead = oldList[i].get();
+            continue;
+        }
+        if (oldList[i]->m_node->hasTagName(bodyTag)) {
+            oldBody = oldList[i].get();
+            continue;
+        }
+
         // Check if this change is between stable nodes. If it is, consider it as "modified".
         if (!m_unusedNodesMap.contains(oldList[i]->m_sha1) && (!i || oldMap[i - 1].first) && (i == oldMap.size() - 1 || oldMap[i + 1].first)) {
             size_t anchorCandidate = i ? oldMap[i - 1].second + 1 : 0;
@@ -297,6 +312,16 @@
             markNodeAsUsed(newMap[i].first);
     }
 
+    // Mark <head> and <body> nodes for merge.
+    if (oldHead || oldBody) {
+        for (size_t i = 0; i < newList.size(); ++i) {
+            if (oldHead && newList[i]->m_node->hasTagName(headTag))
+                merges.set(newList[i].get(), oldHead);
+            if (oldBody && newList[i]->m_node->hasTagName(bodyTag))
+                merges.set(newList[i].get(), oldBody);
+        }
+    }
+
     // 2. Patch nodes marked for merge.
     for (HashMap<Digest*, Digest*>::iterator it = merges.begin(); it != merges.end(); ++it) {
         innerPatchNode(it->second, it->first, ec);
@@ -310,7 +335,7 @@
             continue;
 
         ExceptionCode ec = 0;
-        insertBefore(element, newList[i].get(), element->childNode(i), ec);
+        insertBefore(parentNode, newList[i].get(), parentNode->childNode(i), ec);
         if (ec)
             return;
     }
@@ -320,11 +345,13 @@
         if (!oldMap[i].first)
             continue;
         RefPtr<Node> node = oldMap[i].first->m_node;
-        Node* anchorNode = element->childNode(oldMap[i].second);
+        Node* anchorNode = parentNode->childNode(oldMap[i].second);
         if (node.get() == anchorNode)
             continue;
+        if (node->hasTagName(bodyTag) || node->hasTagName(headTag))
+            continue; // Never move head or body, move the rest of the nodes around them.
 
-        element->insertBefore(node, anchorNode, ec);
+        parentNode->insertBefore(node, anchorNode, ec);
         if (ec)
             return;
     }
@@ -381,9 +408,9 @@
     return adoptPtr(digest);
 }
 
-void DOMEditor::insertBefore(Element* parentElement, Digest* digest, Node* anchor, ExceptionCode& ec)
+void DOMEditor::insertBefore(ContainerNode* parentNode, Digest* digest, Node* anchor, ExceptionCode& ec)
 {
-    parentElement->insertBefore(digest->m_node, anchor, ec);
+    parentNode->insertBefore(digest->m_node, anchor, ec);
     markNodeAsUsed(digest);
 }
 

Modified: trunk/Source/WebCore/inspector/DOMEditor.h (105057 => 105058)


--- trunk/Source/WebCore/inspector/DOMEditor.h	2012-01-16 13:08:29 UTC (rev 105057)
+++ trunk/Source/WebCore/inspector/DOMEditor.h	2012-01-16 13:35:04 UTC (rev 105058)
@@ -43,7 +43,6 @@
 
 class ContainerNode;
 class Document;
-class Element;
 class HTMLElement;
 class NamedNodeMap;
 class Node;
@@ -63,12 +62,11 @@
     typedef Vector<pair<Digest*, size_t> > ResultMap;
     typedef HashMap<String, Digest*> UnusedNodesMap;
 
-    void innerPatchHTMLElement(HTMLElement* oldElement, HTMLElement* newElement, ExceptionCode&);
     void innerPatchNode(Digest* oldNode, Digest* newNode, ExceptionCode&);
     std::pair<ResultMap, ResultMap> diff(const Vector<OwnPtr<Digest> >& oldChildren, const Vector<OwnPtr<Digest> >& newChildren);
-    void innerPatchChildren(Element*, const Vector<OwnPtr<Digest> >& oldChildren, const Vector<OwnPtr<Digest> >& newChildren, ExceptionCode&);
+    void innerPatchChildren(ContainerNode*, const Vector<OwnPtr<Digest> >& oldChildren, const Vector<OwnPtr<Digest> >& newChildren, ExceptionCode&);
     PassOwnPtr<Digest> createDigest(Node*, UnusedNodesMap*);
-    void insertBefore(Element* parentElement, Digest*, Node* anchor, ExceptionCode&);
+    void insertBefore(ContainerNode*, Digest*, Node* anchor, ExceptionCode&);
     void removeChild(Digest*, ExceptionCode&);
     void markNodeAsUsed(Digest*);
 

Modified: trunk/Source/WebCore/inspector/InspectorDOMAgent.cpp (105057 => 105058)


--- trunk/Source/WebCore/inspector/InspectorDOMAgent.cpp	2012-01-16 13:08:29 UTC (rev 105057)
+++ trunk/Source/WebCore/inspector/InspectorDOMAgent.cpp	2012-01-16 13:35:04 UTC (rev 105058)
@@ -649,12 +649,6 @@
         return;
     }
 
-    Element* parentElement = node->parentElement();
-    if (!parentElement) {
-        *errorString = "Can only set outer HTML to nodes within Element";
-        return;
-    }
-
     DOMEditor domEditor(document);
 
     ExceptionCode ec = 0;
@@ -665,14 +659,6 @@
         return;
     }
 
-    bool requiresTotalUpdate = node->isHTMLElement() && (node->nodeName() == "HTML" || node->nodeName() == "BODY" || node->nodeName() == "HEAD");
-    if (requiresTotalUpdate) {
-        RefPtr<Document> document = m_document;
-        reset();
-        setDocument(document.get());
-        return;
-    }
-
     if (!newNode) {
         // The only child node has been deleted.
         return;
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to