diff options
| author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-05-07 11:21:11 +0200 |
|---|---|---|
| committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-05-07 11:21:11 +0200 |
| commit | 2cf6c8816a73e0132bd8fa3b509d62d7c51b6e47 (patch) | |
| tree | 988e8c5b116dd0466244ae2fe5af8ee9be926d76 /Source/WebCore/dom/ContainerNode.cpp | |
| parent | dd91e772430dc294e3bf478c119ef8d43c0a3358 (diff) | |
| download | qtwebkit-2cf6c8816a73e0132bd8fa3b509d62d7c51b6e47.tar.gz | |
Imported WebKit commit 7e538425aa020340619e927792f3d895061fb54b (http://svn.webkit.org/repository/webkit/trunk@116286)
Diffstat (limited to 'Source/WebCore/dom/ContainerNode.cpp')
| -rw-r--r-- | Source/WebCore/dom/ContainerNode.cpp | 375 |
1 files changed, 107 insertions, 268 deletions
diff --git a/Source/WebCore/dom/ContainerNode.cpp b/Source/WebCore/dom/ContainerNode.cpp index 4916eb1fb..20d6f2758 100644 --- a/Source/WebCore/dom/ContainerNode.cpp +++ b/Source/WebCore/dom/ContainerNode.cpp @@ -47,33 +47,38 @@ using namespace std; namespace WebCore { -static void notifyChildInserted(Node*); static void dispatchChildInsertionEvents(Node*); static void dispatchChildRemovalEvents(Node*); +static void updateTreeAfterInsertion(ContainerNode*, Node*, bool shouldLazyAttach); typedef pair<RefPtr<Node>, unsigned> CallbackParameters; typedef pair<NodeCallback, CallbackParameters> CallbackInfo; typedef Vector<CallbackInfo> NodeCallbackQueue; -typedef Vector<RefPtr<Node>, 1> NodeVector; static NodeCallbackQueue* s_postAttachCallbackQueue; static size_t s_attachDepth; static bool s_shouldReEnableMemoryCacheCallsAfterAttach; -static inline void collectNodes(Node* node, NodeVector& nodes) +static void collectTargetNodes(Node* node, NodeVector& nodes) { - for (Node* child = node->firstChild(); child; child = child->nextSibling()) - nodes.append(child); + if (node->nodeType() != Node::DOCUMENT_FRAGMENT_NODE) { + nodes.append(node); + return; + } + getChildNodes(node, nodes); } -static void collectTargetNodes(Node* node, NodeVector& nodes) +static void collectChildrenAndRemoveFromOldParent(Node* node, NodeVector& nodes, ExceptionCode& ec) { if (node->nodeType() != Node::DOCUMENT_FRAGMENT_NODE) { nodes.append(node); + if (ContainerNode* oldParent = node->parentNode()) + oldParent->removeChild(node, ec); return; } - collectNodes(node, nodes); + getChildNodes(node, nodes); + toContainerNode(node)->removeChildren(); } void ContainerNode::removeAllChildren() @@ -84,7 +89,7 @@ void ContainerNode::removeAllChildren() void ContainerNode::takeAllChildrenFrom(ContainerNode* oldParent) { NodeVector children; - collectNodes(oldParent, children); + getChildNodes(oldParent, children); oldParent->removeAllChildren(); for (unsigned i = 0; i < children.size(); ++i) { @@ -134,30 +139,27 @@ bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce return false; } + if (refChild->previousSibling() == newChild || refChild == newChild) // nothing to do + return true; + + RefPtr<Node> next = refChild; + NodeVector targets; - collectTargetNodes(newChild.get(), targets); + collectChildrenAndRemoveFromOldParent(newChild.get(), targets, ec); + if (ec) + return false; if (targets.isEmpty()) return true; - // Now actually add the child(ren) - if (refChild->previousSibling() == newChild || refChild == newChild) // nothing to do - return true; + InspectorInstrumentation::willInsertDOMNode(document(), this); #if ENABLE(MUTATION_OBSERVERS) ChildListMutationScope mutation(this); #endif - RefPtr<Node> next = refChild; - RefPtr<Node> refChildPreviousSibling = refChild->previousSibling(); for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); ++it) { Node* child = it->get(); - // If child is already present in the tree, first remove it from the old location. - if (ContainerNode* oldParent = child->parentNode()) - oldParent->removeChild(child, ec); - if (ec) - return false; - // Due to arbitrary code running in response to a DOM mutation event it's // possible that "next" is no longer a child of "this". // It's also possible that "child" has been inserted elsewhere. @@ -167,29 +169,11 @@ bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce if (child->parentNode()) break; -#if ENABLE(INSPECTOR) - InspectorInstrumentation::willInsertDOMNode(document(), child, this); -#endif - treeScope()->adoptIfNeeded(child); insertBeforeCommon(next.get(), child); - // Send notification about the children change. - childrenChanged(false, refChildPreviousSibling.get(), next.get(), 1); - notifyChildInserted(child); - - // Add child to the rendering tree. - if (attached() && !child->attached() && child->parentNode() == this) { - if (shouldLazyAttach) - child->lazyAttach(); - else - child->attach(); - } - - // Now that the child is attached to the render tree, dispatch - // the relevant mutation events. - dispatchChildInsertionEvents(child); + updateTreeAfterInsertion(this, child, shouldLazyAttach); } dispatchSubtreeModifiedEvent(); @@ -243,7 +227,7 @@ void ContainerNode::parserInsertBefore(PassRefPtr<Node> newChild, Node* nextChil insertBeforeCommon(next.get(), child); childrenChanged(true, nextChildPreviousSibling.get(), nextChild, 1); - notifyChildInserted(child); + ChildNodeInsertionNotifier(this).notify(child); } } @@ -259,7 +243,7 @@ bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce if (oldChild == newChild) // nothing to do return true; - + // Make sure replacing the old child with the new is ok checkReplaceChild(newChild.get(), oldChild, ec); if (ec) @@ -275,7 +259,6 @@ bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce ChildListMutationScope mutation(this); #endif - RefPtr<Node> prev = oldChild->previousSibling(); RefPtr<Node> next = oldChild->nextSibling(); // Remove the node we're replacing @@ -284,83 +267,40 @@ bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce if (ec) return false; - bool isFragment = newChild->nodeType() == DOCUMENT_FRAGMENT_NODE && !newChild->isShadowRoot(); + if (next && (next->previousSibling() == newChild || next == newChild)) // nothing to do + return true; - // Add the new child(ren) - RefPtr<Node> child = isFragment ? newChild->firstChild() : newChild; - while (child) { - // If the new child is already in the right place, we're done. - if (prev && (prev == child || prev == child->previousSibling())) - break; + NodeVector targets; + collectChildrenAndRemoveFromOldParent(newChild.get(), targets, ec); + if (ec) + return false; - // For a fragment we have more children to do. - RefPtr<Node> nextChild = isFragment ? child->nextSibling() : 0; + InspectorInstrumentation::willInsertDOMNode(document(), this); - // Remove child from its old position. - if (ContainerNode* oldParent = child->parentNode()) - oldParent->removeChild(child.get(), ec); - if (ec) - return false; + // Add the new child(ren) + for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); ++it) { + Node* child = it->get(); // Due to arbitrary code running in response to a DOM mutation event it's - // possible that "prev" is no longer a child of "this". + // possible that "next" is no longer a child of "this". // It's also possible that "child" has been inserted elsewhere. // In either of those cases, we'll just stop. - if (prev && prev->parentNode() != this) + if (next && next->parentNode() != this) break; if (child->parentNode()) break; - ASSERT(!child->nextSibling()); - ASSERT(!child->previousSibling()); - -#if ENABLE(INSPECTOR) - InspectorInstrumentation::willInsertDOMNode(document(), child.get(), this); -#endif - - treeScope()->adoptIfNeeded(child.get()); + treeScope()->adoptIfNeeded(child); - // Add child after "prev". + // Add child before "next". forbidEventDispatch(); - Node* next; - if (prev) { - next = prev->nextSibling(); - ASSERT(m_firstChild != next); - prev->setNextSibling(child.get()); - } else { - next = m_firstChild; - m_firstChild = child.get(); - } - if (next) { - ASSERT(m_lastChild != prev); - ASSERT(next->previousSibling() == prev); - next->setPreviousSibling(child.get()); - } else { - ASSERT(m_lastChild == prev); - m_lastChild = child.get(); - } - child->setParent(this); - child->setPreviousSibling(prev.get()); - child->setNextSibling(next); + if (next) + insertBeforeCommon(next.get(), child); + else + appendChildToContainer(child, this); allowEventDispatch(); - childrenChanged(false, prev.get(), next, 1); - notifyChildInserted(child.get()); - - // Add child to the rendering tree - if (attached() && !child->attached() && child->parentNode() == this) { - if (shouldLazyAttach) - child->lazyAttach(); - else - child->attach(); - } - - // Now that the child is attached to the render tree, dispatch - // the relevant mutation events. - dispatchChildInsertionEvents(child.get()); - - prev = child; - child = nextChild.release(); + updateTreeAfterInsertion(this, child, shouldLazyAttach); } dispatchSubtreeModifiedEvent(); @@ -372,7 +312,7 @@ void ContainerNode::willRemove() RefPtr<Node> protect(this); NodeVector children; - collectNodes(this, children); + getChildNodes(this, children); for (size_t i = 0; i < children.size(); ++i) { if (children[i]->parentNode() != this) // Check for child being removed from subtree while removing. continue; @@ -384,11 +324,14 @@ void ContainerNode::willRemove() static void willRemoveChild(Node* child) { - // update auxiliary doc info (e.g. iterators) to note that node is being removed - child->document()->nodeWillBeRemoved(child); +#if ENABLE(MUTATION_OBSERVERS) + ASSERT(child->parentNode()); + ChildListMutationScope(child->parentNode()).willRemoveChild(child); + child->notifyMutationObserversNodeWillDetach(); +#endif - // fire removed from document mutation events. dispatchChildRemovalEvents(child); + child->document()->nodeWillBeRemoved(child); // e.g. mutation event listener can create a new range. child->willRemove(); } @@ -397,7 +340,7 @@ static void willRemoveChildren(ContainerNode* container) container->document()->nodeChildrenWillBeRemoved(container); NodeVector children; - collectNodes(container, children); + getChildNodes(container, children); #if ENABLE(MUTATION_OBSERVERS) ChildListMutationScope mutation(container); @@ -405,6 +348,12 @@ static void willRemoveChildren(ContainerNode* container) for (NodeVector::const_iterator it = children.begin(); it != children.end(); it++) { Node* child = it->get(); + +#if ENABLE(MUTATION_OBSERVERS) + mutation.willRemoveChild(child); + child->notifyMutationObserversNodeWillDetach(); +#endif + // fire removed from document mutation events. dispatchChildRemovalEvents(child); child->willRemove(); @@ -461,11 +410,7 @@ bool ContainerNode::removeChild(Node* oldChild, ExceptionCode& ec) childrenChanged(false, prev, next, -1); - if (child->inDocument()) - child->removedFromDocument(); - else if (child->isContainerNode()) - toContainerNode(child.get())->removedFromTree(true); - + ChildNodeRemovalNotifier(this).notify(child.get()); dispatchSubtreeModifiedEvent(); return child; @@ -511,10 +456,7 @@ void ContainerNode::parserRemoveChild(Node* oldChild) removeBetween(prev, next, oldChild); childrenChanged(true, prev, next, -1); - if (oldChild->inDocument()) - oldChild->removedFromDocument(); - else if (oldChild->isContainerNode()) - toContainerNode(oldChild)->removedFromTree(true); + ChildNodeRemovalNotifier(this).notify(oldChild); } // this differs from other remove functions because it forcibly removes all the children, @@ -575,13 +517,8 @@ void ContainerNode::removeChildren() childrenChanged(false, 0, 0, -static_cast<int>(removedChildrenCount)); - for (i = 0; i < removedChildrenCount; ++i) { - Node* removedChild = removedChildren[i].get(); - if (removedChild->inDocument()) - removedChild->removedFromDocument(); - else if (removedChild->isContainerNode()) - toContainerNode(removedChild)->removedFromTree(true); - } + for (i = 0; i < removedChildrenCount; ++i) + ChildNodeRemovalNotifier(this).notify(removedChildren[i].get()); allowEventDispatch(); dispatchSubtreeModifiedEvent(); @@ -606,64 +543,37 @@ bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, bo return newChild; NodeVector targets; - collectTargetNodes(newChild.get(), targets); + collectChildrenAndRemoveFromOldParent(newChild.get(), targets, ec); + if (ec) + return false; + if (targets.isEmpty()) return true; + InspectorInstrumentation::willInsertDOMNode(document(), this); + #if ENABLE(MUTATION_OBSERVERS) ChildListMutationScope mutation(this); #endif // Now actually add the child(ren) - RefPtr<Node> prev = lastChild(); for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); ++it) { Node* child = it->get(); - // If child is already present in the tree, first remove it - if (ContainerNode* oldParent = child->parentNode()) { - oldParent->removeChild(child, ec); - if (ec) - return false; - - // If the child has a parent again, just stop what we're doing, because - // that means someone is doing something with DOM mutation -- can't re-parent - // a child that already has a parent. - if (child->parentNode()) - break; - } -#if ENABLE(INSPECTOR) - InspectorInstrumentation::willInsertDOMNode(document(), child, this); -#endif + // If the child has a parent again, just stop what we're doing, because + // that means someone is doing something with DOM mutation -- can't re-parent + // a child that already has a parent. + if (child->parentNode()) + break; treeScope()->adoptIfNeeded(child); // Append child to the end of the list forbidEventDispatch(); - child->setParent(this); - if (m_lastChild) { - child->setPreviousSibling(m_lastChild); - m_lastChild->setNextSibling(child); - } else - m_firstChild = child; - m_lastChild = child; + appendChildToContainer(child, this); allowEventDispatch(); - // Send notification about the children change. - childrenChanged(false, prev.get(), 0, 1); - notifyChildInserted(child); - - // Add child to the rendering tree - if (attached() && !child->attached() && child->parentNode() == this) { - if (shouldLazyAttach) - child->lazyAttach(); - else - child->attach(); - } - - // Now that the child is attached to the render tree, dispatch - // the relevant mutation events. - dispatchChildInsertionEvents(child); - prev = child; + updateTreeAfterInsertion(this, child, shouldLazyAttach); } dispatchSubtreeModifiedEvent(); @@ -678,14 +588,14 @@ void ContainerNode::parserAddChild(PassRefPtr<Node> newChild) forbidEventDispatch(); Node* last = m_lastChild; // FIXME: This method should take a PassRefPtr. - appendChildToContainer<Node, ContainerNode>(newChild.get(), this); + appendChildToContainer(newChild.get(), this); treeScope()->adoptIfNeeded(newChild.get()); allowEventDispatch(); - // FIXME: Why doesn't this use notifyChildInserted(newChild) instead? + // FIXME: Why doesn't this use notify(newChild.get()) instead? if (inDocument()) - newChild->insertedIntoDocument(); + ChildNodeInsertionNotifier(this).notifyInsertedIntoDocument(newChild.get()); childrenChanged(true, last, 0, 1); } @@ -709,6 +619,8 @@ void ContainerNode::suspendPostAttachCallbacks() void ContainerNode::resumePostAttachCallbacks() { if (s_attachDepth == 1) { + RefPtr<ContainerNode> protect(this); + if (s_postAttachCallbackQueue) dispatchPostAttachCallbacks(); if (s_shouldReEnableMemoryCacheCallsAfterAttach) { @@ -774,68 +686,6 @@ void ContainerNode::detach() Node::detach(); } -void ContainerNode::insertedIntoDocument() -{ - RefPtr<Node> protect(this); - - Node::insertedIntoDocument(); - insertedIntoTree(false); - - NodeVector children; - collectNodes(this, children); - for (size_t i = 0; i < children.size(); ++i) { - // If we have been removed from the document during this loop, then - // we don't want to tell the rest of our children that they've been - // inserted into the document because they haven't. - if (!inDocument()) - break; - if (children[i]->parentNode() != this) - continue; - children[i]->insertedIntoDocument(); - } -} - -void ContainerNode::removedFromDocument() -{ - Node::removedFromDocument(); - if (document()->cssTarget() == this) - document()->setCSSTarget(0); - removedFromTree(false); - - NodeVector children; - collectNodes(this, children); - for (size_t i = 0; i < children.size(); ++i) { - // If we have been added to the document during this loop, then we - // don't want to tell the rest of our children that they've been - // removed from the document because they haven't. - if (inDocument()) - break; - if (children[i]->parentNode() != this) - continue; - children[i]->removedFromDocument(); - } -} - -void ContainerNode::insertedIntoTree(bool deep) -{ - if (!deep) - return; - for (Node* child = m_firstChild; child; child = child->nextSibling()) { - if (child->isContainerNode()) - toContainerNode(child)->insertedIntoTree(true); - } -} - -void ContainerNode::removedFromTree(bool deep) -{ - if (!deep) - return; - for (Node* child = m_firstChild; child; child = child->nextSibling()) { - if (child->isContainerNode()) - toContainerNode(child)->removedFromTree(true); - } -} - void ContainerNode::childrenChanged(bool changedByParser, Node*, Node*, int childCountDelta) { document()->incDOMTreeVersion(); @@ -927,7 +777,6 @@ bool ContainerNode::getUpperLeftCorner(FloatPoint& point) const return false; } -// FIXME: This doesn't work correctly with transforms. bool ContainerNode::getLowerRightCorner(FloatPoint& point) const { if (!renderer()) @@ -936,8 +785,7 @@ bool ContainerNode::getLowerRightCorner(FloatPoint& point) const RenderObject* o = renderer(); if (!o->isInline() || o->isReplaced()) { RenderBox* box = toRenderBox(o); - point = o->localToAbsolute(FloatPoint(), false, true); - point.move(box->size()); + point = o->localToAbsolute(LayoutPoint(box->size()), false, true); return true; } @@ -962,7 +810,7 @@ bool ContainerNode::getLowerRightCorner(FloatPoint& point) const point = FloatPoint(); if (o->isText()) { RenderText* text = toRenderText(o); - LayoutRect linesBox = text->linesBoundingBox(); + IntRect linesBox = text->linesBoundingBox(); if (!linesBox.maxX() && !linesBox.maxY()) continue; point.moveBy(linesBox.maxXMaxYCorner()); @@ -1083,23 +931,6 @@ Node *ContainerNode::childNode(unsigned index) const return n; } -static void notifyChildInserted(Node* child) -{ - ASSERT(!eventDispatchForbidden()); - -#if ENABLE(INSPECTOR) - InspectorInstrumentation::didInsertDOMNode(child->document(), child); -#endif - - RefPtr<Node> c = child; - RefPtr<Document> document = child->document(); - - Node* parentOrHostNode = c->parentOrHostNode(); - if (parentOrHostNode && parentOrHostNode->inDocument()) - c->insertedIntoDocument(); - else if (c->isContainerNode()) - toContainerNode(c.get())->insertedIntoTree(true); -} static void dispatchChildInsertionEvents(Node* child) { @@ -1111,13 +942,6 @@ static void dispatchChildInsertionEvents(Node* child) RefPtr<Node> c = child; RefPtr<Document> document = child->document(); -#if ENABLE(MUTATION_OBSERVERS) - if (c->parentNode()) { - ChildListMutationScope mutation(c->parentNode()); - mutation.childAdded(c.get()); - } -#endif - if (c->parentNode() && document->hasListenerType(Document::DOMNODEINSERTED_LISTENER)) c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeInsertedEvent, true, c->parentNode())); @@ -1135,21 +959,11 @@ static void dispatchChildRemovalEvents(Node* child) ASSERT(!eventDispatchForbidden()); -#if ENABLE(INSPECTOR) InspectorInstrumentation::willRemoveDOMNode(child->document(), child); -#endif RefPtr<Node> c = child; RefPtr<Document> document = child->document(); -#if ENABLE(MUTATION_OBSERVERS) - if (c->parentNode()) { - ChildListMutationScope mutation(c->parentNode()); - mutation.willRemoveChild(c.get()); - c->notifyMutationObserversNodeWillDetach(); - } -#endif - // dispatch pre-removal mutation events if (c->parentNode() && document->hasListenerType(Document::DOMNODEREMOVED_LISTENER)) c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeRemovedEvent, true, c->parentNode())); @@ -1161,4 +975,29 @@ static void dispatchChildRemovalEvents(Node* child) } } +static void updateTreeAfterInsertion(ContainerNode* parent, Node* child, bool shouldLazyAttach) +{ + ASSERT(parent->refCount()); + ASSERT(child->refCount()); + +#if ENABLE(MUTATION_OBSERVERS) + ChildListMutationScope(parent).childAdded(child); +#endif + + parent->childrenChanged(false, child->previousSibling(), child->nextSibling(), 1); + + ChildNodeInsertionNotifier(parent).notify(child); + + // FIXME: Attachment should be the first operation in this function, but some code + // (for example, HTMLFormControlElement's autofocus support) requires this ordering. + if (parent->attached() && !child->attached() && child->parentNode() == parent) { + if (shouldLazyAttach) + child->lazyAttach(); + else + child->attach(); + } + + dispatchChildInsertionEvents(child); +} + } // namespace WebCore |
