CTTE: Thread references through markup.h
[WebKit-https.git] / Source / WebCore / inspector / DOMEditor.cpp
1 /*
2  * Copyright (C) 2012 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32
33 #if ENABLE(INSPECTOR)
34
35 #include "DOMEditor.h"
36
37 #include "DOMPatchSupport.h"
38 #include "Document.h"
39 #include "Element.h"
40 #include "ExceptionCode.h"
41 #include "InspectorHistory.h"
42 #include "Node.h"
43 #include "Text.h"
44
45 #include "markup.h"
46
47 #include <wtf/RefPtr.h>
48
49 using namespace std;
50
51 namespace WebCore {
52
53 class DOMEditor::RemoveChildAction : public InspectorHistory::Action {
54     WTF_MAKE_NONCOPYABLE(RemoveChildAction);
55 public:
56     RemoveChildAction(Node* parentNode, Node* node)
57         : InspectorHistory::Action("RemoveChild")
58         , m_parentNode(parentNode)
59         , m_node(node)
60     {
61     }
62
63     virtual bool perform(ExceptionCode& ec)
64     {
65         m_anchorNode = m_node->nextSibling();
66         return redo(ec);
67     }
68
69     virtual bool undo(ExceptionCode& ec)
70     {
71         return m_parentNode->insertBefore(m_node.get(), m_anchorNode.get(), ec);
72     }
73
74     virtual bool redo(ExceptionCode& ec)
75     {
76         return m_parentNode->removeChild(m_node.get(), ec);
77     }
78
79 private:
80     RefPtr<Node> m_parentNode;
81     RefPtr<Node> m_node;
82     RefPtr<Node> m_anchorNode;
83 };
84
85 class DOMEditor::InsertBeforeAction : public InspectorHistory::Action {
86     WTF_MAKE_NONCOPYABLE(InsertBeforeAction);
87 public:
88     InsertBeforeAction(Node* parentNode, PassRefPtr<Node> node, Node* anchorNode)
89         : InspectorHistory::Action("InsertBefore")
90         , m_parentNode(parentNode)
91         , m_node(node)
92         , m_anchorNode(anchorNode)
93     {
94     }
95
96     virtual bool perform(ExceptionCode& ec)
97     {
98         if (m_node->parentNode()) {
99             m_removeChildAction = adoptPtr(new RemoveChildAction(m_node->parentNode(), m_node.get()));
100             if (!m_removeChildAction->perform(ec))
101                 return false;
102         }
103         return m_parentNode->insertBefore(m_node.get(), m_anchorNode.get(), ec);
104     }
105
106     virtual bool undo(ExceptionCode& ec)
107     {
108         if (!m_parentNode->removeChild(m_node.get(), ec))
109             return false;
110         if (m_removeChildAction)
111             return m_removeChildAction->undo(ec);
112         return true;
113     }
114
115     virtual bool redo(ExceptionCode& ec)
116     {
117         if (m_removeChildAction && !m_removeChildAction->redo(ec))
118             return false;
119         return m_parentNode->insertBefore(m_node.get(), m_anchorNode.get(), ec);
120     }
121
122 private:
123     RefPtr<Node> m_parentNode;
124     RefPtr<Node> m_node;
125     RefPtr<Node> m_anchorNode;
126     OwnPtr<RemoveChildAction> m_removeChildAction;
127 };
128
129 class DOMEditor::RemoveAttributeAction : public InspectorHistory::Action {
130     WTF_MAKE_NONCOPYABLE(RemoveAttributeAction);
131 public:
132     RemoveAttributeAction(Element* element, const String& name)
133         : InspectorHistory::Action("RemoveAttribute")
134         , m_element(element)
135         , m_name(name)
136     {
137     }
138
139     virtual bool perform(ExceptionCode& ec)
140     {
141         m_value = m_element->getAttribute(m_name);
142         return redo(ec);
143     }
144
145     virtual bool undo(ExceptionCode& ec)
146     {
147         m_element->setAttribute(m_name, m_value, ec);
148         return true;
149     }
150
151     virtual bool redo(ExceptionCode&)
152     {
153         m_element->removeAttribute(m_name);
154         return true;
155     }
156
157 private:
158     RefPtr<Element> m_element;
159     String m_name;
160     String m_value;
161 };
162
163 class DOMEditor::SetAttributeAction : public InspectorHistory::Action {
164     WTF_MAKE_NONCOPYABLE(SetAttributeAction);
165 public:
166     SetAttributeAction(Element* element, const String& name, const String& value)
167         : InspectorHistory::Action("SetAttribute")
168         , m_element(element)
169         , m_name(name)
170         , m_value(value)
171         , m_hadAttribute(false)
172     {
173     }
174
175     virtual bool perform(ExceptionCode& ec)
176     {
177         m_hadAttribute = m_element->hasAttribute(m_name);
178         if (m_hadAttribute)
179             m_oldValue = m_element->getAttribute(m_name);
180         return redo(ec);
181     }
182
183     virtual bool undo(ExceptionCode& ec)
184     {
185         if (m_hadAttribute)
186             m_element->setAttribute(m_name, m_oldValue, ec);
187         else
188             m_element->removeAttribute(m_name);
189         return true;
190     }
191
192     virtual bool redo(ExceptionCode& ec)
193     {
194         m_element->setAttribute(m_name, m_value, ec);
195         return true;
196     }
197
198 private:
199     RefPtr<Element> m_element;
200     String m_name;
201     String m_value;
202     bool m_hadAttribute;
203     String m_oldValue;
204 };
205
206 class DOMEditor::SetOuterHTMLAction : public InspectorHistory::Action {
207     WTF_MAKE_NONCOPYABLE(SetOuterHTMLAction);
208 public:
209     SetOuterHTMLAction(Node& node, const String& html)
210         : InspectorHistory::Action("SetOuterHTML")
211         , m_node(node)
212         , m_nextSibling(node.nextSibling())
213         , m_html(html)
214         , m_newNode(0)
215         , m_history(adoptPtr(new InspectorHistory()))
216         , m_domEditor(adoptPtr(new DOMEditor(m_history.get())))
217     {
218     }
219
220     virtual bool perform(ExceptionCode& ec)
221     {
222         m_oldHTML = createMarkup(m_node.get());
223         DOMPatchSupport domPatchSupport(m_domEditor.get(), &m_node->document());
224         m_newNode = domPatchSupport.patchNode(m_node.get(), m_html, ec);
225         return !ec;
226     }
227
228     virtual bool undo(ExceptionCode& ec)
229     {
230         return m_history->undo(ec);
231     }
232
233     virtual bool redo(ExceptionCode& ec)
234     {
235         return m_history->redo(ec);
236     }
237
238     Node* newNode()
239     {
240         return m_newNode;
241     }
242
243 private:
244     Ref<Node> m_node;
245     RefPtr<Node> m_nextSibling;
246     String m_html;
247     String m_oldHTML;
248     Node* m_newNode;
249     OwnPtr<InspectorHistory> m_history;
250     OwnPtr<DOMEditor> m_domEditor;
251 };
252
253 class DOMEditor::ReplaceWholeTextAction : public InspectorHistory::Action {
254     WTF_MAKE_NONCOPYABLE(ReplaceWholeTextAction);
255 public:
256     ReplaceWholeTextAction(Text* textNode, const String& text)
257         : InspectorHistory::Action("ReplaceWholeText")
258         , m_textNode(textNode)
259         , m_text(text)
260     {
261     }
262
263     virtual bool perform(ExceptionCode& ec)
264     {
265         m_oldText = m_textNode->wholeText();
266         return redo(ec);
267     }
268
269     virtual bool undo(ExceptionCode& ec)
270     {
271         m_textNode->replaceWholeText(m_oldText, ec);
272         return true;
273     }
274
275     virtual bool redo(ExceptionCode& ec)
276     {
277         m_textNode->replaceWholeText(m_text, ec);
278         return true;
279     }
280
281 private:
282     RefPtr<Text> m_textNode;
283     String m_text;
284     String m_oldText;
285 };
286
287 class DOMEditor::ReplaceChildNodeAction : public InspectorHistory::Action {
288     WTF_MAKE_NONCOPYABLE(ReplaceChildNodeAction);
289 public:
290     ReplaceChildNodeAction(Node* parentNode, PassRefPtr<Node> newNode, Node* oldNode)
291         : InspectorHistory::Action("ReplaceChildNode")
292         , m_parentNode(parentNode)
293         , m_newNode(newNode)
294         , m_oldNode(oldNode)
295     {
296     }
297
298     virtual bool perform(ExceptionCode& ec)
299     {
300         return redo(ec);
301     }
302
303     virtual bool undo(ExceptionCode& ec)
304     {
305         return m_parentNode->replaceChild(m_oldNode, m_newNode.get(), ec);
306     }
307
308     virtual bool redo(ExceptionCode& ec)
309     {
310         return m_parentNode->replaceChild(m_newNode, m_oldNode.get(), ec);
311     }
312
313 private:
314     RefPtr<Node> m_parentNode;
315     RefPtr<Node> m_newNode;
316     RefPtr<Node> m_oldNode;
317 };
318
319 class DOMEditor::SetNodeValueAction : public InspectorHistory::Action {
320     WTF_MAKE_NONCOPYABLE(SetNodeValueAction);
321 public:
322     SetNodeValueAction(Node* node, const String& value)
323         : InspectorHistory::Action("SetNodeValue")
324         , m_node(node)
325         , m_value(value)
326     {
327     }
328
329     virtual bool perform(ExceptionCode& ec)
330     {
331         m_oldValue = m_node->nodeValue();
332         return redo(ec);
333     }
334
335     virtual bool undo(ExceptionCode& ec)
336     {
337         m_node->setNodeValue(m_oldValue, ec);
338         return !ec;
339     }
340
341     virtual bool redo(ExceptionCode& ec)
342     {
343         m_node->setNodeValue(m_value, ec);
344         return !ec;
345     }
346
347 private:
348     RefPtr<Node> m_node;
349     String m_value;
350     String m_oldValue;
351 };
352
353 DOMEditor::DOMEditor(InspectorHistory* history) : m_history(history) { }
354
355 DOMEditor::~DOMEditor() { }
356
357 bool DOMEditor::insertBefore(Node* parentNode, PassRefPtr<Node> node, Node* anchorNode, ExceptionCode& ec)
358 {
359     return m_history->perform(adoptPtr(new InsertBeforeAction(parentNode, node, anchorNode)), ec);
360 }
361
362 bool DOMEditor::removeChild(Node* parentNode, Node* node, ExceptionCode& ec)
363 {
364     return m_history->perform(adoptPtr(new RemoveChildAction(parentNode, node)), ec);
365 }
366
367 bool DOMEditor::setAttribute(Element* element, const String& name, const String& value, ExceptionCode& ec)
368 {
369     return m_history->perform(adoptPtr(new SetAttributeAction(element, name, value)), ec);
370 }
371
372 bool DOMEditor::removeAttribute(Element* element, const String& name, ExceptionCode& ec)
373 {
374     return m_history->perform(adoptPtr(new RemoveAttributeAction(element, name)), ec);
375 }
376
377 bool DOMEditor::setOuterHTML(Node& node, const String& html, Node** newNode, ExceptionCode& ec)
378 {
379     OwnPtr<SetOuterHTMLAction> action = adoptPtr(new SetOuterHTMLAction(node, html));
380     SetOuterHTMLAction* rawAction = action.get();
381     bool result = m_history->perform(action.release(), ec);
382     if (result)
383         *newNode = rawAction->newNode();
384     return result;
385 }
386
387 bool DOMEditor::replaceWholeText(Text* textNode, const String& text, ExceptionCode& ec)
388 {
389     return m_history->perform(adoptPtr(new ReplaceWholeTextAction(textNode, text)), ec);
390 }
391
392 bool DOMEditor::replaceChild(Node* parentNode, PassRefPtr<Node> newNode, Node* oldNode, ExceptionCode& ec)
393 {
394     return m_history->perform(adoptPtr(new ReplaceChildNodeAction(parentNode, newNode, oldNode)), ec);
395 }
396
397 bool DOMEditor::setNodeValue(Node* node, const String& value, ExceptionCode& ec)
398 {
399     return m_history->perform(adoptPtr(new SetNodeValueAction(node, value)), ec);
400 }
401
402 static void populateErrorString(const ExceptionCode& ec, ErrorString* errorString)
403 {
404     if (ec) {
405         ExceptionCodeDescription description(ec);
406         *errorString = description.name;
407     }
408 }
409
410 bool DOMEditor::insertBefore(Node* parentNode, PassRefPtr<Node> node, Node* anchorNode, ErrorString* errorString)
411 {
412     ExceptionCode ec = 0;
413     bool result = insertBefore(parentNode, node, anchorNode, ec);
414     populateErrorString(ec, errorString);
415     return result;
416 }
417
418 bool DOMEditor::removeChild(Node* parentNode, Node* node, ErrorString* errorString)
419 {
420     ExceptionCode ec = 0;
421     bool result = removeChild(parentNode, node, ec);
422     populateErrorString(ec, errorString);
423     return result;
424 }
425
426 bool DOMEditor::setAttribute(Element* element, const String& name, const String& value, ErrorString* errorString)
427 {
428     ExceptionCode ec = 0;
429     bool result = setAttribute(element, name, value, ec);
430     populateErrorString(ec, errorString);
431     return result;
432 }
433
434 bool DOMEditor::removeAttribute(Element* element, const String& name, ErrorString* errorString)
435 {
436     ExceptionCode ec = 0;
437     bool result = removeAttribute(element, name, ec);
438     populateErrorString(ec, errorString);
439     return result;
440 }
441
442 bool DOMEditor::setOuterHTML(Node& node, const String& html, Node** newNode, ErrorString* errorString)
443 {
444     ExceptionCode ec = 0;
445     bool result = setOuterHTML(node, html, newNode, ec);
446     populateErrorString(ec, errorString);
447     return result;
448 }
449
450 bool DOMEditor::replaceWholeText(Text* textNode, const String& text, ErrorString* errorString)
451 {
452     ExceptionCode ec = 0;
453     bool result = replaceWholeText(textNode, text, ec);
454     populateErrorString(ec, errorString);
455     return result;
456 }
457
458 } // namespace WebCore
459
460 #endif // ENABLE(INSPECTOR)