diff options
| author | Allan Sandfeld Jensen <allan.jensen@digia.com> | 2013-09-13 12:51:20 +0200 |
|---|---|---|
| committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-09-19 20:50:05 +0200 |
| commit | d441d6f39bb846989d95bcf5caf387b42414718d (patch) | |
| tree | e367e64a75991c554930278175d403c072de6bb8 /Source/WebCore/dom/ContainerNode.cpp | |
| parent | 0060b2994c07842f4c59de64b5e3e430525c4b90 (diff) | |
| download | qtwebkit-d441d6f39bb846989d95bcf5caf387b42414718d.tar.gz | |
Import Qt5x2 branch of QtWebkit for Qt 5.2
Importing a new snapshot of webkit.
Change-Id: I2d01ad12cdc8af8cb015387641120a9d7ea5f10c
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@digia.com>
Diffstat (limited to 'Source/WebCore/dom/ContainerNode.cpp')
| -rw-r--r-- | Source/WebCore/dom/ContainerNode.cpp | 401 |
1 files changed, 181 insertions, 220 deletions
diff --git a/Source/WebCore/dom/ContainerNode.cpp b/Source/WebCore/dom/ContainerNode.cpp index a8ae7c893..47538fe84 100644 --- a/Source/WebCore/dom/ContainerNode.cpp +++ b/Source/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, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 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 @@ -25,32 +25,38 @@ #include "AXObjectCache.h" #include "ChildListMutationScope.h" +#include "Chrome.h" +#include "ChromeClient.h" #include "ContainerNodeAlgorithms.h" -#include "DeleteButtonController.h" +#include "Editor.h" #include "EventNames.h" #include "ExceptionCode.h" #include "FloatRect.h" #include "Frame.h" #include "FrameView.h" +#include "HTMLNames.h" #include "InlineTextBox.h" #include "InsertionPoint.h" #include "InspectorInstrumentation.h" +#include "JSNode.h" #include "LoaderStrategy.h" #include "MemoryCache.h" #include "MutationEvent.h" #include "NodeRenderStyle.h" -#include "ResourceLoadScheduler.h" +#include "NodeTraversal.h" #include "Page.h" #include "PlatformStrategies.h" #include "RenderBox.h" #include "RenderTheme.h" #include "RenderWidget.h" +#include "ResourceLoadScheduler.h" #include "RootInlineBox.h" +#include "TemplateContentDocumentFragment.h" #include <wtf/CurrentTime.h> #include <wtf/Vector.h> -#if USE(JSC) -#include "JSNode.h" +#if ENABLE(DELETION_UI) +#include "DeleteButtonController.h" #endif using namespace std; @@ -59,7 +65,7 @@ namespace WebCore { static void dispatchChildInsertionEvents(Node*); static void dispatchChildRemovalEvents(Node*); -static void updateTreeAfterInsertion(ContainerNode*, Node*, bool shouldLazyAttach); +static void updateTreeAfterInsertion(ContainerNode*, Node*, AttachBehavior); typedef pair<RefPtr<Node>, unsigned> CallbackParameters; typedef pair<NodeCallback, CallbackParameters> CallbackInfo; @@ -76,15 +82,6 @@ ChildNodesLazySnapshot* ChildNodesLazySnapshot::latestSnapshot = 0; unsigned NoEventDispatchAssertion::s_count = 0; #endif -static void collectTargetNodes(Node* node, NodeVector& nodes) -{ - if (node->nodeType() != Node::DOCUMENT_FRAGMENT_NODE) { - nodes.append(node); - return; - } - getChildNodes(node, nodes); -} - static void collectChildrenAndRemoveFromOldParent(Node* node, NodeVector& nodes, ExceptionCode& ec) { if (node->nodeType() != Node::DOCUMENT_FRAGMENT_NODE) { @@ -97,24 +94,37 @@ static void collectChildrenAndRemoveFromOldParent(Node* node, NodeVector& nodes, toContainerNode(node)->removeChildren(); } -void ContainerNode::removeAllChildren() +void ContainerNode::removeDetachedChildren() { - removeAllChildrenInContainer<Node, ContainerNode>(this); + if (connectedSubframeCount()) { + for (Node* child = firstChild(); child; child = child->nextSibling()) + child->updateAncestorConnectedSubframeCountForRemoval(); + } + // FIXME: We should be able to ASSERT(!attached()) here: https://bugs.webkit.org/show_bug.cgi?id=107801 + removeDetachedChildrenInContainer<Node, ContainerNode>(this); } void ContainerNode::takeAllChildrenFrom(ContainerNode* oldParent) { NodeVector children; getChildNodes(oldParent, children); - oldParent->removeAllChildren(); + + if (oldParent->document()->hasMutationObserversOfType(MutationObserver::ChildList)) { + ChildListMutationScope mutation(oldParent); + for (unsigned i = 0; i < children.size(); ++i) + mutation.willRemoveChild(children[i].get()); + } + + // FIXME: We need to do notifyMutationObserversNodeWillDetach() for each child, + // probably inside removeDetachedChildrenInContainer. + + oldParent->removeDetachedChildren(); for (unsigned i = 0; i < children.size(); ++i) { - ExceptionCode ec = 0; if (children[i]->attached()) children[i]->detach(); // FIXME: We need a no mutation event version of adoptNode. - RefPtr<Node> child = document()->adoptNode(children[i].release(), ec); - ASSERT(!ec); + RefPtr<Node> child = document()->adoptNode(children[i].release(), ASSERT_NO_EXCEPTION); parserAppendChild(child.get()); // FIXME: Together with adoptNode above, the tree scope might get updated recursively twice // (if the document changed or oldParent was in a shadow tree, AND *this is in a shadow tree). @@ -127,10 +137,9 @@ void ContainerNode::takeAllChildrenFrom(ContainerNode* oldParent) ContainerNode::~ContainerNode() { - if (AXObjectCache::accessibilityEnabled() && documentInternal() && documentInternal()->axObjectCacheExists()) - documentInternal()->axObjectCache()->remove(this); - - removeAllChildren(); + if (Document* document = documentInternal()) + willBeDeletedFrom(document); + removeDetachedChildren(); } static inline bool isChildTypeAllowed(ContainerNode* newParent, Node* child) @@ -145,31 +154,54 @@ static inline bool isChildTypeAllowed(ContainerNode* newParent, Node* child) return true; } +static inline bool isInTemplateContent(const Node* node) +{ +#if ENABLE(TEMPLATE_ELEMENT) + Document* document = node->document(); + return document && document == document->templateDocument(); +#else + UNUSED_PARAM(node); + return false; +#endif +} + +static inline bool containsConsideringHostElements(const Node* newChild, const Node* newParent) +{ + return (newParent->isInShadowTree() || isInTemplateContent(newParent)) + ? newChild->containsIncludingHostElements(newParent) + : newChild->contains(newParent); +} + static inline ExceptionCode checkAcceptChild(ContainerNode* newParent, Node* newChild, Node* oldChild) { // Not mentioned in spec: throw NOT_FOUND_ERR if newChild is null if (!newChild) return NOT_FOUND_ERR; - // Goes common casae fast path if possible. + // Use common case fast path if possible. if ((newChild->isElementNode() || newChild->isTextNode()) && newParent->isElementNode()) { ASSERT(!newParent->isReadOnlyNode()); ASSERT(!newParent->isDocumentTypeNode()); ASSERT(isChildTypeAllowed(newParent, newChild)); - if (newChild->contains(newParent)) + if (containsConsideringHostElements(newChild, newParent)) return HIERARCHY_REQUEST_ERR; return 0; } + // This should never happen, but also protect release builds from tree corruption. + ASSERT(!newChild->isPseudoElement()); + if (newChild->isPseudoElement()) + return HIERARCHY_REQUEST_ERR; + if (newParent->isReadOnlyNode()) return NO_MODIFICATION_ALLOWED_ERR; if (newChild->inDocument() && newChild->isDocumentTypeNode()) return HIERARCHY_REQUEST_ERR; - if (newChild->contains(newParent)) + if (containsConsideringHostElements(newChild, newParent)) return HIERARCHY_REQUEST_ERR; if (oldChild && newParent->isDocumentNode()) { - if (!static_cast<Document*>(newParent)->canReplaceChild(newChild, oldChild)) + if (!toDocument(newParent)->canReplaceChild(newChild, oldChild)) return HIERARCHY_REQUEST_ERR; } else if (!isChildTypeAllowed(newParent, newChild)) return HIERARCHY_REQUEST_ERR; @@ -177,31 +209,42 @@ static inline ExceptionCode checkAcceptChild(ContainerNode* newParent, Node* new return 0; } -static inline bool checkAddChild(ContainerNode* newParent, Node* newChild, ExceptionCode& ec) +static inline bool checkAcceptChildGuaranteedNodeTypes(ContainerNode* newParent, Node* newChild, ExceptionCode& ec) { - if (ExceptionCode code = checkAcceptChild(newParent, newChild, 0)) { - ec = code; + ASSERT(!newParent->isReadOnlyNode()); + ASSERT(!newParent->isDocumentTypeNode()); + ASSERT(isChildTypeAllowed(newParent, newChild)); + if (newChild->contains(newParent)) { + ec = HIERARCHY_REQUEST_ERR; return false; } return true; } +static inline bool checkAddChild(ContainerNode* newParent, Node* newChild, ExceptionCode& ec) +{ + ec = checkAcceptChild(newParent, newChild, 0); + if (ec) + return false; + + return true; +} + static inline bool checkReplaceChild(ContainerNode* newParent, Node* newChild, Node* oldChild, ExceptionCode& ec) { - if (ExceptionCode code = checkAcceptChild(newParent, newChild, oldChild)) { - ec = code; + ec = checkAcceptChild(newParent, newChild, oldChild); + if (ec) return false; - } - + return true; } -bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode& ec, bool shouldLazyAttach) +bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode& ec, AttachBehavior attachBehavior) { // Check that this node is not "floating". // If it is, it can be deleted as a side effect of sending mutation events. - ASSERT(refCount() || parentOrHostNode()); + ASSERT(refCount() || parentOrShadowHostNode()); RefPtr<Node> protect(this); @@ -209,7 +252,7 @@ bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce // insertBefore(node, 0) is equivalent to appendChild(node) if (!refChild) - return appendChild(newChild, ec, shouldLazyAttach); + return appendChild(newChild, ec, attachBehavior); // Make sure adding the new child is OK. if (!checkAddChild(this, newChild.get(), ec)) @@ -233,12 +276,13 @@ bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce if (targets.isEmpty()) return true; + // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events. + if (!checkAcceptChildGuaranteedNodeTypes(this, newChild.get(), ec)) + return false; + InspectorInstrumentation::willInsertDOMNode(document(), this); -#if ENABLE(MUTATION_OBSERVERS) ChildListMutationScope mutation(this); -#endif - for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); ++it) { Node* child = it->get(); @@ -255,7 +299,7 @@ bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce insertBeforeCommon(next.get(), child); - updateTreeAfterInsertion(this, child, shouldLazyAttach); + updateTreeAfterInsertion(this, child, attachBehavior); } dispatchSubtreeModifiedEvent(); @@ -283,7 +327,7 @@ void ContainerNode::insertBeforeCommon(Node* nextChild, Node* newChild) ASSERT(m_firstChild == nextChild); m_firstChild = newChild; } - newChild->setParentOrHostNode(this); + newChild->setParentOrShadowHostNode(this); newChild->setPreviousSibling(prev); newChild->setNextSibling(nextChild); } @@ -293,32 +337,32 @@ void ContainerNode::parserInsertBefore(PassRefPtr<Node> newChild, Node* nextChil ASSERT(newChild); ASSERT(nextChild); ASSERT(nextChild->parentNode() == this); - - NodeVector targets; - collectTargetNodes(newChild.get(), targets); - if (targets.isEmpty()) - return; + ASSERT(!newChild->isDocumentFragment()); +#if ENABLE(TEMPLATE_ELEMENT) + ASSERT(!hasTagName(HTMLNames::templateTag)); +#endif if (nextChild->previousSibling() == newChild || nextChild == newChild) // nothing to do return; - RefPtr<Node> next = nextChild; - RefPtr<Node> nextChildPreviousSibling = nextChild->previousSibling(); - for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); ++it) { - Node* child = it->get(); + if (document() != newChild->document()) + document()->adoptNode(newChild.get(), ASSERT_NO_EXCEPTION); - insertBeforeCommon(next.get(), child); + insertBeforeCommon(nextChild, newChild.get()); - childrenChanged(true, nextChildPreviousSibling.get(), nextChild, 1); - ChildNodeInsertionNotifier(this).notify(child); - } + newChild->updateAncestorConnectedSubframeCountForInsertion(); + + ChildListMutationScope(this).childAdded(newChild.get()); + + childrenChanged(true, newChild->previousSibling(), nextChild, 1); + ChildNodeInsertionNotifier(this).notify(newChild.get()); } -bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode& ec, bool shouldLazyAttach) +bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode& ec, AttachBehavior attachBehavior) { // Check that this node is not "floating". // If it is, it can be deleted as a side effect of sending mutation events. - ASSERT(refCount() || parentOrHostNode()); + ASSERT(refCount() || parentOrShadowHostNode()); RefPtr<Node> protect(this); @@ -342,9 +386,7 @@ bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce return false; } -#if ENABLE(MUTATION_OBSERVERS) ChildListMutationScope mutation(this); -#endif RefPtr<Node> next = oldChild->nextSibling(); @@ -396,7 +438,7 @@ bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce appendChildToContainer(child, this); } - updateTreeAfterInsertion(this, child, shouldLazyAttach); + updateTreeAfterInsertion(this, child, attachBehavior); } dispatchSubtreeModifiedEvent(); @@ -405,12 +447,9 @@ bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce static void willRemoveChild(Node* child) { -#if ENABLE(MUTATION_OBSERVERS) ASSERT(child->parentNode()); ChildListMutationScope(child->parentNode()).willRemoveChild(child); child->notifyMutationObserversNodeWillDetach(); -#endif - dispatchChildRemovalEvents(child); child->document()->nodeWillBeRemoved(child); // e.g. mutation event listener can create a new range. ChildFrameDisconnector(child).disconnect(); @@ -423,23 +462,17 @@ static void willRemoveChildren(ContainerNode* container) container->document()->nodeChildrenWillBeRemoved(container); -#if ENABLE(MUTATION_OBSERVERS) ChildListMutationScope mutation(container); -#endif - - for (NodeVector::const_iterator it = children.begin(); it != children.end(); it++) { + for (NodeVector::const_iterator it = children.begin(); it != children.end(); ++it) { Node* child = it->get(); - -#if ENABLE(MUTATION_OBSERVERS) mutation.willRemoveChild(child); child->notifyMutationObserversNodeWillDetach(); -#endif // fire removed from document mutation events. dispatchChildRemovalEvents(child); } - ChildFrameDisconnector(container, ChildFrameDisconnector::DoNotIncludeRoot).disconnect(); + ChildFrameDisconnector(container).disconnect(ChildFrameDisconnector::DescendantsOnly); } void ContainerNode::disconnectDescendantFrames() @@ -451,7 +484,7 @@ 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() || parentOrHostNode()); + ASSERT(refCount() || parentOrShadowHostNode()); RefPtr<Node> protect(this); @@ -528,7 +561,7 @@ void ContainerNode::removeBetween(Node* previousChild, Node* nextChild, Node* ol oldChild->setPreviousSibling(0); oldChild->setNextSibling(0); - oldChild->setParentOrHostNode(0); + oldChild->setParentOrShadowHostNode(0); document()->adoptIfNeeded(oldChild); } @@ -537,10 +570,16 @@ void ContainerNode::parserRemoveChild(Node* oldChild) { ASSERT(oldChild); ASSERT(oldChild->parentNode() == this); + ASSERT(!oldChild->isDocumentFragment()); Node* prev = oldChild->previousSibling(); Node* next = oldChild->nextSibling(); + oldChild->updateAncestorConnectedSubframeCountForRemoval(); + + ChildListMutationScope(this).willRemoveChild(oldChild); + oldChild->notifyMutationObserversNodeWillDetach(); + removeBetween(prev, next, oldChild); childrenChanged(true, prev, next, -1); @@ -568,59 +607,34 @@ void ContainerNode::removeChildren() // and remove... e.g. stop loading frames, fire unload events. willRemoveChildren(protect.get()); - Vector<RefPtr<Node>, 10> removedChildren; + NodeVector removedChildren; { WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates; - NoEventDispatchAssertion assertNoEventDispatch; - removedChildren.reserveInitialCapacity(childNodeCount()); - while (RefPtr<Node> n = m_firstChild) { - Node* next = n->nextSibling(); - - // Remove the node from the tree before calling detach or removedFromDocument (4427024, 4129744). - // removeChild() does this after calling detach(). There is no explanation for - // this discrepancy between removeChild() and its optimized version removeChildren(). - n->setPreviousSibling(0); - n->setNextSibling(0); - n->setParentOrHostNode(0); - document()->adoptIfNeeded(n.get()); - - m_firstChild = next; - if (n == m_lastChild) - m_lastChild = 0; - removedChildren.append(n.release()); - } - - size_t removedChildrenCount = removedChildren.size(); - size_t i; - - // Detach the nodes only after properly removed from the tree because - // a. detaching requires a proper DOM tree (for counters and quotes for - // example) and during the previous loop the next sibling still points to - // the node being removed while the node being removed does not point back - // and does not point to the same parent as its next sibling. - // b. destroying Renderers of standalone nodes is sometimes faster. - for (i = 0; i < removedChildrenCount; ++i) { - Node* removedChild = removedChildren[i].get(); - if (removedChild->attached()) - removedChild->detach(); + { + NoEventDispatchAssertion assertNoEventDispatch; + removedChildren.reserveInitialCapacity(childNodeCount()); + while (RefPtr<Node> n = m_firstChild) { + removedChildren.append(m_firstChild); + removeBetween(0, m_firstChild->nextSibling(), m_firstChild); + } } - childrenChanged(false, 0, 0, -static_cast<int>(removedChildrenCount)); - - for (i = 0; i < removedChildrenCount; ++i) + childrenChanged(false, 0, 0, -static_cast<int>(removedChildren.size())); + + for (size_t i = 0; i < removedChildren.size(); ++i) ChildNodeRemovalNotifier(this).notify(removedChildren[i].get()); } dispatchSubtreeModifiedEvent(); } -bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, bool shouldLazyAttach) +bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, AttachBehavior attachBehavior) { RefPtr<ContainerNode> protect(this); // Check that this node is not "floating". // If it is, it can be deleted as a side effect of sending mutation events. - ASSERT(refCount() || parentOrHostNode()); + ASSERT(refCount() || parentOrShadowHostNode()); ec = 0; @@ -639,13 +653,14 @@ bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, bo if (targets.isEmpty()) return true; - InspectorInstrumentation::willInsertDOMNode(document(), this); + // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events. + if (!checkAcceptChildGuaranteedNodeTypes(this, newChild.get(), ec)) + return false; -#if ENABLE(MUTATION_OBSERVERS) - ChildListMutationScope mutation(this); -#endif + InspectorInstrumentation::willInsertDOMNode(document(), this); // Now actually add the child(ren) + ChildListMutationScope mutation(this); for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); ++it) { Node* child = it->get(); @@ -663,7 +678,7 @@ bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, bo appendChildToContainer(child, this); } - updateTreeAfterInsertion(this, child, shouldLazyAttach); + updateTreeAfterInsertion(this, child, attachBehavior); } dispatchSubtreeModifiedEvent(); @@ -674,6 +689,13 @@ void ContainerNode::parserAppendChild(PassRefPtr<Node> newChild) { ASSERT(newChild); ASSERT(!newChild->parentNode()); // Use appendChild if you need to handle reparenting (and want DOM mutation events). + ASSERT(!newChild->isDocumentFragment()); +#if ENABLE(TEMPLATE_ELEMENT) + ASSERT(!hasTagName(HTMLNames::templateTag)); +#endif + + if (document() != newChild->document()) + document()->adoptNode(newChild.get(), ASSERT_NO_EXCEPTION); Node* last = m_lastChild; { @@ -683,6 +705,10 @@ void ContainerNode::parserAppendChild(PassRefPtr<Node> newChild) treeScope()->adoptIfNeeded(newChild.get()); } + newChild->updateAncestorConnectedSubframeCountForInsertion(); + + ChildListMutationScope(this).childAdded(newChild.get()); + childrenChanged(true, last, 0, 1); ChildNodeInsertionNotifier(this).notify(newChild.get()); } @@ -699,11 +725,7 @@ void ContainerNode::suspendPostAttachCallbacks() s_shouldReEnableMemoryCacheCallsAfterAttach = true; } } -#if USE(PLATFORM_STRATEGIES) platformStrategies()->loaderStrategy()->resourceLoadScheduler()->suspendPendingRequests(); -#else - resourceLoadScheduler()->suspendPendingRequests(); -#endif } ++s_attachDepth; } @@ -720,11 +742,7 @@ void ContainerNode::resumePostAttachCallbacks() if (Page* page = document()->page()) page->setMemoryCacheClientCallsEnabled(true); } -#if USE(PLATFORM_STRATEGIES) platformStrategies()->loaderStrategy()->resourceLoadScheduler()->resumePendingRequests(); -#else - resourceLoadScheduler()->resumePendingRequests(); -#endif } --s_attachDepth; } @@ -769,17 +787,17 @@ void ContainerNode::scheduleSetNeedsStyleRecalc(StyleChangeType changeType) setNeedsStyleRecalc(changeType); } -void ContainerNode::attach() +void ContainerNode::attach(const AttachContext& context) { - attachChildren(); - Node::attach(); + attachChildren(context); + Node::attach(context); } -void ContainerNode::detach() +void ContainerNode::detach(const AttachContext& context) { - detachChildren(); + detachChildren(context); clearChildNeedsStyleRecalc(); - Node::detach(); + Node::detach(context); } void ContainerNode::childrenChanged(bool changedByParser, Node*, Node*, int childCountDelta) @@ -790,20 +808,38 @@ void ContainerNode::childrenChanged(bool changedByParser, Node*, Node*, int chil invalidateNodeListCachesInAncestors(); } -void ContainerNode::cloneChildNodes(ContainerNode *clone) +inline static void cloneChildNodesAvoidingDeleteButton(ContainerNode* parent, ContainerNode* clonedParent, HTMLElement* deleteButtonContainerElement) { - HTMLElement* deleteButtonContainerElement = 0; - if (Frame* frame = document()->frame()) - deleteButtonContainerElement = frame->editor()->deleteButtonController()->containerElement(); - ExceptionCode ec = 0; - for (Node* n = firstChild(); n && !ec; n = n->nextSibling()) { - if (n == deleteButtonContainerElement) + for (Node* child = parent->firstChild(); child && !ec; child = child->nextSibling()) { + +#if ENABLE(DELETION_UI) + if (child == deleteButtonContainerElement) continue; - clone->appendChild(n->cloneNode(true), ec); +#else + UNUSED_PARAM(deleteButtonContainerElement); +#endif + + RefPtr<Node> clonedChild = child->cloneNode(false); + clonedParent->appendChild(clonedChild, ec); + + if (!ec && child->isContainerNode()) + cloneChildNodesAvoidingDeleteButton(toContainerNode(child), toContainerNode(clonedChild.get()), deleteButtonContainerElement); } } +void ContainerNode::cloneChildNodes(ContainerNode *clone) +{ +#if ENABLE(DELETION_UI) + HTMLElement* deleteButtonContainerElement = 0; + if (Frame* frame = document()->frame()) + deleteButtonContainerElement = frame->editor().deleteButtonController()->containerElement(); + cloneChildNodesAvoidingDeleteButton(this, clone, deleteButtonContainerElement); +#else + cloneChildNodesAvoidingDeleteButton(this, clone, 0); +#endif +} + bool ContainerNode::getUpperLeftCorner(FloatPoint& point) const { if (!renderer()) @@ -852,7 +888,7 @@ bool ContainerNode::getUpperLeftCorner(FloatPoint& point) const RenderBox* box = toRenderBox(o); point.moveBy(box->location()); } - point = o->container()->localToAbsolute(point, UseTransforms | SnapOffsetForTransforms); + point = o->container()->localToAbsolute(point, UseTransforms); return true; } } @@ -932,76 +968,6 @@ LayoutRect ContainerNode::boundingBox() const return enclosingLayoutRect(FloatRect(upperLeft, lowerRight.expandedTo(upperLeft) - upperLeft)); } -void ContainerNode::setFocus(bool received) -{ - if (focused() == received) - return; - - Node::setFocus(received); - - // note that we need to recalc the style - setNeedsStyleRecalc(); -} - -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 = renderStyle()->affectedByActive() || (isElementNode() && toElement(this)->childrenAffectedByActive()); - if (reactsToPress) - setNeedsStyleRecalc(); - if (renderStyle()->hasAppearance()) { - if (renderer()->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::updateStyleForAllDocuments(); - // 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 (renderStyle()->affectedByHover() || (isElementNode() && toElement(this)->childrenAffectedByHover())) - setNeedsStyleRecalc(); - if (renderer() && renderer()->style()->hasAppearance()) - renderer()->theme()->stateChanged(renderer(), HoverState); - } -} - unsigned ContainerNode::childNodeCount() const { unsigned count = 0; @@ -1020,7 +986,6 @@ Node *ContainerNode::childNode(unsigned index) const return n; } - static void dispatchChildInsertionEvents(Node* child) { if (child->isInShadowTree()) @@ -1036,7 +1001,7 @@ static void dispatchChildInsertionEvents(Node* child) // dispatch the DOMNodeInsertedIntoDocument event to all descendants if (c->inDocument() && document->hasListenerType(Document::DOMNODEINSERTEDINTODOCUMENT_LISTENER)) { - for (; c; c = c->traverseNextNode(child)) + for (; c; c = NodeTraversal::next(c.get(), child)) c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeInsertedIntoDocumentEvent, false)); } } @@ -1050,9 +1015,7 @@ static void dispatchChildRemovalEvents(Node* child) ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden()); -#if USE(JSC) willCreatePossiblyOrphanedTreeByRemoval(child); -#endif InspectorInstrumentation::willRemoveDOMNode(child->document(), child); RefPtr<Node> c = child; @@ -1064,19 +1027,17 @@ static void dispatchChildRemovalEvents(Node* child) // dispatch the DOMNodeRemovedFromDocument event to all descendants if (c->inDocument() && document->hasListenerType(Document::DOMNODEREMOVEDFROMDOCUMENT_LISTENER)) { - for (; c; c = c->traverseNextNode(child)) + for (; c; c = NodeTraversal::next(c.get(), child)) c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeRemovedFromDocumentEvent, false)); } } -static void updateTreeAfterInsertion(ContainerNode* parent, Node* child, bool shouldLazyAttach) +static void updateTreeAfterInsertion(ContainerNode* parent, Node* child, AttachBehavior attachBehavior) { ASSERT(parent->refCount()); ASSERT(child->refCount()); -#if ENABLE(MUTATION_OBSERVERS) ChildListMutationScope(parent).childAdded(child); -#endif parent->childrenChanged(false, child->previousSibling(), child->nextSibling(), 1); @@ -1085,7 +1046,7 @@ static void updateTreeAfterInsertion(ContainerNode* parent, Node* child, bool sh // FIXME: Attachment should be the first operation in this function, but some code // (for example, HTMLFormControlElement's autofocus support) requires this ordering. if (parent->attached() && !child->attached() && child->parentNode() == parent) { - if (shouldLazyAttach) + if (attachBehavior == AttachLazily) child->lazyAttach(); else child->attach(); |
