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 Apple Inc. All rights reserved.
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.
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.
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.
24 #include "ContainerNode.h"
26 #include "ContainerNodeAlgorithms.h"
27 #include "DeleteButtonController.h"
28 #include "EventNames.h"
29 #include "ExceptionCode.h"
30 #include "FloatRect.h"
32 #include "FrameView.h"
33 #include "InlineTextBox.h"
34 #include "MutationEvent.h"
35 #include "RenderTheme.h"
36 #include "RootInlineBox.h"
37 #include <wtf/CurrentTime.h>
41 static void dispatchChildInsertionEvents(Node*, ExceptionCode&);
42 static void dispatchChildRemovalEvents(Node*, ExceptionCode&);
44 typedef Vector<std::pair<NodeCallback, RefPtr<Node> > > NodeCallbackQueue;
45 static NodeCallbackQueue* s_postAttachCallbackQueue = 0;
47 static size_t s_attachDepth = 0;
49 void ContainerNode::removeAllChildren()
51 removeAllChildrenInContainer<Node, ContainerNode>(this);
54 ContainerNode::~ContainerNode()
59 bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode& ec, bool shouldLazyAttach)
61 // Check that this node is not "floating".
62 // If it is, it can be deleted as a side effect of sending mutation events.
63 ASSERT(refCount() || parent());
67 // insertBefore(node, 0) is equivalent to appendChild(node)
69 return appendChild(newChild, ec, shouldLazyAttach);
71 // Make sure adding the new child is OK.
72 checkAddChild(newChild.get(), ec);
76 // NOT_FOUND_ERR: Raised if refChild is not a child of this node
77 if (refChild->parentNode() != this) {
82 bool isFragment = newChild->nodeType() == DOCUMENT_FRAGMENT_NODE;
84 // If newChild is a DocumentFragment with no children; there's nothing to do.
86 if (isFragment && !newChild->firstChild())
89 // Now actually add the child(ren)
90 if (refChild->previousSibling() == newChild || refChild == newChild) // nothing to do
93 RefPtr<Node> next = refChild;
94 RefPtr<Node> prev = refChild->previousSibling();
96 int childCountDelta = 0;
97 RefPtr<Node> child = isFragment ? newChild->firstChild() : newChild;
99 RefPtr<Node> nextChild = isFragment ? child->nextSibling() : 0;
101 // If child is already present in the tree, first remove it from the old location.
102 if (Node* oldParent = child->parentNode())
103 oldParent->removeChild(child.get(), ec);
107 // FIXME: After sending the mutation events, "this" could be destroyed.
108 // We can prevent that by doing a "ref", but first we have to make sure
109 // that no callers call with ref count == 0 and parent = 0 (as of this
110 // writing, there are definitely callers who call that way).
112 // Due to arbitrary code running in response to a DOM mutation event it's
113 // possible that "next" is no longer a child of "this".
114 // It's also possible that "child" has been inserted elsewhere.
115 // In either of those cases, we'll just stop.
116 if (next->parentNode() != this)
118 if (child->parentNode())
121 ASSERT(!child->nextSibling());
122 ASSERT(!child->previousSibling());
126 // Add child before "next".
127 forbidEventDispatch();
128 Node* prev = next->previousSibling();
129 ASSERT(m_lastChild != prev);
130 next->setPreviousSibling(child.get());
132 ASSERT(m_firstChild != next);
133 ASSERT(prev->nextSibling() == next);
134 prev->setNextSibling(child.get());
136 ASSERT(m_firstChild == next);
137 m_firstChild = child.get();
139 child->setParent(this);
140 child->setPreviousSibling(prev);
141 child->setNextSibling(next.get());
142 allowEventDispatch();
144 // Dispatch the mutation events.
145 dispatchChildInsertionEvents(child.get(), ec);
147 // Add child to the rendering tree.
148 if (attached() && !child->attached() && child->parent() == this) {
149 if (shouldLazyAttach)
155 child = nextChild.release();
158 document()->setDocumentChanged(true);
160 childrenChanged(false, prev.get(), next.get(), childCountDelta);
161 dispatchSubtreeModifiedEvent();
165 bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode& ec, bool shouldLazyAttach)
167 // Check that this node is not "floating".
168 // If it is, it can be deleted as a side effect of sending mutation events.
169 ASSERT(refCount() || parent());
173 if (oldChild == newChild) // nothing to do
176 // Make sure replacing the old child with the new is ok
177 checkReplaceChild(newChild.get(), oldChild, ec);
181 // NOT_FOUND_ERR: Raised if oldChild is not a child of this node.
182 if (!oldChild || oldChild->parentNode() != this) {
187 RefPtr<Node> prev = oldChild->previousSibling();
188 RefPtr<Node> next = oldChild->nextSibling();
190 // Remove the node we're replacing
191 RefPtr<Node> removedChild = oldChild;
192 removeChild(oldChild, ec);
196 // FIXME: After sending the mutation events, "this" could be destroyed.
197 // We can prevent that by doing a "ref", but first we have to make sure
198 // that no callers call with ref count == 0 and parent = 0 (as of this
199 // writing, there are definitely callers who call that way).
201 bool isFragment = newChild->nodeType() == DOCUMENT_FRAGMENT_NODE;
203 // Add the new child(ren)
204 int childCountDelta = 0;
205 RefPtr<Node> child = isFragment ? newChild->firstChild() : newChild;
207 // If the new child is already in the right place, we're done.
208 if (prev && (prev == child || prev == child->previousSibling()))
211 // For a fragment we have more children to do.
212 RefPtr<Node> nextChild = isFragment ? child->nextSibling() : 0;
214 // Remove child from its old position.
215 if (Node* oldParent = child->parentNode())
216 oldParent->removeChild(child.get(), ec);
220 // Due to arbitrary code running in response to a DOM mutation event it's
221 // possible that "prev" is no longer a child of "this".
222 // It's also possible that "child" has been inserted elsewhere.
223 // In either of those cases, we'll just stop.
224 if (prev && prev->parentNode() != this)
226 if (child->parentNode())
231 ASSERT(!child->nextSibling());
232 ASSERT(!child->previousSibling());
234 // Add child after "prev".
235 forbidEventDispatch();
238 next = prev->nextSibling();
239 ASSERT(m_firstChild != next);
240 prev->setNextSibling(child.get());
243 m_firstChild = child.get();
246 ASSERT(m_lastChild != prev);
247 ASSERT(next->previousSibling() == prev);
248 next->setPreviousSibling(child.get());
250 ASSERT(m_lastChild == prev);
251 m_lastChild = child.get();
253 child->setParent(this);
254 child->setPreviousSibling(prev.get());
255 child->setNextSibling(next);
256 allowEventDispatch();
258 // Dispatch the mutation events
259 dispatchChildInsertionEvents(child.get(), ec);
261 // Add child to the rendering tree
262 if (attached() && !child->attached() && child->parent() == this) {
263 if (shouldLazyAttach)
270 child = nextChild.release();
273 document()->setDocumentChanged(true);
275 childrenChanged(false, prev.get(), next.get(), childCountDelta);
276 dispatchSubtreeModifiedEvent();
280 void ContainerNode::willRemove()
282 for (Node *n = m_firstChild; n != 0; n = n->nextSibling())
284 EventTargetNode::willRemove();
287 static ExceptionCode willRemoveChild(Node *child)
289 ExceptionCode ec = 0;
291 // fire removed from document mutation events.
292 dispatchChildRemovalEvents(child, ec);
296 if (child->attached())
302 bool ContainerNode::removeChild(Node* oldChild, ExceptionCode& ec)
304 // Check that this node is not "floating".
305 // If it is, it can be deleted as a side effect of sending mutation events.
306 ASSERT(refCount() || parent());
310 // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
311 if (isReadOnlyNode()) {
312 ec = NO_MODIFICATION_ALLOWED_ERR;
316 // NOT_FOUND_ERR: Raised if oldChild is not a child of this node.
317 if (!oldChild || oldChild->parentNode() != this) {
322 RefPtr<Node> child = oldChild;
324 ec = willRemoveChild(child.get());
328 // Mutation events might have moved this child into a different parent.
329 if (child->parentNode() != this) {
334 document()->removeFocusedNodeOfSubtree(child.get());
336 // FIXME: After sending the mutation events, "this" could be destroyed.
337 // We can prevent that by doing a "ref", but first we have to make sure
338 // that no callers call with ref count == 0 and parent = 0 (as of this
339 // writing, there are definitely callers who call that way).
341 forbidEventDispatch();
343 // Remove from rendering tree
344 if (child->attached())
349 prev = child->previousSibling();
350 next = child->nextSibling();
353 next->setPreviousSibling(prev);
355 prev->setNextSibling(next);
356 if (m_firstChild == child)
358 if (m_lastChild == child)
361 child->setPreviousSibling(0);
362 child->setNextSibling(0);
365 allowEventDispatch();
367 document()->setDocumentChanged(true);
369 // Dispatch post-removal mutation events
370 childrenChanged(false, prev, next, -1);
371 dispatchSubtreeModifiedEvent();
373 if (child->inDocument())
374 child->removedFromDocument();
376 child->removedFromTree(true);
381 // this differs from other remove functions because it forcibly removes all the children,
382 // regardless of read-only status or event exceptions, e.g.
383 bool ContainerNode::removeChildren()
390 // do any prep work needed before actually starting to detach
391 // and remove... e.g. stop loading frames, fire unload events
392 for (n = m_firstChild; n; n = n->nextSibling())
395 // exclude this node when looking for removed focusedNode since only children will be removed
396 document()->removeFocusedNodeOfSubtree(this, true);
398 forbidEventDispatch();
399 int childCountDelta = 0;
400 while ((n = m_firstChild) != 0) {
403 Node *next = n->nextSibling();
407 // Remove the node from the tree before calling detach or removedFromDocument (4427024, 4129744)
408 n->setPreviousSibling(0);
409 n->setNextSibling(0);
413 if (n == m_lastChild)
420 n->removedFromDocument();
424 allowEventDispatch();
426 // Dispatch a single post-removal mutation event denoting a modified subtree.
427 childrenChanged(false, 0, 0, childCountDelta);
428 dispatchSubtreeModifiedEvent();
433 bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, bool shouldLazyAttach)
435 // Check that this node is not "floating".
436 // If it is, it can be deleted as a side effect of sending mutation events.
437 ASSERT(refCount() || parent());
441 // Make sure adding the new child is ok
442 checkAddChild(newChild.get(), ec);
446 if (newChild == m_lastChild) // nothing to do
449 bool isFragment = newChild->nodeType() == DOCUMENT_FRAGMENT_NODE;
451 // If newChild is a DocumentFragment with no children.... there's nothing to do.
452 // Just return the document fragment
453 if (isFragment && !newChild->firstChild())
456 // Now actually add the child(ren)
457 int childCountDelta = 0;
458 RefPtr<Node> prev = lastChild();
459 RefPtr<Node> child = isFragment ? newChild->firstChild() : newChild;
461 // For a fragment we have more children to do.
462 RefPtr<Node> nextChild = isFragment ? child->nextSibling() : 0;
464 // If child is already present in the tree, first remove it
465 if (Node* oldParent = child->parentNode()) {
466 oldParent->removeChild(child.get(), ec);
470 // If the child has a parent again, just stop what we're doing, because
471 // that means someone is doing something with DOM mutation -- can't re-parent
472 // a child that already has a parent.
473 if (child->parentNode())
477 // Append child to the end of the list
479 forbidEventDispatch();
480 child->setParent(this);
482 child->setPreviousSibling(m_lastChild);
483 m_lastChild->setNextSibling(child.get());
485 m_firstChild = child.get();
486 m_lastChild = child.get();
487 allowEventDispatch();
489 // Dispatch the mutation events
490 dispatchChildInsertionEvents(child.get(), ec);
492 // Add child to the rendering tree
493 if (attached() && !child->attached() && child->parent() == this) {
494 if (shouldLazyAttach)
500 child = nextChild.release();
503 document()->setDocumentChanged(true);
504 childrenChanged(false, prev.get(), 0, childCountDelta);
505 dispatchSubtreeModifiedEvent();
509 ContainerNode* ContainerNode::addChild(PassRefPtr<Node> newChild)
511 // This function is only used during parsing.
512 // It does not send any DOM mutation events.
514 // Check for consistency with DTD, but only when parsing HTML.
515 if (document()->isHTMLDocument() && !childAllowed(newChild.get()))
518 forbidEventDispatch();
519 Node* last = m_lastChild;
520 appendChildToContainer<Node, ContainerNode>(newChild.get(), this);
521 allowEventDispatch();
523 document()->incDOMTreeVersion();
525 newChild->insertedIntoDocument();
526 childrenChanged(true, last, 0, 1);
528 if (newChild->isElementNode())
529 return static_cast<ContainerNode*>(newChild.get());
533 void ContainerNode::suspendPostAttachCallbacks()
538 void ContainerNode::resumePostAttachCallbacks()
540 if (s_attachDepth == 1 && s_postAttachCallbackQueue)
541 dispatchPostAttachCallbacks();
545 void ContainerNode::queuePostAttachCallback(NodeCallback callback, Node* node)
547 if (!s_postAttachCallbackQueue)
548 s_postAttachCallbackQueue = new NodeCallbackQueue;
550 s_postAttachCallbackQueue->append(std::pair<NodeCallback, RefPtr<Node> >(callback, node));
553 void ContainerNode::dispatchPostAttachCallbacks()
555 // We recalculate size() each time through the loop because a callback
556 // can add more callbacks to the end of the queue.
557 for (size_t i = 0; i < s_postAttachCallbackQueue->size(); ++i) {
558 std::pair<NodeCallback, RefPtr<Node> >& pair = (*s_postAttachCallbackQueue)[i];
559 NodeCallback callback = pair.first;
560 Node* node = pair.second.get();
564 s_postAttachCallbackQueue->clear();
567 void ContainerNode::attach()
571 for (Node* child = m_firstChild; child; child = child->nextSibling())
573 EventTargetNode::attach();
575 if (s_attachDepth == 1 && s_postAttachCallbackQueue)
576 dispatchPostAttachCallbacks();
580 void ContainerNode::detach()
582 for (Node* child = m_firstChild; child; child = child->nextSibling())
584 setHasChangedChild(false);
585 EventTargetNode::detach();
588 void ContainerNode::insertedIntoDocument()
590 EventTargetNode::insertedIntoDocument();
591 insertedIntoTree(false);
592 for (Node* child = m_firstChild; child; child = child->nextSibling())
593 child->insertedIntoDocument();
596 void ContainerNode::removedFromDocument()
598 EventTargetNode::removedFromDocument();
599 setInDocument(false);
600 removedFromTree(false);
601 for (Node* child = m_firstChild; child; child = child->nextSibling())
602 child->removedFromDocument();
605 void ContainerNode::insertedIntoTree(bool deep)
609 for (Node* child = m_firstChild; child; child = child->nextSibling())
610 child->insertedIntoTree(true);
613 void ContainerNode::removedFromTree(bool deep)
617 for (Node* child = m_firstChild; child; child = child->nextSibling())
618 child->removedFromTree(true);
621 void ContainerNode::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
623 Node::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
624 if (!changedByParser && childCountDelta)
625 document()->nodeChildrenChanged(this);
626 if (document()->hasNodeListCaches())
627 notifyNodeListsChildrenChanged();
630 void ContainerNode::cloneChildNodes(ContainerNode *clone)
632 // disable the delete button so it's elements are not serialized into the markup
633 if (document()->frame())
634 document()->frame()->editor()->deleteButtonController()->disable();
635 ExceptionCode ec = 0;
636 for (Node* n = firstChild(); n && !ec; n = n->nextSibling())
637 clone->appendChild(n->cloneNode(true), ec);
638 if (document()->frame())
639 document()->frame()->editor()->deleteButtonController()->enable();
642 // FIXME: This doesn't work correctly with transforms.
643 bool ContainerNode::getUpperLeftCorner(FloatPoint& point) const
647 // What is this code really trying to do?
648 RenderObject *o = renderer();
651 if (!o->isInline() || o->isReplaced()) {
652 point = o->localToAbsolute();
656 // find the next text/image child, to get a position
661 else if (o->nextSibling())
662 o = o->nextSibling();
664 RenderObject *next = 0;
665 while (!next && o->parent()) {
667 next = o->nextSibling();
675 if (!o->isInline() || o->isReplaced()) {
676 point = o->localToAbsolute();
680 if (p->element() && p->element() == this && o->isText() && !o->isBR() && !toRenderText(o)->firstTextBox()) {
681 // do nothing - skip unrendered whitespace that is a child or next sibling of the anchor
682 } else if ((o->isText() && !o->isBR()) || o->isReplaced()) {
683 point = o->container()->localToAbsolute();
684 if (o->isText() && toRenderText(o)->firstTextBox()) {
685 point.move(toRenderText(o)->linesBoundingBox().x(),
686 toRenderText(o)->firstTextBox()->root()->topOverflow());
687 } else if (o->isBox()) {
688 RenderBox* box = toRenderBox(o);
689 point.move(box->x(), box->y());
695 // If the target doesn't have any children or siblings that could be used to calculate the scroll position, we must be
696 // at the end of the document. Scroll to the bottom. FIXME: who said anything about scrolling?
697 if (!o && document()->view()) {
698 point = FloatPoint(0, document()->view()->contentsHeight());
704 // FIXME: This doesn't work correctly with transforms.
705 bool ContainerNode::getLowerRightCorner(FloatPoint& point) const
710 RenderObject *o = renderer();
711 if (!o->isInline() || o->isReplaced())
713 RenderBox* box = toRenderBox(o);
714 point = o->localToAbsolute();
715 point.move(box->width(), box->height());
719 // find the last text/image child, to get a position
723 else if (o->previousSibling())
724 o = o->previousSibling();
726 RenderObject *prev = 0;
731 prev = o->previousSibling();
735 if (o->isText() || o->isReplaced()) {
736 point = o->container()->localToAbsolute();
738 RenderText* text = toRenderText(o);
739 IntRect linesBox = text->linesBoundingBox();
740 point.move(linesBox.x() + linesBox.width(), linesBox.height());
742 RenderBox* box = toRenderBox(o);
743 point.move(box->x() + box->width(), box->y() + box->height());
751 IntRect ContainerNode::getRect() const
753 FloatPoint upperLeft, lowerRight;
754 bool foundUpperLeft = getUpperLeftCorner(upperLeft);
755 bool foundLowerRight = getLowerRightCorner(lowerRight);
757 // If we've found one corner, but not the other,
758 // then we should just return a point at the corner that we did find.
759 if (foundUpperLeft != foundLowerRight)
762 lowerRight = upperLeft;
764 upperLeft = lowerRight;
767 lowerRight.setX(max(upperLeft.x(), lowerRight.x()));
768 lowerRight.setY(max(upperLeft.y(), lowerRight.y()));
770 return enclosingIntRect(FloatRect(upperLeft, lowerRight - upperLeft));
773 void ContainerNode::setFocus(bool received)
775 if (focused() == received)
778 EventTargetNode::setFocus(received);
780 // note that we need to recalc the style
784 void ContainerNode::setActive(bool down, bool pause)
786 if (down == active()) return;
788 EventTargetNode::setActive(down);
790 // note that we need to recalc the style
791 // FIXME: Move to Element
793 bool reactsToPress = renderer()->style()->affectedByActiveRules();
796 if (renderer() && renderer()->style()->hasAppearance()) {
797 if (theme()->stateChanged(renderer(), PressedState))
798 reactsToPress = true;
800 if (reactsToPress && pause) {
801 // The delay here is subtle. It relies on an assumption, namely that the amount of time it takes
802 // to repaint the "down" state of the control is about the same time as it would take to repaint the
803 // "up" state. Once you assume this, you can just delay for 100ms - that time (assuming that after you
804 // leave this method, it will be about that long before the flush of the up state happens again).
805 #ifdef HAVE_FUNC_USLEEP
806 double startTime = currentTime();
809 // Ensure there are no pending changes
810 Document::updateDocumentsRendering();
811 // Do an immediate repaint.
813 renderer()->repaint(true);
815 // FIXME: Find a substitute for usleep for Win32.
816 // Better yet, come up with a way of doing this that doesn't use this sort of thing at all.
817 #ifdef HAVE_FUNC_USLEEP
818 // Now pause for a small amount of time (1/10th of a second from before we repainted in the pressed state)
819 double remainingTime = 0.1 - (currentTime() - startTime);
820 if (remainingTime > 0)
821 usleep(static_cast<useconds_t>(remainingTime * 1000000.0));
827 void ContainerNode::setHovered(bool over)
829 if (over == hovered()) return;
831 EventTargetNode::setHovered(over);
833 // note that we need to recalc the style
834 // FIXME: Move to Element
836 if (renderer()->style()->affectedByHoverRules())
838 if (renderer() && renderer()->style()->hasAppearance())
839 theme()->stateChanged(renderer(), HoverState);
843 unsigned ContainerNode::childNodeCount() const
847 for (n = firstChild(); n; n = n->nextSibling())
852 Node *ContainerNode::childNode(unsigned index) const
855 Node *n = firstChild();
856 for (i = 0; n != 0 && i < index; i++)
857 n = n->nextSibling();
861 static void dispatchChildInsertionEvents(Node* child, ExceptionCode& ec)
863 ASSERT(!eventDispatchForbidden());
865 RefPtr<Node> c = child;
866 DocPtr<Document> doc = child->document();
868 if (c->parentNode() && c->parentNode()->inDocument())
869 c->insertedIntoDocument();
871 c->insertedIntoTree(true);
873 if (c->parentNode() &&
874 doc->hasListenerType(Document::DOMNODEINSERTED_LISTENER) &&
875 c->isEventTargetNode()) {
877 EventTargetNodeCast(c.get())->dispatchEvent(MutationEvent::create(eventNames().DOMNodeInsertedEvent, true, false,
878 c->parentNode(), String(), String(), String(), 0), ec);
883 // dispatch the DOMNodeInsertedIntoDocument event to all descendants
884 if (c->inDocument() && doc->hasListenerType(Document::DOMNODEINSERTEDINTODOCUMENT_LISTENER))
885 for (; c; c = c->traverseNextNode(child)) {
886 if (!c->isEventTargetNode())
890 EventTargetNodeCast(c.get())->dispatchEvent(MutationEvent::create(eventNames().DOMNodeInsertedIntoDocumentEvent, false, false,
891 0, String(), String(), String(), 0), ec);
897 static void dispatchChildRemovalEvents(Node* child, ExceptionCode& ec)
899 RefPtr<Node> c = child;
900 DocPtr<Document> doc = child->document();
902 // update auxiliary doc info (e.g. iterators) to note that node is being removed
903 doc->nodeWillBeRemoved(child);
905 // dispatch pre-removal mutation events
906 if (c->parentNode() &&
907 doc->hasListenerType(Document::DOMNODEREMOVED_LISTENER) &&
908 c->isEventTargetNode()) {
910 EventTargetNodeCast(c.get())->dispatchEvent(MutationEvent::create(eventNames().DOMNodeRemovedEvent, true, false,
911 c->parentNode(), String(), String(), String(), 0), ec);
916 // dispatch the DOMNodeRemovedFromDocument event to all descendants
917 if (c->inDocument() && doc->hasListenerType(Document::DOMNODEREMOVEDFROMDOCUMENT_LISTENER))
918 for (; c; c = c->traverseNextNode(child)) {
919 if (!c->isEventTargetNode())
922 EventTargetNodeCast(c.get())->dispatchEvent(MutationEvent::create(eventNames().DOMNodeRemovedFromDocumentEvent, false, false,
923 0, String(), String(), String(), 0), ec);