summaryrefslogtreecommitdiffstats
path: root/WebCore/dom/ContainerNode.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/dom/ContainerNode.cpp')
-rw-r--r--WebCore/dom/ContainerNode.cpp159
1 files changed, 78 insertions, 81 deletions
diff --git a/WebCore/dom/ContainerNode.cpp b/WebCore/dom/ContainerNode.cpp
index 958fc4e..91b633f 100644
--- a/WebCore/dom/ContainerNode.cpp
+++ b/WebCore/dom/ContainerNode.cpp
@@ -2,7 +2,7 @@
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* (C) 2001 Dirk Mueller (mueller@kde.org)
- * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -32,6 +32,7 @@
#include "FrameView.h"
#include "InlineTextBox.h"
#include "MutationEvent.h"
+#include "Page.h"
#include "RenderTheme.h"
#include "RootInlineBox.h"
#include <wtf/CurrentTime.h>
@@ -42,16 +43,10 @@ static void dispatchChildInsertionEvents(Node*, ExceptionCode&);
static void dispatchChildRemovalEvents(Node*, ExceptionCode&);
typedef Vector<std::pair<NodeCallback, RefPtr<Node> > > NodeCallbackQueue;
-static NodeCallbackQueue* s_postAttachCallbackQueue = 0;
+static NodeCallbackQueue* s_postAttachCallbackQueue;
-static size_t s_attachDepth = 0;
-
-ContainerNode::ContainerNode(Document* doc, bool isElement)
- : EventTargetNode(doc, isElement, true)
- , m_firstChild(0)
- , m_lastChild(0)
-{
-}
+static size_t s_attachDepth;
+static bool s_shouldReEnableMemoryCacheCallsAfterAttach;
void ContainerNode::removeAllChildren()
{
@@ -98,9 +93,8 @@ bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce
return true;
RefPtr<Node> next = refChild;
- RefPtr<Node> prev = refChild->previousSibling();
+ RefPtr<Node> refChildPreviousSibling = refChild->previousSibling();
- int childCountDelta = 0;
RefPtr<Node> child = isFragment ? newChild->firstChild() : newChild;
while (child) {
RefPtr<Node> nextChild = isFragment ? child->nextSibling() : 0;
@@ -128,8 +122,6 @@ bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce
ASSERT(!child->nextSibling());
ASSERT(!child->previousSibling());
- childCountDelta++;
-
// Add child before "next".
forbidEventDispatch();
Node* prev = next->previousSibling();
@@ -149,6 +141,7 @@ bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce
allowEventDispatch();
// Dispatch the mutation events.
+ childrenChanged(false, refChildPreviousSibling.get(), next.get(), 1);
dispatchChildInsertionEvents(child.get(), ec);
// Add child to the rendering tree.
@@ -163,8 +156,6 @@ bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce
}
document()->setDocumentChanged(true);
- if (childCountDelta)
- childrenChanged(false, prev.get(), next.get(), childCountDelta);
dispatchSubtreeModifiedEvent();
return true;
}
@@ -222,7 +213,7 @@ bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce
if (Node* oldParent = child->parentNode())
oldParent->removeChild(child.get(), ec);
if (ec)
- return 0;
+ return false;
// Due to arbitrary code running in response to a DOM mutation event it's
// possible that "prev" is no longer a child of "this".
@@ -288,7 +279,7 @@ void ContainerNode::willRemove()
{
for (Node *n = m_firstChild; n != 0; n = n->nextSibling())
n->willRemove();
- EventTargetNode::willRemove();
+ Node::willRemove();
}
static ExceptionCode willRemoveChild(Node *child)
@@ -392,25 +383,25 @@ bool ContainerNode::removeChildren()
if (!m_firstChild)
return false;
- Node* n;
+ // The container node can be removed from event handlers.
+ RefPtr<Node> protect(this);
- // do any prep work needed before actually starting to detach
- // and remove... e.g. stop loading frames, fire unload events
- for (n = m_firstChild; n; n = n->nextSibling())
- willRemoveChild(n);
+ // Do any prep work needed before actually starting to detach
+ // and remove... e.g. stop loading frames, fire unload events.
+ // FIXME: Adding new children from event handlers can cause an infinite loop here.
+ for (RefPtr<Node> n = m_firstChild; n; n = n->nextSibling())
+ willRemoveChild(n.get());
// exclude this node when looking for removed focusedNode since only children will be removed
document()->removeFocusedNodeOfSubtree(this, true);
forbidEventDispatch();
int childCountDelta = 0;
- while ((n = m_firstChild) != 0) {
+ while (RefPtr<Node> n = m_firstChild) {
childCountDelta--;
- Node *next = n->nextSibling();
+ Node* next = n->nextSibling();
- n->ref();
-
// Remove the node from the tree before calling detach or removedFromDocument (4427024, 4129744)
n->setPreviousSibling(0);
n->setNextSibling(0);
@@ -425,8 +416,6 @@ bool ContainerNode::removeChildren()
if (n->inDocument())
n->removedFromDocument();
-
- n->deref();
}
allowEventDispatch();
@@ -461,7 +450,6 @@ bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, bo
return true;
// Now actually add the child(ren)
- int childCountDelta = 0;
RefPtr<Node> prev = lastChild();
RefPtr<Node> child = isFragment ? newChild->firstChild() : newChild;
while (child) {
@@ -482,7 +470,6 @@ bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, bo
}
// Append child to the end of the list
- childCountDelta++;
forbidEventDispatch();
child->setParent(this);
if (m_lastChild) {
@@ -494,6 +481,7 @@ bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, bo
allowEventDispatch();
// Dispatch the mutation events
+ childrenChanged(false, prev.get(), 0, 1);
dispatchChildInsertionEvents(child.get(), ec);
// Add child to the rendering tree
@@ -508,7 +496,6 @@ bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, bo
}
document()->setDocumentChanged(true);
- childrenChanged(false, prev.get(), 0, childCountDelta);
dispatchSubtreeModifiedEvent();
return true;
}
@@ -539,13 +526,29 @@ ContainerNode* ContainerNode::addChild(PassRefPtr<Node> newChild)
void ContainerNode::suspendPostAttachCallbacks()
{
+ if (!s_attachDepth) {
+ ASSERT(!s_shouldReEnableMemoryCacheCallsAfterAttach);
+ if (Page* page = document()->page()) {
+ if (page->areMemoryCacheClientCallsEnabled()) {
+ page->setMemoryCacheClientCallsEnabled(false);
+ s_shouldReEnableMemoryCacheCallsAfterAttach = true;
+ }
+ }
+ }
++s_attachDepth;
}
void ContainerNode::resumePostAttachCallbacks()
{
- if (s_attachDepth == 1 && s_postAttachCallbackQueue)
- dispatchPostAttachCallbacks();
+ if (s_attachDepth == 1) {
+ if (s_postAttachCallbackQueue)
+ dispatchPostAttachCallbacks();
+ if (s_shouldReEnableMemoryCacheCallsAfterAttach) {
+ s_shouldReEnableMemoryCacheCallsAfterAttach = false;
+ if (Page* page = document()->page())
+ page->setMemoryCacheClientCallsEnabled(true);
+ }
+ }
--s_attachDepth;
}
@@ -573,15 +576,13 @@ void ContainerNode::dispatchPostAttachCallbacks()
void ContainerNode::attach()
{
- ++s_attachDepth;
+ suspendPostAttachCallbacks();
for (Node* child = m_firstChild; child; child = child->nextSibling())
child->attach();
- EventTargetNode::attach();
+ Node::attach();
- if (s_attachDepth == 1 && s_postAttachCallbackQueue)
- dispatchPostAttachCallbacks();
- --s_attachDepth;
+ resumePostAttachCallbacks();
}
void ContainerNode::detach()
@@ -589,39 +590,40 @@ void ContainerNode::detach()
for (Node* child = m_firstChild; child; child = child->nextSibling())
child->detach();
setHasChangedChild(false);
- EventTargetNode::detach();
+ Node::detach();
}
void ContainerNode::insertedIntoDocument()
{
- EventTargetNode::insertedIntoDocument();
- for (Node *child = m_firstChild; child; child = child->nextSibling())
+ Node::insertedIntoDocument();
+ insertedIntoTree(false);
+ for (Node* child = m_firstChild; child; child = child->nextSibling())
child->insertedIntoDocument();
}
void ContainerNode::removedFromDocument()
{
- EventTargetNode::removedFromDocument();
- for (Node *child = m_firstChild; child; child = child->nextSibling())
+ Node::removedFromDocument();
+ setInDocument(false);
+ removedFromTree(false);
+ for (Node* child = m_firstChild; child; child = child->nextSibling())
child->removedFromDocument();
}
void ContainerNode::insertedIntoTree(bool deep)
{
- EventTargetNode::insertedIntoTree(deep);
- if (deep) {
- for (Node *child = m_firstChild; child; child = child->nextSibling())
- child->insertedIntoTree(deep);
- }
+ if (!deep)
+ return;
+ for (Node* child = m_firstChild; child; child = child->nextSibling())
+ child->insertedIntoTree(true);
}
void ContainerNode::removedFromTree(bool deep)
{
- EventTargetNode::removedFromTree(deep);
- if (deep) {
- for (Node *child = m_firstChild; child; child = child->nextSibling())
- child->removedFromTree(deep);
- }
+ if (!deep)
+ return;
+ for (Node* child = m_firstChild; child; child = child->nextSibling())
+ child->removedFromTree(true);
}
void ContainerNode::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
@@ -677,13 +679,14 @@ bool ContainerNode::getUpperLeftCorner(FloatPoint& point) const
if (!o)
break;
}
+ ASSERT(o);
if (!o->isInline() || o->isReplaced()) {
point = o->localToAbsolute();
return true;
}
- if (p->element() && p->element() == this && o->isText() && !o->isBR() && !toRenderText(o)->firstTextBox()) {
+ if (p->node() && p->node() == this && o->isText() && !o->isBR() && !toRenderText(o)->firstTextBox()) {
// do nothing - skip unrendered whitespace that is a child or next sibling of the anchor
} else if ((o->isText() && !o->isBR()) || o->isReplaced()) {
point = o->container()->localToAbsolute();
@@ -713,9 +716,8 @@ bool ContainerNode::getLowerRightCorner(FloatPoint& point) const
if (!renderer())
return false;
- RenderObject *o = renderer();
- if (!o->isInline() || o->isReplaced())
- {
+ RenderObject* o = renderer();
+ if (!o->isInline() || o->isReplaced()) {
RenderBox* box = toRenderBox(o);
point = o->localToAbsolute();
point.move(box->width(), box->height());
@@ -729,8 +731,8 @@ bool ContainerNode::getLowerRightCorner(FloatPoint& point) const
else if (o->previousSibling())
o = o->previousSibling();
else {
- RenderObject *prev = 0;
- while(!prev) {
+ RenderObject* prev = 0;
+ while (!prev) {
o = o->parent();
if (!o)
return false;
@@ -738,12 +740,13 @@ bool ContainerNode::getLowerRightCorner(FloatPoint& point) const
}
o = prev;
}
+ ASSERT(o);
if (o->isText() || o->isReplaced()) {
point = o->container()->localToAbsolute();
if (o->isText()) {
RenderText* text = toRenderText(o);
IntRect linesBox = text->linesBoundingBox();
- point.move(linesBox.x() + linesBox.width(), linesBox.height());
+ point.move(linesBox.x() + linesBox.width(), linesBox.y() + linesBox.height());
} else {
RenderBox* box = toRenderBox(o);
point.move(box->x() + box->width(), box->y() + box->height());
@@ -762,8 +765,7 @@ IntRect ContainerNode::getRect() const
// If we've found one corner, but not the other,
// then we should just return a point at the corner that we did find.
- if (foundUpperLeft != foundLowerRight)
- {
+ if (foundUpperLeft != foundLowerRight) {
if (foundUpperLeft)
lowerRight = upperLeft;
else
@@ -781,7 +783,7 @@ void ContainerNode::setFocus(bool received)
if (focused() == received)
return;
- EventTargetNode::setFocus(received);
+ Node::setFocus(received);
// note that we need to recalc the style
setChanged();
@@ -791,7 +793,7 @@ void ContainerNode::setActive(bool down, bool pause)
{
if (down == active()) return;
- EventTargetNode::setActive(down);
+ Node::setActive(down);
// note that we need to recalc the style
// FIXME: Move to Element
@@ -834,7 +836,7 @@ void ContainerNode::setHovered(bool over)
{
if (over == hovered()) return;
- EventTargetNode::setHovered(over);
+ Node::setHovered(over);
// note that we need to recalc the style
// FIXME: Move to Element
@@ -876,11 +878,11 @@ static void dispatchChildInsertionEvents(Node* child, ExceptionCode& ec)
else
c->insertedIntoTree(true);
- if (c->parentNode() &&
- doc->hasListenerType(Document::DOMNODEINSERTED_LISTENER) &&
- c->isEventTargetNode()) {
+ doc->incDOMTreeVersion();
+
+ if (c->parentNode() && doc->hasListenerType(Document::DOMNODEINSERTED_LISTENER)) {
ec = 0;
- EventTargetNodeCast(c.get())->dispatchEvent(MutationEvent::create(eventNames().DOMNodeInsertedEvent, true, false,
+ c->dispatchEvent(MutationEvent::create(eventNames().DOMNodeInsertedEvent, true, false,
c->parentNode(), String(), String(), String(), 0), ec);
if (ec)
return;
@@ -889,11 +891,8 @@ static void dispatchChildInsertionEvents(Node* child, ExceptionCode& ec)
// dispatch the DOMNodeInsertedIntoDocument event to all descendants
if (c->inDocument() && doc->hasListenerType(Document::DOMNODEINSERTEDINTODOCUMENT_LISTENER))
for (; c; c = c->traverseNextNode(child)) {
- if (!c->isEventTargetNode())
- continue;
-
ec = 0;
- EventTargetNodeCast(c.get())->dispatchEvent(MutationEvent::create(eventNames().DOMNodeInsertedIntoDocumentEvent, false, false,
+ c->dispatchEvent(MutationEvent::create(eventNames().DOMNodeInsertedIntoDocumentEvent, false, false,
0, String(), String(), String(), 0), ec);
if (ec)
return;
@@ -908,12 +907,12 @@ static void dispatchChildRemovalEvents(Node* child, ExceptionCode& ec)
// update auxiliary doc info (e.g. iterators) to note that node is being removed
doc->nodeWillBeRemoved(child);
+ doc->incDOMTreeVersion();
+
// dispatch pre-removal mutation events
- if (c->parentNode() &&
- doc->hasListenerType(Document::DOMNODEREMOVED_LISTENER) &&
- c->isEventTargetNode()) {
+ if (c->parentNode() && doc->hasListenerType(Document::DOMNODEREMOVED_LISTENER)) {
ec = 0;
- EventTargetNodeCast(c.get())->dispatchEvent(MutationEvent::create(eventNames().DOMNodeRemovedEvent, true, false,
+ c->dispatchEvent(MutationEvent::create(eventNames().DOMNodeRemovedEvent, true, false,
c->parentNode(), String(), String(), String(), 0), ec);
if (ec)
return;
@@ -922,10 +921,8 @@ static void dispatchChildRemovalEvents(Node* child, ExceptionCode& ec)
// dispatch the DOMNodeRemovedFromDocument event to all descendants
if (c->inDocument() && doc->hasListenerType(Document::DOMNODEREMOVEDFROMDOCUMENT_LISTENER))
for (; c; c = c->traverseNextNode(child)) {
- if (!c->isEventTargetNode())
- continue;
ec = 0;
- EventTargetNodeCast(c.get())->dispatchEvent(MutationEvent::create(eventNames().DOMNodeRemovedFromDocumentEvent, false, false,
+ c->dispatchEvent(MutationEvent::create(eventNames().DOMNodeRemovedFromDocumentEvent, false, false,
0, String(), String(), String(), 0), ec);
if (ec)
return;