2009-02-10 Adam Treat <adam.treat@torchmobile.com>
[WebKit-https.git] / WebCore / dom / ContainerNode.cpp
index 703e715..2950fb3 100644 (file)
@@ -1,10 +1,8 @@
-/**
- * This file is part of the DOM implementation for KDE.
- *
+/*
  * 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 Apple Computer, Inc.
+ * 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
  *
  * You should have received a copy of the GNU Library General Public License
  * along with this library; see the file COPYING.LIB.  If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
  */
 
 #include "config.h"
 #include "ContainerNode.h"
 
-#include "Document.h"
+#include "ContainerNodeAlgorithms.h"
+#include "DeleteButtonController.h"
 #include "EventNames.h"
 #include "ExceptionCode.h"
+#include "FloatRect.h"
+#include "Frame.h"
 #include "FrameView.h"
 #include "InlineTextBox.h"
-#include "IntRect.h"
-#include "RenderText.h"
-#include "SystemTime.h"
-#include "dom2_eventsimpl.h"
+#include "MutationEvent.h"
 #include "RenderTheme.h"
+#include "RootInlineBox.h"
+#include <wtf/CurrentTime.h>
 
 namespace WebCore {
 
-using namespace EventNames;
-
 static void dispatchChildInsertionEvents(Node*, ExceptionCode&);
 static void dispatchChildRemovalEvents(Node*, ExceptionCode&);
 
-ContainerNode::ContainerNode(Document* doc)
-    : EventTargetNode(doc), m_firstChild(0), m_lastChild(0)
-{
-}
+typedef Vector<std::pair<NodeCallback, RefPtr<Node> > > NodeCallbackQueue;
+static NodeCallbackQueue* s_postAttachCallbackQueue = 0;
+
+static size_t s_attachDepth = 0;
 
 void ContainerNode::removeAllChildren()
 {
-    // Avoid deep recursion when destroying the node tree.
-    static bool alreadyInsideDestructor; 
-    bool topLevel = !alreadyInsideDestructor;
-    if (topLevel)
-        alreadyInsideDestructor = true;
-    
-    // List of nodes to be deleted.
-    static Node *head;
-    static Node *tail;
-    
-    // We have to tell all children that their parent has died.
-    Node *n;
-    Node *next;
-
-    for (n = m_firstChild; n != 0; n = next ) {
-        next = n->nextSibling();
-        n->setPreviousSibling(0);
-        n->setNextSibling(0);
-        n->setParent(0);
-        
-        if ( !n->refCount() ) {
-            // Add the node to the list of nodes to be deleted.
-            // Reuse the nextSibling pointer for this purpose.
-            if (tail)
-                tail->setNextSibling(n);
-            else
-                head = n;
-            tail = n;
-        } else if (n->inDocument())
-            n->removedFromDocument();
-    }
-    
-    // Only for the top level call, do the actual deleting.
-    if (topLevel) {
-        while ((n = head) != 0) {
-            next = n->nextSibling();
-            n->setNextSibling(0);
-
-            head = next;
-            if (next == 0)
-                tail = 0;
-            
-            delete n;
-        }
-        
-        alreadyInsideDestructor = false;
-        m_firstChild = 0;
-        m_lastChild = 0;
-    }
+    removeAllChildrenInContainer<Node, ContainerNode>(this);
 }
 
 ContainerNode::~ContainerNode()
@@ -106,18 +56,7 @@ ContainerNode::~ContainerNode()
     removeAllChildren();
 }
 
