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 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"
30 #include "EventNames.h"
31 #include "ExceptionCode.h"
32 #include "FloatRect.h"
34 #include "FrameView.h"
35 #include "InlineTextBox.h"
36 #include "MutationEvent.h"
37 #include "RenderTheme.h"
38 #include "RootInlineBox.h"
39 #include "SystemTime.h"
40 #include <wtf/Vector.h>
44 static void dispatchChildInsertionEvents(Node
*, ExceptionCode
&);
45 static void dispatchChildRemovalEvents(Node
*, ExceptionCode
&);
47 typedef Vector
<std::pair
<NodeCallback
, RefPtr
<Node
> > > NodeCallbackQueue
;
48 static NodeCallbackQueue
* s_postAttachCallbackQueue
= 0;
50 static size_t s_attachDepth
= 0;
52 ContainerNode::ContainerNode(Document
* doc
, bool isElement
)
53 : EventTargetNode(doc
, isElement
, true)
59 void ContainerNode::removeAllChildren()
61 removeAllChildrenInContainer
<Node
, ContainerNode
>(this);
64 ContainerNode::~ContainerNode()
69 bool ContainerNode::insertBefore(PassRefPtr
<Node
> newChild
, Node
* refChild
, ExceptionCode
& ec
, bool shouldLazyAttach
)
71 // Check that this node is not "floating".
72 // If it is, it can be deleted as a side effect of sending mutation events.
73 ASSERT(refCount() || parent());
77 // insertBefore(node, 0) is equivalent to appendChild(node)
79 return appendChild(newChild
, ec
, shouldLazyAttach
);
81 // Make sure adding the new child is OK.
82 checkAddChild(newChild
.get(), ec
);
86 // NOT_FOUND_ERR: Raised if refChild is not a child of this node
87 if (refChild
->parentNode() != this) {
92 bool isFragment
= newChild
->nodeType() == DOCUMENT_FRAGMENT_NODE
;
94 // If newChild is a DocumentFragment with no children; there's nothing to do.
96 if (isFragment
&& !newChild
->firstChild())
99 // Now actually add the child(ren)
100 if (refChild
->previousSibling() == newChild
|| refChild
== newChild
) // nothing to do
103 RefPtr
<Node
> next
= refChild
;
104 RefPtr
<Node
> prev
= refChild
->previousSibling();
106 int childCountDelta
= 0;
107 RefPtr
<Node
> child
= isFragment
? newChild
->firstChild() : newChild
;
109 RefPtr
<Node
> nextChild
= isFragment
? child
->nextSibling() : 0;
111 // If child is already present in the tree, first remove it from the old location.
112 if (Node
* oldParent
= child
->parentNode())
113 oldParent
->removeChild(child
.get(), ec
);
117 // FIXME: After sending the mutation events, "this" could be destroyed.
118 // We can prevent that by doing a "ref", but first we have to make sure
119 // that no callers call with ref count == 0 and parent = 0 (as of this
120 // writing, there are definitely callers who call that way).
122 // Due to arbitrary code running in response to a DOM mutation event it's
123 // possible that "next" is no longer a child of "this".
124 // It's also possible that "child" has been inserted elsewhere.
125 // In either of those cases, we'll just stop.
126 if (next
->parentNode() != this)
128 if (child
->parentNode())
131 ASSERT(!child
->nextSibling());
132 ASSERT(!child
->previousSibling());
136 // Add child before "next".
137 forbidEventDispatch();
138 Node
* prev
= next
->previousSibling();
139 ASSERT(m_lastChild
!= prev
);
140 next
->setPreviousSibling(child
.get());
142 ASSERT(m_firstChild
!= next
);
143 ASSERT(prev
->nextSibling() == next
);
144 prev
->setNextSibling(child
.get());
146 ASSERT(m_firstChild
== next
);
147 m_firstChild
= child
.get();
149 child
->setParent(this);
150 child
->setPreviousSibling(prev
);
151 child
->setNextSibling(next
.get());
152 allowEventDispatch();
154 // Dispatch the mutation events.
155 dispatchChildInsertionEvents(child
.get(), ec
);
157 // Add child to the rendering tree.
158 if (attached() && !child
->attached() && child
->parent() == this) {
159 if (shouldLazyAttach
)
165 child
= nextChild
.release();
168 document()->setDocumentChanged(true);
170 childrenChanged(false, prev
.get(), next
.get(), childCountDelta
);
171 dispatchSubtreeModifiedEvent();
175 bool ContainerNode::replaceChild(PassRefPtr
<Node
> newChild
, Node
* oldChild
, ExceptionCode
& ec
, bool shouldLazyAttach
)
177 // Check that this node is not "floating".
178 // If it is, it can be deleted as a side effect of sending mutation events.
179 ASSERT(refCount() || parent());
183 if (oldChild
== newChild
) // nothing to do
186 // Make sure replacing the old child with the new is ok
187 checkReplaceChild(newChild
.get(), oldChild
, ec
);
191 // NOT_FOUND_ERR: Raised if oldChild is not a child of this node.
192 if (!oldChild
|| oldChild
->parentNode() != this) {
197 RefPtr
<Node
> prev
= oldChild
->previousSibling();
198 RefPtr
<Node
> next
= oldChild
->nextSibling();
200 // Remove the node we're replacing
201 RefPtr
<Node
> removedChild
= oldChild
;
202 removeChild(oldChild
, ec
);
206 // FIXME: After sending the mutation events, "this" could be destroyed.
207 // We can prevent that by doing a "ref", but first we have to make sure
208 // that no callers call with ref count == 0 and parent = 0 (as of this
209 // writing, there are definitely callers who call that way).
211 bool isFragment
= newChild
->nodeType() == DOCUMENT_FRAGMENT_NODE
;
213 // Add the new child(ren)
214 int childCountDelta
= 0;
215 RefPtr
<Node
> child
= isFragment
? newChild
->firstChild() : newChild
;
217 // If the new child is already in the right place, we're done.
218 if (prev
&& (prev
== child
|| prev
== child
->previousSibling()))
221 // For a fragment we have more children to do.
222 RefPtr
<Node
> nextChild
= isFragment
? child
->nextSibling() : 0;
224 // Remove child from its old position.
225 if (Node
* oldParent
= child
->parentNode())
226 oldParent
->removeChild(child
.get(), ec
);
230 // Due to arbitrary code running in response to a DOM mutation event it's
231 // possible that "prev" is no longer a child of "this".
232 // It's also possible that "child" has been inserted elsewhere.
233 // In either of those cases, we'll just stop.
234 if (prev
&& prev
->parentNode() != this)
236 if (child
->parentNode())
241 ASSERT(!child
->nextSibling());
242 ASSERT(!child
->previousSibling());
244 // Add child after "prev".
245 forbidEventDispatch();
248 next
= prev
->nextSibling();
249 ASSERT(m_firstChild
!= next
);
250 prev
->setNextSibling(child
.get());
253 m_firstChild
= child
.get();
256 ASSERT(m_lastChild
!= prev
);
257 ASSERT(next
->previousSibling() == prev
);
258 next
->setPreviousSibling(child
.get());
260 ASSERT(m_lastChild
== prev
);
261 m_lastChild
= child
.get();
263 child
->setParent(this);
264 child
->setPreviousSibling(prev
.get());
265 child
->setNextSibling(next
);
266 allowEventDispatch();
268 // Dispatch the mutation events
269 dispatchChildInsertionEvents(child
.get(), ec
);
271 // Add child to the rendering tree
272 if (attached() && !child
->attached() && child
->parent() == this) {
273 if (shouldLazyAttach
)
280 child
= nextChild
.release();
283 document()->setDocumentChanged(true);
285 childrenChanged(false, prev
.get(), next
.get(), childCountDelta
);
286 dispatchSubtreeModifiedEvent();
290 void ContainerNode::willRemove()
292 for (Node
*n
= m_firstChild
; n
!= 0; n
= n
->nextSibling())
294 EventTargetNode::willRemove();
297 static ExceptionCode
willRemoveChild(Node
*child
)
299 ExceptionCode ec
= 0;
301 // fire removed from document mutation events.
302 dispatchChildRemovalEvents(child
, ec
);
306 if (child
->attached())
312 bool ContainerNode::removeChild(Node
* oldChild
, ExceptionCode
& ec
)
314 // Check that this node is not "floating".
315 // If it is, it can be deleted as a side effect of sending mutation events.
316 ASSERT(refCount() || parent());
320 // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
321 if (isReadOnlyNode()) {
322 ec
= NO_MODIFICATION_ALLOWED_ERR
;
326 // NOT_FOUND_ERR: Raised if oldChild is not a child of this node.
327 if (!oldChild
|| oldChild
->parentNode() != this) {
332 RefPtr
<Node
> child
= oldChild
;
334 ec
= willRemoveChild(child
.get());
338 // Mutation events might have moved this child into a different parent.
339 if (child
->parentNode() != this) {
344 document()->removeFocusedNodeOfSubtree(child
.get());
346 // FIXME: After sending the mutation events, "this" could be destroyed.
347 // We can prevent that by doing a "ref", but first we have to make sure
348 // that no callers call with ref count == 0 and parent = 0 (as of this
349 // writing, there are definitely callers who call that way).
351 forbidEventDispatch();
353 // Remove from rendering tree
354 if (child
->attached())
359 prev
= child
->previousSibling();
360 next
= child
->nextSibling();
363 next
->setPreviousSibling(prev
);
365 prev
->setNextSibling(next
);
366 if (m_firstChild
== child
)
368 if (m_lastChild
== child
)
371 child
->setPreviousSibling(0);
372 child
->setNextSibling(0);
375 allowEventDispatch();
377 document()->setDocumentChanged(true);
379 // Dispatch post-removal mutation events
380 childrenChanged(false, prev
, next
, -1);
381 dispatchSubtreeModifiedEvent();
383 if (child
->inDocument())
384 child
->removedFromDocument();
386 child
->removedFromTree(true);
391 // this differs from other remove functions because it forcibly removes all the children,
392 // regardless of read-only status or event exceptions, e.g.
393 bool ContainerNode::removeChildren()
400 // do any prep work needed before actually starting to detach
401 // and remove... e.g. stop loading frames, fire unload events
402 for (n
= m_firstChild
; n
; n
= n
->nextSibling())
405 // exclude this node when looking for removed focusedNode since only children will be removed
406 document()->removeFocusedNodeOfSubtree(this, true);
408 forbidEventDispatch();
409 int childCountDelta
= 0;
410 while ((n
= m_firstChild
) != 0) {
413 Node
*next
= n
->nextSibling();
417 // Remove the node from the tree before calling detach or removedFromDocument (4427024, 4129744)
418 n
->setPreviousSibling(0);
419 n
->setNextSibling(0);
423 if (n
== m_lastChild
)
430 n
->removedFromDocument();
434 allowEventDispatch();
436 // Dispatch a single post-removal mutation event denoting a modified subtree.
437 childrenChanged(false, 0, 0, childCountDelta
);
438 dispatchSubtreeModifiedEvent();
443 bool ContainerNode::appendChild(PassRefPtr
<Node
> newChild
, ExceptionCode
& ec
, bool shouldLazyAttach
)
445 // Check that this node is not "floating".
446 // If it is, it can be deleted as a side effect of sending mutation events.
447 ASSERT(refCount() || parent());
451 // Make sure adding the new child is ok
452 checkAddChild(newChild
.get(), ec
);
456 if (newChild
== m_lastChild
) // nothing to do
459 bool isFragment
= newChild
->nodeType() == DOCUMENT_FRAGMENT_NODE
;
461 // If newChild is a DocumentFragment with no children.... there's nothing to do.
462 // Just return the document fragment
463 if (isFragment
&& !newChild
->firstChild())
466 // Now actually add the child(ren)
467 int childCountDelta
= 0;
468 RefPtr
<Node
> prev
= lastChild();
469 RefPtr
<Node
> child
= isFragment
? newChild
->firstChild() : newChild
;
471 // For a fragment we have more children to do.
472 RefPtr
<Node
> nextChild
= isFragment
? child
->nextSibling() : 0;
474 // If child is already present in the tree, first remove it
475 if (Node
* oldParent
= child
->parentNode()) {
476 oldParent
->removeChild(child
.get(), ec
);
480 // If the child has a parent again, just stop what we're doing, because
481 // that means someone is doing something with DOM mutation -- can't re-parent
482 // a child that already has a parent.
483 if (child
->parentNode())
487 // Append child to the end of the list
489 forbidEventDispatch();
490 child
->setParent(this);
492 child
->setPreviousSibling(m_lastChild
);
493 m_lastChild
->setNextSibling(child
.get());
495 m_firstChild
= child
.get();
496 m_lastChild
= child
.get();
497 allowEventDispatch();
499 // Dispatch the mutation events
500 dispatchChildInsertionEvents(child
.get(), ec
);
502 // Add child to the rendering tree
503 if (attached() && !child
->attached() && child
->parent() == this) {
504 if (shouldLazyAttach
)
510 child
= nextChild
.release();
513 document()->setDocumentChanged(true);
514 childrenChanged(false, prev
.get(), 0, childCountDelta
);
515 dispatchSubtreeModifiedEvent();
519 ContainerNode
* ContainerNode::addChild(PassRefPtr
<Node
> newChild
)
521 // This function is only used during parsing.
522 // It does not send any DOM mutation events.
524 // Check for consistency with DTD, but only when parsing HTML.
525 if (document()->isHTMLDocument() && !childAllowed(newChild
.get()))
528 forbidEventDispatch();
529 Node
* last
= m_lastChild
;
530 appendChildToContainer
<Node
, ContainerNode
>(newChild
.get(), this);
531 allowEventDispatch();
533 document()->incDOMTreeVersion();
535 newChild
->insertedIntoDocument();
536 childrenChanged(true, last
, 0, 1);
538 if (newChild
->isElementNode())
539 return static_cast<ContainerNode
*>(newChild
.get());
543 void ContainerNode::suspendPostAttachCallbacks()
548 void ContainerNode::resumePostAttachCallbacks()
550 if (s_attachDepth
== 1 && s_postAttachCallbackQueue
)
551 dispatchPostAttachCallbacks();
555 void ContainerNode::queuePostAttachCallback(NodeCallback callback
, Node
* node
)
557 if (!s_postAttachCallbackQueue
)
558 s_postAttachCallbackQueue
= new NodeCallbackQueue
;
560 s_postAttachCallbackQueue
->append(std::pair
<NodeCallback
, RefPtr
<Node
> >(callback
, node
));
563 void ContainerNode::dispatchPostAttachCallbacks()
565 // We recalculate size() each time through the loop because a callback
566 // can add more callbacks to the end of the queue.
567 for (size_t i
= 0; i
< s_postAttachCallbackQueue
->size(); ++i
) {
568 std::pair
<NodeCallback
, RefPtr
<Node
> >& pair
= (*s_postAttachCallbackQueue
)[i
];
569 NodeCallback callback
= pair
.first
;
570 Node
* node
= pair
.second
.get();
574 s_postAttachCallbackQueue
->clear();
577 void ContainerNode::attach()
581 for (Node
* child
= m_firstChild
; child
; child
= child
->nextSibling())
583 EventTargetNode::attach();
585 if (s_attachDepth
== 1 && s_postAttachCallbackQueue
)
586 dispatchPostAttachCallbacks();
590 void ContainerNode::detach()
592 for (Node
* child
= m_firstChild
; child
; child
= child
->nextSibling())
594 setHasChangedChild(false);
595 EventTargetNode::detach();
598 void ContainerNode::insertedIntoDocument()
600 EventTargetNode::insertedIntoDocument();
601 for (Node
*child
= m_firstChild
; child
; child
= child
->nextSibling())
602 child
->insertedIntoDocument();
605 void ContainerNode::removedFromDocument()
607 EventTargetNode::removedFromDocument();
608 for (Node
*child
= m_firstChild
; child
; child
= child
->nextSibling())
609 child
->removedFromDocument();
612 void ContainerNode::insertedIntoTree(bool deep
)
614 EventTargetNode::insertedIntoTree(deep
);
616 for (Node
*child
= m_firstChild
; child
; child
= child
->nextSibling())
617 child
->insertedIntoTree(deep
);
621 void ContainerNode::removedFromTree(bool deep
)
623 EventTargetNode::removedFromTree(deep
);
625 for (Node
*child
= m_firstChild
; child
; child
= child
->nextSibling())
626 child
->removedFromTree(deep
);
630 void ContainerNode::childrenChanged(bool changedByParser
, Node
* beforeChange
, Node
* afterChange
, int childCountDelta
)
632 Node::childrenChanged(changedByParser
, beforeChange
, afterChange
, childCountDelta
);
633 if (!changedByParser
&& childCountDelta
)
634 document()->nodeChildrenChanged(this);
635 if (document()->hasNodeListCaches())
636 notifyNodeListsChildrenChanged();
639 void ContainerNode::cloneChildNodes(ContainerNode
*clone
)
641 // disable the delete button so it's elements are not serialized into the markup
642 if (document()->frame())
643 document()->frame()->editor()->deleteButtonController()->disable();
644 ExceptionCode ec
= 0;
645 for (Node
* n
= firstChild(); n
&& !ec
; n
= n
->nextSibling())
646 clone
->appendChild(n
->cloneNode(true), ec
);
647 if (document()->frame())
648 document()->frame()->editor()->deleteButtonController()->enable();
651 // FIXME: This doesn't work correctly with transforms.
652 bool ContainerNode::getUpperLeftCorner(FloatPoint
& point
) const
656 // What is this code really trying to do?
657 RenderObject
*o
= renderer();
660 if (!o
->isInline() || o
->isReplaced()) {
661 point
= o
->localToAbsolute();
665 // find the next text/image child, to get a position
670 else if (o
->nextSibling())
671 o
= o
->nextSibling();
673 RenderObject
*next
= 0;
674 while (!next
&& o
->parent()) {
676 next
= o
->nextSibling();
684 if (!o
->isInline() || o
->isReplaced()) {
685 point
= o
->localToAbsolute();
689 if (p
->element() && p
->element() == this && o
->isText() && !o
->isBR() && !static_cast<RenderText
*>(o
)->firstTextBox()) {
690 // do nothing - skip unrendered whitespace that is a child or next sibling of the anchor
691 } else if ((o
->isText() && !o
->isBR()) || o
->isReplaced()) {
692 point
= o
->container()->localToAbsolute();
693 if (o
->isText() && static_cast<RenderText
*>(o
)->firstTextBox()) {
694 point
.move(static_cast<RenderText
*>(o
)->minXPos(),
695 static_cast<RenderText
*>(o
)->firstTextBox()->root()->topOverflow());
697 point
.move(o
->xPos(), o
->yPos());
702 // If the target doesn't have any children or siblings that could be used to calculate the scroll position, we must be
703 // at the end of the document. Scroll to the bottom. FIXME: who said anything about scrolling?
704 if (!o
&& document()->view()) {
705 point
= FloatPoint(0, document()->view()->contentsHeight());
711 // FIXME: This doesn't work correctly with transforms.
712 bool ContainerNode::getLowerRightCorner(FloatPoint
& point
) const
717 RenderObject
*o
= renderer();
718 if (!o
->isInline() || o
->isReplaced())
720 point
= o
->localToAbsolute();
721 point
.move(o
->width(),
722 o
->height() + o
->borderTopExtra() + o
->borderBottomExtra());
726 // find the last text/image child, to get a position
730 else if (o
->previousSibling())
731 o
= o
->previousSibling();
733 RenderObject
*prev
= 0;
738 prev
= o
->previousSibling();
742 if (o
->isText() || o
->isReplaced()) {
743 point
= o
->container()->localToAbsolute();
746 xOffset
= static_cast<RenderText
*>(o
)->minXPos() + o
->width();
748 xOffset
= o
->xPos() + o
->width();
750 point
.move(xOffset
, o
->yPos() + o
->height());
757 IntRect
ContainerNode::getRect() const
759 FloatPoint upperLeft
, lowerRight
;
760 bool foundUpperLeft
= getUpperLeftCorner(upperLeft
);
761 bool foundLowerRight
= getLowerRightCorner(lowerRight
);
763 // If we've found one corner, but not the other,
764 // then we should just return a point at the corner that we did find.
765 if (foundUpperLeft
!= foundLowerRight
)
768 lowerRight
= upperLeft
;
770 upperLeft
= lowerRight
;
773 lowerRight
.setX(max(upperLeft
.x(), lowerRight
.x()));
774 lowerRight
.setY(max(upperLeft
.y(), lowerRight
.y()));
776 return enclosingIntRect(FloatRect(upperLeft
, lowerRight
- upperLeft
));
779 void ContainerNode::setFocus(bool received
)
781 if (focused() == received
)
784 EventTargetNode::setFocus(received
);
786 // note that we need to recalc the style
790 void ContainerNode::setActive(bool down
, bool pause
)
792 if (down
== active()) return;
794 EventTargetNode::setActive(down
);
796 // note that we need to recalc the style
797 // FIXME: Move to Element
799 bool reactsToPress
= renderer()->style()->affectedByActiveRules();
802 if (renderer() && renderer()->style()->hasAppearance()) {
803 if (theme()->stateChanged(renderer(), PressedState
))
804 reactsToPress
= true;
806 if (reactsToPress
&& pause
) {
807 // The delay here is subtle. It relies on an assumption, namely that the amount of time it takes
808 // to repaint the "down" state of the control is about the same time as it would take to repaint the
809 // "up" state. Once you assume this, you can just delay for 100ms - that time (assuming that after you
810 // leave this method, it will be about that long before the flush of the up state happens again).
811 #ifdef HAVE_FUNC_USLEEP
812 double startTime
= currentTime();
815 // Ensure there are no pending changes
816 Document::updateDocumentsRendering();
817 // Do an immediate repaint.
819 renderer()->repaint(true);
821 // FIXME: Find a substitute for usleep for Win32.
822 // Better yet, come up with a way of doing this that doesn't use this sort of thing at all.
823 #ifdef HAVE_FUNC_USLEEP
824 // Now pause for a small amount of time (1/10th of a second from before we repainted in the pressed state)
825 double remainingTime
= 0.1 - (currentTime() - startTime
);
826 if (remainingTime
> 0)
827 usleep(static_cast<useconds_t
>(remainingTime
* 1000000.0));
833 void ContainerNode::setHovered(bool over
)
835 if (over
== hovered()) return;
837 EventTargetNode::setHovered(over
);
839 // note that we need to recalc the style
840 // FIXME: Move to Element
842 if (renderer()->style()->affectedByHoverRules())
844 if (renderer() && renderer()->style()->hasAppearance())
845 theme()->stateChanged(renderer(), HoverState
);
849 unsigned ContainerNode::childNodeCount() const
853 for (n
= firstChild(); n
; n
= n
->nextSibling())
858 Node
*ContainerNode::childNode(unsigned index
) const
861 Node
*n
= firstChild();
862 for (i
= 0; n
!= 0 && i
< index
; i
++)
863 n
= n
->nextSibling();
867 static void dispatchChildInsertionEvents(Node
* child
, ExceptionCode
& ec
)
869 ASSERT(!eventDispatchForbidden());
871 RefPtr
<Node
> c
= child
;
872 DocPtr
<Document
> doc
= child
->document();
874 if (c
->parentNode() && c
->parentNode()->inDocument())
875 c
->insertedIntoDocument();
877 c
->insertedIntoTree(true);
879 if (c
->parentNode() &&
880 doc
->hasListenerType(Document::DOMNODEINSERTED_LISTENER
) &&
881 c
->isEventTargetNode()) {
883 EventTargetNodeCast(c
.get())->dispatchEvent(MutationEvent::create(eventNames().DOMNodeInsertedEvent
, true, false,
884 c
->parentNode(), String(), String(), String(), 0), ec
);
889 // dispatch the DOMNodeInsertedIntoDocument event to all descendants
890 if (c
->inDocument() && doc
->hasListenerType(Document::DOMNODEINSERTEDINTODOCUMENT_LISTENER
))
891 for (; c
; c
= c
->traverseNextNode(child
)) {
892 if (!c
->isEventTargetNode())
896 EventTargetNodeCast(c
.get())->dispatchEvent(MutationEvent::create(eventNames().DOMNodeInsertedIntoDocumentEvent
, false, false,
897 0, String(), String(), String(), 0), ec
);
903 static void dispatchChildRemovalEvents(Node
* child
, ExceptionCode
& ec
)
905 RefPtr
<Node
> c
= child
;
906 DocPtr
<Document
> doc
= child
->document();
908 // update auxiliary doc info (e.g. iterators) to note that node is being removed
909 doc
->nodeWillBeRemoved(child
);
911 // dispatch pre-removal mutation events
912 if (c
->parentNode() &&
913 doc
->hasListenerType(Document::DOMNODEREMOVED_LISTENER
) &&
914 c
->isEventTargetNode()) {
916 EventTargetNodeCast(c
.get())->dispatchEvent(MutationEvent::create(eventNames().DOMNodeRemovedEvent
, true, false,
917 c
->parentNode(), String(), String(), String(), 0), ec
);
922 // dispatch the DOMNodeRemovedFromDocument event to all descendants
923 if (c
->inDocument() && doc
->hasListenerType(Document::DOMNODEREMOVEDFROMDOCUMENT_LISTENER
))
924 for (; c
; c
= c
->traverseNextNode(child
)) {
925 if (!c
->isEventTargetNode())
928 EventTargetNodeCast(c
.get())->dispatchEvent(MutationEvent::create(eventNames().DOMNodeRemovedFromDocumentEvent
, false, false,
929 0, String(), String(), String(), 0), ec
);