15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2012 Google Inc. All rights reserved.
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modification, are permitted provided that the following conditions are
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * met:
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     * Redistributions of source code must retain the above copyright
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * notice, this list of conditions and the following disclaimer.
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     * Redistributions in binary form must reproduce the above
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * copyright notice, this list of conditions and the following disclaimer
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * in the documentation and/or other materials provided with the
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * distribution.
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     * Neither the name of Google Inc. nor the names of its
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * contributors may be used to endorse or promote products derived from
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * this software without specific prior written permission.
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h"
3253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/inspector/DOMPatchSupport.h"
3353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
34197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#include "bindings/core/v8/ExceptionState.h"
35197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#include "bindings/core/v8/ExceptionStatePlaceholder.h"
3653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/dom/Attribute.h"
3753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/dom/ContextFeatures.h"
3853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/dom/Document.h"
3953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/dom/DocumentFragment.h"
4053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/dom/Node.h"
41c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)#include "core/dom/NodeTraversal.h"
4209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)#include "core/dom/XMLDocument.h"
43d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)#include "core/html/HTMLBodyElement.h"
4453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/html/HTMLDocument.h"
45d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)#include "core/html/HTMLHeadElement.h"
4653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/html/parser/HTMLDocumentParser.h"
4753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/inspector/DOMEditor.h"
4853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/inspector/InspectorHistory.h"
4953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/xml/parser/XMLDocumentParser.h"
50a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch#include "platform/Crypto.h"
51a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch#include "public/platform/Platform.h"
52e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch#include "wtf/Deque.h"
53e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch#include "wtf/HashTraits.h"
54e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch#include "wtf/RefPtr.h"
55e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch#include "wtf/text/Base64.h"
56e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch#include "wtf/text/CString.h"
575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
58c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)namespace blink {
595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)struct DOMPatchSupport::Digest {
615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    explicit Digest(Node* node) : m_node(node) { }
625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    String m_sha1;
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    String m_attrsSHA1;
655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Node* m_node;
665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Vector<OwnPtr<Digest> > m_children;
675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)};
685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
698abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)void DOMPatchSupport::patchDocument(Document& document, const String& markup)
705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    InspectorHistory history;
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DOMEditor domEditor(&history);
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DOMPatchSupport patchSupport(&domEditor, document);
745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    patchSupport.patchDocument(markup);
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
778abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)DOMPatchSupport::DOMPatchSupport(DOMEditor* domEditor, Document& document)
785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    : m_domEditor(domEditor)
795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_document(document)
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void DOMPatchSupport::patchDocument(const String& markup)
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
85d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    RefPtrWillBeRawPtr<Document> newDocument = nullptr;
86c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    if (document().isHTMLDocument())
87e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch        newDocument = HTMLDocument::create();
88c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    else if (document().isXHTMLDocument())
8909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        newDocument = XMLDocument::createXHTML();
90c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    else if (document().isXMLDocument())
9109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        newDocument = XMLDocument::create();
9253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
9353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    ASSERT(newDocument);
94c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    newDocument->setContextFeatures(document().contextFeatures());
95d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    RefPtrWillBeRawPtr<DocumentParser> parser = nullptr;
96c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    if (document().isHTMLDocument())
97d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        parser = HTMLDocumentParser::create(toHTMLDocument(*newDocument), false);
9853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    else
99d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        parser = XMLDocumentParser::create(*newDocument, 0);
1007242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    parser->pinToMainThread();
1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser->insert(markup); // Use insert() so that the parser will not yield.
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser->finish();
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    parser->detach();
1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
105c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    OwnPtr<Digest> oldInfo = createDigest(document().documentElement(), 0);
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    OwnPtr<Digest> newInfo = createDigest(newDocument->documentElement(), &m_unusedNodesMap);
1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1081fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch    if (!innerPatchNode(oldInfo.get(), newInfo.get(), IGNORE_EXCEPTION)) {
1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Fall back to rewrite.
110c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        document().write(markup);
111c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        document().close();
1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)Node* DOMPatchSupport::patchNode(Node* node, const String& markup, ExceptionState& exceptionState)
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Don't parse <html> as a fragment.
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (node->isDocumentNode() || (node->parentNode() && node->parentNode()->isDocumentNode())) {
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        patchDocument(markup);
1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return 0;
1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Node* previousSibling = node->previousSibling();
124c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    RefPtrWillBeRawPtr<DocumentFragment> fragment = DocumentFragment::create(document());
125c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    Node* targetNode = node->parentElementOrShadowRoot() ? node->parentElementOrShadowRoot() : document().documentElement();
126d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
127d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // Use the document BODY as the context element when editing immediate shadow root children,
128d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // as it provides an equivalent parsing context.
129d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    if (targetNode->isShadowRoot())
130c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        targetNode = document().body();
131d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    Element* targetElement = toElement(targetNode);
132d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
133d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // FIXME: This code should use one of createFragment* in markup.h
134c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    if (document().isHTMLDocument())
135d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        fragment->parseHTML(markup, targetElement);
13653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    else
137d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        fragment->parseXML(markup, targetElement);
1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Compose the old list.
1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ContainerNode* parentNode = node->parentNode();
1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Vector<OwnPtr<Digest> > oldList;
1425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (Node* child = parentNode->firstChild(); child; child = child->nextSibling())
1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        oldList.append(createDigest(child, 0));
1445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Compose the new list.
1461e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    String markupCopy = markup.lower();
1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Vector<OwnPtr<Digest> > newList;
1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (Node* child = parentNode->firstChild(); child != node; child = child->nextSibling())
1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        newList.append(createDigest(child, 0));
1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (Node* child = fragment->firstChild(); child; child = child->nextSibling()) {
151c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        if (isHTMLHeadElement(*child) && !child->hasChildren() && markupCopy.find("</head>") == kNotFound)
1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue; // HTML5 parser inserts empty <head> tag whenever it parses <body>
153c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        if (isHTMLBodyElement(*child) && !child->hasChildren() && markupCopy.find("</body>") == kNotFound)
1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue; // HTML5 parser inserts empty <body> tag whenever it parses </head>
1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        newList.append(createDigest(child, &m_unusedNodesMap));
1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (Node* child = node->nextSibling(); child; child = child->nextSibling())
1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        newList.append(createDigest(child, 0));
1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
16051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    if (!innerPatchChildren(parentNode, oldList, newList, exceptionState)) {
1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Fall back to total replace.
16251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        if (!m_domEditor->replaceChild(parentNode, fragment.release(), node, exceptionState))
1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return 0;
1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return previousSibling ? previousSibling->nextSibling() : parentNode->firstChild();
1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
16851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)bool DOMPatchSupport::innerPatchNode(Digest* oldDigest, Digest* newDigest, ExceptionState& exceptionState)
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (oldDigest->m_sha1 == newDigest->m_sha1)
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true;
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Node* oldNode = oldDigest->m_node;
1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Node* newNode = newDigest->m_node;
1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (newNode->nodeType() != oldNode->nodeType() || newNode->nodeName() != oldNode->nodeName())
17751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        return m_domEditor->replaceChild(oldNode->parentNode(), newNode, oldNode, exceptionState);
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (oldNode->nodeValue() != newNode->nodeValue()) {
18051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        if (!m_domEditor->setNodeValue(oldNode, newNode->nodeValue(), exceptionState))
1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return false;
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
184f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    if (!oldNode->isElementNode())
1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true;
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Patch attributes
188926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    Element* oldElement = toElement(oldNode);
189926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    Element* newElement = toElement(newNode);
1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (oldDigest->m_attrsSHA1 != newDigest->m_attrsSHA1) {
1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // FIXME: Create a function in Element for removing all properties. Take in account whether did/willModifyAttribute are important.
192c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        while (oldElement->attributesWithoutUpdate().size()) {
193c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)            const Attribute& attribute = oldElement->attributesWithoutUpdate().at(0);
194c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)            if (!m_domEditor->removeAttribute(oldElement, attribute.localName(), exceptionState))
195c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)                return false;
1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // FIXME: Create a function in Element for copying properties. cloneDataFromElement() is close but not enough for this case.
199c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        AttributeCollection attributes = newElement->attributesWithoutUpdate();
200e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)        AttributeCollection::iterator end = attributes.end();
201e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)        for (AttributeCollection::iterator it = attributes.begin(); it != end; ++it) {
202c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)            if (!m_domEditor->setAttribute(oldElement, it->name().localName(), it->value(), exceptionState))
203c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)                return false;
2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
20751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    bool result = innerPatchChildren(oldElement, oldDigest->m_children, newDigest->m_children, exceptionState);
2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_unusedNodesMap.remove(newDigest->m_sha1);
2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return result;
2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)pair<DOMPatchSupport::ResultMap, DOMPatchSupport::ResultMap>
2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)DOMPatchSupport::diff(const Vector<OwnPtr<Digest> >& oldList, const Vector<OwnPtr<Digest> >& newList)
2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ResultMap newMap(newList.size());
2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ResultMap oldMap(oldList.size());
2175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (size_t i = 0; i < oldMap.size(); ++i) {
2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        oldMap[i].first = 0;
2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        oldMap[i].second = 0;
2215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (size_t i = 0; i < newMap.size(); ++i) {
2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        newMap[i].first = 0;
2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        newMap[i].second = 0;
2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Trim head and tail.
2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (size_t i = 0; i < oldList.size() && i < newList.size() && oldList[i]->m_sha1 == newList[i]->m_sha1; ++i) {
2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        oldMap[i].first = oldList[i].get();
2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        oldMap[i].second = i;
2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        newMap[i].first = newList[i].get();
2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        newMap[i].second = i;
2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (size_t i = 0; i < oldList.size() && i < newList.size() && oldList[oldList.size() - i - 1]->m_sha1 == newList[newList.size() - i - 1]->m_sha1; ++i) {
2365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        size_t oldIndex = oldList.size() - i - 1;
2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        size_t newIndex = newList.size() - i - 1;
2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        oldMap[oldIndex].first = oldList[oldIndex].get();
2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        oldMap[oldIndex].second = newIndex;
2405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        newMap[newIndex].first = newList[newIndex].get();
2415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        newMap[newIndex].second = oldIndex;
2425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    typedef HashMap<String, Vector<size_t> > DiffTable;
2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DiffTable newTable;
2465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DiffTable oldTable;
2475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (size_t i = 0; i < newList.size(); ++i) {
24909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        newTable.add(newList[i]->m_sha1, Vector<size_t>()).storedValue->value.append(i);
2505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (size_t i = 0; i < oldList.size(); ++i) {
25309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        oldTable.add(oldList[i]->m_sha1, Vector<size_t>()).storedValue->value.append(i);
2545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (DiffTable::iterator newIt = newTable.begin(); newIt != newTable.end(); ++newIt) {
2575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (newIt->value.size() != 1)
2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue;
2595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        DiffTable::iterator oldIt = oldTable.find(newIt->key);
2615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (oldIt == oldTable.end() || oldIt->value.size() != 1)
2625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue;
2635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2645d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)        newMap[newIt->value[0]] = std::make_pair(newList[newIt->value[0]].get(), oldIt->value[0]);
2655d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)        oldMap[oldIt->value[0]] = std::make_pair(oldList[oldIt->value[0]].get(), newIt->value[0]);
2665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (size_t i = 0; newList.size() > 0 && i < newList.size() - 1; ++i) {
2695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!newMap[i].first || newMap[i + 1].first)
2705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue;
2715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        size_t j = newMap[i].second + 1;
2735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (j < oldMap.size() && !oldMap[j].first && newList[i + 1]->m_sha1 == oldList[j]->m_sha1) {
2745d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)            newMap[i + 1] = std::make_pair(newList[i + 1].get(), j);
2755d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)            oldMap[j] = std::make_pair(oldList[j].get(), i + 1);
2765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (size_t i = newList.size() - 1; newList.size() > 0 && i > 0; --i) {
2805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!newMap[i].first || newMap[i - 1].first || newMap[i].second <= 0)
2815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue;
2825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        size_t j = newMap[i].second - 1;
2845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!oldMap[j].first && newList[i - 1]->m_sha1 == oldList[j]->m_sha1) {
2855d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)            newMap[i - 1] = std::make_pair(newList[i - 1].get(), j);
2865d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)            oldMap[j] = std::make_pair(oldList[j].get(), i - 1);
2875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
2885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#ifdef DEBUG_DOM_PATCH_SUPPORT
2915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    dumpMap(oldMap, "OLD");
2925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    dumpMap(newMap, "NEW");
2935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif
2945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2955d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)    return std::make_pair(oldMap, newMap);
2965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
29851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)bool DOMPatchSupport::innerPatchChildren(ContainerNode* parentNode, const Vector<OwnPtr<Digest> >& oldList, const Vector<OwnPtr<Digest> >& newList, ExceptionState& exceptionState)
2995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
3005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    pair<ResultMap, ResultMap> resultMaps = diff(oldList, newList);
3015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ResultMap& oldMap = resultMaps.first;
3025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ResultMap& newMap = resultMaps.second;
3035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Digest* oldHead = 0;
3055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Digest* oldBody = 0;
3065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // 1. First strip everything except for the nodes that retain. Collect pending merges.
3085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    HashMap<Digest*, Digest*> merges;
3095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    HashSet<size_t, WTF::IntHash<size_t>, WTF::UnsignedWithZeroKeyHashTraits<size_t> > usedNewOrdinals;
3105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (size_t i = 0; i < oldList.size(); ++i) {
3115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (oldMap[i].first) {
3125267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)            if (usedNewOrdinals.add(oldMap[i].second).isNewEntry)
3135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                continue;
3145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            oldMap[i].first = 0;
3155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            oldMap[i].second = 0;
3165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
3175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Always match <head> and <body> tags with each other - we can't remove them from the DOM
3195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // upon patching.
320d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        if (isHTMLHeadElement(*oldList[i]->m_node)) {
3215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            oldHead = oldList[i].get();
3225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue;
3235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
324d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        if (isHTMLBodyElement(*oldList[i]->m_node)) {
3255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            oldBody = oldList[i].get();
3265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue;
3275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
3285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Check if this change is between stable nodes. If it is, consider it as "modified".
3305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!m_unusedNodesMap.contains(oldList[i]->m_sha1) && (!i || oldMap[i - 1].first) && (i == oldMap.size() - 1 || oldMap[i + 1].first)) {
3315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            size_t anchorCandidate = i ? oldMap[i - 1].second + 1 : 0;
33293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)            size_t anchorAfter = (i == oldMap.size() - 1) ? anchorCandidate + 1 : oldMap[i + 1].second;
3335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (anchorAfter - anchorCandidate == 1 && anchorCandidate < newList.size())
3345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                merges.set(newList[anchorCandidate].get(), oldList[i].get());
3355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            else {
33651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)                if (!removeChildAndMoveToNew(oldList[i].get(), exceptionState))
3375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    return false;
3385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
3395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        } else {
34051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)            if (!removeChildAndMoveToNew(oldList[i].get(), exceptionState))
3415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return false;
3425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
3435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Mark retained nodes as used, do not reuse node more than once.
3465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    HashSet<size_t, WTF::IntHash<size_t>, WTF::UnsignedWithZeroKeyHashTraits<size_t> >  usedOldOrdinals;
3475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (size_t i = 0; i < newList.size(); ++i) {
3485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!newMap[i].first)
3495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue;
3505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        size_t oldOrdinal = newMap[i].second;
3515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (usedOldOrdinals.contains(oldOrdinal)) {
3525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // Do not map node more than once
3535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            newMap[i].first = 0;
3545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            newMap[i].second = 0;
3555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue;
3565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
3575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        usedOldOrdinals.add(oldOrdinal);
3585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        markNodeAsUsed(newMap[i].first);
3595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Mark <head> and <body> nodes for merge.
3625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (oldHead || oldBody) {
3635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (size_t i = 0; i < newList.size(); ++i) {
364d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            if (oldHead && isHTMLHeadElement(*newList[i]->m_node))
3655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                merges.set(newList[i].get(), oldHead);
366d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            if (oldBody && isHTMLBodyElement(*newList[i]->m_node))
3675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                merges.set(newList[i].get(), oldBody);
3685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
3695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // 2. Patch nodes marked for merge.
3725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (HashMap<Digest*, Digest*>::iterator it = merges.begin(); it != merges.end(); ++it) {
37351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        if (!innerPatchNode(it->value, it->key, exceptionState))
3745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return false;
3755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // 3. Insert missing nodes.
3785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (size_t i = 0; i < newMap.size(); ++i) {
3795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (newMap[i].first || merges.contains(newList[i].get()))
3805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue;
381c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        if (!insertBeforeAndMarkAsUsed(parentNode, newList[i].get(), NodeTraversal::childAt(*parentNode, i), exceptionState))
3825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return false;
3835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // 4. Then put all nodes that retained into their slots (sort by new index).
3865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (size_t i = 0; i < oldMap.size(); ++i) {
3875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!oldMap[i].first)
3885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue;
389f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        RefPtrWillBeRawPtr<Node> node = oldMap[i].first->m_node;
390c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        Node* anchorNode = NodeTraversal::childAt(*parentNode, oldMap[i].second);
391d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        if (node == anchorNode)
3925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue;
393d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        if (isHTMLBodyElement(*node) || isHTMLHeadElement(*node))
3945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue; // Never move head or body, move the rest of the nodes around them.
3955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
39651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        if (!m_domEditor->insertBefore(parentNode, node.release(), anchorNode, exceptionState))
3975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return false;
3985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
4005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
402a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdochstatic void addStringToDigestor(blink::WebCryptoDigestor* digestor, const String& string)
4035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
404a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    digestor->consume(reinterpret_cast<const unsigned char*>(string.utf8().data()), string.length());
4055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)PassOwnPtr<DOMPatchSupport::Digest> DOMPatchSupport::createDigest(Node* node, UnusedNodesMap* unusedNodesMap)
4085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Digest* digest = new Digest(node);
4105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
411a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    OwnPtr<blink::WebCryptoDigestor> digestor = createDigestor(HashAlgorithmSha1);
412a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    DigestValue digestResult;
4135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Node::NodeType nodeType = node->nodeType();
415a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    digestor->consume(reinterpret_cast<const unsigned char*>(&nodeType), sizeof(nodeType));
416a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    addStringToDigestor(digestor.get(), node->nodeName());
417a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    addStringToDigestor(digestor.get(), node->nodeValue());
4185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
419f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    if (node->isElementNode()) {
420f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        Element& element = toElement(*node);
421f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        Node* child = element.firstChild();
4225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        while (child) {
4235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            OwnPtr<Digest> childInfo = createDigest(child, unusedNodesMap);
424a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch            addStringToDigestor(digestor.get(), childInfo->m_sha1);
4255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            child = child->nextSibling();
4265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            digest->m_children.append(childInfo.release());
4275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
4285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
429c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        AttributeCollection attributes = element.attributesWithoutUpdate();
430c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        if (!attributes.isEmpty()) {
431a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch            OwnPtr<blink::WebCryptoDigestor> attrsDigestor = createDigestor(HashAlgorithmSha1);
432e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)            AttributeCollection::iterator end = attributes.end();
433e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)            for (AttributeCollection::iterator it = attributes.begin(); it != end; ++it) {
434f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)                addStringToDigestor(attrsDigestor.get(), it->name().toString());
435f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)                addStringToDigestor(attrsDigestor.get(), it->value().string());
4365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
437a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch            finishDigestor(attrsDigestor.get(), digestResult);
438a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch            digest->m_attrsSHA1 = base64Encode(reinterpret_cast<const char*>(digestResult.data()), 10);
439a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch            addStringToDigestor(digestor.get(), digest->m_attrsSHA1);
440a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch            digestResult.clear();
4415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
4425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
443a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    finishDigestor(digestor.get(), digestResult);
444a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    digest->m_sha1 = base64Encode(reinterpret_cast<const char*>(digestResult.data()), 10);
4455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (unusedNodesMap)
4475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        unusedNodesMap->add(digest->m_sha1, digest);
4485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return adoptPtr(digest);
4495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
45151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)bool DOMPatchSupport::insertBeforeAndMarkAsUsed(ContainerNode* parentNode, Digest* digest, Node* anchor, ExceptionState& exceptionState)
4525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
45351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    bool result = m_domEditor->insertBefore(parentNode, digest->m_node, anchor, exceptionState);
4545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    markNodeAsUsed(digest);
4555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return result;
4565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
45851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)bool DOMPatchSupport::removeChildAndMoveToNew(Digest* oldDigest, ExceptionState& exceptionState)
4595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
460f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    RefPtrWillBeRawPtr<Node> oldNode = oldDigest->m_node;
46151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    if (!m_domEditor->removeChild(oldNode->parentNode(), oldNode.get(), exceptionState))
4625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
4635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Diff works within levels. In order not to lose the node identity when user
4655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // prepends his HTML with "<div>" (i.e. all nodes are shifted to the next nested level),
4665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // prior to dropping the original node on the floor, check whether new DOM has a digest
4675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // with matching sha1. If it does, replace it with the original DOM chunk. Chances are
4685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // high that it will get merged back into the original DOM during the further patching.
4695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    UnusedNodesMap::iterator it = m_unusedNodesMap.find(oldDigest->m_sha1);
4705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (it != m_unusedNodesMap.end()) {
4715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        Digest* newDigest = it->value;
4725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        Node* newNode = newDigest->m_node;
47351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        if (!m_domEditor->replaceChild(newNode->parentNode(), oldNode, newNode, exceptionState))
4745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return false;
4755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        newDigest->m_node = oldNode.get();
4765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        markNodeAsUsed(newDigest);
4775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true;
4785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
4795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (size_t i = 0; i < oldDigest->m_children.size(); ++i) {
48151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        if (!removeChildAndMoveToNew(oldDigest->m_children[i].get(), exceptionState))
4825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return false;
4835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
4845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
4855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void DOMPatchSupport::markNodeAsUsed(Digest* digest)
4885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Deque<Digest*> queue;
4905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    queue.append(digest);
4915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    while (!queue.isEmpty()) {
4925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        Digest* first = queue.takeFirst();
4935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_unusedNodesMap.remove(first->m_sha1);
4945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (size_t i = 0; i < first->m_children.size(); ++i)
4955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            queue.append(first->m_children[i].get());
4965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
4975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#ifdef DEBUG_DOM_PATCH_SUPPORT
5005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static String nodeName(Node* node)
5015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
5028abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    if (node->document().isXHTMLDocument())
5035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)         return node->nodeName();
5045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return node->nodeName().lower();
5055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
5065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void DOMPatchSupport::dumpMap(const ResultMap& map, const String& name)
5085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
5095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    fprintf(stderr, "\n\n");
5105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (size_t i = 0; i < map.size(); ++i)
5115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        fprintf(stderr, "%s[%lu]: %s (%p) - [%lu]\n", name.utf8().data(), i, map[i].first ? nodeName(map[i].first->m_node).utf8().data() : "", map[i].first, map[i].second);
5125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
5135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif
5145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
515c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)} // namespace blink
5165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
517