summaryrefslogtreecommitdiff
path: root/Source/WebCore/dom/ContainerNode.cpp
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-05-07 11:21:11 +0200
committerSimon Hausmann <simon.hausmann@nokia.com>2012-05-07 11:21:11 +0200
commit2cf6c8816a73e0132bd8fa3b509d62d7c51b6e47 (patch)
tree988e8c5b116dd0466244ae2fe5af8ee9be926d76 /Source/WebCore/dom/ContainerNode.cpp
parentdd91e772430dc294e3bf478c119ef8d43c0a3358 (diff)
downloadqtwebkit-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.cpp375
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