Node.appendChild(null) / replaceChild(null, null) / removeChild(null) / insertBefore...
[WebKit-https.git] / Source / WebCore / dom / ContainerNode.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2001 Dirk Mueller (mueller@kde.org)
5  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #include "config.h"
24 #include "ContainerNode.h"
25
26 #include "AXObjectCache.h"
27 #include "ChildListMutationScope.h"
28 #include "Chrome.h"
29 #include "ChromeClient.h"
30 #include "ClassCollection.h"
31 #include "ContainerNodeAlgorithms.h"
32 #include "Editor.h"
33 #include "FloatRect.h"
34 #include "FrameView.h"
35 #include "GenericCachedHTMLCollection.h"
36 #include "HTMLFormControlsCollection.h"
37 #include "HTMLOptionsCollection.h"
38 #include "HTMLTableRowsCollection.h"
39 #include "InlineTextBox.h"
40 #include "InsertionPoint.h"
41 #include "JSLazyEventListener.h"
42 #include "JSNode.h"
43 #include "LabelsNodeList.h"
44 #include "MutationEvent.h"
45 #include "NameNodeList.h"
46 #include "NodeOrString.h"
47 #include "NodeRareData.h"
48 #include "NodeRenderStyle.h"
49 #include "RadioNodeList.h"
50 #include "RenderBox.h"
51 #include "RenderTheme.h"
52 #include "RenderWidget.h"
53 #include "ResourceLoadScheduler.h"
54 #include "RootInlineBox.h"
55 #include "SVGDocumentExtensions.h"
56 #include "SVGElement.h"
57 #include "SVGNames.h"
58 #include "SelectorQuery.h"
59 #include "TemplateContentDocumentFragment.h"
60 #include <algorithm>
61 #include <wtf/CurrentTime.h>
62
63 namespace WebCore {
64
65 static void dispatchChildInsertionEvents(Node&);
66 static void dispatchChildRemovalEvents(Node&);
67
68 ChildNodesLazySnapshot* ChildNodesLazySnapshot::latestSnapshot = 0;
69
70 #ifndef NDEBUG
71 unsigned NoEventDispatchAssertion::s_count = 0;
72 #endif
73
74 static void collectChildrenAndRemoveFromOldParent(Node& node, NodeVector& nodes, ExceptionCode& ec)
75 {
76     if (!is<DocumentFragment>(node)) {
77         nodes.append(node);
78         if (ContainerNode* oldParent = node.parentNode())
79             oldParent->removeChild(node, ec);
80         return;
81     }
82
83     getChildNodes(node, nodes);
84     downcast<DocumentFragment>(node).removeChildren();
85 }
86
87 // FIXME: This function must get a new name.
88 // It removes all children, not just a category called "detached children".
89 // So this name is terribly confusing.
90 void ContainerNode::removeDetachedChildren()
91 {
92     if (connectedSubframeCount()) {
93         for (Node* child = firstChild(); child; child = child->nextSibling())
94             child->updateAncestorConnectedSubframeCountForRemoval();
95     }
96     // FIXME: We should be able to ASSERT(!attached()) here: https://bugs.webkit.org/show_bug.cgi?id=107801
97     removeDetachedChildrenInContainer<Node, ContainerNode>(*this);
98 }
99
100 static inline void destroyRenderTreeIfNeeded(Node& child)
101 {
102     // FIXME: Get rid of the named flow test.
103     if (!child.renderer() && !child.isNamedFlowContentNode())
104         return;
105     if (is<Element>(child))
106         Style::detachRenderTree(downcast<Element>(child));
107     else if (is<Text>(child))
108         Style::detachTextRenderer(downcast<Text>(child));
109 }
110
111 void ContainerNode::takeAllChildrenFrom(ContainerNode* oldParent)
112 {
113     ASSERT(oldParent);
114
115     NodeVector children;
116     getChildNodes(*oldParent, children);
117
118     if (oldParent->document().hasMutationObserversOfType(MutationObserver::ChildList)) {
119         ChildListMutationScope mutation(*oldParent);
120         for (auto& child : children)
121             mutation.willRemoveChild(child);
122     }
123
124     // FIXME: We need to do notifyMutationObserversNodeWillDetach() for each child,
125     // probably inside removeDetachedChildrenInContainer.
126
127     oldParent->removeDetachedChildren();
128
129     for (auto& child : children) {
130         destroyRenderTreeIfNeeded(child);
131
132         // FIXME: We need a no mutation event version of adoptNode.
133         RefPtr<Node> adoptedChild = document().adoptNode(&child.get(), ASSERT_NO_EXCEPTION);
134         parserAppendChild(adoptedChild.get());
135         // FIXME: Together with adoptNode above, the tree scope might get updated recursively twice
136         // (if the document changed or oldParent was in a shadow tree, AND *this is in a shadow tree).
137         // Can we do better?
138         treeScope().adoptIfNeeded(adoptedChild.get());
139     }
140 }
141
142 ContainerNode::~ContainerNode()
143 {
144     if (!isDocumentNode())
145         willBeDeletedFrom(document());
146     removeDetachedChildren();
147 }
148
149 static inline bool isChildTypeAllowed(ContainerNode& newParent, Node& child)
150 {
151     if (!child.isDocumentFragment())
152         return newParent.childTypeAllowed(child.nodeType());
153
154     for (Node* node = child.firstChild(); node; node = node->nextSibling()) {
155         if (!newParent.childTypeAllowed(node->nodeType()))
156             return false;
157     }
158     return true;
159 }
160
161 static inline bool isInTemplateContent(const Node* node)
162 {
163 #if ENABLE(TEMPLATE_ELEMENT)
164     Document& document = node->document();
165     return &document == document.templateDocument();
166 #else
167     UNUSED_PARAM(node);
168     return false;
169 #endif
170 }
171
172 static inline bool containsConsideringHostElements(const Node& newChild, const Node& newParent)
173 {
174     return (newParent.isInShadowTree() || isInTemplateContent(&newParent))
175         ? newChild.containsIncludingHostElements(&newParent)
176         : newChild.contains(&newParent);
177 }
178
179 static inline ExceptionCode checkAcceptChild(ContainerNode& newParent, Node& newChild, Node* oldChild)
180 {
181     // Use common case fast path if possible.
182     if ((newChild.isElementNode() || newChild.isTextNode()) && newParent.isElementNode()) {
183         ASSERT(!newParent.isReadOnlyNode());
184         ASSERT(!newParent.isDocumentTypeNode());
185         ASSERT(isChildTypeAllowed(newParent, newChild));
186         if (containsConsideringHostElements(newChild, newParent))
187             return HIERARCHY_REQUEST_ERR;
188         return 0;
189     }
190
191     // This should never happen, but also protect release builds from tree corruption.
192     ASSERT(!newChild.isPseudoElement());
193     if (newChild.isPseudoElement())
194         return HIERARCHY_REQUEST_ERR;
195
196     if (newParent.isReadOnlyNode())
197         return NO_MODIFICATION_ALLOWED_ERR;
198     if (containsConsideringHostElements(newChild, newParent))
199         return HIERARCHY_REQUEST_ERR;
200
201     if (oldChild && is<Document>(newParent)) {
202         if (!downcast<Document>(newParent).canReplaceChild(newChild, *oldChild))
203             return HIERARCHY_REQUEST_ERR;
204     } else if (!isChildTypeAllowed(newParent, newChild))
205         return HIERARCHY_REQUEST_ERR;
206
207     return 0;
208 }
209
210 static inline bool checkAcceptChildGuaranteedNodeTypes(ContainerNode& newParent, Node& newChild, ExceptionCode& ec)
211 {
212     ASSERT(!newParent.isReadOnlyNode());
213     ASSERT(!newParent.isDocumentTypeNode());
214     ASSERT(isChildTypeAllowed(newParent, newChild));
215     if (newChild.contains(&newParent)) {
216         ec = HIERARCHY_REQUEST_ERR;
217         return false;
218     }
219
220     return true;
221 }
222
223 static inline bool checkAddChild(ContainerNode& newParent, Node& newChild, ExceptionCode& ec)
224 {
225     ec = checkAcceptChild(newParent, newChild, nullptr);
226     return !ec;
227 }
228
229 static inline bool checkReplaceChild(ContainerNode& newParent, Node& newChild, Node& oldChild, ExceptionCode& ec)
230 {
231     ec = checkAcceptChild(newParent, newChild, &oldChild);
232     return !ec;
233 }
234
235 bool ContainerNode::insertBefore(Ref<Node>&& newChild, Node* refChild, ExceptionCode& ec)
236 {
237     // Check that this node is not "floating".
238     // If it is, it can be deleted as a side effect of sending mutation events.
239     ASSERT(refCount() || parentOrShadowHostNode());
240
241     Ref<ContainerNode> protect(*this);
242
243     ec = 0;
244
245     // insertBefore(node, 0) is equivalent to appendChild(node)
246     if (!refChild)
247         return appendChild(WTF::move(newChild), ec);
248
249     // Make sure adding the new child is OK.
250     if (!checkAddChild(*this, newChild, ec))
251         return false;
252
253     // NOT_FOUND_ERR: Raised if refChild is not a child of this node
254     if (refChild->parentNode() != this) {
255         ec = NOT_FOUND_ERR;
256         return false;
257     }
258
259     if (refChild->previousSibling() == newChild.ptr() || refChild == newChild.ptr()) // nothing to do
260         return true;
261
262     Ref<Node> next(*refChild);
263
264     NodeVector targets;
265     collectChildrenAndRemoveFromOldParent(newChild, targets, ec);
266     if (ec)
267         return false;
268     if (targets.isEmpty())
269         return true;
270
271     // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events.
272     if (!checkAcceptChildGuaranteedNodeTypes(*this, newChild, ec))
273         return false;
274
275     InspectorInstrumentation::willInsertDOMNode(document(), *this);
276
277     ChildListMutationScope mutation(*this);
278     for (auto it = targets.begin(), end = targets.end(); it != end; ++it) {
279         Node& child = it->get();
280
281         // Due to arbitrary code running in response to a DOM mutation event it's
282         // possible that "next" is no longer a child of "this".
283         // It's also possible that "child" has been inserted elsewhere.
284         // In either of those cases, we'll just stop.
285         if (next->parentNode() != this)
286             break;
287         if (child.parentNode())
288             break;
289
290         treeScope().adoptIfNeeded(&child);
291
292         insertBeforeCommon(next, child);
293
294         updateTreeAfterInsertion(child);
295     }
296
297     dispatchSubtreeModifiedEvent();
298     return true;
299 }
300
301 void ContainerNode::insertBeforeCommon(Node& nextChild, Node& newChild)
302 {
303     NoEventDispatchAssertion assertNoEventDispatch;
304
305     ASSERT(!newChild.parentNode()); // Use insertBefore if you need to handle reparenting (and want DOM mutation events).
306     ASSERT(!newChild.nextSibling());
307     ASSERT(!newChild.previousSibling());
308     ASSERT(!newChild.isShadowRoot());
309
310     Node* prev = nextChild.previousSibling();
311     ASSERT(m_lastChild != prev);
312     nextChild.setPreviousSibling(&newChild);
313     if (prev) {
314         ASSERT(m_firstChild != &nextChild);
315         ASSERT(prev->nextSibling() == &nextChild);
316         prev->setNextSibling(&newChild);
317     } else {
318         ASSERT(m_firstChild == &nextChild);
319         m_firstChild = &newChild;
320     }
321     newChild.setParentNode(this);
322     newChild.setPreviousSibling(prev);
323     newChild.setNextSibling(&nextChild);
324 }
325
326 void ContainerNode::notifyChildInserted(Node& child, ChildChangeSource source)
327 {
328     ChildListMutationScope(*this).childAdded(child);
329
330     NodeVector postInsertionNotificationTargets;
331     ChildNodeInsertionNotifier(*this).notify(child, postInsertionNotificationTargets);
332
333     ChildChange change;
334     change.type = child.isElementNode() ? ElementInserted : child.isTextNode() ? TextInserted : NonContentsChildChanged;
335     change.previousSiblingElement = ElementTraversal::previousSibling(child);
336     change.nextSiblingElement = ElementTraversal::nextSibling(child);
337     change.source = source;
338
339     childrenChanged(change);
340
341     for (auto& target : postInsertionNotificationTargets)
342         target->finishedInsertingSubtree();
343 }
344
345 void ContainerNode::notifyChildRemoved(Node& child, Node* previousSibling, Node* nextSibling, ChildChangeSource source)
346 {
347     ChildNodeRemovalNotifier(*this).notify(child);
348
349     ChildChange change;
350     change.type = is<Element>(child) ? ElementRemoved : is<Text>(child) ? TextRemoved : NonContentsChildChanged;
351     change.previousSiblingElement = (!previousSibling || is<Element>(*previousSibling)) ? downcast<Element>(previousSibling) : ElementTraversal::previousSibling(*previousSibling);
352     change.nextSiblingElement = (!nextSibling || is<Element>(*nextSibling)) ? downcast<Element>(nextSibling) : ElementTraversal::nextSibling(*nextSibling);
353     change.source = source;
354
355     childrenChanged(change);
356 }
357
358 void ContainerNode::parserInsertBefore(PassRefPtr<Node> newChild, Node* nextChild)
359 {
360     ASSERT(newChild);
361     ASSERT(nextChild);
362     ASSERT(nextChild->parentNode() == this);
363     ASSERT(!newChild->isDocumentFragment());
364 #if ENABLE(TEMPLATE_ELEMENT)
365     ASSERT(!hasTagName(HTMLNames::templateTag));
366 #endif
367
368     if (nextChild->previousSibling() == newChild || nextChild == newChild) // nothing to do
369         return;
370
371     if (&document() != &newChild->document())
372         document().adoptNode(newChild.get(), ASSERT_NO_EXCEPTION);
373
374     insertBeforeCommon(*nextChild, *newChild.get());
375
376     newChild->updateAncestorConnectedSubframeCountForInsertion();
377
378     notifyChildInserted(*newChild, ChildChangeSourceParser);
379
380     newChild->setNeedsStyleRecalc(ReconstructRenderTree);
381 }
382
383 bool ContainerNode::replaceChild(Ref<Node>&& newChild, Node& oldChild, ExceptionCode& ec)
384 {
385     // Check that this node is not "floating".
386     // If it is, it can be deleted as a side effect of sending mutation events.
387     ASSERT(refCount() || parentOrShadowHostNode());
388
389     Ref<ContainerNode> protect(*this);
390
391     ec = 0;
392
393     if (&oldChild == newChild.ptr()) // nothing to do
394         return true;
395
396     // Make sure replacing the old child with the new is ok
397     if (!checkReplaceChild(*this, newChild, oldChild, ec))
398         return false;
399
400     // NOT_FOUND_ERR: Raised if oldChild is not a child of this node.
401     if (oldChild.parentNode() != this) {
402         ec = NOT_FOUND_ERR;
403         return false;
404     }
405
406     ChildListMutationScope mutation(*this);
407
408     RefPtr<Node> next = oldChild.nextSibling();
409
410     // Remove the node we're replacing
411     Ref<Node> removedChild(oldChild);
412     removeChild(oldChild, ec);
413     if (ec)
414         return false;
415
416     if (next && (next->previousSibling() == newChild.ptr() || next == newChild.ptr())) // nothing to do
417         return true;
418
419     // Does this one more time because removeChild() fires a MutationEvent.
420     if (!checkReplaceChild(*this, newChild, oldChild, ec))
421         return false;
422
423     NodeVector targets;
424     collectChildrenAndRemoveFromOldParent(newChild, targets, ec);
425     if (ec)
426         return false;
427
428     // Does this yet another check because collectChildrenAndRemoveFromOldParent() fires a MutationEvent.
429     if (!checkReplaceChild(*this, newChild, oldChild, ec))
430         return false;
431
432     InspectorInstrumentation::willInsertDOMNode(document(), *this);
433
434     // Add the new child(ren)
435     for (auto& child : targets) {
436         // Due to arbitrary code running in response to a DOM mutation event it's
437         // possible that "next" is no longer a child of "this".
438         // It's also possible that "child" has been inserted elsewhere.
439         // In either of those cases, we'll just stop.
440         if (next && next->parentNode() != this)
441             break;
442         if (child->parentNode())
443             break;
444
445         treeScope().adoptIfNeeded(child.ptr());
446
447         // Add child before "next".
448         {
449             NoEventDispatchAssertion assertNoEventDispatch;
450             if (next)
451                 insertBeforeCommon(*next, child.get());
452             else
453                 appendChildToContainer(child.ptr(), *this);
454         }
455
456         updateTreeAfterInsertion(child.get());
457     }
458
459     dispatchSubtreeModifiedEvent();
460     return true;
461 }
462
463 void ContainerNode::willRemoveChild(Node& child)
464 {
465     ASSERT(child.parentNode());
466
467     ChildListMutationScope(*child.parentNode()).willRemoveChild(child);
468     child.notifyMutationObserversNodeWillDetach();
469     dispatchChildRemovalEvents(child);
470
471     if (child.parentNode() != this)
472         return;
473
474     child.document().nodeWillBeRemoved(child); // e.g. mutation event listener can create a new range.
475     if (is<ContainerNode>(child))
476         disconnectSubframesIfNeeded(downcast<ContainerNode>(child), RootAndDescendants);
477 }
478
479 static void willRemoveChildren(ContainerNode& container)
480 {
481     NodeVector children;
482     getChildNodes(container, children);
483
484     ChildListMutationScope mutation(container);
485     for (auto& child : children) {
486         mutation.willRemoveChild(child.get());
487         child->notifyMutationObserversNodeWillDetach();
488
489         // fire removed from document mutation events.
490         dispatchChildRemovalEvents(child.get());
491     }
492
493     container.document().nodeChildrenWillBeRemoved(container);
494
495     disconnectSubframesIfNeeded(container, DescendantsOnly);
496 }
497
498 void ContainerNode::disconnectDescendantFrames()
499 {
500     disconnectSubframesIfNeeded(*this, RootAndDescendants);
501 }
502
503 bool ContainerNode::removeChild(Node& oldChild, ExceptionCode& ec)
504 {
505     // Check that this node is not "floating".
506     // If it is, it can be deleted as a side effect of sending mutation events.
507     ASSERT(refCount() || parentOrShadowHostNode());
508
509     Ref<ContainerNode> protect(*this);
510
511     ec = 0;
512
513     // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
514     if (isReadOnlyNode()) {
515         ec = NO_MODIFICATION_ALLOWED_ERR;
516         return false;
517     }
518
519     // NOT_FOUND_ERR: Raised if oldChild is not a child of this node.
520     if (oldChild.parentNode() != this) {
521         ec = NOT_FOUND_ERR;
522         return false;
523     }
524
525     Ref<Node> child(oldChild);
526
527     document().removeFocusedNodeOfSubtree(child.ptr());
528
529 #if ENABLE(FULLSCREEN_API)
530     document().removeFullScreenElementOfSubtree(&child.get());
531 #endif
532
533     // Events fired when blurring currently focused node might have moved this
534     // child into a different parent.
535     if (child->parentNode() != this) {
536         ec = NOT_FOUND_ERR;
537         return false;
538     }
539
540     willRemoveChild(child);
541
542     // Mutation events might have moved this child into a different parent.
543     if (child->parentNode() != this) {
544         ec = NOT_FOUND_ERR;
545         return false;
546     }
547
548     {
549         WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
550
551         Node* prev = child->previousSibling();
552         Node* next = child->nextSibling();
553         removeBetween(prev, next, child);
554
555         notifyChildRemoved(child, prev, next, ChildChangeSourceAPI);
556     }
557
558
559     if (document().svgExtensions()) {
560         Element* shadowHost = this->shadowHost();
561         if (!shadowHost || !shadowHost->hasTagName(SVGNames::useTag))
562             document().accessSVGExtensions().rebuildElements();
563     }
564
565     dispatchSubtreeModifiedEvent();
566
567     return true;
568 }
569
570 void ContainerNode::removeBetween(Node* previousChild, Node* nextChild, Node& oldChild)
571 {
572     InspectorInstrumentation::didRemoveDOMNode(oldChild.document(), oldChild);
573
574     NoEventDispatchAssertion assertNoEventDispatch;
575
576     ASSERT(oldChild.parentNode() == this);
577
578     destroyRenderTreeIfNeeded(oldChild);
579
580     if (nextChild)
581         nextChild->setPreviousSibling(previousChild);
582     if (previousChild)
583         previousChild->setNextSibling(nextChild);
584     if (m_firstChild == &oldChild)
585         m_firstChild = nextChild;
586     if (m_lastChild == &oldChild)
587         m_lastChild = previousChild;
588
589     oldChild.setPreviousSibling(0);
590     oldChild.setNextSibling(0);
591     oldChild.setParentNode(0);
592
593     document().adoptIfNeeded(&oldChild);
594 }
595
596 void ContainerNode::parserRemoveChild(Node& oldChild)
597 {
598     ASSERT(oldChild.parentNode() == this);
599     ASSERT(!oldChild.isDocumentFragment());
600
601     Node* prev = oldChild.previousSibling();
602     Node* next = oldChild.nextSibling();
603
604     oldChild.updateAncestorConnectedSubframeCountForRemoval();
605
606     ChildListMutationScope(*this).willRemoveChild(oldChild);
607     oldChild.notifyMutationObserversNodeWillDetach();
608
609     removeBetween(prev, next, oldChild);
610
611     notifyChildRemoved(oldChild, prev, next, ChildChangeSourceParser);
612 }
613
614 // this differs from other remove functions because it forcibly removes all the children,
615 // regardless of read-only status or event exceptions, e.g.
616 void ContainerNode::removeChildren()
617 {
618     if (!m_firstChild)
619         return;
620
621     // The container node can be removed from event handlers.
622     Ref<ContainerNode> protect(*this);
623
624     // exclude this node when looking for removed focusedNode since only children will be removed
625     document().removeFocusedNodeOfSubtree(this, true);
626
627 #if ENABLE(FULLSCREEN_API)
628     document().removeFullScreenElementOfSubtree(this, true);
629 #endif
630
631     // Do any prep work needed before actually starting to detach
632     // and remove... e.g. stop loading frames, fire unload events.
633     willRemoveChildren(*this);
634
635     {
636         WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
637         {
638             NoEventDispatchAssertion assertNoEventDispatch;
639             while (RefPtr<Node> n = m_firstChild) {
640                 removeBetween(0, m_firstChild->nextSibling(), *m_firstChild);
641                 ChildNodeRemovalNotifier(*this).notify(*n);
642             }
643         }
644
645         ChildChange change = { AllChildrenRemoved, nullptr, nullptr, ChildChangeSourceAPI };
646         childrenChanged(change);
647     }
648
649     if (document().svgExtensions()) {
650         Element* shadowHost = this->shadowHost();
651         if (!shadowHost || !shadowHost->hasTagName(SVGNames::useTag))
652             document().accessSVGExtensions().rebuildElements();
653     }
654
655     dispatchSubtreeModifiedEvent();
656 }
657
658 bool ContainerNode::appendChild(Ref<Node>&& newChild, ExceptionCode& ec)
659 {
660     Ref<ContainerNode> protect(*this);
661
662     // Check that this node is not "floating".
663     // If it is, it can be deleted as a side effect of sending mutation events.
664     ASSERT(refCount() || parentOrShadowHostNode());
665
666     ec = 0;
667
668     // Make sure adding the new child is ok
669     if (!checkAddChild(*this, newChild, ec))
670         return false;
671
672     if (newChild.ptr() == m_lastChild) // nothing to do
673         return true;
674
675     NodeVector targets;
676     collectChildrenAndRemoveFromOldParent(newChild, targets, ec);
677     if (ec)
678         return false;
679
680     if (targets.isEmpty())
681         return true;
682
683     // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events.
684     if (!checkAcceptChildGuaranteedNodeTypes(*this, newChild, ec))
685         return false;
686
687     InspectorInstrumentation::willInsertDOMNode(document(), *this);
688
689     // Now actually add the child(ren)
690     ChildListMutationScope mutation(*this);
691     for (auto& child : targets) {
692         // If the child has a parent again, just stop what we're doing, because
693         // that means someone is doing something with DOM mutation -- can't re-parent
694         // a child that already has a parent.
695         if (child->parentNode())
696             break;
697
698         treeScope().adoptIfNeeded(child.ptr());
699
700         // Append child to the end of the list
701         {
702             NoEventDispatchAssertion assertNoEventDispatch;
703             appendChildToContainer(child.ptr(), *this);
704         }
705
706         updateTreeAfterInsertion(child.get());
707     }
708
709     dispatchSubtreeModifiedEvent();
710     return true;
711 }
712
713 void ContainerNode::parserAppendChild(PassRefPtr<Node> newChild)
714 {
715     ASSERT(newChild);
716     ASSERT(!newChild->parentNode()); // Use appendChild if you need to handle reparenting (and want DOM mutation events).
717     ASSERT(!newChild->isDocumentFragment());
718 #if ENABLE(TEMPLATE_ELEMENT)
719     ASSERT(!hasTagName(HTMLNames::templateTag));
720 #endif
721
722     if (&document() != &newChild->document())
723         document().adoptNode(newChild.get(), ASSERT_NO_EXCEPTION);
724
725     {
726         NoEventDispatchAssertion assertNoEventDispatch;
727         // FIXME: This method should take a PassRefPtr.
728         appendChildToContainer(newChild.get(), *this);
729         treeScope().adoptIfNeeded(newChild.get());
730     }
731
732     newChild->updateAncestorConnectedSubframeCountForInsertion();
733
734     notifyChildInserted(*newChild, ChildChangeSourceParser);
735
736     newChild->setNeedsStyleRecalc(ReconstructRenderTree);
737 }
738
739 void ContainerNode::childrenChanged(const ChildChange& change)
740 {
741     document().incDOMTreeVersion();
742     if (change.source == ChildChangeSourceAPI && change.type != TextChanged)
743         document().updateRangesAfterChildrenChanged(*this);
744     invalidateNodeListAndCollectionCachesInAncestors();
745 }
746
747 void ContainerNode::cloneChildNodes(ContainerNode& clone)
748 {
749     ExceptionCode ec = 0;
750     Document& targetDocument = clone.document();
751     for (Node* child = firstChild(); child && !ec; child = child->nextSibling()) {
752         Ref<Node> clonedChild = child->cloneNodeInternal(targetDocument, CloningOperation::SelfWithTemplateContent);
753         clone.appendChild(clonedChild.copyRef(), ec);
754
755         if (!ec && is<ContainerNode>(*child))
756             downcast<ContainerNode>(*child).cloneChildNodes(downcast<ContainerNode>(clonedChild.get()));
757     }
758 }
759
760 unsigned ContainerNode::countChildNodes() const
761 {
762     unsigned count = 0;
763     for (Node* child = firstChild(); child; child = child->nextSibling())
764         ++count;
765     return count;
766 }
767
768 Node* ContainerNode::traverseToChildAt(unsigned index) const
769 {
770     Node* child = firstChild();
771     for (; child && index > 0; --index)
772         child = child->nextSibling();
773     return child;
774 }
775
776 static void dispatchChildInsertionEvents(Node& child)
777 {
778     if (child.isInShadowTree())
779         return;
780
781     ASSERT_WITH_SECURITY_IMPLICATION(!NoEventDispatchAssertion::isEventDispatchForbidden());
782
783     RefPtr<Node> c = &child;
784     Ref<Document> document(child.document());
785
786     if (c->parentNode() && document->hasListenerType(Document::DOMNODEINSERTED_LISTENER))
787         c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeInsertedEvent, true, c->parentNode()));
788
789     // dispatch the DOMNodeInsertedIntoDocument event to all descendants
790     if (c->inDocument() && document->hasListenerType(Document::DOMNODEINSERTEDINTODOCUMENT_LISTENER)) {
791         for (; c; c = NodeTraversal::next(*c, &child))
792             c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeInsertedIntoDocumentEvent, false));
793     }
794 }
795
796 static void dispatchChildRemovalEvents(Node& child)
797 {
798     if (child.isInShadowTree()) {
799         InspectorInstrumentation::willRemoveDOMNode(child.document(), child);
800         return;
801     }
802
803     ASSERT_WITH_SECURITY_IMPLICATION(!NoEventDispatchAssertion::isEventDispatchForbidden());
804
805     willCreatePossiblyOrphanedTreeByRemoval(&child);
806     InspectorInstrumentation::willRemoveDOMNode(child.document(), child);
807
808     RefPtr<Node> c = &child;
809     Ref<Document> document(child.document());
810
811     // dispatch pre-removal mutation events
812     if (c->parentNode() && document->hasListenerType(Document::DOMNODEREMOVED_LISTENER))
813         c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeRemovedEvent, true, c->parentNode()));
814
815     // dispatch the DOMNodeRemovedFromDocument event to all descendants
816     if (c->inDocument() && document->hasListenerType(Document::DOMNODEREMOVEDFROMDOCUMENT_LISTENER)) {
817         for (; c; c = NodeTraversal::next(*c, &child))
818             c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeRemovedFromDocumentEvent, false));
819     }
820 }
821
822 void ContainerNode::updateTreeAfterInsertion(Node& child)
823 {
824     ASSERT(child.refCount());
825
826     notifyChildInserted(child, ChildChangeSourceAPI);
827
828     child.setNeedsStyleRecalc(ReconstructRenderTree);
829
830     dispatchChildInsertionEvents(child);
831 }
832
833 void ContainerNode::setAttributeEventListener(const AtomicString& eventType, const QualifiedName& attributeName, const AtomicString& attributeValue)
834 {
835     setAttributeEventListener(eventType, JSLazyEventListener::createForNode(*this, attributeName, attributeValue));
836 }
837
838 Element* ContainerNode::querySelector(const String& selectors, ExceptionCode& ec)
839 {
840     if (SelectorQuery* selectorQuery = document().selectorQueryForString(selectors, ec))
841         return selectorQuery->queryFirst(*this);
842     return nullptr;
843 }
844
845 RefPtr<NodeList> ContainerNode::querySelectorAll(const String& selectors, ExceptionCode& ec)
846 {
847     if (SelectorQuery* selectorQuery = document().selectorQueryForString(selectors, ec))
848         return selectorQuery->queryAll(*this);
849     return nullptr;
850 }
851
852 Ref<HTMLCollection> ContainerNode::getElementsByTagName(const AtomicString& localName)
853 {
854     ASSERT(!localName.isNull());
855
856     if (document().isHTMLDocument())
857         return ensureRareData().ensureNodeLists().addCachedCollection<HTMLTagCollection>(*this, ByHTMLTag, localName);
858     return ensureRareData().ensureNodeLists().addCachedCollection<TagCollection>(*this, ByTag, localName);
859 }
860
861 RefPtr<NodeList> ContainerNode::getElementsByTagNameForObjC(const AtomicString& localName)
862 {
863     if (localName.isNull())
864         return nullptr;
865
866     return getElementsByTagName(localName);
867 }
868
869 Ref<HTMLCollection> ContainerNode::getElementsByTagNameNS(const AtomicString& namespaceURI, const AtomicString& localName)
870 {
871     ASSERT(!localName.isNull());
872
873     if (namespaceURI == starAtom)
874         return getElementsByTagName(localName);
875
876     return ensureRareData().ensureNodeLists().addCachedCollectionWithQualifiedName(*this, namespaceURI.isEmpty() ? nullAtom : namespaceURI, localName);
877 }
878
879 RefPtr<NodeList> ContainerNode::getElementsByTagNameNSForObjC(const AtomicString& namespaceURI, const AtomicString& localName)
880 {
881     if (localName.isNull())
882         return nullptr;
883
884     return getElementsByTagNameNS(namespaceURI, localName);
885 }
886
887 Ref<NodeList> ContainerNode::getElementsByName(const String& elementName)
888 {
889     return ensureRareData().ensureNodeLists().addCacheWithAtomicName<NameNodeList>(*this, elementName);
890 }
891
892 Ref<HTMLCollection> ContainerNode::getElementsByClassName(const AtomicString& classNames)
893 {
894     return ensureRareData().ensureNodeLists().addCachedCollection<ClassCollection>(*this, ByClass, classNames);
895 }
896
897 Ref<NodeList> ContainerNode::getElementsByClassNameForObjC(const AtomicString& classNames)
898 {
899     return getElementsByClassName(classNames);
900 }
901
902 Ref<RadioNodeList> ContainerNode::radioNodeList(const AtomicString& name)
903 {
904     ASSERT(hasTagName(HTMLNames::formTag) || hasTagName(HTMLNames::fieldsetTag));
905     return ensureRareData().ensureNodeLists().addCacheWithAtomicName<RadioNodeList>(*this, name);
906 }
907
908 Ref<HTMLCollection> ContainerNode::children()
909 {
910     return ensureRareData().ensureNodeLists().addCachedCollection<GenericCachedHTMLCollection<CollectionTypeTraits<NodeChildren>::traversalType>>(*this, NodeChildren);
911 }
912
913 Element* ContainerNode::firstElementChild() const
914 {
915     return ElementTraversal::firstChild(*this);
916 }
917
918 Element* ContainerNode::lastElementChild() const
919 {
920     return ElementTraversal::lastChild(*this);
921 }
922
923 unsigned ContainerNode::childElementCount() const
924 {
925     auto children = childrenOfType<Element>(*this);
926     return std::distance(children.begin(), children.end());
927 }
928
929 void ContainerNode::append(Vector<NodeOrString>&& nodeOrStringVector, ExceptionCode& ec)
930 {
931     RefPtr<Node> node = convertNodesOrStringsIntoNode(*this, WTF::move(nodeOrStringVector), ec);
932     if (ec || !node)
933         return;
934
935     appendChild(node.releaseNonNull(), ec);
936 }
937
938 void ContainerNode::prepend(Vector<NodeOrString>&& nodeOrStringVector, ExceptionCode& ec)
939 {
940     RefPtr<Node> node = convertNodesOrStringsIntoNode(*this, WTF::move(nodeOrStringVector), ec);
941     if (ec || !node)
942         return;
943
944     insertBefore(node.releaseNonNull(), firstChild(), ec);
945 }
946
947 HTMLCollection* ContainerNode::cachedHTMLCollection(CollectionType type)
948 {
949     return hasRareData() && rareData()->nodeLists() ? rareData()->nodeLists()->cachedCollection<HTMLCollection>(type) : nullptr;
950 }
951
952 } // namespace WebCore