Changeset 107257 in webkit
- Timestamp:
- Feb 9, 2012 9:42:09 AM (12 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 12 edited
- 2 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/CMakeLists.txt
r107194 r107257 879 879 inspector/DOMEditor.cpp 880 880 inspector/DOMNodeHighlighter.cpp 881 inspector/DOMPatchSupport.cpp 881 882 inspector/IdentifiersFactory.cpp 882 883 inspector/InjectedScript.cpp -
trunk/Source/WebCore/ChangeLog
r107256 r107257 1 2012-02-09 Pavel Feldman <pfeldman@google.com> 2 3 Web Inspector: rename DOMEditor to DOMPatchSupport, move undoable actions from 4 InspectorDOMAgent to the new DOMEditor. 5 https://bugs.webkit.org/show_bug.cgi?id=78245 6 7 Reviewed by Yury Semikhatsky. 8 9 * CMakeLists.txt: 10 * GNUmakefile.list.am: 11 * Target.pri: 12 * WebCore.gypi: 13 * WebCore.vcproj/WebCore.vcproj: 14 * WebCore.xcodeproj/project.pbxproj: 15 * inspector/DOMEditor.cpp: 16 (DOMEditor::DOMAction): 17 (WebCore::DOMEditor::DOMAction::DOMAction): 18 (WebCore::DOMEditor::DOMAction::perform): 19 (WebCore::DOMEditor::DOMAction::undo): 20 (DOMEditor::RemoveChildAction): 21 (WebCore::DOMEditor::RemoveChildAction::RemoveChildAction): 22 (WebCore::DOMEditor::RemoveChildAction::perform): 23 (WebCore::DOMEditor::RemoveChildAction::undo): 24 (DOMEditor::InsertBeforeAction): 25 (WebCore::DOMEditor::InsertBeforeAction::InsertBeforeAction): 26 (WebCore::DOMEditor::InsertBeforeAction::perform): 27 (WebCore::DOMEditor::InsertBeforeAction::undo): 28 (DOMEditor::RemoveAttributeAction): 29 (WebCore::DOMEditor::RemoveAttributeAction::RemoveAttributeAction): 30 (WebCore::DOMEditor::RemoveAttributeAction::perform): 31 (WebCore::DOMEditor::RemoveAttributeAction::undo): 32 (DOMEditor::SetAttributeAction): 33 (WebCore::DOMEditor::SetAttributeAction::SetAttributeAction): 34 (WebCore::DOMEditor::SetAttributeAction::perform): 35 (WebCore::DOMEditor::SetAttributeAction::undo): 36 (DOMEditor::SetOuterHTMLAction): 37 (WebCore::DOMEditor::SetOuterHTMLAction::SetOuterHTMLAction): 38 (WebCore::DOMEditor::SetOuterHTMLAction::perform): 39 (WebCore::DOMEditor::SetOuterHTMLAction::undo): 40 (WebCore::DOMEditor::SetOuterHTMLAction::newNode): 41 (DOMEditor::ReplaceWholeTextAction): 42 (WebCore::DOMEditor::ReplaceWholeTextAction::ReplaceWholeTextAction): 43 (WebCore::DOMEditor::ReplaceWholeTextAction::perform): 44 (WebCore::DOMEditor::ReplaceWholeTextAction::undo): 45 (WebCore::DOMEditor::DOMEditor): 46 (WebCore): 47 (WebCore::DOMEditor::~DOMEditor): 48 (WebCore::DOMEditor::insertBefore): 49 (WebCore::DOMEditor::removeChild): 50 (WebCore::DOMEditor::setAttribute): 51 (WebCore::DOMEditor::removeAttribute): 52 (WebCore::DOMEditor::setOuterHTML): 53 (WebCore::DOMEditor::replaceWholeText): 54 * inspector/DOMEditor.h: 55 (WebCore): 56 (DOMEditor): 57 * inspector/DOMPatchSupport.cpp: Copied from Source/WebCore/inspector/DOMEditor.cpp. 58 (WebCore::DOMPatchSupport::DOMPatchSupport): 59 (WebCore::DOMPatchSupport::~DOMPatchSupport): 60 (WebCore::DOMPatchSupport::patchDocument): 61 (WebCore::DOMPatchSupport::patchNode): 62 (WebCore::DOMPatchSupport::innerPatchNode): 63 (WebCore): 64 (WebCore::DOMPatchSupport::diff): 65 (WebCore::DOMPatchSupport::innerPatchChildren): 66 (WebCore::DOMPatchSupport::createDigest): 67 (WebCore::DOMPatchSupport::insertBefore): 68 (WebCore::DOMPatchSupport::removeChild): 69 (WebCore::DOMPatchSupport::markNodeAsUsed): 70 (WebCore::DOMPatchSupport::dumpMap): 71 * inspector/DOMPatchSupport.h: Copied from Source/WebCore/inspector/DOMEditor.h. 72 (DOMPatchSupport): 73 * inspector/InspectorDOMAgent.cpp: 74 (WebCore::InspectorDOMAgent::InspectorDOMAgent): 75 (WebCore::InspectorDOMAgent::setFrontend): 76 (WebCore::InspectorDOMAgent::clearFrontend): 77 (WebCore::InspectorDOMAgent::reset): 78 (WebCore::InspectorDOMAgent::setAttributeValue): 79 (WebCore::InspectorDOMAgent::setAttributesAsText): 80 (WebCore::InspectorDOMAgent::removeAttribute): 81 (WebCore::InspectorDOMAgent::removeNode): 82 (WebCore::InspectorDOMAgent::setNodeName): 83 (WebCore::InspectorDOMAgent::setOuterHTML): 84 (WebCore::InspectorDOMAgent::setNodeValue): 85 (WebCore::InspectorDOMAgent::moveTo): 86 * inspector/InspectorDOMAgent.h: 87 (WebCore): 88 (InspectorDOMAgent): 89 * inspector/InspectorPageAgent.cpp: 90 (WebCore::InspectorPageAgent::setDocumentContent): 91 1 92 2012-02-09 Mark Rowe <mrowe@apple.com> 2 93 -
trunk/Source/WebCore/GNUmakefile.list.am
r107175 r107257 2345 2345 Source/WebCore/inspector/DOMNodeHighlighter.cpp \ 2346 2346 Source/WebCore/inspector/DOMNodeHighlighter.h \ 2347 Source/WebCore/inspector/DOMPatchSupport.cpp \ 2348 Source/WebCore/inspector/DOMPatchSupport.h \ 2347 2349 Source/WebCore/inspector/DOMWrapperVisitor.h \ 2348 2350 Source/WebCore/inspector/IdentifiersFactory.cpp \ -
trunk/Source/WebCore/Target.pri
r107175 r107257 856 856 inspector/DOMEditor.cpp \ 857 857 inspector/DOMNodeHighlighter.cpp \ 858 inspector/DOMPatchSupport.cpp \ 858 859 inspector/IdentifiersFactory.cpp \ 859 860 inspector/InjectedScript.cpp \ … … 1921 1922 inspector/DOMEditor.h \ 1922 1923 inspector/DOMNodeHighlighter.h \ 1924 inspector/DOMPatchSupport.h \ 1923 1925 inspector/DOMWrapperVisitor.h \ 1924 1926 inspector/IdentifiersFactory.h \ -
trunk/Source/WebCore/WebCore.gypi
r107235 r107257 2344 2344 'inspector/DOMNodeHighlighter.cpp', 2345 2345 'inspector/DOMNodeHighlighter.h', 2346 'inspector/DOMPatchSupport.cpp', 2347 'inspector/DOMPatchSupport.h', 2346 2348 'inspector/DOMWrapperVisitor.h', 2347 2349 'inspector/IdentifiersFactory.cpp', -
trunk/Source/WebCore/WebCore.vcproj/WebCore.vcproj
r107235 r107257 71155 71155 </File> 71156 71156 <File 71157 RelativePath="..\inspector\DOMPatchSupport.cpp" 71158 > 71159 </File> 71160 <File 71161 RelativePath="..\inspector\DOMPatchSupport.h" 71162 > 71163 </File> 71164 <File 71157 71165 RelativePath="..\inspector\DOMWrapperVisitor.h" 71158 71166 > -
trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj
r107175 r107257 1891 1891 7A54857F14E02D51006AE05A /* InspectorHistory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7A54857D14E02D51006AE05A /* InspectorHistory.cpp */; }; 1892 1892 7A54858014E02D51006AE05A /* InspectorHistory.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A54857E14E02D51006AE05A /* InspectorHistory.h */; }; 1893 7A54881714E432A1006AE05A /* DOMPatchSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A54881514E432A1006AE05A /* DOMPatchSupport.h */; }; 1894 7A54881814E432A1006AE05A /* DOMPatchSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7A54881614E432A1006AE05A /* DOMPatchSupport.cpp */; }; 1893 1895 7A674BDB0F9EBF4E006CF099 /* PageGroupLoadDeferrer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7A674BD90F9EBF4E006CF099 /* PageGroupLoadDeferrer.cpp */; }; 1894 1896 7A674BDC0F9EBF4E006CF099 /* PageGroupLoadDeferrer.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A674BDA0F9EBF4E006CF099 /* PageGroupLoadDeferrer.h */; }; … … 8774 8776 7A54857D14E02D51006AE05A /* InspectorHistory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorHistory.cpp; sourceTree = "<group>"; }; 8775 8777 7A54857E14E02D51006AE05A /* InspectorHistory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorHistory.h; sourceTree = "<group>"; }; 8778 7A54881514E432A1006AE05A /* DOMPatchSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMPatchSupport.h; sourceTree = "<group>"; }; 8779 7A54881614E432A1006AE05A /* DOMPatchSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DOMPatchSupport.cpp; sourceTree = "<group>"; }; 8776 8780 7A563E5412DE32B000F4536D /* InjectedScriptSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InjectedScriptSource.h; sourceTree = "<group>"; }; 8777 8781 7A563F9512DF5C9100F4536D /* InjectedScriptSource.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = InjectedScriptSource.js; sourceTree = "<group>"; }; … … 14011 14015 4F1442261339FD6200E0D6F8 /* DOMNodeHighlighter.cpp */, 14012 14016 4F1442271339FD6200E0D6F8 /* DOMNodeHighlighter.h */, 14017 7A54881514E432A1006AE05A /* DOMPatchSupport.h */, 14018 7A54881614E432A1006AE05A /* DOMPatchSupport.cpp */, 14013 14019 F35AE5AB14925F5B004D5776 /* DOMWrapperVisitor.h */, 14014 14020 5913A23F13D49EBA00F5B05C /* IdentifiersFactory.cpp */, … … 24156 24162 10FB084B14E15C7E00A3DB98 /* PublicURLManager.h in Headers */, 24157 24163 7A54858014E02D51006AE05A /* InspectorHistory.h in Headers */, 24164 7A54881714E432A1006AE05A /* DOMPatchSupport.h in Headers */, 24158 24165 ); 24159 24166 runOnlyForDeploymentPostprocessing = 0; … … 27093 27100 7A54857F14E02D51006AE05A /* InspectorHistory.cpp in Sources */, 27094 27101 CDAA8D0A14D71B2E0061EA60 /* PlatformClockCM.mm in Sources */, 27102 7A54881814E432A1006AE05A /* DOMPatchSupport.cpp in Sources */, 27095 27103 ); 27096 27104 runOnlyForDeploymentPostprocessing = 0; -
trunk/Source/WebCore/inspector/DOMEditor.cpp
r107242 r107257 34 34 #if ENABLE(INSPECTOR) 35 35 36 #include "Attribute.h" 37 #include "Base64.h" 36 #include "DOMPatchSupport.h" 38 37 #include "Document.h" 39 #include "DocumentFragment.h" 40 #include "HTMLDocument.h" 41 #include "HTMLDocumentParser.h" 42 #include "HTMLElement.h" 43 #include "HTMLHeadElement.h" 44 #include "HTMLNames.h" 38 #include "Element.h" 39 #include "ExceptionCode.h" 40 #include "InspectorHistory.h" 45 41 #include "Node.h" 46 47 #include <wtf/Deque.h> 42 #include "Text.h" 43 44 #include "markup.h" 45 48 46 #include <wtf/RefPtr.h> 49 #include <wtf/SHA1.h>50 #include <wtf/text/CString.h>51 47 52 48 using namespace std; … … 54 50 namespace WebCore { 55 51 56 using HTMLNames::bodyTag; 57 using HTMLNames::headTag; 58 using HTMLNames::htmlTag; 59 60 struct DOMEditor::Digest { 61 explicit Digest(Node* node) : m_node(node) { } 62 63 String m_sha1; 64 String m_attrsSHA1; 65 Node* m_node; 66 Vector<OwnPtr<Digest> > m_children; 67 }; 68 69 DOMEditor::DOMEditor(Document* document) : m_document(document) { } 52 class DOMEditor::DOMAction : public InspectorHistory::Action { 53 public: 54 DOMAction(const String& name) : InspectorHistory::Action(name) { } 55 56 virtual bool perform(ErrorString* errorString) 57 { 58 ExceptionCode ec = 0; 59 bool result = perform(ec); 60 if (ec) { 61 ExceptionCodeDescription description(ec); 62 *errorString = description.name; 63 } 64 return result && !ec; 65 } 66 67 virtual bool undo(ErrorString* errorString) 68 { 69 ExceptionCode ec = 0; 70 bool result = undo(ec); 71 if (ec) { 72 ExceptionCodeDescription description(ec); 73 *errorString = description.name; 74 } 75 return result && !ec; 76 } 77 78 virtual bool perform(ExceptionCode&) = 0; 79 80 virtual bool undo(ExceptionCode&) = 0; 81 82 private: 83 RefPtr<Node> m_parentNode; 84 RefPtr<Node> m_node; 85 RefPtr<Node> m_anchorNode; 86 }; 87 88 class DOMEditor::RemoveChildAction : public DOMEditor::DOMAction { 89 WTF_MAKE_NONCOPYABLE(RemoveChildAction); 90 public: 91 RemoveChildAction(Node* parentNode, Node* node) 92 : DOMEditor::DOMAction("RemoveChild") 93 , m_parentNode(parentNode) 94 , m_node(node) 95 { 96 } 97 98 virtual bool perform(ExceptionCode& ec) 99 { 100 m_anchorNode = m_node->nextSibling(); 101 return m_parentNode->removeChild(m_node.get(), ec); 102 } 103 104 virtual bool undo(ExceptionCode& ec) 105 { 106 return m_parentNode->insertBefore(m_node.get(), m_anchorNode.get(), ec); 107 } 108 109 private: 110 RefPtr<Node> m_parentNode; 111 RefPtr<Node> m_node; 112 RefPtr<Node> m_anchorNode; 113 }; 114 115 class DOMEditor::InsertBeforeAction : public DOMEditor::DOMAction { 116 WTF_MAKE_NONCOPYABLE(InsertBeforeAction); 117 public: 118 InsertBeforeAction(Node* parentNode, Node* node, Node* anchorNode) 119 : DOMEditor::DOMAction("InsertBefore") 120 , m_parentNode(parentNode) 121 , m_node(node) 122 , m_anchorNode(anchorNode) 123 { 124 } 125 126 virtual bool perform(ExceptionCode& ec) 127 { 128 if (m_node->parentNode()) { 129 m_removeChildAction = adoptPtr(new RemoveChildAction(m_node->parentNode(), m_node.get())); 130 if (!m_removeChildAction->perform(ec)) 131 return false; 132 } 133 return m_parentNode->insertBefore(m_node.get(), m_anchorNode.get(), ec); 134 } 135 136 virtual bool undo(ExceptionCode& ec) 137 { 138 if (m_removeChildAction) 139 return m_removeChildAction->undo(ec); 140 141 return m_parentNode->removeChild(m_node.get(), ec); 142 } 143 144 private: 145 RefPtr<Node> m_parentNode; 146 RefPtr<Node> m_node; 147 RefPtr<Node> m_anchorNode; 148 OwnPtr<RemoveChildAction> m_removeChildAction; 149 }; 150 151 class DOMEditor::RemoveAttributeAction : public DOMEditor::DOMAction { 152 WTF_MAKE_NONCOPYABLE(RemoveAttributeAction); 153 public: 154 RemoveAttributeAction(Element* element, const String& name) 155 : DOMEditor::DOMAction("RemoveAttribute") 156 , m_element(element) 157 , m_name(name) 158 { 159 } 160 161 virtual bool perform(ExceptionCode&) 162 { 163 m_value = m_element->getAttribute(m_name); 164 m_element->removeAttribute(m_name); 165 return true; 166 } 167 168 virtual bool undo(ExceptionCode& ec) 169 { 170 m_element->setAttribute(m_name, m_value, ec); 171 return true; 172 } 173 174 private: 175 RefPtr<Element> m_element; 176 String m_name; 177 String m_value; 178 }; 179 180 class DOMEditor::SetAttributeAction : public DOMEditor::DOMAction { 181 WTF_MAKE_NONCOPYABLE(SetAttributeAction); 182 public: 183 SetAttributeAction(Element* element, const String& name, const String& value) 184 : DOMEditor::DOMAction("SetAttribute") 185 , m_element(element) 186 , m_name(name) 187 , m_value(value) 188 , m_hadAttribute(false) 189 { 190 } 191 192 virtual bool perform(ExceptionCode& ec) 193 { 194 m_hadAttribute = m_element->hasAttribute(m_name); 195 if (m_hadAttribute) 196 m_oldValue = m_element->getAttribute(m_name); 197 m_element->setAttribute(m_name, m_value, ec); 198 return !ec; 199 } 200 201 virtual bool undo(ExceptionCode& ec) 202 { 203 if (m_hadAttribute) 204 m_element->setAttribute(m_name, m_oldValue, ec); 205 else 206 m_element->removeAttribute(m_name); 207 return true; 208 } 209 210 private: 211 RefPtr<Element> m_element; 212 String m_name; 213 String m_value; 214 bool m_hadAttribute; 215 String m_oldValue; 216 }; 217 218 class DOMEditor::SetOuterHTMLAction : public DOMEditor::DOMAction { 219 WTF_MAKE_NONCOPYABLE(SetOuterHTMLAction); 220 public: 221 SetOuterHTMLAction(Node* node, const String& html) 222 : DOMEditor::DOMAction("SetOuterHTML") 223 , m_node(node) 224 , m_nextSibling(node->nextSibling()) 225 , m_html(html) 226 , m_newNode(0) 227 { 228 } 229 230 virtual bool perform(ExceptionCode& ec) 231 { 232 m_oldHTML = createMarkup(m_node.get()); 233 DOMPatchSupport domPatchSupport(m_node->ownerDocument()); 234 m_newNode = domPatchSupport.patchNode(m_node.get(), m_html, ec); 235 return !ec; 236 } 237 238 virtual bool undo(ExceptionCode& ec) 239 { 240 DOMPatchSupport domPatchSupport(m_newNode->ownerDocument()); 241 Node* node = domPatchSupport.patchNode(m_newNode, m_oldHTML, ec); 242 if (ec || !node) 243 return false; 244 // HTML editing could have produced extra nodes. Remove them if necessary. 245 node = node->nextSibling(); 246 247 while (!ec && node && node != m_nextSibling.get()) { 248 Node* nodeToRemove = node; 249 node = node->nextSibling(); 250 nodeToRemove->remove(ec); 251 } 252 return !ec; 253 } 254 255 Node* newNode() 256 { 257 return m_newNode; 258 } 259 260 private: 261 RefPtr<Node> m_node; 262 RefPtr<Node> m_nextSibling; 263 String m_html; 264 String m_oldHTML; 265 Node* m_newNode; 266 }; 267 268 class DOMEditor::ReplaceWholeTextAction : public DOMEditor::DOMAction { 269 WTF_MAKE_NONCOPYABLE(ReplaceWholeTextAction); 270 public: 271 ReplaceWholeTextAction(Text* textNode, const String& text) 272 : DOMAction("ReplaceWholeText") 273 , m_textNode(textNode) 274 , m_text(text) 275 { 276 } 277 278 virtual bool perform(ExceptionCode& ec) 279 { 280 m_oldText = m_textNode->wholeText(); 281 m_textNode->replaceWholeText(m_text, ec); 282 return true; 283 } 284 285 virtual bool undo(ExceptionCode& ec) 286 { 287 m_textNode->replaceWholeText(m_oldText, ec); 288 return true; 289 } 290 291 private: 292 RefPtr<Text> m_textNode; 293 String m_text; 294 String m_oldText; 295 }; 296 297 DOMEditor::DOMEditor(InspectorHistory* history) : m_history(history) { } 70 298 71 299 DOMEditor::~DOMEditor() { } 72 300 73 void DOMEditor::patchDocument(const String& markup) 74 { 75 RefPtr<HTMLDocument> newDocument = HTMLDocument::create(0, KURL()); 76 RefPtr<DocumentParser> parser = HTMLDocumentParser::create(newDocument.get(), false); 77 parser->insert(markup); // Use insert() so that the parser will not yield. 78 parser->finish(); 79 parser->detach(); 80 81 ExceptionCode ec = 0; 82 OwnPtr<Digest> oldInfo = createDigest(m_document->documentElement(), 0); 83 OwnPtr<Digest> newInfo = createDigest(newDocument->documentElement(), &m_unusedNodesMap); 84 innerPatchNode(oldInfo.get(), newInfo.get(), ec); 85 86 if (ec) { 87 // Fall back to rewrite. 88 m_document->write(markup); 89 m_document->close(); 90 } 91 } 92 93 Node* DOMEditor::patchNode(Node* node, const String& markup, ExceptionCode& ec) 94 { 95 // Don't parse <html> as a fragment. 96 if (node->isDocumentNode() || (node->parentNode() && node->parentNode()->isDocumentNode())) { 97 patchDocument(markup); 98 return 0; 99 } 100 101 Node* previousSibling = node->previousSibling(); 102 RefPtr<DocumentFragment> fragment = DocumentFragment::create(m_document); 103 fragment->parseHTML(markup, node->parentElement() ? node->parentElement() : m_document->documentElement()); 104 105 // Compose the old list. 106 ContainerNode* parentNode = node->parentNode(); 107 Vector<OwnPtr<Digest> > oldList; 108 for (Node* child = parentNode->firstChild(); child; child = child->nextSibling()) 109 oldList.append(createDigest(child, 0)); 110 111 // Compose the new list. 112 String markupCopy = markup; 113 markupCopy.makeLower(); 114 Vector<OwnPtr<Digest> > newList; 115 for (Node* child = parentNode->firstChild(); child != node; child = child->nextSibling()) 116 newList.append(createDigest(child, 0)); 117 for (Node* child = fragment->firstChild(); child; child = child->nextSibling()) { 118 if (child->hasTagName(headTag) && !child->firstChild() && markupCopy.find("</head>") == notFound) 119 continue; // HTML5 parser inserts empty <head> tag whenever it parses <body> 120 if (child->hasTagName(bodyTag) && !child->firstChild() && markupCopy.find("</body>") == notFound) 121 continue; // HTML5 parser inserts empty <body> tag whenever it parses </head> 122 newList.append(createDigest(child, &m_unusedNodesMap)); 123 } 124 for (Node* child = node->nextSibling(); child; child = child->nextSibling()) 125 newList.append(createDigest(child, 0)); 126 127 innerPatchChildren(parentNode, oldList, newList, ec); 128 if (ec) { 129 // Fall back to total replace. 130 ec = 0; 131 parentNode->replaceChild(fragment.release(), node, ec); 132 if (ec) 133 return 0; 134 } 135 return previousSibling ? previousSibling->nextSibling() : parentNode->firstChild(); 136 } 137 138 void DOMEditor::innerPatchNode(Digest* oldDigest, Digest* newDigest, ExceptionCode& ec) 139 { 140 if (oldDigest->m_sha1 == newDigest->m_sha1) 141 return; 142 143 Node* oldNode = oldDigest->m_node; 144 Node* newNode = newDigest->m_node; 145 146 if (newNode->nodeType() != oldNode->nodeType() || newNode->nodeName() != oldNode->nodeName()) { 147 oldNode->parentNode()->replaceChild(newNode, oldNode, ec); 148 return; 149 } 150 151 if (oldNode->nodeValue() != newNode->nodeValue()) 152 oldNode->setNodeValue(newNode->nodeValue(), ec); 153 if (ec) 154 return; 155 156 if (oldNode->nodeType() != Node::ELEMENT_NODE) 157 return; 158 159 // Patch attributes 160 Element* oldElement = static_cast<Element*>(oldNode); 161 Element* newElement = static_cast<Element*>(newNode); 162 if (oldDigest->m_attrsSHA1 != newDigest->m_attrsSHA1) { 163 // FIXME: Create a function in Element for removing all properties. Take in account whether did/willModifyAttribute are important. 164 if (oldElement->hasAttributesWithoutUpdate()) { 165 while (oldElement->attributeCount()) 166 oldElement->removeAttribute(0); 167 } 168 169 // FIXME: Create a function in Element for copying properties. setAttributesFromElement() is close but not enough for this case. 170 if (newElement->hasAttributesWithoutUpdate()) { 171 size_t numAttrs = newElement->attributeCount(); 172 for (size_t i = 0; i < numAttrs; ++i) { 173 const Attribute* attribute = newElement->attributeItem(i); 174 oldElement->setAttribute(attribute->name(), attribute->value()); 175 } 176 } 177 } 178 179 innerPatchChildren(oldElement, oldDigest->m_children, newDigest->m_children, ec); 180 m_unusedNodesMap.remove(newDigest->m_sha1); 181 } 182 183 pair<DOMEditor::ResultMap, DOMEditor::ResultMap> 184 DOMEditor::diff(const Vector<OwnPtr<Digest> >& oldList, const Vector<OwnPtr<Digest> >& newList) 185 { 186 ResultMap newMap(newList.size()); 187 ResultMap oldMap(oldList.size()); 188 189 for (size_t i = 0; i < oldMap.size(); ++i) { 190 oldMap[i].first = 0; 191 oldMap[i].second = 0; 192 } 193 194 for (size_t i = 0; i < newMap.size(); ++i) { 195 newMap[i].first = 0; 196 newMap[i].second = 0; 197 } 198 199 // Trim head and tail. 200 for (size_t i = 0; i < oldList.size() && i < newList.size() && oldList[i]->m_sha1 == newList[i]->m_sha1; ++i) { 201 oldMap[i].first = oldList[i].get(); 202 oldMap[i].second = i; 203 newMap[i].first = newList[i].get(); 204 newMap[i].second = i; 205 } 206 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) { 207 size_t oldIndex = oldList.size() - i - 1; 208 size_t newIndex = newList.size() - i - 1; 209 oldMap[oldIndex].first = oldList[oldIndex].get(); 210 oldMap[oldIndex].second = newIndex; 211 newMap[newIndex].first = newList[newIndex].get(); 212 newMap[newIndex].second = oldIndex; 213 } 214 215 typedef HashMap<String, Vector<size_t> > DiffTable; 216 DiffTable newTable; 217 DiffTable oldTable; 218 219 for (size_t i = 0; i < newList.size(); ++i) { 220 DiffTable::iterator it = newTable.add(newList[i]->m_sha1, Vector<size_t>()).first; 221 it->second.append(i); 222 } 223 224 for (size_t i = 0; i < oldList.size(); ++i) { 225 DiffTable::iterator it = oldTable.add(oldList[i]->m_sha1, Vector<size_t>()).first; 226 it->second.append(i); 227 } 228 229 for (DiffTable::iterator newIt = newTable.begin(); newIt != newTable.end(); ++newIt) { 230 if (newIt->second.size() != 1) 231 continue; 232 233 DiffTable::iterator oldIt = oldTable.find(newIt->first); 234 if (oldIt == oldTable.end() || oldIt->second.size() != 1) 235 continue; 236 237 newMap[newIt->second[0]] = make_pair(newList[newIt->second[0]].get(), oldIt->second[0]); 238 oldMap[oldIt->second[0]] = make_pair(oldList[oldIt->second[0]].get(), newIt->second[0]); 239 } 240 241 for (size_t i = 0; newList.size() > 0 && i < newList.size() - 1; ++i) { 242 if (!newMap[i].first || newMap[i + 1].first) 243 continue; 244 245 size_t j = newMap[i].second + 1; 246 if (j < oldMap.size() && !oldMap[j].first && newList[i + 1]->m_sha1 == oldList[j]->m_sha1) { 247 newMap[i + 1] = make_pair(newList[i + 1].get(), j); 248 oldMap[j] = make_pair(oldList[j].get(), i + 1); 249 } 250 } 251 252 for (size_t i = newList.size() - 1; newList.size() > 0 && i > 0; --i) { 253 if (!newMap[i].first || newMap[i - 1].first || newMap[i].second <= 0) 254 continue; 255 256 size_t j = newMap[i].second - 1; 257 if (!oldMap[j].first && newList[i - 1]->m_sha1 == oldList[j]->m_sha1) { 258 newMap[i - 1] = make_pair(newList[i - 1].get(), j); 259 oldMap[j] = make_pair(oldList[j].get(), i - 1); 260 } 261 } 262 263 #ifdef DEBUG_DOM_EDITOR 264 dumpMap(oldMap, "OLD"); 265 dumpMap(newMap, "NEW"); 266 #endif 267 268 return make_pair(oldMap, newMap); 269 } 270 271 void DOMEditor::innerPatchChildren(ContainerNode* parentNode, const Vector<OwnPtr<Digest> >& oldList, const Vector<OwnPtr<Digest> >& newList, ExceptionCode& ec) 272 { 273 pair<ResultMap, ResultMap> resultMaps = diff(oldList, newList); 274 ResultMap& oldMap = resultMaps.first; 275 ResultMap& newMap = resultMaps.second; 276 277 Digest* oldHead = 0; 278 Digest* oldBody = 0; 279 280 // 1. First strip everything except for the nodes that retain. Collect pending merges. 281 HashMap<Digest*, Digest*> merges; 282 HashSet<size_t> usedNewOrdinals; 283 for (size_t i = 0; i < oldList.size(); ++i) { 284 if (oldMap[i].first) { 285 if (!usedNewOrdinals.contains(oldMap[i].second)) { 286 usedNewOrdinals.add(oldMap[i].second); 287 continue; 288 } 289 oldMap[i].first = 0; 290 oldMap[i].second = 0; 291 } 292 293 // Always match <head> and <body> tags with each other - we can't remove them from the DOM 294 // upon patching. 295 if (oldList[i]->m_node->hasTagName(headTag)) { 296 oldHead = oldList[i].get(); 297 continue; 298 } 299 if (oldList[i]->m_node->hasTagName(bodyTag)) { 300 oldBody = oldList[i].get(); 301 continue; 302 } 303 304 // Check if this change is between stable nodes. If it is, consider it as "modified". 305 if (!m_unusedNodesMap.contains(oldList[i]->m_sha1) && (!i || oldMap[i - 1].first) && (i == oldMap.size() - 1 || oldMap[i + 1].first)) { 306 size_t anchorCandidate = i ? oldMap[i - 1].second + 1 : 0; 307 size_t anchorAfter = i == oldMap.size() - 1 ? anchorCandidate + 1 : oldMap[i + 1].second; 308 if (anchorAfter - anchorCandidate == 1 && anchorCandidate < newList.size()) 309 merges.set(newList[anchorCandidate].get(), oldList[i].get()); 310 else { 311 removeChild(oldList[i].get(), ec); 312 if (ec) 313 return; 314 } 315 } else { 316 removeChild(oldList[i].get(), ec); 317 if (ec) 318 return; 319 } 320 } 321 322 // Mark retained nodes as used, do not reuse node more than once. 323 HashSet<size_t> usedOldOrdinals; 324 for (size_t i = 0; i < newList.size(); ++i) { 325 if (!newMap[i].first) 326 continue; 327 size_t oldOrdinal = newMap[i].second; 328 if (usedOldOrdinals.contains(oldOrdinal)) { 329 // Do not map node more than once 330 newMap[i].first = 0; 331 newMap[i].second = 0; 332 continue; 333 } 334 usedOldOrdinals.add(oldOrdinal); 335 markNodeAsUsed(newMap[i].first); 336 } 337 338 // Mark <head> and <body> nodes for merge. 339 if (oldHead || oldBody) { 340 for (size_t i = 0; i < newList.size(); ++i) { 341 if (oldHead && newList[i]->m_node->hasTagName(headTag)) 342 merges.set(newList[i].get(), oldHead); 343 if (oldBody && newList[i]->m_node->hasTagName(bodyTag)) 344 merges.set(newList[i].get(), oldBody); 345 } 346 } 347 348 // 2. Patch nodes marked for merge. 349 for (HashMap<Digest*, Digest*>::iterator it = merges.begin(); it != merges.end(); ++it) { 350 innerPatchNode(it->second, it->first, ec); 351 if (ec) 352 return; 353 } 354 355 // 3. Insert missing nodes. 356 for (size_t i = 0; i < newMap.size(); ++i) { 357 if (newMap[i].first || merges.contains(newList[i].get())) 358 continue; 359 360 ExceptionCode ec = 0; 361 insertBefore(parentNode, newList[i].get(), parentNode->childNode(i), ec); 362 if (ec) 363 return; 364 } 365 366 // 4. Then put all nodes that retained into their slots (sort by new index). 367 for (size_t i = 0; i < oldMap.size(); ++i) { 368 if (!oldMap[i].first) 369 continue; 370 RefPtr<Node> node = oldMap[i].first->m_node; 371 Node* anchorNode = parentNode->childNode(oldMap[i].second); 372 if (node.get() == anchorNode) 373 continue; 374 if (node->hasTagName(bodyTag) || node->hasTagName(headTag)) 375 continue; // Never move head or body, move the rest of the nodes around them. 376 377 parentNode->insertBefore(node, anchorNode, ec); 378 if (ec) 379 return; 380 } 381 } 382 383 static void addStringToSHA1(SHA1& sha1, const String& string) 384 { 385 CString cString = string.utf8(); 386 sha1.addBytes(reinterpret_cast<const uint8_t*>(cString.data()), cString.length()); 387 } 388 389 PassOwnPtr<DOMEditor::Digest> DOMEditor::createDigest(Node* node, UnusedNodesMap* unusedNodesMap) 390 { 391 Digest* digest = new Digest(node); 392 393 SHA1 sha1; 394 395 Node::NodeType nodeType = node->nodeType(); 396 sha1.addBytes(reinterpret_cast<const uint8_t*>(&nodeType), sizeof(nodeType)); 397 addStringToSHA1(sha1, node->nodeName()); 398 addStringToSHA1(sha1, node->nodeValue()); 399 400 if (node->nodeType() == Node::ELEMENT_NODE) { 401 Node* child = node->firstChild(); 402 while (child) { 403 OwnPtr<Digest> childInfo = createDigest(child, unusedNodesMap); 404 addStringToSHA1(sha1, childInfo->m_sha1); 405 child = child->nextSibling(); 406 digest->m_children.append(childInfo.release()); 407 } 408 Element* element = static_cast<Element*>(node); 409 410 if (element->hasAttributesWithoutUpdate()) { 411 size_t numAttrs = element->attributeCount(); 412 SHA1 attrsSHA1; 413 for (size_t i = 0; i < numAttrs; ++i) { 414 const Attribute* attribute = element->attributeItem(i); 415 addStringToSHA1(attrsSHA1, attribute->name().toString()); 416 addStringToSHA1(attrsSHA1, attribute->value()); 417 } 418 Vector<uint8_t, 20> attrsHash; 419 attrsSHA1.computeHash(attrsHash); 420 digest->m_attrsSHA1 = base64Encode(reinterpret_cast<const char*>(attrsHash.data()), 10); 421 addStringToSHA1(sha1, digest->m_attrsSHA1); 422 } 423 } 424 425 Vector<uint8_t, 20> hash; 426 sha1.computeHash(hash); 427 digest->m_sha1 = base64Encode(reinterpret_cast<const char*>(hash.data()), 10); 428 if (unusedNodesMap) 429 unusedNodesMap->add(digest->m_sha1, digest); 430 return adoptPtr(digest); 431 } 432 433 void DOMEditor::insertBefore(ContainerNode* parentNode, Digest* digest, Node* anchor, ExceptionCode& ec) 434 { 435 parentNode->insertBefore(digest->m_node, anchor, ec); 436 markNodeAsUsed(digest); 437 } 438 439 void DOMEditor::removeChild(Digest* oldDigest, ExceptionCode& ec) 440 { 441 RefPtr<Node> oldNode = oldDigest->m_node; 442 oldNode->parentNode()->removeChild(oldNode.get(), ec); 443 444 // Diff works within levels. In order not to lose the node identity when user 445 // prepends his HTML with "<div>" (i.e. all nodes are shifted to the next nested level), 446 // prior to dropping the original node on the floor, check whether new DOM has a digest 447 // with matching sha1. If it does, replace it with the original DOM chunk. Chances are 448 // high that it will get merged back into the original DOM during the further patching. 449 450 UnusedNodesMap::iterator it = m_unusedNodesMap.find(oldDigest->m_sha1); 451 if (it != m_unusedNodesMap.end()) { 452 Digest* newDigest = it->second; 453 Node* newNode = newDigest->m_node; 454 newNode->parentNode()->replaceChild(oldNode, newNode, ec); 455 newDigest->m_node = oldNode.get(); 456 markNodeAsUsed(newDigest); 457 return; 458 } 459 460 for (size_t i = 0; i < oldDigest->m_children.size(); ++i) 461 removeChild(oldDigest->m_children[i].get(), ec); 462 } 463 464 void DOMEditor::markNodeAsUsed(Digest* digest) 465 { 466 Deque<Digest*> queue; 467 queue.append(digest); 468 while (!queue.isEmpty()) { 469 Digest* first = queue.takeFirst(); 470 m_unusedNodesMap.remove(first->m_sha1); 471 for (size_t i = 0; i < first->m_children.size(); ++i) 472 queue.append(first->m_children[i].get()); 473 } 474 } 475 476 #ifdef DEBUG_DOM_EDITOR 477 static String nodeName(Node* node) 478 { 479 if (node->document()->isXHTMLDocument()) 480 return node->nodeName(); 481 return node->nodeName().lower(); 482 } 483 484 void DOMEditor::dumpMap(const ResultMap& map, const String& name) 485 { 486 fprintf(stderr, "\n\n"); 487 for (size_t i = 0; i < map.size(); ++i) 488 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); 489 } 490 #endif 301 bool DOMEditor::insertBefore(Node* parentNode, Node* node, Node* anchorNode, ErrorString* errorString) 302 { 303 return m_history->perform(adoptPtr(new InsertBeforeAction(parentNode, node, anchorNode)), errorString); 304 } 305 306 bool DOMEditor::removeChild(Node* parentNode, Node* node, ErrorString* errorString) 307 { 308 return m_history->perform(adoptPtr(new RemoveChildAction(parentNode, node)), errorString); 309 } 310 311 bool DOMEditor::setAttribute(Element* element, const String& name, const String& value, ErrorString* errorString) 312 { 313 return m_history->perform(adoptPtr(new SetAttributeAction(element, name, value)), errorString); 314 } 315 316 bool DOMEditor::removeAttribute(Element* element, const String& name, ErrorString* errorString) 317 { 318 return m_history->perform(adoptPtr(new RemoveAttributeAction(element, name)), errorString); 319 } 320 321 bool DOMEditor::setOuterHTML(Node* node, const String& html, Node** newNode, ErrorString* errorString) 322 { 323 OwnPtr<SetOuterHTMLAction> action = adoptPtr(new SetOuterHTMLAction(node, html)); 324 SetOuterHTMLAction* rawAction = action.get(); 325 bool result = m_history->perform(action.release(), errorString); 326 if (result) 327 *newNode = rawAction->newNode(); 328 return result; 329 } 330 331 bool DOMEditor::replaceWholeText(Text* textNode, const String& text, ErrorString* errorString) 332 { 333 return m_history->perform(adoptPtr(new ReplaceWholeTextAction(textNode, text)), errorString); 334 } 491 335 492 336 } // namespace WebCore -
trunk/Source/WebCore/inspector/DOMEditor.h
r107242 r107257 32 32 #define DOMEditor_h 33 33 34 #include "ExceptionCode.h"35 36 #include <wtf/HashMap.h>37 #include <wtf/OwnPtr.h>38 #include <wtf/PassOwnPtr.h>39 #include <wtf/Vector.h>40 34 #include <wtf/text/WTFString.h> 41 35 42 36 namespace WebCore { 43 37 44 class ContainerNode; 45 class Document; 46 class NamedNodeMap; 38 class Element; 39 class InspectorHistory; 47 40 class Node; 41 class Text; 48 42 49 43 #if ENABLE(INSPECTOR) 50 44 45 typedef String ErrorString; 46 51 47 class DOMEditor { 48 WTF_MAKE_NONCOPYABLE(DOMEditor); 52 49 public: 53 explicit DOMEditor( Document*);54 virtual~DOMEditor();50 explicit DOMEditor(InspectorHistory*); 51 ~DOMEditor(); 55 52 56 void patchDocument(const String& markup); 57 Node* patchNode(Node*, const String& markup, ExceptionCode&); 53 bool insertBefore(Node* parentNode, Node*, Node* anchorNode, ErrorString*); 54 bool removeChild(Node* parentNode, Node*, ErrorString*); 55 bool setAttribute(Element*, const String& name, const String& value, ErrorString*); 56 bool removeAttribute(Element*, const String& name, ErrorString*); 57 bool setOuterHTML(Node*, const String& html, Node** newNode, ErrorString*); 58 bool replaceWholeText(Text*, const String& text, ErrorString*); 58 59 59 60 private: 60 struct Digest; 61 typedef Vector<pair<Digest*, size_t> > ResultMap; 62 typedef HashMap<String, Digest*> UnusedNodesMap; 61 class DOMAction; 62 class RemoveChildAction; 63 class InsertBeforeAction; 64 class RemoveAttributeAction; 65 class SetAttributeAction; 66 class SetOuterHTMLAction; 67 class ReplaceWholeTextAction; 63 68 64 void innerPatchNode(Digest* oldNode, Digest* newNode, ExceptionCode&); 65 std::pair<ResultMap, ResultMap> diff(const Vector<OwnPtr<Digest> >& oldChildren, const Vector<OwnPtr<Digest> >& newChildren); 66 void innerPatchChildren(ContainerNode*, const Vector<OwnPtr<Digest> >& oldChildren, const Vector<OwnPtr<Digest> >& newChildren, ExceptionCode&); 67 PassOwnPtr<Digest> createDigest(Node*, UnusedNodesMap*); 68 void insertBefore(ContainerNode*, Digest*, Node* anchor, ExceptionCode&); 69 void removeChild(Digest*, ExceptionCode&); 70 void markNodeAsUsed(Digest*); 71 #ifdef DEBUG_DOM_EDITOR 72 void dumpMap(const ResultMap&, const String& name); 73 #endif 74 75 Document* m_document; 76 77 UnusedNodesMap m_unusedNodesMap; 69 InspectorHistory* m_history; 78 70 }; 79 71 -
trunk/Source/WebCore/inspector/DOMPatchSupport.cpp
r107256 r107257 30 30 31 31 #include "config.h" 32 #include "DOM Editor.h"32 #include "DOMPatchSupport.h" 33 33 34 34 #if ENABLE(INSPECTOR) … … 58 58 using HTMLNames::htmlTag; 59 59 60 struct DOM Editor::Digest {60 struct DOMPatchSupport::Digest { 61 61 explicit Digest(Node* node) : m_node(node) { } 62 62 … … 67 67 }; 68 68 69 DOM Editor::DOMEditor(Document* document) : m_document(document) { }70 71 DOM Editor::~DOMEditor() { }72 73 void DOM Editor::patchDocument(const String& markup)69 DOMPatchSupport::DOMPatchSupport(Document* document) : m_document(document) { } 70 71 DOMPatchSupport::~DOMPatchSupport() { } 72 73 void DOMPatchSupport::patchDocument(const String& markup) 74 74 { 75 75 RefPtr<HTMLDocument> newDocument = HTMLDocument::create(0, KURL()); … … 91 91 } 92 92 93 Node* DOM Editor::patchNode(Node* node, const String& markup, ExceptionCode& ec)93 Node* DOMPatchSupport::patchNode(Node* node, const String& markup, ExceptionCode& ec) 94 94 { 95 95 // Don't parse <html> as a fragment. … … 136 136 } 137 137 138 void DOM Editor::innerPatchNode(Digest* oldDigest, Digest* newDigest, ExceptionCode& ec)138 void DOMPatchSupport::innerPatchNode(Digest* oldDigest, Digest* newDigest, ExceptionCode& ec) 139 139 { 140 140 if (oldDigest->m_sha1 == newDigest->m_sha1) … … 181 181 } 182 182 183 pair<DOM Editor::ResultMap, DOMEditor::ResultMap>184 DOM Editor::diff(const Vector<OwnPtr<Digest> >& oldList, const Vector<OwnPtr<Digest> >& newList)183 pair<DOMPatchSupport::ResultMap, DOMPatchSupport::ResultMap> 184 DOMPatchSupport::diff(const Vector<OwnPtr<Digest> >& oldList, const Vector<OwnPtr<Digest> >& newList) 185 185 { 186 186 ResultMap newMap(newList.size()); … … 261 261 } 262 262 263 #ifdef DEBUG_DOM_ EDITOR263 #ifdef DEBUG_DOM_PATCH_SUPPORT 264 264 dumpMap(oldMap, "OLD"); 265 265 dumpMap(newMap, "NEW"); … … 269 269 } 270 270 271 void DOM Editor::innerPatchChildren(ContainerNode* parentNode, const Vector<OwnPtr<Digest> >& oldList, const Vector<OwnPtr<Digest> >& newList, ExceptionCode& ec)271 void DOMPatchSupport::innerPatchChildren(ContainerNode* parentNode, const Vector<OwnPtr<Digest> >& oldList, const Vector<OwnPtr<Digest> >& newList, ExceptionCode& ec) 272 272 { 273 273 pair<ResultMap, ResultMap> resultMaps = diff(oldList, newList); … … 387 387 } 388 388 389 PassOwnPtr<DOM Editor::Digest> DOMEditor::createDigest(Node* node, UnusedNodesMap* unusedNodesMap)389 PassOwnPtr<DOMPatchSupport::Digest> DOMPatchSupport::createDigest(Node* node, UnusedNodesMap* unusedNodesMap) 390 390 { 391 391 Digest* digest = new Digest(node); … … 431 431 } 432 432 433 void DOM Editor::insertBefore(ContainerNode* parentNode, Digest* digest, Node* anchor, ExceptionCode& ec)433 void DOMPatchSupport::insertBefore(ContainerNode* parentNode, Digest* digest, Node* anchor, ExceptionCode& ec) 434 434 { 435 435 parentNode->insertBefore(digest->m_node, anchor, ec); … … 437 437 } 438 438 439 void DOM Editor::removeChild(Digest* oldDigest, ExceptionCode& ec)439 void DOMPatchSupport::removeChild(Digest* oldDigest, ExceptionCode& ec) 440 440 { 441 441 RefPtr<Node> oldNode = oldDigest->m_node; … … 462 462 } 463 463 464 void DOM Editor::markNodeAsUsed(Digest* digest)464 void DOMPatchSupport::markNodeAsUsed(Digest* digest) 465 465 { 466 466 Deque<Digest*> queue; … … 474 474 } 475 475 476 #ifdef DEBUG_DOM_ EDITOR476 #ifdef DEBUG_DOM_PATCH_SUPPORT 477 477 static String nodeName(Node* node) 478 478 { … … 482 482 } 483 483 484 void DOM Editor::dumpMap(const ResultMap& map, const String& name)484 void DOMPatchSupport::dumpMap(const ResultMap& map, const String& name) 485 485 { 486 486 fprintf(stderr, "\n\n"); -
trunk/Source/WebCore/inspector/DOMPatchSupport.h
r107256 r107257 29 29 */ 30 30 31 #ifndef DOM Editor_h32 #define DOM Editor_h31 #ifndef DOMPatchSupport_h 32 #define DOMPatchSupport_h 33 33 34 34 #include "ExceptionCode.h" … … 49 49 #if ENABLE(INSPECTOR) 50 50 51 class DOMEditor { 51 class DOMPatchSupport { 52 WTF_MAKE_NONCOPYABLE(DOMPatchSupport); 52 53 public: 53 explicit DOM Editor(Document*);54 virtual ~DOM Editor();54 explicit DOMPatchSupport(Document*); 55 virtual ~DOMPatchSupport(); 55 56 56 57 void patchDocument(const String& markup); … … 69 70 void removeChild(Digest*, ExceptionCode&); 70 71 void markNodeAsUsed(Digest*); 71 #ifdef DEBUG_DOM_ EDITOR72 #ifdef DEBUG_DOM_PATCH_SUPPORT 72 73 void dumpMap(const ResultMap&, const String& name); 73 74 #endif … … 82 83 } // namespace WebCore 83 84 84 #endif // !defined(DOM Editor_h)85 #endif // !defined(DOMPatchSupport_h) -
trunk/Source/WebCore/inspector/InspectorDOMAgent.cpp
r107217 r107257 49 49 #include "DOMEditor.h" 50 50 #include "DOMNodeHighlighter.h" 51 #include "DOMPatchSupport.h" 51 52 #include "DOMWindow.h" 52 53 #include "Document.h" … … 67 68 #include "InspectorClient.h" 68 69 #include "InspectorFrontend.h" 70 #include "InspectorHistory.h" 69 71 #include "InspectorPageAgent.h" 70 72 #include "InspectorState.h" … … 178 180 } 179 181 180 class InspectorDOMAgent::DOMAction : public InspectorHistory::Action {181 public:182 DOMAction(const String& name) : InspectorHistory::Action(name) { }183 184 virtual bool perform(ErrorString* errorString)185 {186 ExceptionCode ec = 0;187 bool result = perform(ec);188 if (ec) {189 ExceptionCodeDescription description(ec);190 *errorString = description.name;191 }192 return result && !ec;193 }194 195 virtual bool undo(ErrorString* errorString)196 {197 ExceptionCode ec = 0;198 bool result = undo(ec);199 if (ec) {200 ExceptionCodeDescription description(ec);201 *errorString = description.name;202 }203 return result && !ec;204 }205 206 virtual bool perform(ExceptionCode&) = 0;207 208 virtual bool undo(ExceptionCode&) = 0;209 210 private:211 RefPtr<Node> m_parentNode;212 RefPtr<Node> m_node;213 RefPtr<Node> m_anchorNode;214 };215 216 class InspectorDOMAgent::RemoveChildAction : public InspectorDOMAgent::DOMAction {217 WTF_MAKE_NONCOPYABLE(RemoveChildAction);218 public:219 RemoveChildAction(Node* parentNode, Node* node)220 : InspectorDOMAgent::DOMAction("RemoveChild")221 , m_parentNode(parentNode)222 , m_node(node)223 {224 }225 226 virtual bool perform(ExceptionCode& ec)227 {228 m_anchorNode = m_node->nextSibling();229 return m_parentNode->removeChild(m_node.get(), ec);230 }231 232 virtual bool undo(ExceptionCode& ec)233 {234 return m_parentNode->insertBefore(m_node.get(), m_anchorNode.get(), ec);235 }236 237 private:238 RefPtr<Node> m_parentNode;239 RefPtr<Node> m_node;240 RefPtr<Node> m_anchorNode;241 };242 243 class InspectorDOMAgent::InsertBeforeAction : public InspectorDOMAgent::DOMAction {244 WTF_MAKE_NONCOPYABLE(InsertBeforeAction);245 public:246 InsertBeforeAction(Node* parentNode, Node* node, Node* anchorNode)247 : InspectorDOMAgent::DOMAction("InsertBefore")248 , m_parentNode(parentNode)249 , m_node(node)250 , m_anchorNode(anchorNode)251 {252 }253 254 virtual bool perform(ExceptionCode& ec)255 {256 if (m_node->parentNode()) {257 m_removeChildAction = adoptPtr(new RemoveChildAction(m_node->parentNode(), m_node.get()));258 if (!m_removeChildAction->perform(ec))259 return false;260 }261 return m_parentNode->insertBefore(m_node.get(), m_anchorNode.get(), ec);262 }263 264 virtual bool undo(ExceptionCode& ec)265 {266 if (m_removeChildAction)267 return m_removeChildAction->undo(ec);268 269 return m_parentNode->removeChild(m_node.get(), ec);270 }271 272 private:273 RefPtr<Node> m_parentNode;274 RefPtr<Node> m_node;275 RefPtr<Node> m_anchorNode;276 OwnPtr<RemoveChildAction> m_removeChildAction;277 };278 279 class InspectorDOMAgent::RemoveAttributeAction : public InspectorDOMAgent::DOMAction {280 WTF_MAKE_NONCOPYABLE(RemoveAttributeAction);281 public:282 RemoveAttributeAction(Element* element, const String& name)283 : InspectorDOMAgent::DOMAction("RemoveAttribute")284 , m_element(element)285 , m_name(name)286 {287 }288 289 virtual bool perform(ExceptionCode&)290 {291 m_value = m_element->getAttribute(m_name);292 m_element->removeAttribute(m_name);293 return true;294 }295 296 virtual bool undo(ExceptionCode& ec)297 {298 m_element->setAttribute(m_name, m_value, ec);299 return true;300 }301 302 private:303 RefPtr<Element> m_element;304 String m_name;305 String m_value;306 };307 308 class InspectorDOMAgent::SetAttributeAction : public InspectorDOMAgent::DOMAction {309 WTF_MAKE_NONCOPYABLE(SetAttributeAction);310 public:311 SetAttributeAction(Element* element, const String& name, const String& value)312 : InspectorDOMAgent::DOMAction("SetAttribute")313 , m_element(element)314 , m_name(name)315 , m_value(value)316 , m_hadAttribute(false)317 {318 }319 320 virtual bool perform(ExceptionCode& ec)321 {322 m_hadAttribute = m_element->hasAttribute(m_name);323 if (m_hadAttribute)324 m_oldValue = m_element->getAttribute(m_name);325 m_element->setAttribute(m_name, m_value, ec);326 return !ec;327 }328 329 virtual bool undo(ExceptionCode& ec)330 {331 if (m_hadAttribute)332 m_element->setAttribute(m_name, m_oldValue, ec);333 else334 m_element->removeAttribute(m_name);335 return true;336 }337 338 private:339 RefPtr<Element> m_element;340 String m_name;341 String m_value;342 bool m_hadAttribute;343 String m_oldValue;344 };345 346 class InspectorDOMAgent::SetOuterHTMLAction : public InspectorDOMAgent::DOMAction {347 WTF_MAKE_NONCOPYABLE(SetOuterHTMLAction);348 public:349 SetOuterHTMLAction(Node* node, const String& html)350 : InspectorDOMAgent::DOMAction("SetOuterHTML")351 , m_node(node)352 , m_nextSibling(node->nextSibling())353 , m_html(html)354 , m_newNode(0)355 {356 }357 358 virtual bool perform(ExceptionCode& ec)359 {360 m_oldHTML = createMarkup(m_node.get());361 DOMEditor domEditor(m_node->ownerDocument());362 m_newNode = domEditor.patchNode(m_node.get(), m_html, ec);363 return !ec;364 }365 366 virtual bool undo(ExceptionCode& ec)367 {368 DOMEditor domEditor(m_newNode->ownerDocument());369 Node* node = domEditor.patchNode(m_newNode, m_oldHTML, ec);370 if (ec || !node)371 return false;372 // HTML editing could have produced extra nodes. Remove them if necessary.373 node = node->nextSibling();374 375 while (!ec && node && node != m_nextSibling.get()) {376 Node* nodeToRemove = node;377 node = node->nextSibling();378 nodeToRemove->remove(ec);379 }380 return !ec;381 }382 383 Node* newNode()384 {385 return m_newNode;386 }387 388 private:389 RefPtr<Node> m_node;390 RefPtr<Node> m_nextSibling;391 String m_html;392 String m_oldHTML;393 Node* m_newNode;394 };395 396 class InspectorDOMAgent::ReplaceWholeTextAction : public InspectorDOMAgent::DOMAction {397 WTF_MAKE_NONCOPYABLE(ReplaceWholeTextAction);398 public:399 ReplaceWholeTextAction(Text* textNode, const String& text)400 : DOMAction("ReplaceWholeText")401 , m_textNode(textNode)402 , m_text(text)403 {404 }405 406 virtual bool perform(ExceptionCode& ec)407 {408 m_oldText = m_textNode->wholeText();409 m_textNode->replaceWholeText(m_text, ec);410 return true;411 }412 413 virtual bool undo(ExceptionCode& ec)414 {415 m_textNode->replaceWholeText(m_oldText, ec);416 return true;417 }418 419 private:420 RefPtr<Text> m_textNode;421 String m_text;422 String m_oldText;423 };424 425 182 InspectorDOMAgent::InspectorDOMAgent(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent, InspectorClient* client, InspectorState* inspectorState, InjectedScriptManager* injectedScriptManager) 426 183 : InspectorBaseAgent<InspectorDOMAgent>("DOM", instrumentingAgents, inspectorState) … … 432 189 , m_lastNodeId(1) 433 190 , m_searchingForNode(false) 434 , m_history(adoptPtr(new InspectorHistory()))435 191 { 436 192 } … … 446 202 { 447 203 ASSERT(!m_frontend); 204 m_history = adoptPtr(new InspectorHistory()); 205 m_domEditor = adoptPtr(new DOMEditor(m_history.get())); 206 448 207 m_frontend = frontend->dom(); 449 208 m_instrumentingAgents->setInspectorDOMAgent(this); … … 457 216 { 458 217 ASSERT(m_frontend); 218 219 m_history.clear(); 220 m_domEditor.clear(); 459 221 setSearchingForNode(false, 0); 460 222 … … 500 262 void InspectorDOMAgent::reset() 501 263 { 502 m_history->reset(); 264 if (m_history) 265 m_history->reset(); 503 266 m_searchResults.clear(); 504 267 discardBindings(); … … 766 529 return; 767 530 768 m_ history->perform(adoptPtr(new SetAttributeAction(element, name, value)), errorString);531 m_domEditor->setAttribute(element, name, value, errorString); 769 532 m_history->markUndoableState(); 770 533 } … … 797 560 Element* childElement = toElement(child); 798 561 if (!childElement->hasAttributes() && name) { 799 m_history->perform(adoptPtr(new RemoveAttributeAction(element, *name)), errorString); 562 m_domEditor->removeAttribute(element, *name, errorString); 563 m_history->markUndoableState(); 800 564 return; 801 565 } … … 807 571 const Attribute* attribute = childElement->attributeItem(i); 808 572 foundOriginalAttribute = foundOriginalAttribute || (name && attribute->name().toString() == *name); 809 if (!m_ history->perform(adoptPtr(new SetAttributeAction(element, attribute->name().toString(), attribute->value())), errorString))573 if (!m_domEditor->setAttribute(element, attribute->name().toString(), attribute->value(), errorString)) 810 574 return; 811 575 } 812 576 813 577 if (!foundOriginalAttribute && name && !name->stripWhiteSpace().isEmpty()) 814 m_ history->perform(adoptPtr(new RemoveAttributeAction(element, *name)), errorString);578 m_domEditor->removeAttribute(element, *name, errorString); 815 579 816 580 m_history->markUndoableState(); … … 823 587 return; 824 588 825 m_ history->perform(adoptPtr(new RemoveAttributeAction(element, name)), errorString);589 m_domEditor->removeAttribute(element, name, errorString); 826 590 m_history->markUndoableState(); 827 591 } … … 839 603 } 840 604 841 m_ history->perform(adoptPtr(new RemoveChildAction(parentNode, node)), errorString);605 m_domEditor->removeChild(parentNode, node, errorString); 842 606 m_history->markUndoableState(); 843 607 } … … 862 626 Node* child; 863 627 while ((child = oldNode->firstChild())) { 864 if (!m_ history->perform(adoptPtr(new InsertBeforeAction(newElem.get(), child, 0)), errorString))628 if (!m_domEditor->insertBefore(newElem.get(), child, 0, errorString)) 865 629 return; 866 630 } … … 868 632 // Replace the old node with the new node 869 633 ContainerNode* parent = oldNode->parentNode(); 870 if (!m_ history->perform(adoptPtr(new InsertBeforeAction(parent, newElem.get(), oldNode->nextSibling())), errorString))871 return; 872 if (!m_ history->perform(adoptPtr(new RemoveChildAction(parent, oldNode)), errorString))634 if (!m_domEditor->insertBefore(parent, newElem.get(), oldNode->nextSibling(), errorString)) 635 return; 636 if (!m_domEditor->removeChild(parent, oldNode, errorString)) 873 637 return; 874 638 m_history->markUndoableState(); … … 891 655 { 892 656 if (!nodeId) { 893 DOM Editor domEditor(m_document.get());894 dom Editor.patchDocument(outerHTML);657 DOMPatchSupport domPatchSupport(m_document.get()); 658 domPatchSupport.patchDocument(outerHTML); 895 659 return; 896 660 } … … 906 670 } 907 671 908 DOMEditor domEditor(document);909 910 OwnPtr<SetOuterHTMLAction> action = adoptPtr(new SetOuterHTMLAction(node, outerHTML));911 SetOuterHTMLAction* rawAction = action.get();912 672 Node* newNode = 0; 913 if (!m_ history->perform(action.release(), errorString))673 if (!m_domEditor->setOuterHTML(node, outerHTML, &newNode, errorString)) 914 674 return; 915 675 m_history->markUndoableState(); 916 917 newNode = rawAction->newNode();918 676 919 677 if (!newNode) { … … 940 698 } 941 699 942 m_ history->perform(adoptPtr(new ReplaceWholeTextAction(static_cast<Text*>(node), value)), errorString);700 m_domEditor->replaceWholeText(static_cast<Text*>(node), value, errorString); 943 701 } 944 702 … … 1298 1056 } 1299 1057 1300 if (!m_ history->perform(adoptPtr(new InsertBeforeAction(targetElement, node, anchorNode)), errorString))1058 if (!m_domEditor->insertBefore(targetElement, node, anchorNode, errorString)) 1301 1059 return; 1302 1060 m_history->markUndoableState(); -
trunk/Source/WebCore/inspector/InspectorDOMAgent.h
r106953 r107257 36 36 #include "InspectorBaseAgent.h" 37 37 #include "InspectorFrontend.h" 38 #include "InspectorHistory.h"39 38 #include "InspectorValues.h" 40 39 #include "Timer.h" … … 53 52 class ContainerNode; 54 53 class CharacterData; 54 class DOMEditor; 55 55 class Document; 56 56 class Element; … … 58 58 class GraphicsContext; 59 59 class InspectorClient; 60 class InspectorDOMAgent;61 60 class InspectorFrontend; 61 class InspectorHistory; 62 62 class InspectorPageAgent; 63 63 class IntRect; … … 194 194 195 195 private: 196 class DOMAction;197 class RemoveChildAction;198 class InsertBeforeAction;199 class RemoveAttributeAction;200 class SetAttributeAction;201 class SetOuterHTMLAction;202 class ReplaceWholeTextAction;203 204 196 InspectorDOMAgent(InstrumentingAgents*, InspectorPageAgent*, InspectorClient*, InspectorState*, InjectedScriptManager*); 205 197 … … 255 247 bool m_searchingForNode; 256 248 OwnPtr<InspectorHistory> m_history; 249 OwnPtr<DOMEditor> m_domEditor; 257 250 }; 258 251 -
trunk/Source/WebCore/inspector/InspectorPageAgent.cpp
r105600 r107257 43 43 #include "Cookie.h" 44 44 #include "CookieJar.h" 45 #include "DOM Editor.h"45 #include "DOMPatchSupport.h" 46 46 #include "Document.h" 47 47 #include "DocumentLoader.h" … … 572 572 return; 573 573 } 574 DOM Editor editor(document);575 editor.patchDocument(html);574 DOMPatchSupport patcher(document); 575 patcher.patchDocument(html); 576 576 } 577 577
Note: See TracChangeset
for help on using the changeset viewer.