[WTF] Add makeUnique<T>, which ensures T is fast-allocated, makeUnique / makeUniqueWi...
[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 #include "DOMEditor.h"
33
34 #include "DOMException.h"
35 #include "DOMPatchSupport.h"
36 #include "Document.h"
37 #include "Element.h"
38 #include "InspectorHistory.h"
39 #include "Node.h"
40 #include "Text.h"
41 #include "markup.h"
42 #include <wtf/RefPtr.h>
43
44 namespace WebCore {
45
46 class DOMEditor::RemoveChildAction final : public InspectorHistory::Action {
47     WTF_MAKE_NONCOPYABLE(RemoveChildAction);
48 public:
49     RemoveChildAction(Node& parentNode, Node& node)
50         : InspectorHistory::Action()
51         , m_parentNode(parentNode)
52         , m_node(node)
53     {
54     }
55
56     ExceptionOr<void> perform() final
57     {
58         m_anchorNode = m_node->nextSibling();
59         return redo();
60     }
61
62     ExceptionOr<void> undo() final
63     {
64         return m_parentNode->insertBefore(m_node, m_anchorNode.get());
65     }
66
67     ExceptionOr<void> redo() final
68     {
69         return m_parentNode->removeChild(m_node);
70     }
71
72 private:
73     Ref<Node> m_parentNode;
74     Ref<Node> m_node;
75     RefPtr<Node> m_anchorNode;
76 };
77
78 class DOMEditor::InsertBeforeAction final : public InspectorHistory::Action {
79 public:
80     InsertBeforeAction(Node& parentNode, Ref<Node>&& node, Node* anchorNode)
81         : InspectorHistory::Action()
82         , m_parentNode(parentNode)
83         , m_node(WTFMove(node))
84         , m_anchorNode(anchorNode)
85     {
86     }
87
88 private:
89     ExceptionOr<void> perform() final
90     {
91         if (m_node->parentNode()) {
92             m_removeChildAction = makeUnique<RemoveChildAction>(*m_node->parentNode(), m_node);
93             auto result = m_removeChildAction->perform();
94             if (result.hasException())
95                 return result.releaseException();
96         }
97         return m_parentNode->insertBefore(m_node, m_anchorNode.get());
98     }
99
100     ExceptionOr<void> undo() final
101     {
102         auto result = m_parentNode->removeChild(m_node);
103         if (result.hasException())
104             return result.releaseException();
105         if (!m_removeChildAction)
106             return { };
107         return m_removeChildAction->undo();
108     }
109
110     ExceptionOr<void> redo() final
111     {
112         if (m_removeChildAction) {
113             auto result = m_removeChildAction->redo();
114             if (result.hasException())
115                 return result.releaseException();
116         }
117         return m_parentNode->insertBefore(m_node, m_anchorNode.get());
118     }
119
120     Ref<Node> m_parentNode;
121     Ref<Node> m_node;
122     RefPtr<Node> m_anchorNode;
123     std::unique_ptr<RemoveChildAction> m_removeChildAction;
124 };
125
126 class DOMEditor::RemoveAttributeAction final : public InspectorHistory::Action {
127     WTF_MAKE_NONCOPYABLE(RemoveAttributeAction);
128 public:
129     RemoveAttributeAction(Element& element, const String& name)
130         : InspectorHistory::Action()
131         , m_element(element)
132         , m_name(name)
133     {
134     }
135
136 private:
137     ExceptionOr<void> perform() final
138     {
139         m_value = m_element->getAttribute(m_name);
140         return redo();
141     }
142
143     ExceptionOr<void> undo() final
144     {
145         return m_element->setAttribute(m_name, m_value);
146     }
147
148     ExceptionOr<void> redo() final
149     {
150         m_element->removeAttribute(m_name);
151         return { };
152     }
153
154     Ref<Element> m_element;
155     String m_name;
156     String m_value;
157 };
158
159 class DOMEditor::SetAttributeAction final : public InspectorHistory::Action {
160     WTF_MAKE_NONCOPYABLE(SetAttributeAction);
161 public:
162     SetAttributeAction(Element& element, const AtomString& name, const AtomString& value)
163         : InspectorHistory::Action()
164         , m_element(element)
165         , m_name(name)
166         , m_value(value)
167     {
168     }
169
170 private:
171     ExceptionOr<void> perform() final
172     {
173         m_oldValue = m_element->getAttribute(m_name);
174         return redo();
175     }
176
177     ExceptionOr<void> undo() final
178     {
179         if (m_oldValue.isNull()) {
180             m_element->removeAttribute(m_name);
181             return { };
182         }
183         return m_element->setAttribute(m_name, m_oldValue);
184     }
185
186     ExceptionOr<void> redo() final
187     {
188         return m_element->setAttribute(m_name, m_value);
189     }
190
191     Ref<Element> m_element;
192     AtomString m_name;
193     AtomString m_value;
194     AtomString m_oldValue;
195 };
196
197 class DOMEditor::SetOuterHTMLAction final : public InspectorHistory::Action {
198 public:
199     SetOuterHTMLAction(Node& node, const String& html)
200         : InspectorHistory::Action()
201         , m_node(node)
202         , m_nextSibling(node.nextSibling())
203         , m_html(html)
204     {
205     }
206
207     Node* newNode() const
208     {
209         return m_newNode.get();
210     }
211
212 private:
213     ExceptionOr<void> perform() final
214     {
215         m_oldHTML = serializeFragment(m_node.get(), SerializedNodes::SubtreeIncludingNode);
216         auto result = DOMPatchSupport { m_domEditor, m_node->document() }.patchNode(m_node, m_html);
217         if (result.hasException())
218             return result.releaseException();
219         m_newNode = result.releaseReturnValue();
220         return { };
221     }
222
223     ExceptionOr<void> undo() final
224     {
225         return m_history.undo();
226     }
227
228     ExceptionOr<void> redo() final
229     {
230         return m_history.redo();
231     }
232
233     Ref<Node> m_node;
234     RefPtr<Node> m_nextSibling;
235     String m_html;
236     String m_oldHTML;
237     RefPtr<Node> m_newNode { nullptr };
238     InspectorHistory m_history;
239     DOMEditor m_domEditor { m_history };
240 };
241
242 class DOMEditor::InsertAdjacentHTMLAction final : public InspectorHistory::Action {
243     WTF_MAKE_NONCOPYABLE(InsertAdjacentHTMLAction);
244 public:
245     InsertAdjacentHTMLAction(Element& element, const String& position, const String& html)
246         : InspectorHistory::Action()
247         , m_element(element)
248         , m_position(position)
249         , m_html(html)
250     {
251     }
252
253 private:
254     ExceptionOr<void> perform() final
255     {
256         return redo();
257     }
258
259     ExceptionOr<void> undo() final
260     {
261         for (auto& addedNode : m_addedNodes)
262             addedNode->remove();
263         m_addedNodes.clear();
264         return { };
265     }
266
267     ExceptionOr<void> redo() final
268     {
269         auto result = m_element->insertAdjacentHTML(m_position, m_html, &m_addedNodes);
270         if (result.hasException())
271             return result.releaseException();
272         return { };
273     }
274
275     Ref<Element> m_element;
276     NodeVector m_addedNodes;
277     String m_position;
278     String m_html;
279 };
280
281 class DOMEditor::ReplaceWholeTextAction final : public InspectorHistory::Action {
282     WTF_MAKE_NONCOPYABLE(ReplaceWholeTextAction);
283 public:
284     ReplaceWholeTextAction(Text& textNode, const String& text)
285         : InspectorHistory::Action()
286         , m_textNode(textNode)
287         , m_text(text)
288     {
289     }
290
291 private:
292     ExceptionOr<void> perform() final
293     {
294         m_oldText = m_textNode->wholeText();
295         return redo();
296     }
297
298     ExceptionOr<void> undo() final
299     {
300         m_textNode->replaceWholeText(m_oldText);
301         return { };
302     }
303
304     ExceptionOr<void> redo() final
305     {
306         m_textNode->replaceWholeText(m_text);
307         return { };
308     }
309
310     Ref<Text> m_textNode;
311     String m_text;
312     String m_oldText;
313 };
314
315 class DOMEditor::ReplaceChildNodeAction final: public InspectorHistory::Action {
316     WTF_MAKE_NONCOPYABLE(ReplaceChildNodeAction);
317 public:
318     ReplaceChildNodeAction(Node& parentNode, Ref<Node>&& newNode, Node& oldNode)
319         : InspectorHistory::Action()
320         , m_parentNode(parentNode)
321         , m_newNode(WTFMove(newNode))
322         , m_oldNode(oldNode)
323     {
324     }
325
326 private:
327     ExceptionOr<void> perform() final
328     {
329         return redo();
330     }
331
332     ExceptionOr<void> undo() final
333     {
334         return m_parentNode->replaceChild(m_oldNode, m_newNode);
335     }
336
337     ExceptionOr<void> redo() final
338     {
339         return m_parentNode->replaceChild(m_newNode, m_oldNode);
340     }
341
342     Ref<Node> m_parentNode;
343     Ref<Node> m_newNode;
344     Ref<Node> m_oldNode;
345 };
346
347 class DOMEditor::SetNodeValueAction final : public InspectorHistory::Action {
348     WTF_MAKE_NONCOPYABLE(SetNodeValueAction);
349 public:
350     SetNodeValueAction(Node& node, const String& value)
351         : InspectorHistory::Action()
352         , m_node(node)
353         , m_value(value)
354     {
355     }
356
357 private:
358     ExceptionOr<void> perform() final
359     {
360         m_oldValue = m_node->nodeValue();
361         return redo();
362     }
363
364     ExceptionOr<void> undo() final
365     {
366         return m_node->setNodeValue(m_oldValue);
367     }
368
369     ExceptionOr<void> redo() final
370     {
371         return m_node->setNodeValue(m_value);
372     }
373
374     Ref<Node> m_node;
375     String m_value;
376     String m_oldValue;
377 };
378
379 DOMEditor::DOMEditor(InspectorHistory& history)
380     : m_history(history)
381 {
382 }
383
384 DOMEditor::~DOMEditor() = default;
385
386 ExceptionOr<void> DOMEditor::insertBefore(Node& parentNode, Ref<Node>&& node, Node* anchorNode)
387 {
388     return m_history.perform(makeUnique<InsertBeforeAction>(parentNode, WTFMove(node), anchorNode));
389 }
390
391 ExceptionOr<void> DOMEditor::removeChild(Node& parentNode, Node& node)
392 {
393     return m_history.perform(makeUnique<RemoveChildAction>(parentNode, node));
394 }
395
396 ExceptionOr<void> DOMEditor::setAttribute(Element& element, const String& name, const String& value)
397 {
398     return m_history.perform(makeUnique<SetAttributeAction>(element, name, value));
399 }
400
401 ExceptionOr<void> DOMEditor::removeAttribute(Element& element, const String& name)
402 {
403     return m_history.perform(makeUnique<RemoveAttributeAction>(element, name));
404 }
405
406 ExceptionOr<void> DOMEditor::setOuterHTML(Node& node, const String& html, Node*& newNode)
407 {
408     auto action = makeUnique<SetOuterHTMLAction>(node, html);
409     auto& rawAction = *action;
410     auto result = m_history.perform(WTFMove(action));
411     if (!result.hasException())
412         newNode = rawAction.newNode();
413     return result;
414 }
415
416 ExceptionOr<void> DOMEditor::insertAdjacentHTML(Element& element, const String& where, const String& html)
417 {
418     return m_history.perform(makeUnique<InsertAdjacentHTMLAction>(element, where, html));
419 }
420
421 ExceptionOr<void> DOMEditor::replaceWholeText(Text& textNode, const String& text)
422 {
423     return m_history.perform(makeUnique<ReplaceWholeTextAction>(textNode, text));
424 }
425
426 ExceptionOr<void> DOMEditor::replaceChild(Node& parentNode, Ref<Node>&& newNode, Node& oldNode)
427 {
428     return m_history.perform(makeUnique<ReplaceChildNodeAction>(parentNode, WTFMove(newNode), oldNode));
429 }
430
431 ExceptionOr<void> DOMEditor::setNodeValue(Node& node, const String& value)
432 {
433     return m_history.perform(makeUnique<SetNodeValueAction>(node, value));
434 }
435
436 static bool populateErrorString(ExceptionOr<void>&& result, ErrorString& errorString)
437 {
438     if (!result.hasException())
439         return true;
440     errorString = DOMException::name(result.releaseException().code());
441     return false;
442 }
443
444 bool DOMEditor::insertBefore(Node& parentNode, Ref<Node>&& node, Node* anchorNode, ErrorString& errorString)
445 {
446     return populateErrorString(insertBefore(parentNode, WTFMove(node), anchorNode), errorString);
447 }
448
449 bool DOMEditor::removeChild(Node& parentNode, Node& node, ErrorString& errorString)
450 {
451     return populateErrorString(removeChild(parentNode, node), errorString);
452 }
453
454 bool DOMEditor::setAttribute(Element& element, const String& name, const String& value, ErrorString& errorString)
455 {
456     return populateErrorString(setAttribute(element, name, value), errorString);
457 }
458
459 bool DOMEditor::removeAttribute(Element& element, const String& name, ErrorString& errorString)
460 {
461     return populateErrorString(removeAttribute(element, name), errorString);
462 }
463
464 bool DOMEditor::setOuterHTML(Node& node, const String& html, Node*& newNode, ErrorString& errorString)
465 {
466     return populateErrorString(setOuterHTML(node, html, newNode), errorString);
467 }
468
469 bool DOMEditor::insertAdjacentHTML(Element& element, const String& where, const String& html, ErrorString& errorString)
470 {
471     return populateErrorString(insertAdjacentHTML(element, where, html), errorString);
472 }
473
474 bool DOMEditor::replaceWholeText(Text& textNode, const String& text, ErrorString& errorString)
475 {
476     return populateErrorString(replaceWholeText(textNode, text), errorString);
477 }
478
479 } // namespace WebCore