-
-Node* ContainerNode::firstChild() const
-{
-    return m_firstChild;
-}
-
-Node* ContainerNode::lastChild() const
-{
-    return m_lastChild;
-}
-
-bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode& ec)
+bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode& ec, bool shouldLazyAttach)
 {
     // Check that this node is not "floating".
     // If it is, it can be deleted as a side effect of sending mutation events.
@@ -127,7 +66,7 @@ bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce
 
     // insertBefore(node, 0) is equivalent to appendChild(node)
     if (!refChild)
-        return appendChild(newChild, ec);
+        return appendChild(newChild, ec, shouldLazyAttach);
 
     // Make sure adding the new child is OK.
     checkAddChild(newChild.get(), ec);
@@ -152,7 +91,9 @@ bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce
         return true;
 
     RefPtr<Node> next = refChild;
+    RefPtr<Node> prev = refChild->previousSibling();
 
+    int childCountDelta = 0;
     RefPtr<Node> child = isFragment ? newChild->firstChild() : newChild;
     while (child) {
         RefPtr<Node> nextChild = isFragment ? child->nextSibling() : 0;
@@ -177,20 +118,22 @@ bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce
         if (child->parentNode())
             break;
 
-        assert(!child->nextSibling());
-        assert(!child->previousSibling());
+        ASSERT(!child->nextSibling());
+        ASSERT(!child->previousSibling());
+
+        childCountDelta++;
 
         // Add child before "next".
         forbidEventDispatch();
         Node* prev = next->previousSibling();
-        assert(m_lastChild != prev);
+        ASSERT(m_lastChild != prev);
         next->setPreviousSibling(child.get());
         if (prev) {
-            assert(m_firstChild != next);
-            assert(prev->nextSibling() == next);
+            ASSERT(m_firstChild != next);
+            ASSERT(prev->nextSibling() == next);
             prev->setNextSibling(child.get());
         } else {
-            assert(m_firstChild == next);
+            ASSERT(m_firstChild == next);
             m_firstChild = child.get();
         }
         child->setParent(this);
@@ -198,22 +141,28 @@ bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce
         child->setNextSibling(next.get());
         allowEventDispatch();
 
-        // Add child to the rendering tree.
-        if (attached() && !child->attached())
-            child->attach();
-
         // Dispatch the mutation events.
         dispatchChildInsertionEvents(child.get(), ec);
+                
+        // Add child to the rendering tree.
+        if (attached() && !child->attached() && child->parent() == this) {
+            if (shouldLazyAttach)
+                child->lazyAttach();
+            else
+                child->attach();
+        }
 
         child = nextChild.release();
     }
 
     document()->setDocumentChanged(true);
+    if (childCountDelta)
+        childrenChanged(false, prev.get(), next.get(), childCountDelta);
     dispatchSubtreeModifiedEvent();
     return true;
 }
 
-bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode& ec)
+bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode& ec, bool shouldLazyAttach)
 {
     // Check that this node is not "floating".
     // If it is, it can be deleted as a side effect of sending mutation events.
@@ -224,8 +173,8 @@ bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce
     if (oldChild == newChild) // nothing to do
         return true;
     
-    // Make sure adding the new child is ok
-    checkAddChild(newChild.get(), ec);
+    // Make sure replacing the old child with the new is ok
+    checkReplaceChild(newChild.get(), oldChild, ec);
     if (ec)
         return false;
 
@@ -236,6 +185,7 @@ bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce
     }
 
     RefPtr<Node> prev = oldChild->previousSibling();
+    RefPtr<Node> next = oldChild->nextSibling();
 
     // Remove the node we're replacing
     RefPtr<Node> removedChild = oldChild;
@@ -251,6 +201,7 @@ bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce
     bool isFragment = newChild->nodeType() == DOCUMENT_FRAGMENT_NODE;
 
     // Add the new child(ren)
+    int childCountDelta = 0;
     RefPtr<Node> child = isFragment ? newChild->firstChild() : newChild;
     while (child) {
         // If the new child is already in the right place, we're done.
@@ -264,7 +215,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".
@@ -275,26 +226,28 @@ bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce
         if (child->parentNode())
             break;
 
-        assert(!child->nextSibling());
-        assert(!child->previousSibling());
+        childCountDelta++;
+
+        ASSERT(!child->nextSibling());
+        ASSERT(!child->previousSibling());
 
         // Add child after "prev".
         forbidEventDispatch();
         Node* next;
         if (prev) {
             next = prev->nextSibling();
-            assert(m_firstChild != next);
+            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);
+            ASSERT(m_lastChild != prev);
+            ASSERT(next->previousSibling() == prev);
             next->setPreviousSibling(child.get());
         } else {
-            assert(m_lastChild == prev);
+            ASSERT(m_lastChild == prev);
             m_lastChild = child.get();
         }
         child->setParent(this);
