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