Diff
Modified: trunk/Source/WebCore/CMakeLists.txt (104585 => 104586)
--- trunk/Source/WebCore/CMakeLists.txt 2012-01-10 16:54:29 UTC (rev 104585)
+++ trunk/Source/WebCore/CMakeLists.txt 2012-01-10 17:01:05 UTC (rev 104586)
@@ -870,6 +870,7 @@
inspector/ConsoleMessage.cpp
inspector/ContentSearchUtils.cpp
+ inspector/DOMEditor.cpp
inspector/DOMNodeHighlighter.cpp
inspector/IdentifiersFactory.cpp
inspector/InjectedScript.cpp
Modified: trunk/Source/WebCore/ChangeLog (104585 => 104586)
--- trunk/Source/WebCore/ChangeLog 2012-01-10 16:54:29 UTC (rev 104585)
+++ trunk/Source/WebCore/ChangeLog 2012-01-10 17:01:05 UTC (rev 104586)
@@ -1,3 +1,40 @@
+2012-01-10 Pavel Feldman <[email protected]>
+
+ Web Inspector: add "free flow DOM editing" experiment.
+ https://bugs.webkit.org/show_bug.cgi?id=75955
+
+ This change enables HTML editing from Resources panel experiment.
+
+ Reviewed by Yury Semikhatsky.
+
+ * CMakeLists.txt:
+ * English.lproj/localizedStrings.js:
+ * GNUmakefile.list.am:
+ * Target.pri:
+ * WebCore.gypi:
+ * WebCore.vcproj/WebCore.vcproj:
+ * WebCore.xcodeproj/project.pbxproj:
+ * inspector/DOMEditor.cpp: Added.
+ (WebCore::DOMEditor::DOMEditor):
+ (WebCore::DOMEditor::~DOMEditor):
+ (WebCore::DOMEditor::patch):
+ (WebCore::DOMEditor::NodeDigest::NodeDigest):
+ (WebCore::DOMEditor::patchElement):
+ (WebCore::DOMEditor::patchNode):
+ (WebCore::DOMEditor::patchChildren):
+ (WebCore::addStringToSHA1):
+ (WebCore::DOMEditor::createNodeDigest):
+ * inspector/DOMEditor.h: Added.
+ * inspector/InspectorDOMAgent.cpp:
+ (WebCore::InspectorDOMAgent::setOuterHTML):
+ * inspector/front-end/DOMAgent.js:
+ (WebInspector.DOMAgent):
+ (WebInspector.DOMModelResourceBinding):
+ (WebInspector.DOMModelResourceBinding.prototype.setContent):
+ (WebInspector.DOMModelResourceBinding.prototype.canSetContent):
+ * inspector/front-end/Settings.js:
+ (WebInspector.ExperimentsSettings):
+
2012-01-10 Stephen Chenney <[email protected]>
[Chromium] Shift PathSkia to use Skia's new RawIter
Modified: trunk/Source/WebCore/English.lproj/localizedStrings.js
(Binary files differ)
Modified: trunk/Source/WebCore/GNUmakefile.list.am (104585 => 104586)
--- trunk/Source/WebCore/GNUmakefile.list.am 2012-01-10 16:54:29 UTC (rev 104585)
+++ trunk/Source/WebCore/GNUmakefile.list.am 2012-01-10 17:01:05 UTC (rev 104586)
@@ -2327,6 +2327,8 @@
Source/WebCore/inspector/ConsoleMessage.h \
Source/WebCore/inspector/ContentSearchUtils.cpp \
Source/WebCore/inspector/ContentSearchUtils.h \
+ Source/WebCore/inspector/DOMEditor.cpp \
+ Source/WebCore/inspector/DOMEditor.h \
Source/WebCore/inspector/DOMNodeHighlighter.cpp \
Source/WebCore/inspector/DOMNodeHighlighter.h \
Source/WebCore/inspector/DOMWrapperVisitor.h \
Modified: trunk/Source/WebCore/Target.pri (104585 => 104586)
--- trunk/Source/WebCore/Target.pri 2012-01-10 16:54:29 UTC (rev 104585)
+++ trunk/Source/WebCore/Target.pri 2012-01-10 17:01:05 UTC (rev 104586)
@@ -849,6 +849,7 @@
html/shadow/TextControlInnerElements.cpp \
inspector/ConsoleMessage.cpp \
inspector/ContentSearchUtils.cpp \
+ inspector/DOMEditor.cpp \
inspector/DOMNodeHighlighter.cpp \
inspector/IdentifiersFactory.cpp \
inspector/InjectedScript.cpp \
@@ -1907,6 +1908,7 @@
html/track/WebVTTTokenizer.h \
inspector/ConsoleMessage.h \
inspector/ContentSearchUtils.h \
+ inspector/DOMEditor.h \
inspector/DOMNodeHighlighter.h \
inspector/DOMWrapperVisitor.h \
inspector/IdentifiersFactory.h \
Modified: trunk/Source/WebCore/WebCore.gypi (104585 => 104586)
--- trunk/Source/WebCore/WebCore.gypi 2012-01-10 16:54:29 UTC (rev 104585)
+++ trunk/Source/WebCore/WebCore.gypi 2012-01-10 17:01:05 UTC (rev 104586)
@@ -2730,6 +2730,8 @@
'inspector/ConsoleMessage.h',
'inspector/ContentSearchUtils.cpp',
'inspector/ContentSearchUtils.h',
+ 'inspector/DOMEditor.cpp',
+ 'inspector/DOMEditor.h',
'inspector/DOMNodeHighlighter.cpp',
'inspector/DOMNodeHighlighter.h',
'inspector/DOMWrapperVisitor.h',
Modified: trunk/Source/WebCore/WebCore.vcproj/WebCore.vcproj (104585 => 104586)
--- trunk/Source/WebCore/WebCore.vcproj/WebCore.vcproj 2012-01-10 16:54:29 UTC (rev 104585)
+++ trunk/Source/WebCore/WebCore.vcproj/WebCore.vcproj 2012-01-10 17:01:05 UTC (rev 104586)
@@ -71130,6 +71130,14 @@
>
</File>
<File
+ RelativePath="..\inspector\DOMEditor.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\inspector\DOMEditor.h"
+ >
+ </File>
+ <File
RelativePath="..\inspector\DOMNodeHighlighter.cpp"
>
</File>
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (104585 => 104586)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2012-01-10 16:54:29 UTC (rev 104585)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2012-01-10 17:01:05 UTC (rev 104586)
@@ -1852,6 +1852,8 @@
7AA51B6F1483B61600AD2752 /* InspectorBaseAgent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7AA51B6D1483B61600AD2752 /* InspectorBaseAgent.cpp */; };
7AA51DD5148506A900AD2752 /* InspectorMemoryAgent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7AA51DD3148506A900AD2752 /* InspectorMemoryAgent.cpp */; };
7AA51DD6148506A900AD2752 /* InspectorMemoryAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 7AA51DD4148506A900AD2752 /* InspectorMemoryAgent.h */; };
+ 7AABA25914BC613300AA9A11 /* DOMEditor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7AABA25714BC613300AA9A11 /* DOMEditor.cpp */; };
+ 7AABA25A14BC613300AA9A11 /* DOMEditor.h in Headers */ = {isa = PBXBuildFile; fileRef = 7AABA25814BC613300AA9A11 /* DOMEditor.h */; };
7AB0B1C01211A62200A76940 /* InspectorDatabaseAgent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7AB0B1BE1211A62200A76940 /* InspectorDatabaseAgent.cpp */; };
7AB0B1C11211A62200A76940 /* InspectorDatabaseAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 7AB0B1BF1211A62200A76940 /* InspectorDatabaseAgent.h */; };
7ADE722610CBBB9B006B3B3A /* ContextMenuProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ADE722510CBBB9B006B3B3A /* ContextMenuProvider.h */; };
@@ -9162,6 +9164,8 @@
7AA51B6D1483B61600AD2752 /* InspectorBaseAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorBaseAgent.cpp; sourceTree = "<group>"; };
7AA51DD3148506A900AD2752 /* InspectorMemoryAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorMemoryAgent.cpp; sourceTree = "<group>"; };
7AA51DD4148506A900AD2752 /* InspectorMemoryAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorMemoryAgent.h; sourceTree = "<group>"; };
+ 7AABA25714BC613300AA9A11 /* DOMEditor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DOMEditor.cpp; sourceTree = "<group>"; };
+ 7AABA25814BC613300AA9A11 /* DOMEditor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMEditor.h; sourceTree = "<group>"; };
7AB0B1BE1211A62200A76940 /* InspectorDatabaseAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorDatabaseAgent.cpp; sourceTree = "<group>"; };
7AB0B1BF1211A62200A76940 /* InspectorDatabaseAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorDatabaseAgent.h; sourceTree = "<group>"; };
7ADE722510CBBB9B006B3B3A /* ContextMenuProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContextMenuProvider.h; sourceTree = "<group>"; };
@@ -14573,6 +14577,8 @@
41F0618C0F5F069800A07EAC /* ConsoleMessage.h */,
59102FB914327D3B003C9D04 /* ContentSearchUtils.cpp */,
59102FBA14327D3B003C9D04 /* ContentSearchUtils.h */,
+ 7AABA25714BC613300AA9A11 /* DOMEditor.cpp */,
+ 7AABA25814BC613300AA9A11 /* DOMEditor.h */,
4F1442261339FD6200E0D6F8 /* DOMNodeHighlighter.cpp */,
4F1442271339FD6200E0D6F8 /* DOMNodeHighlighter.h */,
F35AE5AB14925F5B004D5776 /* DOMWrapperVisitor.h */,
@@ -24897,6 +24903,7 @@
FD537353137B651800008DCE /* ZeroPole.h in Headers */,
974A862314B7ADBB003FDC76 /* FrameDestructionObserver.h in Headers */,
97D2AD0414B823A60093DF32 /* DOMWindowProperty.h in Headers */,
+ 7AABA25A14BC613300AA9A11 /* DOMEditor.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -27803,6 +27810,7 @@
FD537352137B651800008DCE /* ZeroPole.cpp in Sources */,
974A862214B7ADBB003FDC76 /* FrameDestructionObserver.cpp in Sources */,
97D2AD0314B823A60093DF32 /* DOMWindowProperty.cpp in Sources */,
+ 7AABA25914BC613300AA9A11 /* DOMEditor.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Added: trunk/Source/WebCore/inspector/DOMEditor.cpp (0 => 104586)
--- trunk/Source/WebCore/inspector/DOMEditor.cpp (rev 0)
+++ trunk/Source/WebCore/inspector/DOMEditor.cpp 2012-01-10 17:01:05 UTC (rev 104586)
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DOMEditor.h"
+
+#if ENABLE(INSPECTOR)
+
+#include "Base64.h"
+#include "Document.h"
+#include "HTMLDocument.h"
+#include "HTMLDocumentParser.h"
+#include "HTMLElement.h"
+#include "HTMLHeadElement.h"
+#include "Node.h"
+
+#include <wtf/RefPtr.h>
+#include <wtf/SHA1.h>
+#include <wtf/text/CString.h>
+
+using namespace std;
+
+namespace WebCore {
+
+struct DOMEditor::NodeDigest {
+ NodeDigest(Node* node) : m_node(node) { }
+
+ String m_digest;
+ String m_attrsDigest;
+ Node* m_node;
+ Vector<OwnPtr<NodeDigest> > m_children;
+};
+
+DOMEditor::DOMEditor(Document* document) : m_document(document) { }
+
+DOMEditor::~DOMEditor() { }
+
+void DOMEditor::patch(const String& markup)
+{
+ RefPtr<HTMLDocument> newDocument = HTMLDocument::create(0, KURL());
+ RefPtr<DocumentParser> parser = HTMLDocumentParser::create(newDocument.get(), false);
+ parser->insert(markup); // Use insert() so that the parser will not yield.
+ parser->finish();
+ parser->detach();
+
+ if (!patchElement(m_document->head(), newDocument->head()) || !patchElement(m_document->body(), newDocument->body())) {
+ // Fall back to rewrite.
+ m_document->write(markup);
+ m_document->close();
+ }
+}
+
+bool DOMEditor::patchElement(Element* oldElement, Element* newElement)
+{
+ if (oldElement) {
+ if (newElement) {
+ OwnPtr<NodeDigest> oldInfo = createNodeDigest(oldElement);
+ OwnPtr<NodeDigest> newInfo = createNodeDigest(newElement);
+ return patchNode(oldInfo.get(), newInfo.get());
+ }
+ oldElement->removeAllChildren();
+ return true;
+ }
+ if (newElement) {
+ ExceptionCode ec = 0;
+ m_document->documentElement()->appendChild(newElement, ec);
+ return !ec;
+ }
+ return true;
+}
+
+bool DOMEditor::patchNode(NodeDigest* oldDigest, NodeDigest* newDigest)
+{
+ if (oldDigest->m_digest == newDigest->m_digest)
+ return true;
+
+ Node* oldNode = oldDigest->m_node;
+ Node* newNode = newDigest->m_node;
+
+ if (newNode->nodeType() != oldNode->nodeType() || newNode->nodeName() != oldNode->nodeName()) {
+ ExceptionCode ec = 0;
+ oldNode->parentNode()->replaceChild(newNode, oldNode, ec);
+ if (ec)
+ return false;
+ return true;
+ }
+
+ ExceptionCode ec = 0;
+ if (oldNode->nodeValue() != newNode->nodeValue())
+ oldNode->setNodeValue(newNode->nodeValue(), ec);
+ if (ec)
+ return false;
+
+ if (oldNode->nodeType() == Node::ELEMENT_NODE && oldDigest->m_attrsDigest != newDigest->m_attrsDigest) {
+ Element* oldElement = static_cast<Element*>(oldNode);
+ Element* newElement = static_cast<Element*>(newNode);
+ oldElement->setAttributesFromElement(*newElement);
+ }
+ if (oldDigest->m_node->nodeType() != Node::ELEMENT_NODE)
+ return true;
+
+ return patchChildren(static_cast<ContainerNode*>(oldNode), oldDigest->m_children, newDigest->m_children);
+}
+
+bool DOMEditor::patchChildren(ContainerNode* oldParent, Vector<OwnPtr<NodeDigest> >& oldList, Vector<OwnPtr<NodeDigest> >& newList)
+{
+ // Trim tail.
+ size_t offset = 0;
+ for (; offset < oldList.size() && offset < newList.size() && oldList[oldList.size() - offset - 1]->m_digest == newList[newList.size() - offset - 1]->m_digest; ++offset) { }
+ if (offset > 0) {
+ oldList.resize(oldList.size() - offset);
+ newList.resize(newList.size() - offset);
+ }
+
+ // Trim head.
+ for (offset = 0; offset < oldList.size() && offset < newList.size() && oldList[offset]->m_digest == newList[offset]->m_digest; ++offset) { }
+ if (offset > 0) {
+ oldList.remove(0, offset);
+ newList.remove(0, offset);
+ }
+
+ // Diff the children lists.
+ typedef Vector<pair<NodeDigest*, size_t> > ResultMap;
+ ResultMap newMap(newList.size());
+ ResultMap oldMap(oldList.size());
+
+ for (size_t i = 0; i < oldMap.size(); ++i)
+ oldMap[i].first = 0;
+ for (size_t i = 0; i < newMap.size(); ++i)
+ newMap[i].first = 0;
+
+ typedef HashMap<String, Vector<size_t> > DiffTable;
+ DiffTable newTable;
+ DiffTable oldTable;
+
+ for (size_t i = 0; i < newList.size(); ++i) {
+ DiffTable::iterator it = newTable.add(newList[i]->m_digest, Vector<size_t>()).first;
+ it->second.append(i);
+ }
+
+ for (size_t i = 0; i < oldList.size(); ++i) {
+ DiffTable::iterator it = oldTable.add(oldList[i]->m_digest, Vector<size_t>()).first;
+ it->second.append(i);
+ }
+
+ for (DiffTable::iterator newIt = newTable.begin(); newIt != newTable.end(); ++newIt) {
+ if (newIt->second.size() != 1)
+ continue;
+
+ DiffTable::iterator oldIt = oldTable.find(newIt->first);
+ if (oldIt == oldTable.end() || oldIt->second.size() != 1)
+ continue;
+ make_pair(newList[newIt->second[0]].get(), oldIt->second[0]);
+ newMap[newIt->second[0]] = make_pair(newList[newIt->second[0]].get(), oldIt->second[0]);
+ oldMap[oldIt->second[0]] = make_pair(oldList[oldIt->second[0]].get(), newIt->second[0]);
+ }
+
+ for (size_t i = 0; newList.size() > 0 && i < newList.size() - 1; ++i) {
+ if (!newMap[i].first || newMap[i + 1].first)
+ continue;
+
+ size_t j = newMap[i].second + 1;
+ if (j < oldMap.size() && !oldMap[j].first && newList[i + 1]->m_digest == oldList[j]->m_digest) {
+ newMap[i + 1] = make_pair(newList[i + 1].get(), j);
+ oldMap[j] = make_pair(oldList[j].get(), i + 1);
+ }
+ }
+
+ for (size_t i = newList.size() - 1; newList.size() > 0 && i > 0; --i) {
+ if (!newMap[i].first || newMap[i - 1].first || newMap[i].second <= 0)
+ continue;
+
+ size_t j = newMap[i].second - 1;
+ if (!oldMap[j].first && newList[i - 1]->m_digest == oldList[j]->m_digest) {
+ newMap[i - 1] = make_pair(newList[i - 1].get(), j);
+ oldMap[j] = make_pair(oldList[j].get(), i - 1);
+ }
+ }
+
+ HashSet<NodeDigest*> merges;
+ for (size_t i = 0; i < oldList.size(); ++i) {
+ if (oldMap[i].first)
+ continue;
+
+ // Check if this change is between stable nodes. If it is, consider it as "modified".
+ if ((!i || oldMap[i - 1].first) && (i == oldMap.size() - 1 || oldMap[i + 1].first)) {
+ size_t anchorBefore = i ? oldMap[i - 1].second : -1;
+ size_t anchorAfter = i == oldMap.size() - 1 ? anchorBefore + 2 : oldMap[i + 1].second;
+ if (anchorAfter - anchorBefore == 2 && anchorBefore + 1 < newList.size()) {
+ if (!patchNode(oldList[i].get(), newList[anchorBefore + 1].get()))
+ return false;
+
+ merges.add(newList[anchorBefore + 1].get());
+ } else
+ oldList[i]->m_node->parentNode()->removeChild(oldList[i]->m_node);
+ } else {
+ ContainerNode* parentNode = static_cast<ContainerNode*>(oldList[i]->m_node->parentNode());
+ parentNode->removeChild(oldList[i]->m_node);
+ }
+ }
+
+ for (size_t i = 0; i < newMap.size(); ++i) {
+ if (newMap[i].first || merges.contains(newList[i].get()))
+ continue;
+
+ ExceptionCode ec = 0;
+ oldParent->insertBefore(newList[i]->m_node, oldParent->childNode(i + offset), ec);
+ return !ec;
+ }
+
+ return true;
+}
+
+static void addStringToSHA1(SHA1& sha1, const String& string)
+{
+ CString cString = string.utf8();
+ sha1.addBytes(reinterpret_cast<const uint8_t*>(cString.data()), cString.length());
+}
+
+PassOwnPtr<DOMEditor::NodeDigest> DOMEditor::createNodeDigest(Node* node)
+{
+ NodeDigest* nodeDigest = new NodeDigest(node);
+
+ SHA1 sha1;
+
+ Node::NodeType nodeType = node->nodeType();
+ sha1.addBytes(reinterpret_cast<const uint8_t*>(&nodeType), sizeof(nodeType));
+ addStringToSHA1(sha1, node->nodeName());
+ addStringToSHA1(sha1, node->nodeValue());
+
+ if (node->nodeType() == Node::ELEMENT_NODE) {
+ Node* child = node->firstChild();
+ while (child) {
+ OwnPtr<NodeDigest> childInfo = createNodeDigest(child);
+ addStringToSHA1(sha1, childInfo->m_digest);
+ child = child->nextSibling();
+ nodeDigest->m_children.append(childInfo.release());
+ }
+
+ Element* element = static_cast<Element*>(node);
+ const NamedNodeMap* attrMap = element->attributes(true);
+ if (attrMap && attrMap->length()) {
+ unsigned numAttrs = attrMap->length();
+ SHA1 attrsSHA1;
+ for (unsigned i = 0; i < numAttrs; ++i) {
+ const Attribute* attribute = attrMap->attributeItem(i);
+ addStringToSHA1(attrsSHA1, attribute->name().toString());
+ addStringToSHA1(attrsSHA1, attribute->value());
+ }
+ Vector<uint8_t, 20> attrsHash;
+ attrsSHA1.computeHash(attrsHash);
+ nodeDigest->m_attrsDigest = base64Encode(reinterpret_cast<const char*>(attrsHash.data()), 10);
+ addStringToSHA1(sha1, nodeDigest->m_attrsDigest);
+ }
+ }
+
+ Vector<uint8_t, 20> hash;
+ sha1.computeHash(hash);
+ nodeDigest->m_digest = base64Encode(reinterpret_cast<const char*>(hash.data()), 10);
+ return adoptPtr(nodeDigest);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INSPECTOR)
Property changes on: trunk/Source/WebCore/inspector/DOMEditor.cpp
___________________________________________________________________
Added: svn:eol-style
Added: trunk/Source/WebCore/inspector/DOMEditor.h (0 => 104586)
--- trunk/Source/WebCore/inspector/DOMEditor.h (rev 0)
+++ trunk/Source/WebCore/inspector/DOMEditor.h 2012-01-10 17:01:05 UTC (rev 104586)
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DOMEditor_h
+#define DOMEditor_h
+
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class ContainerNode;
+class Document;
+class Element;
+class Node;
+
+#if ENABLE(INSPECTOR)
+
+class DOMEditor {
+public:
+ explicit DOMEditor(Document*);
+ virtual ~DOMEditor();
+
+ void patch(const String& markup);
+
+private:
+ struct NodeDigest;
+
+ bool patchElement(Element* oldElement, Element* newElement);
+ bool patchNode(NodeDigest* oldNode, NodeDigest* newNode);
+ bool patchChildren(ContainerNode* oldParent, Vector<OwnPtr<NodeDigest> >& oldChildren, Vector<OwnPtr<NodeDigest> >& newChildren);
+ PassOwnPtr<NodeDigest> createNodeDigest(Node*);
+
+ Document* m_document;
+};
+
+#endif // ENABLE(INSPECTOR)
+
+} // namespace WebCore
+
+#endif // !defined(DOMEditor_h)
Property changes on: trunk/Source/WebCore/inspector/DOMEditor.h
___________________________________________________________________
Added: svn:eol-style
Modified: trunk/Source/WebCore/inspector/InspectorDOMAgent.cpp (104585 => 104586)
--- trunk/Source/WebCore/inspector/InspectorDOMAgent.cpp 2012-01-10 16:54:29 UTC (rev 104585)
+++ trunk/Source/WebCore/inspector/InspectorDOMAgent.cpp 2012-01-10 17:01:05 UTC (rev 104586)
@@ -47,6 +47,7 @@
#include "ContainerNode.h"
#include "Cookie.h"
#include "CookieJar.h"
+#include "DOMEditor.h"
#include "DOMNodeHighlighter.h"
#include "DOMWindow.h"
#include "Document.h"
@@ -632,13 +633,22 @@
void InspectorDOMAgent::setOuterHTML(ErrorString* errorString, int nodeId, const String& outerHTML, int* newId)
{
+ if (!nodeId) {
+ DOMEditor domEditor(m_document.get());
+ domEditor.patch(outerHTML);
+ *newId = 0;
+ return;
+ }
+
Node* node = assertNode(errorString, nodeId);
if (!node)
return;
- Element* parentElement = node->parentElement();
- if (!parentElement)
+ Node* parentNode = node->parentNode();
+ if (!parentNode) {
+ *errorString = "Editing of the detached nodes is not supported";
return;
+ }
Document* document = node->ownerDocument();
if (!document->isHTMLDocument()) {
@@ -649,10 +659,10 @@
Node* previousSibling = node->previousSibling(); // Remember previous sibling before replacing node.
RefPtr<DocumentFragment> fragment = DocumentFragment::create(document);
- fragment->parseHTML(outerHTML, parentElement);
+ fragment->parseHTML(outerHTML, parentNode->nodeType() == Node::ELEMENT_NODE ? static_cast<Element*>(parentNode) : document->documentElement());
ExceptionCode ec = 0;
- parentElement->replaceChild(fragment.release(), node, ec);
+ parentNode->replaceChild(fragment.release(), node, ec);
if (ec) {
*errorString = "Failed to replace Node with new contents";
return;
@@ -670,7 +680,7 @@
return;
}
- Node* newNode = previousSibling ? previousSibling->nextSibling() : parentElement->firstChild();
+ Node* newNode = previousSibling ? previousSibling->nextSibling() : parentNode->firstChild();
if (!newNode) {
// The only child node has been deleted.
*newId = 0;
Modified: trunk/Source/WebCore/inspector/front-end/DOMAgent.js (104585 => 104586)
--- trunk/Source/WebCore/inspector/front-end/DOMAgent.js 2012-01-10 16:54:29 UTC (rev 104585)
+++ trunk/Source/WebCore/inspector/front-end/DOMAgent.js 2012-01-10 17:01:05 UTC (rev 104586)
@@ -529,6 +529,8 @@
this._document = null;
this._attributeLoadNodeIds = {};
InspectorBackend.registerDOMDispatcher(new WebInspector.DOMDispatcher(this));
+ if (WebInspector.experimentsSettings.freeFlowDOMEditing.isEnabled())
+ new WebInspector.DOMModelResourceBinding(this);
}
WebInspector.DOMAgent.Events = {
@@ -1074,3 +1076,27 @@
* @type {?WebInspector.DOMAgent}
*/
WebInspector.domAgent = null;
+
+/**
+ * @constructor
+ * @implements {WebInspector.ResourceDomainModelBinding}
+ */
+WebInspector.DOMModelResourceBinding = function(domAgent)
+{
+ this._domAgent = domAgent;
+ WebInspector.Resource.registerDomainModelBinding(WebInspector.Resource.Type.Document, this);
+}
+
+WebInspector.DOMModelResourceBinding.prototype = {
+ setContent: function(resource, content, majorChange, userCallback)
+ {
+ DOMAgent.setOuterHTML(0, content, userCallback);
+ },
+
+ canSetContent: function()
+ {
+ return true;
+ }
+}
+
+WebInspector.DOMModelResourceBinding.prototype.__proto__ = WebInspector.ResourceDomainModelBinding.prototype;
Modified: trunk/Source/WebCore/inspector/front-end/Settings.js (104585 => 104586)
--- trunk/Source/WebCore/inspector/front-end/Settings.js 2012-01-10 16:54:29 UTC (rev 104585)
+++ trunk/Source/WebCore/inspector/front-end/Settings.js 2012-01-10 17:01:05 UTC (rev 104586)
@@ -169,6 +169,7 @@
// FIXME: Move out from experiments once navigator is production-ready.
this.useScriptsNavigator = this._createExperiment("useScriptsNavigator", "Use file navigator and tabbed editor container in scripts panel");
this.sourceFrameAlwaysEditable = this._createExperiment("sourceFrameAlwaysEditable", "Make resources always editable");
+ this.freeFlowDOMEditing = this._createExperiment("freeFlowDOMEditing", "Enable free flow DOM editing");
this._cleanUpSetting();
}