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