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 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 "core/dom/ContainerNode.h"
25
26#include "bindings/v8/ExceptionState.h"
27#include "bindings/v8/ExceptionStatePlaceholder.h"
28#include "core/dom/ChildListMutationScope.h"
29#include "core/dom/ContainerNodeAlgorithms.h"
30#include "core/dom/EventNames.h"
31#include "core/dom/ExceptionCode.h"
32#include "core/dom/FullscreenElementStack.h"
33#include "core/dom/MutationEvent.h"
34#include "core/dom/NodeRareData.h"
35#include "core/dom/NodeRenderStyle.h"
36#include "core/dom/NodeTraversal.h"
37#include "core/html/HTMLCollection.h"
38#include "core/rendering/InlineTextBox.h"
39#include "core/rendering/RenderText.h"
40#include "core/rendering/RenderTheme.h"
41#include "core/rendering/RenderWidget.h"
42#include "wtf/Vector.h"
43
44using namespace std;
45
46namespace WebCore {
47
48static void dispatchChildInsertionEvents(Node*);
49static void dispatchChildRemovalEvents(Node*);
50static void updateTreeAfterInsertion(ContainerNode*, Node*, AttachBehavior);
51
52typedef pair<NodeCallback, RefPtr<Node> > CallbackInfo;
53typedef Vector<CallbackInfo> NodeCallbackQueue;
54
55static NodeCallbackQueue* s_postAttachCallbackQueue;
56
57static size_t s_attachDepth;
58
59ChildNodesLazySnapshot* ChildNodesLazySnapshot::latestSnapshot = 0;
60
61#ifndef NDEBUG
62unsigned NoEventDispatchAssertion::s_count = 0;
63#endif
64
65static void collectChildrenAndRemoveFromOldParent(Node* node, NodeVector& nodes, ExceptionState& es)
66{
67    if (node->nodeType() != Node::DOCUMENT_FRAGMENT_NODE) {
68        nodes.append(node);
69        if (ContainerNode* oldParent = node->parentNode())
70            oldParent->removeChild(node, es);
71        return;
72    }
73    getChildNodes(node, nodes);
74    toContainerNode(node)->removeChildren();
75}
76
77void ContainerNode::removeDetachedChildren()
78{
79    if (connectedSubframeCount()) {
80        for (Node* child = firstChild(); child; child = child->nextSibling())
81            child->updateAncestorConnectedSubframeCountForRemoval();
82    }
83    // FIXME: We should be able to ASSERT(!attached()) here: https://bugs.webkit.org/show_bug.cgi?id=107801
84    removeDetachedChildrenInContainer<Node, ContainerNode>(this);
85}
86
87void ContainerNode::takeAllChildrenFrom(ContainerNode* oldParent)
88{
89    NodeVector children;
90    getChildNodes(oldParent, children);
91
92    if (oldParent->document()->hasMutationObserversOfType(MutationObserver::ChildList)) {
93        ChildListMutationScope mutation(oldParent);
94        for (unsigned i = 0; i < children.size(); ++i)
95            mutation.willRemoveChild(children[i].get());
96    }
97
98    // FIXME: We need to do notifyMutationObserversNodeWillDetach() for each child,
99    // probably inside removeDetachedChildrenInContainer.
100
101    oldParent->removeDetachedChildren();
102
103    for (unsigned i = 0; i < children.size(); ++i) {
104        if (children[i]->attached())
105            children[i]->detach();
106        // FIXME: We need a no mutation event version of adoptNode.
107        RefPtr<Node> child = document()->adoptNode(children[i].release(), ASSERT_NO_EXCEPTION);
108        parserAppendChild(child.get());
109        // FIXME: Together with adoptNode above, the tree scope might get updated recursively twice
110        // (if the document changed or oldParent was in a shadow tree, AND *this is in a shadow tree).
111        // Can we do better?
112        treeScope()->adoptIfNeeded(child.get());
113        if (attached() && !child->attached())
114            child->attach();
115    }
116}
117
118ContainerNode::~ContainerNode()
119{
120    if (Document* document = documentInternal())
121        willBeDeletedFrom(document);
122    removeDetachedChildren();
123}
124
125static inline bool isChildTypeAllowed(ContainerNode* newParent, Node* child)
126{
127    if (!child->isDocumentFragment())
128        return newParent->childTypeAllowed(child->nodeType());
129
130    for (Node* node = child->firstChild(); node; node = node->nextSibling()) {
131        if (!newParent->childTypeAllowed(node->nodeType()))
132            return false;
133    }
134    return true;
135}
136
137static inline bool isInTemplateContent(const Node* node)
138{
139    Document* document = node->document();
140    return document && document == document->templateDocument();
141}
142
143static inline bool containsConsideringHostElements(const Node* newChild, const Node* newParent)
144{
145    return (newParent->isInShadowTree() || isInTemplateContent(newParent))
146        ? newChild->containsIncludingHostElements(newParent)
147        : newChild->contains(newParent);
148}
149
150static inline bool checkAcceptChild(ContainerNode* newParent, Node* newChild, Node* oldChild, ExceptionState& es)
151{
152    // Not mentioned in spec: throw NotFoundError if newChild is null
153    if (!newChild) {
154        es.throwDOMException(NotFoundError);
155        return false;
156    }
157
158    // Use common case fast path if possible.
159    if ((newChild->isElementNode() || newChild->isTextNode()) && newParent->isElementNode()) {
160        ASSERT(!newParent->isDocumentTypeNode());
161        ASSERT(isChildTypeAllowed(newParent, newChild));
162        if (containsConsideringHostElements(newChild, newParent)) {
163            es.throwDOMException(HierarchyRequestError);
164            return false;
165        }
166        return true;
167    }
168
169    // This should never happen, but also protect release builds from tree corruption.
170    ASSERT(!newChild->isPseudoElement());
171    if (newChild->isPseudoElement()) {
172        es.throwDOMException(HierarchyRequestError);
173        return false;
174    }
175
176    if (newChild->inDocument() && newChild->isDocumentTypeNode()) {
177        es.throwDOMException(HierarchyRequestError);
178        return false;
179    }
180    if (containsConsideringHostElements(newChild, newParent)) {
181        es.throwDOMException(HierarchyRequestError);
182        return false;
183    }
184
185    if (oldChild && newParent->isDocumentNode()) {
186        if (!toDocument(newParent)->canReplaceChild(newChild, oldChild)) {
187            es.throwDOMException(HierarchyRequestError);
188            return false;
189        }
190    } else if (!isChildTypeAllowed(newParent, newChild)) {
191        es.throwDOMException(HierarchyRequestError);
192        return false;
193    }
194
195    return true;
196}
197
198static inline bool checkAcceptChildGuaranteedNodeTypes(ContainerNode* newParent, Node* newChild, ExceptionState& es)
199{
200    ASSERT(!newParent->isDocumentTypeNode());
201    ASSERT(isChildTypeAllowed(newParent, newChild));
202    if (newChild->contains(newParent)) {
203        es.throwDOMException(HierarchyRequestError);
204        return false;
205    }
206
207    return true;
208}
209
210static inline bool checkAddChild(ContainerNode* newParent, Node* newChild, ExceptionState& es)
211{
212    return checkAcceptChild(newParent, newChild, 0, es);
213}
214
215static inline bool checkReplaceChild(ContainerNode* newParent, Node* newChild, Node* oldChild, ExceptionState& es)
216{
217    return checkAcceptChild(newParent, newChild, oldChild, es);
218}
219
220void ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionState& es, AttachBehavior attachBehavior)
221{
222    // Check that this node is not "floating".
223    // If it is, it can be deleted as a side effect of sending mutation events.
224    ASSERT(refCount() || parentOrShadowHostNode());
225
226    RefPtr<Node> protect(this);
227
228    // insertBefore(node, 0) is equivalent to appendChild(node)
229    if (!refChild) {
230        appendChild(newChild, es, attachBehavior);
231        return;
232    }
233
234    // Make sure adding the new child is OK.
235    if (!checkAddChild(this, newChild.get(), es))
236        return;
237
238    // NotFoundError: Raised if refChild is not a child of this node
239    if (refChild->parentNode() != this) {
240        es.throwDOMException(NotFoundError);
241        return;
242    }
243
244    if (refChild->previousSibling() == newChild || refChild == newChild) // nothing to do
245        return;
246
247    RefPtr<Node> next = refChild;
248
249    NodeVector targets;
250    collectChildrenAndRemoveFromOldParent(newChild.get(), targets, es);
251    if (es.hadException())
252        return;
253    if (targets.isEmpty())
254        return;
255
256    // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events.
257    if (!checkAcceptChildGuaranteedNodeTypes(this, newChild.get(), es))
258        return;
259
260    InspectorInstrumentation::willInsertDOMNode(document(), this);
261
262    ChildListMutationScope mutation(this);
263    for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); ++it) {
264        Node* child = it->get();
265
266        // Due to arbitrary code running in response to a DOM mutation event it's
267        // possible that "next" is no longer a child of "this".
268        // It's also possible that "child" has been inserted elsewhere.
269        // In either of those cases, we'll just stop.
270        if (next->parentNode() != this)
271            break;
272        if (child->parentNode())
273            break;
274
275        treeScope()->adoptIfNeeded(child);
276
277        insertBeforeCommon(next.get(), child);
278
279        updateTreeAfterInsertion(this, child, attachBehavior);
280    }
281
282    dispatchSubtreeModifiedEvent();
283}
284
285void ContainerNode::insertBeforeCommon(Node* nextChild, Node* newChild)
286{
287    NoEventDispatchAssertion assertNoEventDispatch;
288
289    ASSERT(newChild);
290    ASSERT(!newChild->parentNode()); // Use insertBefore if you need to handle reparenting (and want DOM mutation events).
291    ASSERT(!newChild->nextSibling());
292    ASSERT(!newChild->previousSibling());
293    ASSERT(!newChild->isShadowRoot());
294
295    Node* prev = nextChild->previousSibling();
296    ASSERT(m_lastChild != prev);
297    nextChild->setPreviousSibling(newChild);
298    if (prev) {
299        ASSERT(m_firstChild != nextChild);
300        ASSERT(prev->nextSibling() == nextChild);
301        prev->setNextSibling(newChild);
302    } else {
303        ASSERT(m_firstChild == nextChild);
304        m_firstChild = newChild;
305    }
306    newChild->setParentOrShadowHostNode(this);
307    newChild->setPreviousSibling(prev);
308    newChild->setNextSibling(nextChild);
309}
310
311void ContainerNode::parserInsertBefore(PassRefPtr<Node> newChild, Node* nextChild)
312{
313    ASSERT(newChild);
314    ASSERT(nextChild);
315    ASSERT(nextChild->parentNode() == this);
316    ASSERT(!newChild->isDocumentFragment());
317    ASSERT(!hasTagName(HTMLNames::templateTag));
318
319    if (nextChild->previousSibling() == newChild || nextChild == newChild) // nothing to do
320        return;
321
322    if (document() != newChild->document())
323        document()->adoptNode(newChild.get(), ASSERT_NO_EXCEPTION);
324
325    insertBeforeCommon(nextChild, newChild.get());
326
327    newChild->updateAncestorConnectedSubframeCountForInsertion();
328
329    ChildListMutationScope(this).childAdded(newChild.get());
330
331    childrenChanged(true, newChild->previousSibling(), nextChild, 1);
332    ChildNodeInsertionNotifier(this).notify(newChild.get());
333}
334
335void ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionState& es, AttachBehavior attachBehavior)
336{
337    // Check that this node is not "floating".
338    // If it is, it can be deleted as a side effect of sending mutation events.
339    ASSERT(refCount() || parentOrShadowHostNode());
340
341    RefPtr<Node> protect(this);
342
343    if (oldChild == newChild) // nothing to do
344        return;
345
346    if (!oldChild) {
347        es.throwDOMException(NotFoundError);
348        return;
349    }
350
351    // Make sure replacing the old child with the new is ok
352    if (!checkReplaceChild(this, newChild.get(), oldChild, es))
353        return;
354
355    // NotFoundError: Raised if oldChild is not a child of this node.
356    if (oldChild->parentNode() != this) {
357        es.throwDOMException(NotFoundError);
358        return;
359    }
360
361    ChildListMutationScope mutation(this);
362
363    RefPtr<Node> next = oldChild->nextSibling();
364
365    // Remove the node we're replacing
366    RefPtr<Node> removedChild = oldChild;
367    removeChild(oldChild, es);
368    if (es.hadException())
369        return;
370
371    if (next && (next->previousSibling() == newChild || next == newChild)) // nothing to do
372        return;
373
374    // Does this one more time because removeChild() fires a MutationEvent.
375    if (!checkReplaceChild(this, newChild.get(), oldChild, es))
376        return;
377
378    NodeVector targets;
379    collectChildrenAndRemoveFromOldParent(newChild.get(), targets, es);
380    if (es.hadException())
381        return;
382
383    // Does this yet another check because collectChildrenAndRemoveFromOldParent() fires a MutationEvent.
384    if (!checkReplaceChild(this, newChild.get(), oldChild, es))
385        return;
386
387    InspectorInstrumentation::willInsertDOMNode(document(), this);
388
389    // Add the new child(ren)
390    for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); ++it) {
391        Node* child = it->get();
392
393        // Due to arbitrary code running in response to a DOM mutation event it's
394        // possible that "next" is no longer a child of "this".
395        // It's also possible that "child" has been inserted elsewhere.
396        // In either of those cases, we'll just stop.
397        if (next && next->parentNode() != this)
398            break;
399        if (child->parentNode())
400            break;
401
402        treeScope()->adoptIfNeeded(child);
403
404        // Add child before "next".
405        {
406            NoEventDispatchAssertion assertNoEventDispatch;
407            if (next)
408                insertBeforeCommon(next.get(), child);
409            else
410                appendChildToContainer(child, this);
411        }
412
413        updateTreeAfterInsertion(this, child, attachBehavior);
414    }
415
416    dispatchSubtreeModifiedEvent();
417}
418
419static void willRemoveChild(Node* child)
420{
421    ASSERT(child->parentNode());
422    ChildListMutationScope(child->parentNode()).willRemoveChild(child);
423    child->notifyMutationObserversNodeWillDetach();
424    dispatchChildRemovalEvents(child);
425    child->document()->nodeWillBeRemoved(child); // e.g. mutation event listener can create a new range.
426    ChildFrameDisconnector(child).disconnect();
427}
428
429static void willRemoveChildren(ContainerNode* container)
430{
431    NodeVector children;
432    getChildNodes(container, children);
433
434    ChildListMutationScope mutation(container);
435    for (NodeVector::const_iterator it = children.begin(); it != children.end(); it++) {
436        Node* child = it->get();
437        mutation.willRemoveChild(child);
438        child->notifyMutationObserversNodeWillDetach();
439
440        // fire removed from document mutation events.
441        dispatchChildRemovalEvents(child);
442    }
443
444    ChildFrameDisconnector(container).disconnect(ChildFrameDisconnector::DescendantsOnly);
445}
446
447void ContainerNode::disconnectDescendantFrames()
448{
449    ChildFrameDisconnector(this).disconnect();
450}
451
452void ContainerNode::removeChild(Node* oldChild, ExceptionState& es)
453{
454    // Check that this node is not "floating".
455    // If it is, it can be deleted as a side effect of sending mutation events.
456    ASSERT(refCount() || parentOrShadowHostNode());
457
458    RefPtr<Node> protect(this);
459
460    // NotFoundError: Raised if oldChild is not a child of this node.
461    if (!oldChild || oldChild->parentNode() != this) {
462        es.throwDOMException(NotFoundError);
463        return;
464    }
465
466    RefPtr<Node> child = oldChild;
467
468    document()->removeFocusedElementOfSubtree(child.get());
469
470    if (FullscreenElementStack* fullscreen = FullscreenElementStack::fromIfExists(document()))
471        fullscreen->removeFullScreenElementOfSubtree(child.get());
472
473    // Events fired when blurring currently focused node might have moved this
474    // child into a different parent.
475    if (child->parentNode() != this) {
476        es.throwDOMException(NotFoundError);
477        return;
478    }
479
480    willRemoveChild(child.get());
481
482    // Mutation events might have moved this child into a different parent.
483    if (child->parentNode() != this) {
484        es.throwDOMException(NotFoundError);
485        return;
486    }
487
488    {
489        WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
490
491        Node* prev = child->previousSibling();
492        Node* next = child->nextSibling();
493        removeBetween(prev, next, child.get());
494        childrenChanged(false, prev, next, -1);
495        ChildNodeRemovalNotifier(this).notify(child.get());
496    }
497    dispatchSubtreeModifiedEvent();
498}
499
500void ContainerNode::removeBetween(Node* previousChild, Node* nextChild, Node* oldChild)
501{
502    NoEventDispatchAssertion assertNoEventDispatch;
503
504    ASSERT(oldChild);
505    ASSERT(oldChild->parentNode() == this);
506
507    // Remove from rendering tree
508    if (oldChild->attached())
509        oldChild->detach();
510
511    if (nextChild)
512        nextChild->setPreviousSibling(previousChild);
513    if (previousChild)
514        previousChild->setNextSibling(nextChild);
515    if (m_firstChild == oldChild)
516        m_firstChild = nextChild;
517    if (m_lastChild == oldChild)
518        m_lastChild = previousChild;
519
520    oldChild->setPreviousSibling(0);
521    oldChild->setNextSibling(0);
522    oldChild->setParentOrShadowHostNode(0);
523
524    document()->adoptIfNeeded(oldChild);
525}
526
527void ContainerNode::parserRemoveChild(Node* oldChild)
528{
529    ASSERT(oldChild);
530    ASSERT(oldChild->parentNode() == this);
531    ASSERT(!oldChild->isDocumentFragment());
532
533    Node* prev = oldChild->previousSibling();
534    Node* next = oldChild->nextSibling();
535
536    oldChild->updateAncestorConnectedSubframeCountForRemoval();
537
538    ChildListMutationScope(this).willRemoveChild(oldChild);
539    oldChild->notifyMutationObserversNodeWillDetach();
540
541    removeBetween(prev, next, oldChild);
542
543    childrenChanged(true, prev, next, -1);
544    ChildNodeRemovalNotifier(this).notify(oldChild);
545}
546
547// this differs from other remove functions because it forcibly removes all the children,
548// regardless of read-only status or event exceptions, e.g.
549void ContainerNode::removeChildren()
550{
551    if (!m_firstChild)
552        return;
553
554    // The container node can be removed from event handlers.
555    RefPtr<ContainerNode> protect(this);
556
557    if (FullscreenElementStack* fullscreen = FullscreenElementStack::fromIfExists(document()))
558        fullscreen->removeFullScreenElementOfSubtree(this, true);
559
560    // Do any prep work needed before actually starting to detach
561    // and remove... e.g. stop loading frames, fire unload events.
562    willRemoveChildren(protect.get());
563
564    {
565        // Removing focus can cause frames to load, either via events (focusout, blur)
566        // or widget updates (e.g., for <embed>).
567        SubframeLoadingDisabler disabler(this);
568
569        // Exclude this node when looking for removed focusedElement since only
570        // children will be removed.
571        // This must be later than willRemoveChildren, which might change focus
572        // state of a child.
573        document()->removeFocusedElementOfSubtree(this, true);
574    }
575
576    document()->nodeChildrenWillBeRemoved(this);
577
578    NodeVector removedChildren;
579    {
580        WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
581        {
582            NoEventDispatchAssertion assertNoEventDispatch;
583            removedChildren.reserveInitialCapacity(childNodeCount());
584            while (m_firstChild) {
585                removedChildren.append(m_firstChild);
586                removeBetween(0, m_firstChild->nextSibling(), m_firstChild);
587            }
588        }
589
590        childrenChanged(false, 0, 0, -static_cast<int>(removedChildren.size()));
591
592        for (size_t i = 0; i < removedChildren.size(); ++i)
593            ChildNodeRemovalNotifier(this).notify(removedChildren[i].get());
594    }
595
596    dispatchSubtreeModifiedEvent();
597}
598
599void ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionState& es, AttachBehavior attachBehavior)
600{
601    RefPtr<ContainerNode> protect(this);
602
603    // Check that this node is not "floating".
604    // If it is, it can be deleted as a side effect of sending mutation events.
605    ASSERT(refCount() || parentOrShadowHostNode());
606
607    // Make sure adding the new child is ok
608    if (!checkAddChild(this, newChild.get(), es))
609        return;
610
611    if (newChild == m_lastChild) // nothing to do
612        return;
613
614    NodeVector targets;
615    collectChildrenAndRemoveFromOldParent(newChild.get(), targets, es);
616    if (es.hadException())
617        return;
618
619    if (targets.isEmpty())
620        return;
621
622    // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events.
623    if (!checkAcceptChildGuaranteedNodeTypes(this, newChild.get(), es))
624        return;
625
626    InspectorInstrumentation::willInsertDOMNode(document(), this);
627
628    // Now actually add the child(ren)
629    ChildListMutationScope mutation(this);
630    for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); ++it) {
631        Node* child = it->get();
632
633        // If the child has a parent again, just stop what we're doing, because
634        // that means someone is doing something with DOM mutation -- can't re-parent
635        // a child that already has a parent.
636        if (child->parentNode())
637            break;
638
639        treeScope()->adoptIfNeeded(child);
640
641        // Append child to the end of the list
642        {
643            NoEventDispatchAssertion assertNoEventDispatch;
644            appendChildToContainer(child, this);
645        }
646
647        updateTreeAfterInsertion(this, child, attachBehavior);
648    }
649
650    dispatchSubtreeModifiedEvent();
651}
652
653void ContainerNode::parserAppendChild(PassRefPtr<Node> newChild)
654{
655    ASSERT(newChild);
656    ASSERT(!newChild->parentNode()); // Use appendChild if you need to handle reparenting (and want DOM mutation events).
657    ASSERT(!newChild->isDocumentFragment());
658    ASSERT(!hasTagName(HTMLNames::templateTag));
659
660    if (document() != newChild->document())
661        document()->adoptNode(newChild.get(), ASSERT_NO_EXCEPTION);
662
663    Node* last = m_lastChild;
664    {
665        NoEventDispatchAssertion assertNoEventDispatch;
666        // FIXME: This method should take a PassRefPtr.
667        appendChildToContainer(newChild.get(), this);
668        treeScope()->adoptIfNeeded(newChild.get());
669    }
670
671    newChild->updateAncestorConnectedSubframeCountForInsertion();
672
673    ChildListMutationScope(this).childAdded(newChild.get());
674
675    childrenChanged(true, last, 0, 1);
676    ChildNodeInsertionNotifier(this).notify(newChild.get());
677}
678
679void ContainerNode::suspendPostAttachCallbacks()
680{
681    ++s_attachDepth;
682}
683
684void ContainerNode::resumePostAttachCallbacks()
685{
686    if (s_attachDepth == 1) {
687        RefPtr<ContainerNode> protect(this);
688
689        if (s_postAttachCallbackQueue)
690            dispatchPostAttachCallbacks();
691    }
692    --s_attachDepth;
693}
694
695void ContainerNode::queuePostAttachCallback(NodeCallback callback, Node* node)
696{
697    if (!s_postAttachCallbackQueue)
698        s_postAttachCallbackQueue = new NodeCallbackQueue;
699    s_postAttachCallbackQueue->append(CallbackInfo(callback, node));
700}
701
702bool ContainerNode::postAttachCallbacksAreSuspended()
703{
704    return s_attachDepth;
705}
706
707void ContainerNode::dispatchPostAttachCallbacks()
708{
709    // We recalculate size() each time through the loop because a callback
710    // can add more callbacks to the end of the queue.
711    for (size_t i = 0; i < s_postAttachCallbackQueue->size(); ++i) {
712        const CallbackInfo& info = (*s_postAttachCallbackQueue)[i];
713        info.first(info.second.get());
714    }
715    s_postAttachCallbackQueue->clear();
716}
717
718void ContainerNode::attach(const AttachContext& context)
719{
720    attachChildren(context);
721    clearChildNeedsStyleRecalc();
722    Node::attach(context);
723}
724
725void ContainerNode::detach(const AttachContext& context)
726{
727    detachChildren(context);
728    clearChildNeedsStyleRecalc();
729    Node::detach(context);
730}
731
732void ContainerNode::childrenChanged(bool changedByParser, Node*, Node*, int childCountDelta)
733{
734    document()->incDOMTreeVersion();
735    if (!changedByParser && childCountDelta)
736        document()->updateRangesAfterChildrenChanged(this);
737    invalidateNodeListCachesInAncestors();
738}
739
740void ContainerNode::cloneChildNodes(ContainerNode *clone)
741{
742    TrackExceptionState es;
743    for (Node* n = firstChild(); n && !es.hadException(); n = n->nextSibling())
744        clone->appendChild(n->cloneNode(true), es);
745}
746
747
748bool ContainerNode::getUpperLeftCorner(FloatPoint& point) const
749{
750    if (!renderer())
751        return false;
752    // What is this code really trying to do?
753    RenderObject* o = renderer();
754    RenderObject* p = o;
755
756    if (!o->isInline() || o->isReplaced()) {
757        point = o->localToAbsolute(FloatPoint(), UseTransforms);
758        return true;
759    }
760
761    // find the next text/image child, to get a position
762    while (o) {
763        p = o;
764        if (o->firstChild()) {
765            o = o->firstChild();
766        } else if (o->nextSibling()) {
767            o = o->nextSibling();
768        } else {
769            RenderObject* next = 0;
770            while (!next && o->parent()) {
771                o = o->parent();
772                next = o->nextSibling();
773            }
774            o = next;
775
776            if (!o)
777                break;
778        }
779        ASSERT(o);
780
781        if (!o->isInline() || o->isReplaced()) {
782            point = o->localToAbsolute(FloatPoint(), UseTransforms);
783            return true;
784        }
785
786        if (p->node() && p->node() == this && o->isText() && !o->isBR() && !toRenderText(o)->firstTextBox()) {
787            // do nothing - skip unrendered whitespace that is a child or next sibling of the anchor
788        } else if ((o->isText() && !o->isBR()) || o->isReplaced()) {
789            point = FloatPoint();
790            if (o->isText() && toRenderText(o)->firstTextBox()) {
791                point.move(toRenderText(o)->linesBoundingBox().x(), toRenderText(o)->firstTextBox()->root()->lineTop());
792            } else if (o->isBox()) {
793                RenderBox* box = toRenderBox(o);
794                point.moveBy(box->location());
795            }
796            point = o->container()->localToAbsolute(point, UseTransforms);
797            return true;
798        }
799    }
800
801    // If the target doesn't have any children or siblings that could be used to calculate the scroll position, we must be
802    // at the end of the document. Scroll to the bottom. FIXME: who said anything about scrolling?
803    if (!o && document()->view()) {
804        point = FloatPoint(0, document()->view()->contentsHeight());
805        return true;
806    }
807    return false;
808}
809
810bool ContainerNode::getLowerRightCorner(FloatPoint& point) const
811{
812    if (!renderer())
813        return false;
814
815    RenderObject* o = renderer();
816    if (!o->isInline() || o->isReplaced()) {
817        RenderBox* box = toRenderBox(o);
818        point = o->localToAbsolute(LayoutPoint(box->size()), UseTransforms);
819        return true;
820    }
821
822    // find the last text/image child, to get a position
823    while (o) {
824        if (o->lastChild()) {
825            o = o->lastChild();
826        } else if (o->previousSibling()) {
827            o = o->previousSibling();
828        } else {
829            RenderObject* prev = 0;
830        while (!prev) {
831            o = o->parent();
832            if (!o)
833                return false;
834            prev = o->previousSibling();
835        }
836        o = prev;
837        }
838        ASSERT(o);
839        if (o->isText() || o->isReplaced()) {
840            point = FloatPoint();
841            if (o->isText()) {
842                RenderText* text = toRenderText(o);
843                IntRect linesBox = text->linesBoundingBox();
844                if (!linesBox.maxX() && !linesBox.maxY())
845                    continue;
846                point.moveBy(linesBox.maxXMaxYCorner());
847            } else {
848                RenderBox* box = toRenderBox(o);
849                point.moveBy(box->frameRect().maxXMaxYCorner());
850            }
851            point = o->container()->localToAbsolute(point, UseTransforms);
852            return true;
853        }
854    }
855    return true;
856}
857
858// FIXME: This override is only needed for inline anchors without an
859// InlineBox and it does not belong in ContainerNode as it reaches into
860// the render and line box trees.
861// https://code.google.com/p/chromium/issues/detail?id=248354
862LayoutRect ContainerNode::boundingBox() const
863{
864    FloatPoint upperLeft, lowerRight;
865    bool foundUpperLeft = getUpperLeftCorner(upperLeft);
866    bool foundLowerRight = getLowerRightCorner(lowerRight);
867
868    // If we've found one corner, but not the other,
869    // then we should just return a point at the corner that we did find.
870    if (foundUpperLeft != foundLowerRight) {
871        if (foundUpperLeft)
872            lowerRight = upperLeft;
873        else
874            upperLeft = lowerRight;
875    }
876
877    return enclosingLayoutRect(FloatRect(upperLeft, lowerRight.expandedTo(upperLeft) - upperLeft));
878}
879
880void ContainerNode::setFocus(bool received)
881{
882    if (focused() == received)
883        return;
884
885    Node::setFocus(received);
886
887    // note that we need to recalc the style
888    setNeedsStyleRecalc();
889}
890
891void ContainerNode::setActive(bool down, bool pause)
892{
893    if (down == active()) return;
894
895    Node::setActive(down);
896
897    // note that we need to recalc the style
898    // FIXME: Move to Element
899    if (renderer()) {
900        if (renderStyle()->affectedByActive() || (isElementNode() && toElement(this)->childrenAffectedByActive()))
901            setNeedsStyleRecalc();
902        if (renderStyle()->hasAppearance())
903            renderer()->theme()->stateChanged(renderer(), PressedState);
904    }
905}
906
907void ContainerNode::setHovered(bool over)
908{
909    if (over == hovered()) return;
910
911    Node::setHovered(over);
912
913    if (!renderer()) {
914        // When setting hover to false, the style needs to be recalc'd even when
915        // there's no renderer (imagine setting display:none in the :hover class,
916        // if a nil renderer would prevent this element from recalculating its
917        // style, it would never go back to its normal style and remain
918        // stuck in its hovered style).
919        if (!over)
920            setNeedsStyleRecalc();
921
922        return;
923    }
924
925    // note that we need to recalc the style
926    // FIXME: Move to Element
927    if (renderer()) {
928        if (renderStyle()->affectedByHover() || (isElementNode() && toElement(this)->childrenAffectedByHover()))
929            setNeedsStyleRecalc();
930        if (renderer() && renderer()->style()->hasAppearance())
931            renderer()->theme()->stateChanged(renderer(), HoverState);
932    }
933}
934
935PassRefPtr<HTMLCollection> ContainerNode::children()
936{
937    return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLCollection>(this, NodeChildren);
938}
939
940Element* ContainerNode::firstElementChild() const
941{
942    return ElementTraversal::firstWithin(this);
943}
944
945Element* ContainerNode::lastElementChild() const
946{
947    Node* n = lastChild();
948    while (n && !n->isElementNode())
949        n = n->previousSibling();
950    return toElement(n);
951}
952
953unsigned ContainerNode::childElementCount() const
954{
955    unsigned count = 0;
956    Node* n = firstChild();
957    while (n) {
958        count += n->isElementNode();
959        n = n->nextSibling();
960    }
961    return count;
962}
963
964unsigned ContainerNode::childNodeCount() const
965{
966    unsigned count = 0;
967    Node *n;
968    for (n = firstChild(); n; n = n->nextSibling())
969        count++;
970    return count;
971}
972
973Node *ContainerNode::childNode(unsigned index) const
974{
975    unsigned i;
976    Node *n = firstChild();
977    for (i = 0; n != 0 && i < index; i++)
978        n = n->nextSibling();
979    return n;
980}
981
982static void dispatchChildInsertionEvents(Node* child)
983{
984    if (child->isInShadowTree())
985        return;
986
987    ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
988
989    RefPtr<Node> c = child;
990    RefPtr<Document> document = child->document();
991
992    if (c->parentNode() && document->hasListenerType(Document::DOMNODEINSERTED_LISTENER))
993        c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeInsertedEvent, true, c->parentNode()));
994
995    // dispatch the DOMNodeInsertedIntoDocument event to all descendants
996    if (c->inDocument() && document->hasListenerType(Document::DOMNODEINSERTEDINTODOCUMENT_LISTENER)) {
997        for (; c; c = NodeTraversal::next(c.get(), child))
998            c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeInsertedIntoDocumentEvent, false));
999    }
1000}
1001
1002static void dispatchChildRemovalEvents(Node* child)
1003{
1004    if (child->isInShadowTree()) {
1005        InspectorInstrumentation::willRemoveDOMNode(child->document(), child);
1006        return;
1007    }
1008
1009    ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
1010
1011    InspectorInstrumentation::willRemoveDOMNode(child->document(), child);
1012
1013    RefPtr<Node> c = child;
1014    RefPtr<Document> document = child->document();
1015
1016    // dispatch pre-removal mutation events
1017    if (c->parentNode() && document->hasListenerType(Document::DOMNODEREMOVED_LISTENER))
1018        c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeRemovedEvent, true, c->parentNode()));
1019
1020    // dispatch the DOMNodeRemovedFromDocument event to all descendants
1021    if (c->inDocument() && document->hasListenerType(Document::DOMNODEREMOVEDFROMDOCUMENT_LISTENER)) {
1022        for (; c; c = NodeTraversal::next(c.get(), child))
1023            c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeRemovedFromDocumentEvent, false));
1024    }
1025}
1026
1027static void updateTreeAfterInsertion(ContainerNode* parent, Node* child, AttachBehavior attachBehavior)
1028{
1029    ASSERT(parent->refCount());
1030    ASSERT(child->refCount());
1031
1032    ChildListMutationScope(parent).childAdded(child);
1033
1034    parent->childrenChanged(false, child->previousSibling(), child->nextSibling(), 1);
1035
1036    ChildNodeInsertionNotifier(parent).notify(child);
1037
1038    // FIXME: Attachment should be the first operation in this function, but some code
1039    // (for example, HTMLFormControlElement's autofocus support) requires this ordering.
1040    if (parent->attached() && !child->attached() && child->parentNode() == parent) {
1041        if (attachBehavior == AttachLazily)
1042            child->lazyAttach();
1043        else
1044            child->attach();
1045    }
1046
1047    dispatchChildInsertionEvents(child);
1048}
1049
1050#ifndef NDEBUG
1051bool childAttachedAllowedWhenAttachingChildren(ContainerNode* node)
1052{
1053    if (node->isShadowRoot())
1054        return true;
1055
1056    if (node->isInsertionPoint())
1057        return true;
1058
1059    if (node->isElementNode() && toElement(node)->shadow())
1060        return true;
1061
1062    return false;
1063}
1064#endif
1065
1066} // namespace WebCore
1067