@@ -302,19 +255,24 @@ bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce
         child->setNextSibling(next);
         allowEventDispatch();
 
-        // Add child to the rendering tree
-        if (attached() && !child->attached())
-            child->attach();
-
         // Dispatch the mutation events
         dispatchChildInsertionEvents(child.get(), ec);
+                
+        // Add child to the rendering tree
+        if (attached() && !child->attached() && child->parent() == this) {
+            if (shouldLazyAttach)
+                child->lazyAttach();
+            else
+                child->attach();
+        }
 
         prev = child;
         child = nextChild.release();
     }
 
-    // ### set style in case it's attached
     document()->setDocumentChanged(true);
+    if (childCountDelta)
+        childrenChanged(false, prev.get(), next.get(), childCountDelta);
     dispatchSubtreeModifiedEvent();
     return true;
 }
@@ -323,6 +281,7 @@ void ContainerNode::willRemove()
 {
     for (Node *n = m_firstChild; n != 0; n = n->nextSibling())
         n->willRemove();
+    Node::willRemove();
 }
 
 static ExceptionCode willRemoveChild(Node *child)
@@ -349,7 +308,7 @@ bool ContainerNode::removeChild(Node* oldChild, ExceptionCode& ec)
     ec = 0;
 
     // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
-    if (isReadOnly()) {
+    if (isReadOnlyNode()) {
         ec = NO_MODIFICATION_ALLOWED_ERR;
         return false;
     }
@@ -361,14 +320,6 @@ bool ContainerNode::removeChild(Node* oldChild, ExceptionCode& ec)
     }
 
     RefPtr<Node> child = oldChild;
-    
-    // dispatch pre-removal mutation events
-    if (document()->hasListenerType(Document::DOMNODEREMOVED_LISTENER)) {
-        EventTargetNodeCast(child.get())->dispatchEvent(new MutationEvent(DOMNodeRemovedEvent, true, false,
-            this, String(), String(), String(), 0), ec, true);
-        if (ec)
-            return false;
-    }
 
     ec = willRemoveChild(child.get());
     if (ec)
@@ -380,6 +331,8 @@ bool ContainerNode::removeChild(Node* oldChild, ExceptionCode& ec)
         return false;
     }
 
+    document()->removeFocusedNodeOfSubtree(child.get());
+    
     // FIXME: After sending the mutation events, "this" could be destroyed.
     // We can prevent that by doing a "ref", but first we have to make sure
     // that no callers call with ref count == 0 and parent = 0 (as of this
@@ -414,6 +367,7 @@ bool ContainerNode::removeChild(Node* oldChild, ExceptionCode& ec)
     document()->setDocumentChanged(true);
 
     // Dispatch post-removal mutation events
+    childrenChanged(false, prev, next, -1);
     dispatchSubtreeModifiedEvent();
 
     if (child->inDocument())
@@ -426,46 +380,57 @@ bool ContainerNode::removeChild(Node* oldChild, ExceptionCode& ec)
 
 // this differs from other remove functions because it forcibly removes all the children,
 // regardless of read-only status or event exceptions, e.g.
-void ContainerNode::removeChildren()
+bool ContainerNode::removeChildren()
 {
-    Node *n;
-    
     if (!m_firstChild)
-        return;
+        return false;
 
+    Node* n;
+    
     // 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);
     
+    // 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) {
+        childCountDelta--;
+
         Node *next = n->nextSibling();
         
         n->ref();
 
-        if (n->attached())
-            n->detach();
+        // Remove the node from the tree before calling detach or removedFromDocument (4427024, 4129744)
         n->setPreviousSibling(0);
         n->setNextSibling(0);
         n->setParent(0);
         
+        m_firstChild = next;
+        if (n == m_lastChild)
+            m_lastChild = 0;
+
+        if (n->attached())
+            n->detach();
+        
         if (n->inDocument())
             n->removedFromDocument();
 
         n->deref();
-
-        m_firstChild = next;
     }
