Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1112)

Unified Diff: third_party/WebKit/WebCore/dom/ContainerNode.cpp

Issue 21165: Revert the merge. Mac build is mysteriously broken. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 11 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/WebKit/WebCore/dom/ContainerNode.h ('k') | third_party/WebKit/WebCore/dom/Document.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/WebKit/WebCore/dom/ContainerNode.cpp
===================================================================
--- third_party/WebKit/WebCore/dom/ContainerNode.cpp (revision 9383)
+++ third_party/WebKit/WebCore/dom/ContainerNode.cpp (working copy)
@@ -1,920 +1,929 @@
-/*
- * 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, 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
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * 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., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include "ContainerNode.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 "MutationEvent.h"
-#include "RenderTheme.h"
-#include "RootInlineBox.h"
-#include <wtf/CurrentTime.h>
-
-namespace WebCore {
-
-static void dispatchChildInsertionEvents(Node*, ExceptionCode&);
-static void dispatchChildRemovalEvents(Node*, ExceptionCode&);
-
-typedef Vector<std::pair<NodeCallback, RefPtr<Node> > > NodeCallbackQueue;
-static NodeCallbackQueue* s_postAttachCallbackQueue = 0;
-
-static size_t s_attachDepth = 0;
-
-void ContainerNode::removeAllChildren()
-{
- removeAllChildrenInContainer<Node, ContainerNode>(this);
-}
-
-ContainerNode::~ContainerNode()
-{
- removeAllChildren();
-}
-
-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.
- ASSERT(refCount() || parent());
-
- ec = 0;
-
- // insertBefore(node, 0) is equivalent to appendChild(node)
- if (!refChild)
- return appendChild(newChild, ec, shouldLazyAttach);
-
- // Make sure adding the new child is OK.
- checkAddChild(newChild.get(), ec);
- if (ec)
- return false;
-
- // NOT_FOUND_ERR: Raised if refChild is not a child of this node
- if (refChild->parentNode() != this) {
- ec = NOT_FOUND_ERR;
- return false;
- }
-
- bool isFragment = newChild->nodeType() == DOCUMENT_FRAGMENT_NODE;
-
- // If newChild is a DocumentFragment with no children; there's nothing to do.
- // Just return true
- if (isFragment && !newChild->firstChild())
- return true;
-
- // Now actually add the child(ren)
- if (refChild->previousSibling() == newChild || refChild == newChild) // nothing to do
- 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;
-
- // If child is already present in the tree, first remove it from the old location.
- if (Node* oldParent = child->parentNode())
- oldParent->removeChild(child.get(), ec);
- if (ec)
- return 0;
-
- // 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
- // writing, there are definitely callers who call that way).
-
- // 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.
- // In either of those cases, we'll just stop.
- if (next->parentNode() != this)
- break;
- if (child->parentNode())
- break;
-
- ASSERT(!child->nextSibling());
- ASSERT(!child->previousSibling());
-
- childCountDelta++;
-
- // Add child before "next".
- forbidEventDispatch();
- Node* prev = next->previousSibling();
- ASSERT(m_lastChild != prev);
- next->setPreviousSibling(child.get());
- if (prev) {
- ASSERT(m_firstChild != next);
- ASSERT(prev->nextSibling() == next);
- prev->setNextSibling(child.get());
- } else {
- ASSERT(m_firstChild == next);
- m_firstChild = child.get();
- }
- child->setParent(this);
- child->setPreviousSibling(prev);
- child->setNextSibling(next.get());
- allowEventDispatch();
-
- // 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 shouldLazyAttach)
-{
- // Check that this node is not "floating".
- // If it is, it can be deleted as a side effect of sending mutation events.
- ASSERT(refCount() || parent());
-
- ec = 0;
-
- 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)
- return false;
-
- // NOT_FOUND_ERR: Raised if oldChild is not a child of this node.
- if (!oldChild || oldChild->parentNode() != this) {
- ec = NOT_FOUND_ERR;
- return false;
- }
-
- RefPtr<Node> prev = oldChild->previousSibling();
- RefPtr<Node> next = oldChild->nextSibling();
-
- // Remove the node we're replacing
- RefPtr<Node> removedChild = oldChild;
- removeChild(oldChild, ec);
- if (ec)
- return false;
-
- // 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
- // writing, there are definitely callers who call that way).
-
- 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.
- if (prev && (prev == child || prev == child->previousSibling()))
- break;
-
- // For a fragment we have more children to do.
- RefPtr<Node> nextChild = isFragment ? child->nextSibling() : 0;
-
- // Remove child from its old position.
- if (Node* oldParent = child->parentNode())
- oldParent->removeChild(child.get(), ec);
- if (ec)
- return 0;
-
- // Due to arbitrary code running in response to a DOM mutation event it's
- // possible that "prev" 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)
- break;
- if (child->parentNode())
- break;
-
- childCountDelta++;
-
- ASSERT(!child->nextSibling());
- ASSERT(!child->previousSibling());
-
- // Add child after "prev".
- 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);
- allowEventDispatch();
-
- // 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();
- }
-
- document()->setDocumentChanged(true);
- if (childCountDelta)
- childrenChanged(false, prev.get(), next.get(), childCountDelta);
- dispatchSubtreeModifiedEvent();
- return true;
-}
-
-void ContainerNode::willRemove()
-{
- for (Node *n = m_firstChild; n != 0; n = n->nextSibling())
- n->willRemove();
- Node::willRemove();
-}
-
-static ExceptionCode willRemoveChild(Node *child)
-{
- ExceptionCode ec = 0;
-
- // fire removed from document mutation events.
- dispatchChildRemovalEvents(child, ec);
- if (ec)
- return ec;
-
- if (child->attached())
- child->willRemove();
-
- return 0;
-}
-
-bool ContainerNode::removeChild(Node* oldChild, ExceptionCode& ec)
-{
- // Check that this node is not "floating".
- // If it is, it can be deleted as a side effect of sending mutation events.
- ASSERT(refCount() || parent());
-
- ec = 0;
-
- // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
- if (isReadOnlyNode()) {
- ec = NO_MODIFICATION_ALLOWED_ERR;
- return false;
- }
-
- // NOT_FOUND_ERR: Raised if oldChild is not a child of this node.
- if (!oldChild || oldChild->parentNode() != this) {
- ec = NOT_FOUND_ERR;
- return false;
- }
-
- RefPtr<Node> child = oldChild;
-
- ec = willRemoveChild(child.get());
- if (ec)
- return false;
-
- // Mutation events might have moved this child into a different parent.
- if (child->parentNode() != this) {
- ec = NOT_FOUND_ERR;
- 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
- // writing, there are definitely callers who call that way).
-
- forbidEventDispatch();
-
- // Remove from rendering tree
- if (child->attached())
- child->detach();
-
- // Remove the child
- Node *prev, *next;
- prev = child->previousSibling();
- next = child->nextSibling();
-
- if (next)
- next->setPreviousSibling(prev);
- if (prev)
- prev->setNextSibling(next);
- if (m_firstChild == child)
- m_firstChild = next;
- if (m_lastChild == child)
- m_lastChild = prev;
-
- child->setPreviousSibling(0);
- child->setNextSibling(0);
- child->setParent(0);
-
- allowEventDispatch();
-
- document()->setDocumentChanged(true);
-
- // Dispatch post-removal mutation events
- childrenChanged(false, prev, next, -1);
- dispatchSubtreeModifiedEvent();
-
- if (child->inDocument())
- child->removedFromDocument();
- else
- child->removedFromTree(true);
-
- return child;
-}
-
-// this differs from other remove functions because it forcibly removes all the children,
-// regardless of read-only status or event exceptions, e.g.
-bool ContainerNode::removeChildren()
-{
- if (!m_firstChild)
- 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();
-
- // 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();
- }
- 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 shouldLazyAttach)
-{
- // Check that this node is not "floating".
- // If it is, it can be deleted as a side effect of sending mutation events.
- ASSERT(refCount() || parent());
-
- ec = 0;
-
- // Make sure adding the new child is ok
- checkAddChild(newChild.get(), ec);
- if (ec)
- return 0;
-
- if (newChild == m_lastChild) // nothing to do
- return newChild;
-
- bool isFragment = newChild->nodeType() == DOCUMENT_FRAGMENT_NODE;
-
- // If newChild is a DocumentFragment with no children.... there's nothing to do.
- // Just return the document fragment
- if (isFragment && !newChild->firstChild())
- 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.
- RefPtr<Node> nextChild = isFragment ? child->nextSibling() : 0;
-
- // If child is already present in the tree, first remove it
- if (Node* oldParent = child->parentNode()) {
- oldParent->removeChild(child.get(), ec);
- if (ec)
- return 0;
-
- // 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;
- }
-
- // Append child to the end of the list
- childCountDelta++;
- forbidEventDispatch();
- child->setParent(this);
- if (m_lastChild) {
- child->setPreviousSibling(m_lastChild);
- m_lastChild->setNextSibling(child.get());
- } else
- m_firstChild = child.get();
- m_lastChild = child.get();
- allowEventDispatch();
-
- // 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;
-}
-
-ContainerNode* ContainerNode::addChild(PassRefPtr<Node> newChild)
-{
- // This function is only used during parsing.
- // It does not send any DOM mutation events.
-
- // Check for consistency with DTD, but only when parsing HTML.
- if (document()->isHTMLDocument() && !childAllowed(newChild.get()))
- return 0;
-
- forbidEventDispatch();
- Node* last = m_lastChild;
- appendChildToContainer<Node, ContainerNode>(newChild.get(), this);
- allowEventDispatch();
-
- document()->incDOMTreeVersion();
- if (inDocument())
- newChild->insertedIntoDocument();
- 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();
- 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();
- setHasChangedChild(false);
- Node::detach();
-}
-
-void ContainerNode::insertedIntoDocument()
-{
- Node::insertedIntoDocument();
- insertedIntoTree(false);
- for (Node* child = m_firstChild; child; child = child->nextSibling())
- child->insertedIntoDocument();
-}
-
-void ContainerNode::removedFromDocument()
-{
- Node::removedFromDocument();
- setInDocument(false);
- removedFromTree(false);
- for (Node* child = m_firstChild; child; child = child->nextSibling())
- child->removedFromDocument();
-}
-
-void ContainerNode::insertedIntoTree(bool deep)
-{
- if (!deep)
- return;
- for (Node* child = m_firstChild; child; child = child->nextSibling())
- child->insertedIntoTree(true);
-}
-
-void ContainerNode::removedFromTree(bool 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(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();
-}
-
-// 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;
-
- if (!o->isInline() || o->isReplaced()) {
- point = o->localToAbsolute();
- return true;
- }
-
- // find the next text/image child, to get a position
- while (o) {
- p = o;
- if (o->firstChild())
- o = o->firstChild();
- else if (o->nextSibling())
- o = o->nextSibling();
- else {
- RenderObject *next = 0;
- while (!next && o->parent()) {
- o = o->parent();
- next = o->nextSibling();
- }
- o = next;
-
- if (!o)
- break;
- }
-
- if (!o->isInline() || o->isReplaced()) {
- point = o->localToAbsolute();
- return true;
- }
-
- 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()) {
- 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. FIXME: who said anything about scrolling?
- if (!o && document()->view()) {
- point = FloatPoint(0, document()->view()->contentsHeight());
- return true;
- }
- return false;
-}
-
-// FIXME: This doesn't work correctly with transforms.
-bool ContainerNode::getLowerRightCorner(FloatPoint& point) const
-{
- if (!renderer())
- return false;
-
- RenderObject *o = renderer();
- if (!o->isInline() || o->isReplaced())
- {
- 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())
- o = o->lastChild();
- else if (o->previousSibling())
- o = o->previousSibling();
- else {
- RenderObject *prev = 0;
- while(!prev) {
- o = o->parent();
- if (!o)
- return false;
- prev = o->previousSibling();
- }
- o = prev;
- }
- 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());
- } else {
- RenderBox* box = toRenderBox(o);
- point.move(box->x() + box->width(), box->y() + box->height());
- }
- return true;
- }
- }
- return true;
-}
-
-IntRect ContainerNode::getRect() const
-{
- 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)
- lowerRight = upperLeft;
- else
- upperLeft = lowerRight;
- }
-
- 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 (focused() == received)
- return;
-
- Node::setFocus(received);
-
- // note that we need to recalc the style
- setChanged();
-}
-
-void ContainerNode::setActive(bool down, bool pause)
-{
- if (down == active()) return;
-
- Node::setActive(down);
-
- // note that we need to recalc the style
- // FIXME: Move to Element
- if (renderer()) {
- bool reactsToPress = renderer()->style()->affectedByActiveRules();
- if (reactsToPress)
- setChanged();
- if (renderer() && renderer()->style()->hasAppearance()) {
- if (theme()->stateChanged(renderer(), PressedState))
- reactsToPress = true;
- }
- if (reactsToPress && pause) {
- // The delay here is subtle. It relies on an assumption, namely that the amount of time it takes
- // 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).
-#ifdef HAVE_FUNC_USLEEP
- double startTime = currentTime();
-#endif
-
- // Ensure there are no pending changes
- Document::updateDocumentsRendering();
- // Do an immediate repaint.
- 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.
-#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)
- usleep(static_cast<useconds_t>(remainingTime * 1000000.0));
-#endif
- }
- }
-}
-
-void ContainerNode::setHovered(bool over)
-{
- if (over == hovered()) return;
-
- Node::setHovered(over);
-
- // note that we need to recalc the style
- // FIXME: Move to Element
- if (renderer()) {
- if (renderer()->style()->affectedByHoverRules())
- setChanged();
- if (renderer() && renderer()->style()->hasAppearance())
- theme()->stateChanged(renderer(), HoverState);
- }
-}
-
-unsigned ContainerNode::childNodeCount() const
-{
- unsigned count = 0;
- Node *n;
- for (n = firstChild(); n; n = n->nextSibling())
- count++;
- return count;
-}
-
-Node *ContainerNode::childNode(unsigned index) const
-{
- unsigned i;
- Node *n = firstChild();
- for (i = 0; n != 0 && i < index; i++)
- n = n->nextSibling();
- return n;
-}
-
-static void dispatchChildInsertionEvents(Node* child, ExceptionCode& ec)
-{
- ASSERT(!eventDispatchForbidden());
-
- RefPtr<Node> c = child;
- 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)) {
- ec = 0;
- c->dispatchEvent(MutationEvent::create(eventNames().DOMNodeInsertedEvent, true, false,
- c->parentNode(), String(), String(), String(), 0), ec);
- if (ec)
- return;
- }
-
- // dispatch the DOMNodeInsertedIntoDocument event to all descendants
- if (c->inDocument() && doc->hasListenerType(Document::DOMNODEINSERTEDINTODOCUMENT_LISTENER))
- for (; c; c = c->traverseNextNode(child)) {
- ec = 0;
- c->dispatchEvent(MutationEvent::create(eventNames().DOMNodeInsertedIntoDocumentEvent, false, false,
- 0, String(), String(), String(), 0), ec);
- if (ec)
- return;
- }
-}
-
-static void dispatchChildRemovalEvents(Node* child, ExceptionCode& ec)
-{
- RefPtr<Node> c = child;
- DocPtr<Document> doc = child->document();
-
- // update auxiliary doc info (e.g. iterators) to note that node is being removed
- doc->nodeWillBeRemoved(child);
-
- // dispatch pre-removal mutation events
- if (c->parentNode() && doc->hasListenerType(Document::DOMNODEREMOVED_LISTENER)) {
- ec = 0;
- c->dispatchEvent(MutationEvent::create(eventNames().DOMNodeRemovedEvent, true, false,
- c->parentNode(), String(), String(), String(), 0), ec);
- if (ec)
- return;
- }
-
- // dispatch the DOMNodeRemovedFromDocument event to all descendants
- if (c->inDocument() && doc->hasListenerType(Document::DOMNODEREMOVEDFROMDOCUMENT_LISTENER))
- for (; c; c = c->traverseNextNode(child)) {
- ec = 0;
- c->dispatchEvent(MutationEvent::create(eventNames().DOMNodeRemovedFromDocumentEvent, false, false,
- 0, String(), String(), String(), 0), ec);
- if (ec)
- return;
- }
-}
-
-}
+/*
+ * 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, 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "ContainerNode.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 "MutationEvent.h"
+#include "RenderTheme.h"
+#include "RootInlineBox.h"
+#include <wtf/CurrentTime.h>
+
+namespace WebCore {
+
+static void dispatchChildInsertionEvents(Node*, ExceptionCode&);
+static void dispatchChildRemovalEvents(Node*, ExceptionCode&);
+
+typedef Vector<std::pair<NodeCallback, RefPtr<Node> > > NodeCallbackQueue;
+static NodeCallbackQueue* s_postAttachCallbackQueue = 0;
+
+static size_t s_attachDepth = 0;
+
+void ContainerNode::removeAllChildren()
+{
+ removeAllChildrenInContainer<Node, ContainerNode>(this);
+}
+
+ContainerNode::~ContainerNode()
+{
+ removeAllChildren();
+}
+
+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.
+ ASSERT(refCount() || parent());
+
+ ec = 0;
+
+ // insertBefore(node, 0) is equivalent to appendChild(node)
+ if (!refChild)
+ return appendChild(newChild, ec, shouldLazyAttach);
+
+ // Make sure adding the new child is OK.
+ checkAddChild(newChild.get(), ec);
+ if (ec)
+ return false;
+
+ // NOT_FOUND_ERR: Raised if refChild is not a child of this node
+ if (refChild->parentNode() != this) {
+ ec = NOT_FOUND_ERR;
+ return false;
+ }
+
+ bool isFragment = newChild->nodeType() == DOCUMENT_FRAGMENT_NODE;
+
+ // If newChild is a DocumentFragment with no children; there's nothing to do.
+ // Just return true
+ if (isFragment && !newChild->firstChild())
+ return true;
+
+ // Now actually add the child(ren)
+ if (refChild->previousSibling() == newChild || refChild == newChild) // nothing to do
+ 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;
+
+ // If child is already present in the tree, first remove it from the old location.
+ if (Node* oldParent = child->parentNode())
+ oldParent->removeChild(child.get(), ec);
+ if (ec)
+ return 0;
+
+ // 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
+ // writing, there are definitely callers who call that way).
+
+ // 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.
+ // In either of those cases, we'll just stop.
+ if (next->parentNode() != this)
+ break;
+ if (child->parentNode())
+ break;
+
+ ASSERT(!child->nextSibling());
+ ASSERT(!child->previousSibling());
+
+ childCountDelta++;
+
+ // Add child before "next".
+ forbidEventDispatch();
+ Node* prev = next->previousSibling();
+ ASSERT(m_lastChild != prev);
+ next->setPreviousSibling(child.get());
+ if (prev) {
+ ASSERT(m_firstChild != next);
+ ASSERT(prev->nextSibling() == next);
+ prev->setNextSibling(child.get());
+ } else {
+ ASSERT(m_firstChild == next);
+ m_firstChild = child.get();
+ }
+ child->setParent(this);
+ child->setPreviousSibling(prev);
+ child->setNextSibling(next.get());
+ allowEventDispatch();
+
+ // 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 shouldLazyAttach)
+{
+ // Check that this node is not "floating".
+ // If it is, it can be deleted as a side effect of sending mutation events.
+ ASSERT(refCount() || parent());
+
+ ec = 0;
+
+ 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)
+ return false;
+
+ // NOT_FOUND_ERR: Raised if oldChild is not a child of this node.
+ if (!oldChild || oldChild->parentNode() != this) {
+ ec = NOT_FOUND_ERR;
+ return false;
+ }
+
+ RefPtr<Node> prev = oldChild->previousSibling();
+ RefPtr<Node> next = oldChild->nextSibling();
+
+ // Remove the node we're replacing
+ RefPtr<Node> removedChild = oldChild;
+ removeChild(oldChild, ec);
+ if (ec)
+ return false;
+
+ // 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
+ // writing, there are definitely callers who call that way).
+
+ 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.
+ if (prev && (prev == child || prev == child->previousSibling()))
+ break;
+
+ // For a fragment we have more children to do.
+ RefPtr<Node> nextChild = isFragment ? child->nextSibling() : 0;
+
+ // Remove child from its old position.
+ if (Node* oldParent = child->parentNode())
+ oldParent->removeChild(child.get(), ec);
+ if (ec)
+ return 0;
+
+ // Due to arbitrary code running in response to a DOM mutation event it's
+ // possible that "prev" 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)
+ break;
+ if (child->parentNode())
+ break;
+
+ childCountDelta++;
+
+ ASSERT(!child->nextSibling());
+ ASSERT(!child->previousSibling());
+
+ // Add child after "prev".
+ 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);
+ allowEventDispatch();
+
+ // 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();
+ }
+
+ document()->setDocumentChanged(true);
+ if (childCountDelta)
+ childrenChanged(false, prev.get(), next.get(), childCountDelta);
+ dispatchSubtreeModifiedEvent();
+ return true;
+}
+
+void ContainerNode::willRemove()
+{
+ for (Node *n = m_firstChild; n != 0; n = n->nextSibling())
+ n->willRemove();
+ EventTargetNode::willRemove();
+}
+
+static ExceptionCode willRemoveChild(Node *child)
+{
+ ExceptionCode ec = 0;
+
+ // fire removed from document mutation events.
+ dispatchChildRemovalEvents(child, ec);
+ if (ec)
+ return ec;
+
+ if (child->attached())
+ child->willRemove();
+
+ return 0;
+}
+
+bool ContainerNode::removeChild(Node* oldChild, ExceptionCode& ec)
+{
+ // Check that this node is not "floating".
+ // If it is, it can be deleted as a side effect of sending mutation events.
+ ASSERT(refCount() || parent());
+
+ ec = 0;
+
+ // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
+ if (isReadOnlyNode()) {
+ ec = NO_MODIFICATION_ALLOWED_ERR;
+ return false;
+ }
+
+ // NOT_FOUND_ERR: Raised if oldChild is not a child of this node.
+ if (!oldChild || oldChild->parentNode() != this) {
+ ec = NOT_FOUND_ERR;
+ return false;
+ }
+
+ RefPtr<Node> child = oldChild;
+
+ ec = willRemoveChild(child.get());
+ if (ec)
+ return false;
+
+ // Mutation events might have moved this child into a different parent.
+ if (child->parentNode() != this) {
+ ec = NOT_FOUND_ERR;
+ 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
+ // writing, there are definitely callers who call that way).
+
+ forbidEventDispatch();
+
+ // Remove from rendering tree
+ if (child->attached())
+ child->detach();
+
+ // Remove the child
+ Node *prev, *next;
+ prev = child->previousSibling();
+ next = child->nextSibling();
+
+ if (next)
+ next->setPreviousSibling(prev);
+ if (prev)
+ prev->setNextSibling(next);
+ if (m_firstChild == child)
+ m_firstChild = next;
+ if (m_lastChild == child)
+ m_lastChild = prev;
+
+ child->setPreviousSibling(0);
+ child->setNextSibling(0);
+ child->setParent(0);
+
+ allowEventDispatch();
+
+ document()->setDocumentChanged(true);
+
+ // Dispatch post-removal mutation events
+ childrenChanged(false, prev, next, -1);
+ dispatchSubtreeModifiedEvent();
+
+ if (child->inDocument())
+ child->removedFromDocument();
+ else
+ child->removedFromTree(true);
+
+ return child;
+}
+
+// this differs from other remove functions because it forcibly removes all the children,
+// regardless of read-only status or event exceptions, e.g.
+bool ContainerNode::removeChildren()
+{
+ if (!m_firstChild)
+ 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();
+
+ // 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();
+ }
+ 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 shouldLazyAttach)
+{
+ // Check that this node is not "floating".
+ // If it is, it can be deleted as a side effect of sending mutation events.
+ ASSERT(refCount() || parent());
+
+ ec = 0;
+
+ // Make sure adding the new child is ok
+ checkAddChild(newChild.get(), ec);
+ if (ec)
+ return 0;
+
+ if (newChild == m_lastChild) // nothing to do
+ return newChild;
+
+ bool isFragment = newChild->nodeType() == DOCUMENT_FRAGMENT_NODE;
+
+ // If newChild is a DocumentFragment with no children.... there's nothing to do.
+ // Just return the document fragment
+ if (isFragment && !newChild->firstChild())
+ 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.
+ RefPtr<Node> nextChild = isFragment ? child->nextSibling() : 0;
+
+ // If child is already present in the tree, first remove it
+ if (Node* oldParent = child->parentNode()) {
+ oldParent->removeChild(child.get(), ec);
+ if (ec)
+ return 0;
+
+ // 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;
+ }
+
+ // Append child to the end of the list
+ childCountDelta++;
+ forbidEventDispatch();
+ child->setParent(this);
+ if (m_lastChild) {
+ child->setPreviousSibling(m_lastChild);
+ m_lastChild->setNextSibling(child.get());
+ } else
+ m_firstChild = child.get();
+ m_lastChild = child.get();
+ allowEventDispatch();
+
+ // 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;
+}
+
+ContainerNode* ContainerNode::addChild(PassRefPtr<Node> newChild)
+{
+ // This function is only used during parsing.
+ // It does not send any DOM mutation events.
+
+ // Check for consistency with DTD, but only when parsing HTML.
+ if (document()->isHTMLDocument() && !childAllowed(newChild.get()))
+ return 0;
+
+ forbidEventDispatch();
+ Node* last = m_lastChild;
+ appendChildToContainer<Node, ContainerNode>(newChild.get(), this);
+ allowEventDispatch();
+
+ document()->incDOMTreeVersion();
+ if (inDocument())
+ newChild->insertedIntoDocument();
+ 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();
+
+ if (s_attachDepth == 1 && s_postAttachCallbackQueue)
+ dispatchPostAttachCallbacks();
+ --s_attachDepth;
+}
+
+void ContainerNode::detach()
+{
+ for (Node* child = m_firstChild; child; child = child->nextSibling())
+ child->detach();
+ setHasChangedChild(false);
+ EventTargetNode::detach();
+}
+
+void ContainerNode::insertedIntoDocument()
+{
+ EventTargetNode::insertedIntoDocument();
+ insertedIntoTree(false);
+ for (Node* child = m_firstChild; child; child = child->nextSibling())
+ child->insertedIntoDocument();
+}
+
+void ContainerNode::removedFromDocument()
+{
+ EventTargetNode::removedFromDocument();
+ setInDocument(false);
+ removedFromTree(false);
+ for (Node* child = m_firstChild; child; child = child->nextSibling())
+ child->removedFromDocument();
+}
+
+void ContainerNode::insertedIntoTree(bool deep)
+{
+ if (!deep)
+ return;
+ for (Node* child = m_firstChild; child; child = child->nextSibling())
+ child->insertedIntoTree(true);
+}
+
+void ContainerNode::removedFromTree(bool 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(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();
+}
+
+// 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;
+
+ if (!o->isInline() || o->isReplaced()) {
+ point = o->localToAbsolute();
+ return true;
+ }
+
+ // find the next text/image child, to get a position
+ while (o) {
+ p = o;
+ if (o->firstChild())
+ o = o->firstChild();
+ else if (o->nextSibling())
+ o = o->nextSibling();
+ else {
+ RenderObject *next = 0;
+ while (!next && o->parent()) {
+ o = o->parent();
+ next = o->nextSibling();
+ }
+ o = next;
+
+ if (!o)
+ break;
+ }
+
+ if (!o->isInline() || o->isReplaced()) {
+ point = o->localToAbsolute();
+ return true;
+ }
+
+ 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()) {
+ 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. FIXME: who said anything about scrolling?
+ if (!o && document()->view()) {
+ point = FloatPoint(0, document()->view()->contentsHeight());
+ return true;
+ }
+ return false;
+}
+
+// FIXME: This doesn't work correctly with transforms.
+bool ContainerNode::getLowerRightCorner(FloatPoint& point) const
+{
+ if (!renderer())
+ return false;
+
+ RenderObject *o = renderer();
+ if (!o->isInline() || o->isReplaced())
+ {
+ 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())
+ o = o->lastChild();
+ else if (o->previousSibling())
+ o = o->previousSibling();
+ else {
+ RenderObject *prev = 0;
+ while(!prev) {
+ o = o->parent();
+ if (!o)
+ return false;
+ prev = o->previousSibling();
+ }
+ o = prev;
+ }
+ 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());
+ } else {
+ RenderBox* box = toRenderBox(o);
+ point.move(box->x() + box->width(), box->y() + box->height());
+ }
+ return true;
+ }
+ }
+ return true;
+}
+
+IntRect ContainerNode::getRect() const
+{
+ 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)
+ lowerRight = upperLeft;
+ else
+ upperLeft = lowerRight;
+ }
+
+ 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 (focused() == received)
+ return;
+
+ EventTargetNode::setFocus(received);
+
+ // note that we need to recalc the style
+ setChanged();
+}
+
+void ContainerNode::setActive(bool down, bool pause)
+{
+ if (down == active()) return;
+
+ EventTargetNode::setActive(down);
+
+ // note that we need to recalc the style
+ // FIXME: Move to Element
+ if (renderer()) {
+ bool reactsToPress = renderer()->style()->affectedByActiveRules();
+ if (reactsToPress)
+ setChanged();
+ if (renderer() && renderer()->style()->hasAppearance()) {
+ if (theme()->stateChanged(renderer(), PressedState))
+ reactsToPress = true;
+ }
+ if (reactsToPress && pause) {
+ // The delay here is subtle. It relies on an assumption, namely that the amount of time it takes
+ // 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).
+#ifdef HAVE_FUNC_USLEEP
+ double startTime = currentTime();
+#endif
+
+ // Ensure there are no pending changes
+ Document::updateDocumentsRendering();
+ // Do an immediate repaint.
+ 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.
+#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)
+ usleep(static_cast<useconds_t>(remainingTime * 1000000.0));
+#endif
+ }
+ }
+}
+
+void ContainerNode::setHovered(bool over)
+{
+ if (over == hovered()) return;
+
+ EventTargetNode::setHovered(over);
+
+ // note that we need to recalc the style
+ // FIXME: Move to Element
+ if (renderer()) {
+ if (renderer()->style()->affectedByHoverRules())
+ setChanged();
+ if (renderer() && renderer()->style()->hasAppearance())
+ theme()->stateChanged(renderer(), HoverState);
+ }
+}
+
+unsigned ContainerNode::childNodeCount() const
+{
+ unsigned count = 0;
+ Node *n;
+ for (n = firstChild(); n; n = n->nextSibling())
+ count++;
+ return count;
+}
+
+Node *ContainerNode::childNode(unsigned index) const
+{
+ unsigned i;
+ Node *n = firstChild();
+ for (i = 0; n != 0 && i < index; i++)
+ n = n->nextSibling();
+ return n;
+}
+
+static void dispatchChildInsertionEvents(Node* child, ExceptionCode& ec)
+{
+ ASSERT(!eventDispatchForbidden());
+
+ RefPtr<Node> c = child;
+ 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()) {
+ ec = 0;
+ EventTargetNodeCast(c.get())->dispatchEvent(MutationEvent::create(eventNames().DOMNodeInsertedEvent, true, false,
+ c->parentNode(), String(), String(), String(), 0), ec);
+ if (ec)
+ return;
+ }
+
+ // 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,
+ 0, String(), String(), String(), 0), ec);
+ if (ec)
+ return;
+ }
+}
+
+static void dispatchChildRemovalEvents(Node* child, ExceptionCode& ec)
+{
+ RefPtr<Node> c = child;
+ DocPtr<Document> doc = child->document();
+
+ // update auxiliary doc info (e.g. iterators) to note that node is being removed
+ doc->nodeWillBeRemoved(child);
+
+ // dispatch pre-removal mutation events
+ if (c->parentNode() &&
+ doc->hasListenerType(Document::DOMNODEREMOVED_LISTENER) &&
+ c->isEventTargetNode()) {
+ ec = 0;
+ EventTargetNodeCast(c.get())->dispatchEvent(MutationEvent::create(eventNames().DOMNodeRemovedEvent, true, false,
+ c->parentNode(), String(), String(), String(), 0), ec);
+ if (ec)
+ return;
+ }
+
+ // 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,
+ 0, String(), String(), String(), 0), ec);
+ if (ec)
+ return;
+ }
+}
+
+}
« no previous file with comments | « third_party/WebKit/WebCore/dom/ContainerNode.h ('k') | third_party/WebKit/WebCore/dom/Document.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698