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