-    m_lastChild = 0;
     allowEventDispatch();
-    
+
     // Dispatch a single post-removal mutation event denoting a modified subtree.
+    childrenChanged(false, 0, 0, childCountDelta);
     dispatchSubtreeModifiedEvent();
-}
 
+    return true;
+}
 
-bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec)
+bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, bool shouldLazyAttach)
 {
     // Check that this node is not "floating".
     // If it is, it can be deleted as a side effect of sending mutation events.
@@ -489,6 +454,8 @@ bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec)
         return true;
 
     // Now actually add the child(ren)
+    int childCountDelta = 0;
+    RefPtr<Node> prev = lastChild();
     RefPtr<Node> child = isFragment ? newChild->firstChild() : newChild;
     while (child) {
         // For a fragment we have more children to do.
@@ -508,6 +475,7 @@ bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec)
         }
 
         // Append child to the end of the list
+        childCountDelta++;
         forbidEventDispatch();
         child->setParent(this);
         if (m_lastChild) {
@@ -518,27 +486,26 @@ bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec)
         m_lastChild = child.get();
         allowEventDispatch();
 
-        // Add child to the rendering tree
-        // ### should we detach() it first if it's already attached?
-        if (attached() && !child->attached())
-            child->attach();
-        
         // Dispatch the mutation events
         dispatchChildInsertionEvents(child.get(), ec);
 
+        // Add child to the rendering tree
+        if (attached() && !child->attached() && child->parent() == this) {
+            if (shouldLazyAttach)
+                child->lazyAttach();
+            else
+                child->attach();
+        }
+        
         child = nextChild.release();
     }
 
     document()->setDocumentChanged(true);
+    childrenChanged(false, prev.get(), 0, childCountDelta);
     dispatchSubtreeModifiedEvent();
     return true;
 }
 
-bool ContainerNode::hasChildNodes() const
-{
-    return m_firstChild;
-}
-
 ContainerNode* ContainerNode::addChild(PassRefPtr<Node> newChild)
 {
     // This function is only used during parsing.
@@ -549,96 +516,149 @@ ContainerNode* ContainerNode::addChild(PassRefPtr<Node> newChild)
         return 0;
 
     forbidEventDispatch();
-    newChild->setParent(this);
-    if (m_lastChild) {
-        newChild->setPreviousSibling(m_lastChild);
-        m_lastChild->setNextSibling(newChild.get());
-    } else
-        m_firstChild = newChild.get();
-    m_lastChild = newChild.get();
+    Node* last = m_lastChild;
+    appendChildToContainer<Node, ContainerNode>(newChild.get(), this);
     allowEventDispatch();
 
+    document()->incDOMTreeVersion();
     if (inDocument())
         newChild->insertedIntoDocument();
-    childrenChanged();
+    childrenChanged(true, last, 0, 1);
     
     if (newChild->isElementNode())
         return static_cast<ContainerNode*>(newChild.get());
     return this;
 }
 
