Assert that updateStyle and updateLayout are only called when it's safe to dispatch...
[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, 2016 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 "AllDescendantsCollection.h"
28 #include "ChildListMutationScope.h"
29 #include "ClassCollection.h"
30 #include "CommonVM.h"
31 #include "ContainerNodeAlgorithms.h"
32 #include "Editor.h"
33 #include "EventNames.h"
34 #include "FloatRect.h"
35 #include "FrameView.h"
36 #include "GenericCachedHTMLCollection.h"
37 #include "HTMLFormControlsCollection.h"
38 #include "HTMLOptionsCollection.h"
39 #include "HTMLSlotElement.h"
40 #include "HTMLTableRowsCollection.h"
41 #include "InlineTextBox.h"
42 #include "InspectorInstrumentation.h"
43 #include "JSNode.h"
44 #include "LabelsNodeList.h"
45 #include "MutationEvent.h"
46 #include "NameNodeList.h"
47 #include "NoEventDispatchAssertion.h"
48 #include "NodeRareData.h"
49 #include "NodeRenderStyle.h"
50 #include "RadioNodeList.h"
51 #include "RenderBox.h"
52 #include "RenderTheme.h"
53 #include "RenderTreeUpdater.h"
54 #include "RenderWidget.h"
55 #include "RootInlineBox.h"
56 #include "RuntimeEnabledFeatures.h"
57 #include "SVGDocumentExtensions.h"
58 #include "SVGElement.h"
59 #include "SVGNames.h"
60 #include "SVGUseElement.h"
61 #include "SelectorQuery.h"
62 #include "TemplateContentDocumentFragment.h"
63 #include <algorithm>
64 #include <wtf/Variant.h>
65
66 namespace WebCore {
67
68 static void dispatchChildInsertionEvents(Node&);
69 static void dispatchChildRemovalEvents(Ref<Node>&);
70
71 ChildNodesLazySnapshot* ChildNodesLazySnapshot::latestSnapshot;
72
73 #if !ASSERT_DISABLED
74 unsigned NoEventDispatchAssertion::s_count = 0;
75 NoEventDispatchAssertion::EventAllowedScope* NoEventDispatchAssertion::EventAllowedScope::s_currentScope = nullptr;
76 #endif
77
78 ALWAYS_INLINE NodeVector ContainerNode::removeAllChildrenWithScriptAssertion(ChildChangeSource source, DeferChildrenChanged deferChildrenChanged)
79 {
80     auto children = collectChildNodes(*this);
81
82     if (source == ContainerNode::ChildChangeSource::API) {
83         ChildListMutationScope mutation(*this);
84         for (auto& child : children) {
85             mutation.willRemoveChild(child.get());
86             child->notifyMutationObserversNodeWillDetach();
87             dispatchChildRemovalEvents(child);
88         }
89     } else {
90         ASSERT(source == ContainerNode::ChildChangeSource::Parser);
91         NoEventDispatchAssertion::InMainThread assertNoEventDispatch;
92         if (UNLIKELY(document().hasMutationObserversOfType(MutationObserver::ChildList))) {
93             ChildListMutationScope mutation(*this);
94             for (auto& child : children)
95                 mutation.willRemoveChild(child.get());
96         }
97     }
98
99     disconnectSubframesIfNeeded(*this, DescendantsOnly);
100
101     WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
102     NoEventDispatchAssertion::InMainThread assertNoEventDispatch;
103
104     document().nodeChildrenWillBeRemoved(*this);
105
106     while (RefPtr<Node> child = m_firstChild) {
107         removeBetween(nullptr, child->nextSibling(), *child);
108         notifyChildNodeRemoved(*this, *child);
109     }
110
111     if (deferChildrenChanged == DeferChildrenChanged::No)
112         childrenChanged(ContainerNode::ChildChange { ContainerNode::AllChildrenRemoved, nullptr, nullptr, source });
113
114     return children;
115 }
116
117 ALWAYS_INLINE bool ContainerNode::removeNodeWithScriptAssertion(Node& childToRemove, ChildChangeSource source)
118 {
119     Ref<Node> protectedChildToRemove(childToRemove);
120     ASSERT_WITH_SECURITY_IMPLICATION(childToRemove.parentNode() == this);
121     {
122         NoEventDispatchAssertion::InMainThread assertNoEventDispatch;
123         ChildListMutationScope(*this).willRemoveChild(childToRemove);
124     }
125
126     ASSERT_WITH_SECURITY_IMPLICATION(NoEventDispatchAssertion::InMainThread::isEventDispatchAllowedInSubtree(childToRemove));
127     if (source == ContainerNode::ChildChangeSource::API) {
128         childToRemove.notifyMutationObserversNodeWillDetach();
129         dispatchChildRemovalEvents(protectedChildToRemove);
130         if (childToRemove.parentNode() != this)
131             return false;
132     }
133
134     if (source == ContainerNode::ChildChangeSource::Parser) {
135         // FIXME: Merge these two code paths. It's a bug in the parser not to update connectedSubframeCount in time.
136         disconnectSubframesIfNeeded(*this, DescendantsOnly);
137     } else {
138         if (is<ContainerNode>(childToRemove))
139             disconnectSubframesIfNeeded(downcast<ContainerNode>(childToRemove), RootAndDescendants);
140     }
141
142     if (childToRemove.parentNode() != this)
143         return false;
144
145     ChildChange change;
146     {
147         WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
148         NoEventDispatchAssertion::InMainThread assertNoEventDispatch;
149
150         document().nodeWillBeRemoved(childToRemove);
151
152         ASSERT_WITH_SECURITY_IMPLICATION(childToRemove.parentNode() == this);
153         ASSERT(!childToRemove.isDocumentFragment());
154
155         RefPtr<Node> previousSibling = childToRemove.previousSibling();
156         RefPtr<Node> nextSibling = childToRemove.nextSibling();
157         removeBetween(previousSibling.get(), nextSibling.get(), childToRemove);
158         notifyChildNodeRemoved(*this, childToRemove);
159
160         change.type = is<Element>(childToRemove) ? ElementRemoved : (is<Text>(childToRemove) ? TextRemoved : NonContentsChildRemoved);
161         change.previousSiblingElement = (!previousSibling || is<Element>(*previousSibling)) ? downcast<Element>(previousSibling.get()) : ElementTraversal::previousSibling(*previousSibling);
162         change.nextSiblingElement = (!nextSibling || is<Element>(*nextSibling)) ? downcast<Element>(nextSibling.get()) : ElementTraversal::nextSibling(*nextSibling);
163         change.source = source;
164     }
165
166     // FIXME: Move childrenChanged into NoEventDispatchAssertion block.
167     childrenChanged(change);
168
169     return true;
170 }
171
172 enum class ReplacedAllChildren { No, Yes };
173
174 template<typename DOMInsertionWork>
175 static ALWAYS_INLINE void executeNodeInsertionWithScriptAssertion(ContainerNode& containerNode, Node& child,
176     ContainerNode::ChildChangeSource source, ReplacedAllChildren replacedAllChildren, DOMInsertionWork doNodeInsertion)
177 {
178     NodeVector postInsertionNotificationTargets;
179     {
180         NoEventDispatchAssertion::InMainThread assertNoEventDispatch;
181         doNodeInsertion();
182         ChildListMutationScope(containerNode).childAdded(child);
183         postInsertionNotificationTargets = notifyChildNodeInserted(containerNode, child);
184     }
185
186     // FIXME: Move childrenChanged into NoEventDispatchAssertion block.
187     if (replacedAllChildren == ReplacedAllChildren::Yes)
188         containerNode.childrenChanged(ContainerNode::ChildChange { ContainerNode::AllChildrenReplaced, nullptr, nullptr, source });
189     else {
190         containerNode.childrenChanged(ContainerNode::ChildChange {
191             child.isElementNode() ? ContainerNode::ElementInserted : (child.isTextNode() ? ContainerNode::TextInserted : ContainerNode::NonContentsChildInserted),
192             ElementTraversal::previousSibling(child),
193             ElementTraversal::nextSibling(child),
194             source
195         });
196     }
197
198     ASSERT(NoEventDispatchAssertion::InMainThread::isEventDispatchAllowedInSubtree(child));
199     for (auto& target : postInsertionNotificationTargets)
200         target->didFinishInsertingNode();
201
202     if (source == ContainerNode::ChildChangeSource::API)
203         dispatchChildInsertionEvents(child);
204 }
205
206 static ExceptionOr<void> collectChildrenAndRemoveFromOldParent(Node& node, NodeVector& nodes)
207 {
208     if (!is<DocumentFragment>(node)) {
209         nodes.append(node);
210         auto* oldParent = node.parentNode();
211         if (!oldParent)
212             return { };
213         return oldParent->removeChild(node);
214     }
215
216     nodes = collectChildNodes(node);
217     downcast<DocumentFragment>(node).removeChildren();
218     return { };
219 }
220
221 // FIXME: This function must get a new name.
222 // It removes all children, not just a category called "detached children".
223 // So this name is terribly confusing.
224 void ContainerNode::removeDetachedChildren()
225 {
226     if (connectedSubframeCount()) {
227         for (Node* child = firstChild(); child; child = child->nextSibling())
228             child->updateAncestorConnectedSubframeCountForRemoval();
229     }
230     // FIXME: We should be able to ASSERT(!attached()) here: https://bugs.webkit.org/show_bug.cgi?id=107801
231     NoEventDispatchAssertion::InMainThread noEventDispatchAssertion;
232     removeDetachedChildrenInContainer(*this);
233 }
234
235 static inline void destroyRenderTreeIfNeeded(Node& child)
236 {
237     bool isElement = is<Element>(child);
238     auto hasDisplayContents = isElement && downcast<Element>(child).hasDisplayContents();
239     if (!child.renderer() && !hasDisplayContents)
240         return;
241     if (isElement)
242         RenderTreeUpdater::tearDownRenderers(downcast<Element>(child));
243     else if (is<Text>(child))
244         RenderTreeUpdater::tearDownRenderer(downcast<Text>(child));
245 }
246
247 void ContainerNode::takeAllChildrenFrom(ContainerNode* oldParent)
248 {
249     ASSERT(oldParent);
250
251     auto children = oldParent->removeAllChildrenWithScriptAssertion(ChildChangeSource::Parser);
252
253     // FIXME: assert that we don't dispatch events here since this container node is still disconnected.
254     for (auto& child : children) {
255         RELEASE_ASSERT(!child->parentNode() && &child->treeScope() == &treeScope());
256         ASSERT(!ensurePreInsertionValidity(child, nullptr).hasException());
257         child->setTreeScopeRecursively(treeScope());
258         parserAppendChild(child);
259     }
260 }
261
262 ContainerNode::~ContainerNode()
263 {
264     if (!isDocumentNode())
265         willBeDeletedFrom(document());
266     removeDetachedChildren();
267 }
268
269 static inline bool isChildTypeAllowed(ContainerNode& newParent, Node& child)
270 {
271     if (!child.isDocumentFragment())
272         return newParent.childTypeAllowed(child.nodeType());
273
274     for (Node* node = child.firstChild(); node; node = node->nextSibling()) {
275         if (!newParent.childTypeAllowed(node->nodeType()))
276             return false;
277     }
278     return true;
279 }
280
281 static inline bool isInTemplateContent(const Node* node)
282 {
283     Document& document = node->document();
284     return &document == document.templateDocument();
285 }
286
287 static inline bool containsConsideringHostElements(const Node& newChild, const Node& newParent)
288 {
289     return (newParent.isInShadowTree() || isInTemplateContent(&newParent))
290         ? newChild.containsIncludingHostElements(&newParent)
291         : newChild.contains(&newParent);
292 }
293
294 static inline ExceptionOr<void> checkAcceptChild(ContainerNode& newParent, Node& newChild, const Node* refChild, Document::AcceptChildOperation operation)
295 {
296     // Use common case fast path if possible.
297     if ((newChild.isElementNode() || newChild.isTextNode()) && newParent.isElementNode()) {
298         ASSERT(!newParent.isDocumentTypeNode());
299         ASSERT(isChildTypeAllowed(newParent, newChild));
300         if (containsConsideringHostElements(newChild, newParent))
301             return Exception { HierarchyRequestError };
302         if (operation == Document::AcceptChildOperation::InsertOrAdd && refChild && refChild->parentNode() != &newParent)
303             return Exception { NotFoundError };
304         return { };
305     }
306
307     // This should never happen, but also protect release builds from tree corruption.
308     ASSERT(!newChild.isPseudoElement());
309     if (newChild.isPseudoElement())
310         return Exception { HierarchyRequestError };
311
312     if (containsConsideringHostElements(newChild, newParent))
313         return Exception { HierarchyRequestError };
314
315     if (operation == Document::AcceptChildOperation::InsertOrAdd && refChild && refChild->parentNode() != &newParent)
316         return Exception { NotFoundError };
317
318     if (is<Document>(newParent)) {
319         if (!downcast<Document>(newParent).canAcceptChild(newChild, refChild, operation))
320             return Exception { HierarchyRequestError };
321     } else if (!isChildTypeAllowed(newParent, newChild))
322         return Exception { HierarchyRequestError };
323
324     return { };
325 }
326
327 static inline ExceptionOr<void> checkAcceptChildGuaranteedNodeTypes(ContainerNode& newParent, Node& newChild)
328 {
329     ASSERT(!newParent.isDocumentTypeNode());
330     ASSERT(isChildTypeAllowed(newParent, newChild));
331     if (newChild.contains(&newParent))
332         return Exception { HierarchyRequestError };
333     return { };
334 }
335
336 // https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
337 ExceptionOr<void> ContainerNode::ensurePreInsertionValidity(Node& newChild, Node* refChild)
338 {
339     return checkAcceptChild(*this, newChild, refChild, Document::AcceptChildOperation::InsertOrAdd);
340 }
341
342 // https://dom.spec.whatwg.org/#concept-node-replace
343 static inline ExceptionOr<void> checkPreReplacementValidity(ContainerNode& newParent, Node& newChild, Node& oldChild)
344 {
345     return checkAcceptChild(newParent, newChild, &oldChild, Document::AcceptChildOperation::Replace);
346 }
347
348 ExceptionOr<void> ContainerNode::insertBefore(Node& newChild, Node* refChild)
349 {
350     // Check that this node is not "floating".
351     // If it is, it can be deleted as a side effect of sending mutation events.
352     ASSERT(refCount() || parentOrShadowHostNode());
353
354     // Make sure adding the new child is OK.
355     auto validityCheckResult = ensurePreInsertionValidity(newChild, refChild);
356     if (validityCheckResult.hasException())
357         return validityCheckResult.releaseException();
358
359     if (refChild == &newChild)
360         refChild = newChild.nextSibling();
361
362     // insertBefore(node, null) is equivalent to appendChild(node)
363     if (!refChild)
364         return appendChildWithoutPreInsertionValidityCheck(newChild);
365
366     Ref<ContainerNode> protectedThis(*this);
367     Ref<Node> next(*refChild);
368
369     NodeVector targets;
370     auto removeResult = collectChildrenAndRemoveFromOldParent(newChild, targets);
371     if (removeResult.hasException())
372         return removeResult.releaseException();
373     if (targets.isEmpty())
374         return { };
375
376     // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events.
377     auto checkAcceptResult = checkAcceptChildGuaranteedNodeTypes(*this, newChild);
378     if (checkAcceptResult.hasException())
379         return checkAcceptResult.releaseException();
380
381     InspectorInstrumentation::willInsertDOMNode(document(), *this);
382
383     ChildListMutationScope mutation(*this);
384     for (auto& child : targets) {
385         // Due to arbitrary code running in response to a DOM mutation event it's
386         // possible that "next" is no longer a child of "this".
387         // It's also possible that "child" has been inserted elsewhere.
388         // In either of those cases, we'll just stop.
389         if (next->parentNode() != this)
390             break;
391         if (child->parentNode())
392             break;
393
394         executeNodeInsertionWithScriptAssertion(*this, child.get(), ChildChangeSource::API, ReplacedAllChildren::No, [&] {
395             child->setTreeScopeRecursively(treeScope());
396             insertBeforeCommon(next, child);
397         });
398     }
399
400     dispatchSubtreeModifiedEvent();
401     return { };
402 }
403
404 void ContainerNode::insertBeforeCommon(Node& nextChild, Node& newChild)
405 {
406     NoEventDispatchAssertion::InMainThread assertNoEventDispatch;
407
408     ASSERT(!newChild.parentNode()); // Use insertBefore if you need to handle reparenting (and want DOM mutation events).
409     ASSERT(!newChild.nextSibling());
410     ASSERT(!newChild.previousSibling());
411     ASSERT(!newChild.isShadowRoot());
412
413     Node* prev = nextChild.previousSibling();
414     ASSERT(m_lastChild != prev);
415     nextChild.setPreviousSibling(&newChild);
416     if (prev) {
417         ASSERT(m_firstChild != &nextChild);
418         ASSERT(prev->nextSibling() == &nextChild);
419         prev->setNextSibling(&newChild);
420     } else {
421         ASSERT(m_firstChild == &nextChild);
422         m_firstChild = &newChild;
423     }
424     newChild.setParentNode(this);
425     newChild.setPreviousSibling(prev);
426     newChild.setNextSibling(&nextChild);
427 }
428
429 void ContainerNode::appendChildCommon(Node& child)
430 {
431     NoEventDispatchAssertion::InMainThread assertNoEventDispatch;
432
433     child.setParentNode(this);
434
435     if (m_lastChild) {
436         child.setPreviousSibling(m_lastChild);
437         m_lastChild->setNextSibling(&child);
438     } else
439         m_firstChild = &child;
440
441     m_lastChild = &child;
442 }
443
444 void ContainerNode::parserInsertBefore(Node& newChild, Node& nextChild)
445 {
446     ASSERT(nextChild.parentNode() == this);
447     ASSERT(!newChild.isDocumentFragment());
448     ASSERT(!hasTagName(HTMLNames::templateTag));
449
450     if (nextChild.previousSibling() == &newChild || &nextChild == &newChild) // nothing to do
451         return;
452
453     executeNodeInsertionWithScriptAssertion(*this, newChild, ChildChangeSource::Parser, ReplacedAllChildren::No, [&] {
454         if (&document() != &newChild.document())
455             document().adoptNode(newChild);
456
457         insertBeforeCommon(nextChild, newChild);
458
459         newChild.updateAncestorConnectedSubframeCountForInsertion();
460     });
461 }
462
463 ExceptionOr<void> ContainerNode::replaceChild(Node& newChild, Node& oldChild)
464 {
465     // Check that this node is not "floating".
466     // If it is, it can be deleted as a side effect of sending mutation events.
467     ASSERT(refCount() || parentOrShadowHostNode());
468
469     Ref<ContainerNode> protectedThis(*this);
470
471     // Make sure replacing the old child with the new is ok
472     auto validityResult = checkPreReplacementValidity(*this, newChild, oldChild);
473     if (validityResult.hasException())
474         return validityResult.releaseException();
475
476     // NotFoundError: Raised if oldChild is not a child of this node.
477     if (oldChild.parentNode() != this)
478         return Exception { NotFoundError };
479
480     RefPtr<Node> refChild = oldChild.nextSibling();
481     if (refChild.get() == &newChild)
482         refChild = refChild->nextSibling();
483
484     NodeVector targets;
485     {
486         ChildListMutationScope mutation(*this);
487         auto collectResult = collectChildrenAndRemoveFromOldParent(newChild, targets);
488         if (collectResult.hasException())
489             return collectResult.releaseException();
490     }
491
492     // Do this one more time because collectChildrenAndRemoveFromOldParent() fires a MutationEvent.
493     validityResult = checkPreReplacementValidity(*this, newChild, oldChild);
494     if (validityResult.hasException())
495         return validityResult.releaseException();
496
497     // Remove the node we're replacing.
498     Ref<Node> protectOldChild(oldChild);
499
500     ChildListMutationScope mutation(*this);
501
502     // If oldChild == newChild then oldChild no longer has a parent at this point.
503     if (oldChild.parentNode()) {
504         auto removeResult = removeChild(oldChild);
505         if (removeResult.hasException())
506             return removeResult.releaseException();
507
508         // Does this one more time because removeChild() fires a MutationEvent.
509         validityResult = checkPreReplacementValidity(*this, newChild, oldChild);
510         if (validityResult.hasException())
511             return validityResult.releaseException();
512     }
513
514     InspectorInstrumentation::willInsertDOMNode(document(), *this);
515
516     // Add the new child(ren).
517     for (auto& child : targets) {
518         // Due to arbitrary code running in response to a DOM mutation event it's
519         // possible that "refChild" is no longer a child of "this".
520         // It's also possible that "child" has been inserted elsewhere.
521         // In either of those cases, we'll just stop.
522         if (refChild && refChild->parentNode() != this)
523             break;
524         if (child->parentNode())
525             break;
526
527         executeNodeInsertionWithScriptAssertion(*this, child.get(), ChildChangeSource::API, ReplacedAllChildren::No, [&] {
528             child->setTreeScopeRecursively(treeScope());
529             if (refChild)
530                 insertBeforeCommon(*refChild, child.get());
531             else
532                 appendChildCommon(child);
533         });
534     }
535
536     dispatchSubtreeModifiedEvent();
537     return { };
538 }
539
540 void ContainerNode::disconnectDescendantFrames()
541 {
542     disconnectSubframesIfNeeded(*this, RootAndDescendants);
543 }
544
545 ExceptionOr<void> ContainerNode::removeChild(Node& oldChild)
546 {
547     // Check that this node is not "floating".
548     // If it is, it can be deleted as a side effect of sending mutation events.
549     ASSERT(refCount() || parentOrShadowHostNode());
550
551     Ref<ContainerNode> protectedThis(*this);
552
553     // NotFoundError: Raised if oldChild is not a child of this node.
554     if (oldChild.parentNode() != this)
555         return Exception { NotFoundError };
556
557     if (!removeNodeWithScriptAssertion(oldChild, ChildChangeSource::API))
558         return Exception { NotFoundError };
559
560     rebuildSVGExtensionsElementsIfNecessary();
561     dispatchSubtreeModifiedEvent();
562
563     return { };
564 }
565
566 void ContainerNode::removeBetween(Node* previousChild, Node* nextChild, Node& oldChild)
567 {
568     InspectorInstrumentation::didRemoveDOMNode(oldChild.document(), oldChild);
569
570     NoEventDispatchAssertion::InMainThread assertNoEventDispatch;
571
572     ASSERT(oldChild.parentNode() == this);
573
574     destroyRenderTreeIfNeeded(oldChild);
575
576     if (nextChild) {
577         nextChild->setPreviousSibling(previousChild);
578         oldChild.setNextSibling(nullptr);
579     } else {
580         ASSERT(m_lastChild == &oldChild);
581         m_lastChild = previousChild;
582     }
583     if (previousChild) {
584         previousChild->setNextSibling(nextChild);
585         oldChild.setPreviousSibling(nullptr);
586     } else {
587         ASSERT(m_firstChild == &oldChild);
588         m_firstChild = nextChild;
589     }
590
591     ASSERT(m_firstChild != &oldChild);
592     ASSERT(m_lastChild != &oldChild);
593     ASSERT(!oldChild.previousSibling());
594     ASSERT(!oldChild.nextSibling());
595     oldChild.setParentNode(nullptr);
596
597     oldChild.setTreeScopeRecursively(document());
598 }
599
600 void ContainerNode::parserRemoveChild(Node& oldChild)
601 {
602     removeNodeWithScriptAssertion(oldChild, ChildChangeSource::Parser);
603 }
604
605 // https://dom.spec.whatwg.org/#concept-node-replace-all
606 void ContainerNode::replaceAllChildren(std::nullptr_t)
607 {
608     ChildListMutationScope mutation(*this);
609     removeChildren();
610 }
611
612 // https://dom.spec.whatwg.org/#concept-node-replace-all
613 void ContainerNode::replaceAllChildren(Ref<Node>&& node)
614 {
615     // This function assumes the input node is not a DocumentFragment and is parentless to decrease complexity.
616     ASSERT(!is<DocumentFragment>(node));
617     ASSERT(!node->parentNode());
618
619     if (!hasChildNodes()) {
620         // appendChildWithoutPreInsertionValidityCheck() can only throw when node has a parent and we already asserted it doesn't.
621         auto result = appendChildWithoutPreInsertionValidityCheck(node);
622         ASSERT_UNUSED(result, !result.hasException());
623         return;
624     }
625
626     Ref<ContainerNode> protectedThis(*this);
627     ChildListMutationScope mutation(*this);
628     removeAllChildrenWithScriptAssertion(ChildChangeSource::API, DeferChildrenChanged::Yes);
629
630     executeNodeInsertionWithScriptAssertion(*this, node.get(), ChildChangeSource::API, ReplacedAllChildren::Yes, [&] {
631         ASSERT(!ensurePreInsertionValidity(node, nullptr).hasException());
632         InspectorInstrumentation::willInsertDOMNode(document(), *this);
633         node->setTreeScopeRecursively(treeScope());
634         appendChildCommon(node);
635     });
636
637     rebuildSVGExtensionsElementsIfNecessary();
638     dispatchSubtreeModifiedEvent();
639 }
640
641 inline void ContainerNode::rebuildSVGExtensionsElementsIfNecessary()
642 {
643     if (document().svgExtensions() && !is<SVGUseElement>(shadowHost()))
644         document().accessSVGExtensions().rebuildElements();
645 }
646
647 // this differs from other remove functions because it forcibly removes all the children,
648 // regardless of read-only status or event exceptions, e.g.
649 void ContainerNode::removeChildren()
650 {
651     if (!m_firstChild)
652         return;
653
654     Ref<ContainerNode> protectedThis(*this);
655     removeAllChildrenWithScriptAssertion(ChildChangeSource::API);
656
657     rebuildSVGExtensionsElementsIfNecessary();
658     dispatchSubtreeModifiedEvent();
659 }
660
661 ExceptionOr<void> ContainerNode::appendChild(Node& newChild)
662 {
663     // Check that this node is not "floating".
664     // If it is, it can be deleted as a side effect of sending mutation events.
665     ASSERT(refCount() || parentOrShadowHostNode());
666
667     // Make sure adding the new child is ok
668     auto validityCheckResult = ensurePreInsertionValidity(newChild, nullptr);
669     if (validityCheckResult.hasException())
670         return validityCheckResult.releaseException();
671
672     return appendChildWithoutPreInsertionValidityCheck(newChild);
673 }
674
675 ExceptionOr<void> ContainerNode::appendChildWithoutPreInsertionValidityCheck(Node& newChild)
676 {
677     Ref<ContainerNode> protectedThis(*this);
678
679     NodeVector targets;
680     auto removeResult = collectChildrenAndRemoveFromOldParent(newChild, targets);
681     if (removeResult.hasException())
682         return removeResult.releaseException();
683
684     if (targets.isEmpty())
685         return { };
686
687     // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events.
688     auto nodeTypeResult = checkAcceptChildGuaranteedNodeTypes(*this, newChild);
689     if (nodeTypeResult.hasException())
690         return nodeTypeResult.releaseException();
691
692     InspectorInstrumentation::willInsertDOMNode(document(), *this);
693
694     // Now actually add the child(ren)
695     ChildListMutationScope mutation(*this);
696     for (auto& child : targets) {
697         // If the child has a parent again, just stop what we're doing, because
698         // that means someone is doing something with DOM mutation -- can't re-parent
699         // a child that already has a parent.
700         if (child->parentNode())
701             break;
702
703         // Append child to the end of the list
704         executeNodeInsertionWithScriptAssertion(*this, child.get(), ChildChangeSource::API, ReplacedAllChildren::No, [&] {
705             child->setTreeScopeRecursively(treeScope());
706             appendChildCommon(child);
707         });
708     }
709
710     dispatchSubtreeModifiedEvent();
711     return { };
712 }
713
714 void ContainerNode::parserAppendChild(Node& newChild)
715 {
716     ASSERT(!newChild.parentNode()); // Use appendChild if you need to handle reparenting (and want DOM mutation events).
717     ASSERT(!newChild.isDocumentFragment());
718     ASSERT(!hasTagName(HTMLNames::templateTag));
719
720     executeNodeInsertionWithScriptAssertion(*this, newChild, ChildChangeSource::Parser, ReplacedAllChildren::No, [&] {
721         if (&document() != &newChild.document())
722             document().adoptNode(newChild);
723
724         appendChildCommon(newChild);
725         newChild.setTreeScopeRecursively(treeScope());
726         newChild.updateAncestorConnectedSubframeCountForInsertion();
727     });
728 }
729
730 void ContainerNode::childrenChanged(const ChildChange& change)
731 {
732     document().incDOMTreeVersion();
733     if (change.source == ChildChangeSource::API && change.type != TextChanged)
734         document().updateRangesAfterChildrenChanged(*this);
735     invalidateNodeListAndCollectionCachesInAncestors();
736 }
737
738 void ContainerNode::cloneChildNodes(ContainerNode& clone)
739 {
740     Document& targetDocument = clone.document();
741     for (Node* child = firstChild(); child; child = child->nextSibling()) {
742         auto clonedChild = child->cloneNodeInternal(targetDocument, CloningOperation::SelfWithTemplateContent);
743         if (!clone.appendChild(clonedChild).hasException() && is<ContainerNode>(*child))
744             downcast<ContainerNode>(*child).cloneChildNodes(downcast<ContainerNode>(clonedChild.get()));
745     }
746 }
747
748 unsigned ContainerNode::countChildNodes() const
749 {
750     unsigned count = 0;
751     for (Node* child = firstChild(); child; child = child->nextSibling())
752         ++count;
753     return count;
754 }
755
756 Node* ContainerNode::traverseToChildAt(unsigned index) const
757 {
758     Node* child = firstChild();
759     for (; child && index > 0; --index)
760         child = child->nextSibling();
761     return child;
762 }
763
764 static void dispatchChildInsertionEvents(Node& child)
765 {
766     if (child.isInShadowTree())
767         return;
768
769     ASSERT_WITH_SECURITY_IMPLICATION(NoEventDispatchAssertion::InMainThread::isEventDispatchAllowedInSubtree(child));
770
771     RefPtr<Node> c = &child;
772     Ref<Document> document(child.document());
773
774     if (c->parentNode() && document->hasListenerType(Document::DOMNODEINSERTED_LISTENER))
775         c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeInsertedEvent, true, c->parentNode()));
776
777     // dispatch the DOMNodeInsertedIntoDocument event to all descendants
778     if (c->isConnected() && document->hasListenerType(Document::DOMNODEINSERTEDINTODOCUMENT_LISTENER)) {
779         for (; c; c = NodeTraversal::next(*c, &child))
780             c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeInsertedIntoDocumentEvent, false));
781     }
782 }
783
784 static void dispatchChildRemovalEvents(Ref<Node>& child)
785 {
786     ASSERT_WITH_SECURITY_IMPLICATION(NoEventDispatchAssertion::InMainThread::isEventDispatchAllowedInSubtree(child));
787     InspectorInstrumentation::willRemoveDOMNode(child->document(), child.get());
788
789     if (child->isInShadowTree())
790         return;
791
792     // FIXME: This doesn't belong in dispatchChildRemovalEvents.
793     // FIXME: Nodes removed from a shadow tree should also be kept alive.
794     willCreatePossiblyOrphanedTreeByRemoval(child.ptr());
795
796     Ref<Document> document = child->document();
797
798     // dispatch pre-removal mutation events
799     if (child->parentNode() && document->hasListenerType(Document::DOMNODEREMOVED_LISTENER))
800         child->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeRemovedEvent, true, child->parentNode()));
801
802     // dispatch the DOMNodeRemovedFromDocument event to all descendants
803     if (child->isConnected() && document->hasListenerType(Document::DOMNODEREMOVEDFROMDOCUMENT_LISTENER)) {
804         for (RefPtr<Node> currentNode = child.copyRef(); currentNode; currentNode = NodeTraversal::next(*currentNode, child.ptr()))
805             currentNode->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeRemovedFromDocumentEvent, false));
806     }
807 }
808
809 ExceptionOr<Element*> ContainerNode::querySelector(const String& selectors)
810 {
811     auto query = document().selectorQueryForString(selectors);
812     if (query.hasException())
813         return query.releaseException();
814     return query.releaseReturnValue().queryFirst(*this);
815 }
816
817 ExceptionOr<Ref<NodeList>> ContainerNode::querySelectorAll(const String& selectors)
818 {
819     auto query = document().selectorQueryForString(selectors);
820     if (query.hasException())
821         return query.releaseException();
822     return query.releaseReturnValue().queryAll(*this);
823 }
824
825 Ref<HTMLCollection> ContainerNode::getElementsByTagName(const AtomicString& qualifiedName)
826 {
827     ASSERT(!qualifiedName.isNull());
828
829     if (qualifiedName == starAtom())
830         return ensureRareData().ensureNodeLists().addCachedCollection<AllDescendantsCollection>(*this, AllDescendants);
831
832     if (document().isHTMLDocument())
833         return ensureRareData().ensureNodeLists().addCachedCollection<HTMLTagCollection>(*this, ByHTMLTag, qualifiedName);
834     return ensureRareData().ensureNodeLists().addCachedCollection<TagCollection>(*this, ByTag, qualifiedName);
835 }
836
837 Ref<HTMLCollection> ContainerNode::getElementsByTagNameNS(const AtomicString& namespaceURI, const AtomicString& localName)
838 {
839     ASSERT(!localName.isNull());
840     return ensureRareData().ensureNodeLists().addCachedTagCollectionNS(*this, namespaceURI.isEmpty() ? nullAtom() : namespaceURI, localName);
841 }
842
843 Ref<NodeList> ContainerNode::getElementsByName(const String& elementName)
844 {
845     return ensureRareData().ensureNodeLists().addCacheWithAtomicName<NameNodeList>(*this, elementName);
846 }
847
848 Ref<HTMLCollection> ContainerNode::getElementsByClassName(const AtomicString& classNames)
849 {
850     return ensureRareData().ensureNodeLists().addCachedCollection<ClassCollection>(*this, ByClass, classNames);
851 }
852
853 Ref<RadioNodeList> ContainerNode::radioNodeList(const AtomicString& name)
854 {
855     ASSERT(hasTagName(HTMLNames::formTag) || hasTagName(HTMLNames::fieldsetTag));
856     return ensureRareData().ensureNodeLists().addCacheWithAtomicName<RadioNodeList>(*this, name);
857 }
858
859 Ref<HTMLCollection> ContainerNode::children()
860 {
861     return ensureRareData().ensureNodeLists().addCachedCollection<GenericCachedHTMLCollection<CollectionTypeTraits<NodeChildren>::traversalType>>(*this, NodeChildren);
862 }
863
864 Element* ContainerNode::firstElementChild() const
865 {
866     return ElementTraversal::firstChild(*this);
867 }
868
869 Element* ContainerNode::lastElementChild() const
870 {
871     return ElementTraversal::lastChild(*this);
872 }
873
874 unsigned ContainerNode::childElementCount() const
875 {
876     auto children = childrenOfType<Element>(*this);
877     return std::distance(children.begin(), children.end());
878 }
879
880 ExceptionOr<void> ContainerNode::append(Vector<NodeOrString>&& vector)
881 {
882     auto result = convertNodesOrStringsIntoNode(WTFMove(vector));
883     if (result.hasException())
884         return result.releaseException();
885
886     auto node = result.releaseReturnValue();
887     if (!node)
888         return { };
889
890     return appendChild(*node);
891 }
892
893 ExceptionOr<void> ContainerNode::prepend(Vector<NodeOrString>&& vector)
894 {
895     auto result = convertNodesOrStringsIntoNode(WTFMove(vector));
896     if (result.hasException())
897         return result.releaseException();
898
899     auto node = result.releaseReturnValue();
900     if (!node)
901         return { };
902
903     return insertBefore(*node, firstChild());
904 }
905
906 HTMLCollection* ContainerNode::cachedHTMLCollection(CollectionType type)
907 {
908     return hasRareData() && rareData()->nodeLists() ? rareData()->nodeLists()->cachedCollection<HTMLCollection>(type) : nullptr;
909 }
910
911 } // namespace WebCore