diff options
Diffstat (limited to 'WebCore/dom/ContainerNode.cpp')
-rw-r--r-- | WebCore/dom/ContainerNode.cpp | 159 |
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; |