+void ContainerNode::suspendPostAttachCallbacks()
+{
+    ++s_attachDepth;
+}
+
+void ContainerNode::resumePostAttachCallbacks()
+{
+    if (s_attachDepth == 1 && s_postAttachCallbackQueue)
+        dispatchPostAttachCallbacks();
+    --s_attachDepth;
+}
+
+void ContainerNode::queuePostAttachCallback(NodeCallback callback, Node* node)
+{
+    if (!s_postAttachCallbackQueue)
+        s_postAttachCallbackQueue = new NodeCallbackQueue;
+    
+    s_postAttachCallbackQueue->append(std::pair<NodeCallback, RefPtr<Node> >(callback, node));
+}
+
+void ContainerNode::dispatchPostAttachCallbacks()
+{
+    // We recalculate size() each time through the loop because a callback
+    // can add more callbacks to the end of the queue.
+    for (size_t i = 0; i < s_postAttachCallbackQueue->size(); ++i) {
+        std::pair<NodeCallback, RefPtr<Node> >& pair = (*s_postAttachCallbackQueue)[i];
+        NodeCallback callback = pair.first;
+        Node* node = pair.second.get();
+
+        callback(node);
+    }
+    s_postAttachCallbackQueue->clear();
+}
+
 void ContainerNode::attach()
 {
+    ++s_attachDepth;
+
     for (Node* child = m_firstChild; child; child = child->nextSibling())
         child->attach();
-    EventTargetNode::attach();
+    Node::attach();
+
+    if (s_attachDepth == 1 && s_postAttachCallbackQueue)
+        dispatchPostAttachCallbacks();
+    --s_attachDepth;
 }
 
 void ContainerNode::detach()
 {
     for (Node* child = m_firstChild; child; child = child->nextSibling())
         child->detach();
-    EventTargetNode::detach();
+    setHasChangedChild(false);
+    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)
+{
+    Node::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
+    if (!changedByParser && childCountDelta)
+        document()->nodeChildrenChanged(this);
+    if (document()->hasNodeListCaches())
+        notifyNodeListsChildrenChanged();
 }
 
-void ContainerNode::cloneChildNodes(Node *clone)
+void ContainerNode::cloneChildNodes(ContainerNode *clone)
 {
+    // disable the delete button so it's elements are not serialized into the markup
+    if (document()->frame())
+        document()->frame()->editor()->deleteButtonController()->disable();
     ExceptionCode ec = 0;
     for (Node* n = firstChild(); n && !ec; n = n->nextSibling())
         clone->appendChild(n->cloneNode(true), ec);
+    if (document()->frame())
+        document()->frame()->editor()->deleteButtonController()->enable();
 }
 
-bool ContainerNode::getUpperLeftCorner(int &xPos, int &yPos) const
+// FIXME: This doesn't work correctly with transforms.
+bool ContainerNode::getUpperLeftCorner(FloatPoint& point) const
 {
     if (!renderer())
         return false;
+    // What is this code really trying to do?
     RenderObject *o = renderer();
     RenderObject *p = o;
 
-    xPos = yPos = 0;
     if (!o->isInline() || o->isReplaced()) {
-        o->absolutePosition(xPos, yPos);
+        point = o->localToAbsolute();
         return true;
     }
 
     // find the next text/image child, to get a position
-    while(o) {
+    while (o) {
         p = o;
         if (o->firstChild())
             o = o->firstChild();
-        else if(o->nextSibling())
+        else if (o->nextSibling())
             o = o->nextSibling();
         else {
             RenderObject *next = 0;
@@ -653,70 +673,75 @@ bool ContainerNode::getUpperLeftCorner(int &xPos, int &yPos) const
         }
 
         if (!o->isInline() || o->isReplaced()) {
-            o->absolutePosition(xPos, yPos);
+            point = o->localToAbsolute();
             return true;
         }
 
-        if (p->element() && p->element() == this && o->isText() && !o->isBR() && !static_cast<RenderText*>(o)->firstTextBox()) {
+        if (p->element() && p->element() == 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()) {
-            o->container()->absolutePosition(xPos, yPos);
-            if (o->isText() && static_cast<RenderText *>(o)->firstTextBox()) {
-                xPos += static_cast<RenderText *>(o)->minXPos();
-                yPos += static_cast<RenderText *>(o)->firstTextBox()->root()->topOverflow();
-            } else {
-                xPos += o->xPos();
-                yPos += o->yPos();
+            point = o->container()->localToAbsolute();
+            if (o->isText() && toRenderText(o)->firstTextBox()) {
+                point.move(toRenderText(o)->linesBoundingBox().x(),
+                           toRenderText(o)->firstTextBox()->root()->topOverflow());
+            } else if (o->isBox()) {
+                RenderBox* box = toRenderBox(o);
+                point.move(box->x(), box->y());
             }
             return true;
         }
     }
     
     // If the target doesn't have any children or siblings that could be used to calculate the scroll position, we must be
-    // at the end of the document.  Scroll to the bottom.
-    if (!o) {
-        yPos += document()->view()->contentsHeight();
+    // at the end of the document.  Scroll to the bottom. FIXME: who said anything about scrolling?
+    if (!o && document()->view()) {
+        point = FloatPoint(0, document()->view()->contentsHeight());
         return true;
     }
     return false;
 }
 
-bool ContainerNode::getLowerRightCorner(int &xPos, int &yPos) const
+// FIXME: This doesn't work correctly with transforms.
+bool ContainerNode::getLowerRightCorner(FloatPoint& point) const
 {
     if (!renderer())
         return false;
 
     RenderObject *o = renderer();
-    xPos = yPos = 0;
     if (!o->isInline() || o->isReplaced())
     {
-        o->absolutePosition(xPos, yPos);
-        xPos += o->width();
-        yPos += o->height() + o->borderTopExtra() + o->borderBottomExtra();
+        RenderBox* box = toRenderBox(o);
+        point = o->localToAbsolute();
+        point.move(box->width(), box->height());
         return true;
     }
+
     // find the last text/image child, to get a position
-    while(o) {
-        if(o->lastChild())
+    while (o) {
+        if (o->lastChild())
             o = o->lastChild();
-        else if(o->previousSibling())
+        else if (o->previousSibling())
             o = o->previousSibling();
         else {
             RenderObject *prev = 0;
             while(!prev) {
                 o = o->parent();
-                if(!o) return false;
+                if (!o)
+                    return false;
                 prev = o->previousSibling();
             }
             o = prev;
         }
         if (o->isText() || o->isReplaced()) {
-            o->container()->absolutePosition(xPos, yPos);
-            if (o->isText())
-                xPos += static_cast<RenderText *>(o)->minXPos() + o->width();
-            else
-                xPos += o->xPos()+o->width();
-            yPos += o->yPos()+o->height();
+            point = o->container()->localToAbsolute();
+            if (o->isText()) {
+                RenderText* text = toRenderText(o);
+                IntRect linesBox = text->linesBoundingBox();
+                point.move(linesBox.x() + linesBox.width(), linesBox.height());
+            } else {
+                RenderBox* box = toRenderBox(o);
+                point.move(box->x() + box->width(), box->y() + box->height());
+            }
             return true;
         }
     }
@@ -725,36 +750,32 @@ bool ContainerNode::getLowerRightCorner(int &xPos, int &yPos) const
 
 IntRect ContainerNode::getRect() const
 {
-    int xPos = 0, yPos = 0, xEnd = 0, yEnd = 0;
-    bool foundUpperLeft = getUpperLeftCorner(xPos,yPos);
-    bool foundLowerRight = getLowerRightCorner(xEnd,yEnd);
+    FloatPoint  upperLeft, lowerRight;
+    bool foundUpperLeft = getUpperLeftCorner(upperLeft);
+    bool foundLowerRight = getLowerRightCorner(lowerRight);
     
     // 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) {
-            xEnd = xPos;
-            yEnd = yPos;
-        } else {
-            xPos = xEnd;
-            yPos = yEnd;
-        }
+        if (foundUpperLeft)
+            lowerRight = upperLeft;
+        else
+            upperLeft = lowerRight;
     } 
 
-    if (xEnd < xPos)
-        xEnd = xPos;
-    if (yEnd < yPos)
-        yEnd = yPos;
-        
-    return IntRect(xPos, yPos, xEnd - xPos, yEnd - yPos);
+    lowerRight.setX(max(upperLeft.x(), lowerRight.x()));
+    lowerRight.setY(max(upperLeft.y(), lowerRight.y()));
+    
+    return enclosingIntRect(FloatRect(upperLeft, lowerRight - upperLeft));
 }
 
 void ContainerNode::setFocus(bool received)
 {
-    if (m_focused == received) return;
+    if (focused() == received)
+        return;
 
-    EventTargetNode::setFocus(received);
+    Node::setFocus(received);
 
     // note that we need to recalc the style
     setChanged();
@@ -764,7 +785,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
@@ -781,16 +802,19 @@ void ContainerNode::setActive(bool down, bool pause)
             // to repaint the "down" state of the control is about the same time as it would take to repaint the
             // "up" state.  Once you assume this, you can just delay for 100ms - that time (assuming that after you
             // leave this method, it will be about that long before the flush of the up state happens again).
-#if HAVE_FUNC_USLEEP
+#ifdef HAVE_FUNC_USLEEP
             double startTime = currentTime();
 #endif
 
+            // Ensure there are no pending changes
+            Document::updateDocumentsRendering();
             // Do an immediate repaint.
-            renderer()->repaint(true);
+            if (renderer())
+                renderer()->repaint(true);
             
             // FIXME: Find a substitute for usleep for Win32.
             // Better yet, come up with a way of doing this that doesn't use this sort of thing at all.            
-#if HAVE_FUNC_USLEEP
+#ifdef HAVE_FUNC_USLEEP
             // Now pause for a small amount of time (1/10th of a second from before we repainted in the pressed state)
             double remainingTime = 0.1 - (currentTime() - startTime);
             if (remainingTime > 0)
@@ -804,7 +828,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
@@ -836,22 +860,20 @@ Node *ContainerNode::childNode(unsigned index) const
 
 static void dispatchChildInsertionEvents(Node* child, ExceptionCode& ec)
 {
-    assert(!eventDispatchForbidden());
+    ASSERT(!eventDispatchForbidden());
 
     RefPtr<Node> c = child;
-    RefPtr<Document> doc = child->document();
+    DocPtr<Document> doc = child->document();
 
     if (c->parentNode() && c->parentNode()->inDocument())
         c->insertedIntoDocument();
     else
         c->insertedIntoTree(true);
 
-    if (c->parentNode() && 
-        doc->hasListenerType(Document::DOMNODEINSERTED_LISTENER) &&
-        c->isEventTargetNode()) {
+    if (c->parentNode() && doc->hasListenerType(Document::DOMNODEINSERTED_LISTENER)) {
         ec = 0;
-        EventTargetNodeCast(c.get())->dispatchEvent(new MutationEvent(DOMNodeInsertedEvent, true, false,
-            c->parentNode(), String(), String(), String(), 0), ec, true);
+        c->dispatchEvent(MutationEvent::create(eventNames().DOMNodeInsertedEvent, true, false,
+            c->parentNode(), String(), String(), String(), 0), ec);
         if (ec)
             return;
     }
@@ -859,12 +881,9 @@ 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(new MutationEvent(DOMNodeInsertedIntoDocumentEvent, false, false,
-                0, String(), String(), String(), 0), ec, true);
+            c->dispatchEvent(MutationEvent::create(eventNames().DOMNodeInsertedIntoDocumentEvent, false, false,
+                0, String(), String(), String(), 0), ec);
             if (ec)
                 return;
         }
@@ -873,18 +892,16 @@ static void dispatchChildInsertionEvents(Node* child, ExceptionCode& ec)
 static void dispatchChildRemovalEvents(Node* child, ExceptionCode& ec)
 {
     RefPtr<Node> c = child;
-    RefPtr<Document> doc = child->document();
+    DocPtr<Document> doc = child->document();
 
     // update auxiliary doc info (e.g. iterators) to note that node is being removed
-    doc->notifyBeforeNodeRemoval(child); // ### use events instead
+    doc->nodeWillBeRemoved(child);
 
     // 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(new MutationEvent(DOMNodeRemovedEvent, true, false,
-            c->parentNode(), String(), String(), String(), 0), ec, true);
+        c->dispatchEvent(MutationEvent::create(eventNames().DOMNodeRemovedEvent, true, false,
+            c->parentNode(), String(), String(), String(), 0), ec);
         if (ec)
             return;
     }
@@ -892,11 +909,9 @@ 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(new MutationEvent(DOMNodeRemovedFromDocumentEvent, false, false,
-                0, String(), String(), String(), 0), ec, true);
+            c->dispatchEvent(MutationEvent::create(eventNames().DOMNodeRemovedFromDocumentEvent, false, false,
+                0, String(), String(), String(), 0), ec);
             if (ec)
                 return;
         }