2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
24 #include "ContainerNode.h"
26 #include "AXObjectCache.h"
27 #include "ChildListMutationScope.h"
28 #include "ContainerNodeAlgorithms.h"
29 #include "DeleteButtonController.h"
30 #include "EventNames.h"
31 #include "ExceptionCode.h"
32 #include "FloatRect.h"
34 #include "FrameView.h"
35 #include "InlineTextBox.h"
36 #include "InsertionPoint.h"
37 #include "InspectorInstrumentation.h"
38 #include "LoaderStrategy.h"
39 #include "MemoryCache.h"
40 #include "MutationEvent.h"
41 #include "NodeRenderStyle.h"
42 #include "NodeTraversal.h"
43 #include "ResourceLoadScheduler.h"
45 #include "PlatformStrategies.h"
46 #include "RenderBox.h"
47 #include "RenderTheme.h"
48 #include "RenderWidget.h"
49 #include "RootInlineBox.h"
50 #include "TemplateContentDocumentFragment.h"
51 #include <wtf/CurrentTime.h>
52 #include <wtf/Vector.h>
62 static void dispatchChildInsertionEvents(Node*);
63 static void dispatchChildRemovalEvents(Node*);
64 static void updateTreeAfterInsertion(ContainerNode*, Node*, bool shouldLazyAttach);
66 typedef pair<RefPtr<Node>, unsigned> CallbackParameters;
67 typedef pair<NodeCallback, CallbackParameters> CallbackInfo;
68 typedef Vector<CallbackInfo> NodeCallbackQueue;
70 static NodeCallbackQueue* s_postAttachCallbackQueue;
72 static size_t s_attachDepth;
73 static bool s_shouldReEnableMemoryCacheCallsAfterAttach;
75 ChildNodesLazySnapshot* ChildNodesLazySnapshot::latestSnapshot = 0;
78 unsigned NoEventDispatchAssertion::s_count = 0;
81 static void collectChildrenAndRemoveFromOldParent(Node* node, NodeVector& nodes, ExceptionCode& ec)
83 if (node->nodeType() != Node::DOCUMENT_FRAGMENT_NODE) {
85 if (ContainerNode* oldParent = node->parentNode())
86 oldParent->removeChild(node, ec);
89 getChildNodes(node, nodes);
90 toContainerNode(node)->removeChildren();
93 void ContainerNode::removeAllChildren()
95 removeAllChildrenInContainer<Node, ContainerNode>(this);
98 void ContainerNode::takeAllChildrenFrom(ContainerNode* oldParent)
101 getChildNodes(oldParent, children);
102 oldParent->removeAllChildren();
104 for (unsigned i = 0; i < children.size(); ++i) {
105 ExceptionCode ec = 0;
106 if (children[i]->attached())
107 children[i]->detach();
108 // FIXME: We need a no mutation event version of adoptNode.
109 RefPtr<Node> child = document()->adoptNode(children[i].release(), ec);
111 parserAppendChild(child.get());
112 // FIXME: Together with adoptNode above, the tree scope might get updated recursively twice
113 // (if the document changed or oldParent was in a shadow tree, AND *this is in a shadow tree).
115 treeScope()->adoptIfNeeded(child.get());
116 if (attached() && !child->attached())
121 ContainerNode::~ContainerNode()
123 if (AXObjectCache::accessibilityEnabled() && documentInternal() && documentInternal()->axObjectCacheExists())
124 documentInternal()->axObjectCache()->remove(this);
129 static inline bool isChildTypeAllowed(ContainerNode* newParent, Node* child)
131 if (!child->isDocumentFragment())
132 return newParent->childTypeAllowed(child->nodeType());
134 for (Node* node = child->firstChild(); node; node = node->nextSibling()) {
135 if (!newParent->childTypeAllowed(node->nodeType()))
141 static inline bool isInTemplateContent(const Node* node)
143 #if ENABLE(TEMPLATE_ELEMENT)
144 Document* document = node->document();
145 return document && document == document->templateContentsOwnerDocument();
152 static inline bool containsConsideringHostElements(const Node* newChild, const Node* newParent)
154 return (newParent->isInShadowTree() || isInTemplateContent(newParent))
155 ? newChild->containsIncludingHostElements(newParent)
156 : newChild->contains(newParent);
159 static inline ExceptionCode checkAcceptChild(ContainerNode* newParent, Node* newChild, Node* oldChild)
161 // Not mentioned in spec: throw NOT_FOUND_ERR if newChild is null
163 return NOT_FOUND_ERR;
165 // Use common case fast path if possible.
166 if ((newChild->isElementNode() || newChild->isTextNode()) && newParent->isElementNode()) {
167 ASSERT(!newParent->isReadOnlyNode());
168 ASSERT(!newParent->isDocumentTypeNode());
169 ASSERT(isChildTypeAllowed(newParent, newChild));
170 if (containsConsideringHostElements(newChild, newParent))
171 return HIERARCHY_REQUEST_ERR;
175 // This should never happen, but also protect release builds from tree corruption.
176 ASSERT(!newChild->isPseudoElement());
177 if (newChild->isPseudoElement())
178 return HIERARCHY_REQUEST_ERR;
180 if (newParent->isReadOnlyNode())
181 return NO_MODIFICATION_ALLOWED_ERR;
182 if (newChild->inDocument() && newChild->isDocumentTypeNode())
183 return HIERARCHY_REQUEST_ERR;
184 if (containsConsideringHostElements(newChild, newParent))
185 return HIERARCHY_REQUEST_ERR;
187 if (oldChild && newParent->isDocumentNode()) {
188 if (!static_cast<Document*>(newParent)->canReplaceChild(newChild, oldChild))
189 return HIERARCHY_REQUEST_ERR;
190 } else if (!isChildTypeAllowed(newParent, newChild))
191 return HIERARCHY_REQUEST_ERR;
196 static inline bool checkAcceptChildGuaranteedNodeTypes(ContainerNode* newParent, Node* newChild, ExceptionCode& ec)
198 ASSERT(!newParent->isReadOnlyNode());
199 ASSERT(!newParent->isDocumentTypeNode());
200 ASSERT(isChildTypeAllowed(newParent, newChild));
201 if (newChild->contains(newParent)) {
202 ec = HIERARCHY_REQUEST_ERR;
209 static inline bool checkAddChild(ContainerNode* newParent, Node* newChild, ExceptionCode& ec)
211 if (ExceptionCode code = checkAcceptChild(newParent, newChild, 0)) {
219 static inline bool checkReplaceChild(ContainerNode* newParent, Node* newChild, Node* oldChild, ExceptionCode& ec)
221 if (ExceptionCode code = checkAcceptChild(newParent, newChild, oldChild)) {
229 bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode& ec, bool shouldLazyAttach)
231 // Check that this node is not "floating".
232 // If it is, it can be deleted as a side effect of sending mutation events.
233 ASSERT(refCount() || parentOrHostNode());
235 RefPtr<Node> protect(this);
239 // insertBefore(node, 0) is equivalent to appendChild(node)
241 return appendChild(newChild, ec, shouldLazyAttach);
243 // Make sure adding the new child is OK.
244 if (!checkAddChild(this, newChild.get(), ec))
247 // NOT_FOUND_ERR: Raised if refChild is not a child of this node
248 if (refChild->parentNode() != this) {
253 if (refChild->previousSibling() == newChild || refChild == newChild) // nothing to do
256 RefPtr<Node> next = refChild;
259 collectChildrenAndRemoveFromOldParent(newChild.get(), targets, ec);
262 if (targets.isEmpty())
265 // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events.
266 if (!checkAcceptChildGuaranteedNodeTypes(this, newChild.get(), ec))
269 InspectorInstrumentation::willInsertDOMNode(document(), this);
271 #if ENABLE(MUTATION_OBSERVERS)
272 ChildListMutationScope mutation(this);
275 for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); ++it) {
276 Node* child = it->get();
278 // Due to arbitrary code running in response to a DOM mutation event it's
279 // possible that "next" is no longer a child of "this".
280 // It's also possible that "child" has been inserted elsewhere.
281 // In either of those cases, we'll just stop.
282 if (next->parentNode() != this)
284 if (child->parentNode())
287 treeScope()->adoptIfNeeded(child);
289 insertBeforeCommon(next.get(), child);
291 updateTreeAfterInsertion(this, child, shouldLazyAttach);
294 dispatchSubtreeModifiedEvent();
298 void ContainerNode::insertBeforeCommon(Node* nextChild, Node* newChild)
300 NoEventDispatchAssertion assertNoEventDispatch;
303 ASSERT(!newChild->parentNode()); // Use insertBefore if you need to handle reparenting (and want DOM mutation events).
304 ASSERT(!newChild->nextSibling());
305 ASSERT(!newChild->previousSibling());
306 ASSERT(!newChild->isShadowRoot());
308 Node* prev = nextChild->previousSibling();
309 ASSERT(m_lastChild != prev);
310 nextChild->setPreviousSibling(newChild);
312 ASSERT(m_firstChild != nextChild);
313 ASSERT(prev->nextSibling() == nextChild);
314 prev->setNextSibling(newChild);
316 ASSERT(m_firstChild == nextChild);
317 m_firstChild = newChild;
319 newChild->setParentOrHostNode(this);
320 newChild->setPreviousSibling(prev);
321 newChild->setNextSibling(nextChild);
324 void ContainerNode::parserInsertBefore(PassRefPtr<Node> newChild, Node* nextChild)
328 ASSERT(nextChild->parentNode() == this);
329 ASSERT(document() == newChild->document());
330 ASSERT(!newChild->isDocumentFragment());
332 if (nextChild->previousSibling() == newChild || nextChild == newChild) // nothing to do
335 insertBeforeCommon(nextChild, newChild.get());
337 childrenChanged(true, newChild->previousSibling(), nextChild, 1);
338 ChildNodeInsertionNotifier(this).notify(newChild.get());
341 bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode& ec, bool shouldLazyAttach)
343 // Check that this node is not "floating".
344 // If it is, it can be deleted as a side effect of sending mutation events.
345 ASSERT(refCount() || parentOrHostNode());
347 RefPtr<Node> protect(this);
351 if (oldChild == newChild) // nothing to do
359 // Make sure replacing the old child with the new is ok
360 if (!checkReplaceChild(this, newChild.get(), oldChild, ec))
363 // NOT_FOUND_ERR: Raised if oldChild is not a child of this node.
364 if (oldChild->parentNode() != this) {
369 #if ENABLE(MUTATION_OBSERVERS)
370 ChildListMutationScope mutation(this);
373 RefPtr<Node> next = oldChild->nextSibling();
375 // Remove the node we're replacing
376 RefPtr<Node> removedChild = oldChild;
377 removeChild(oldChild, ec);
381 if (next && (next->previousSibling() == newChild || next == newChild)) // nothing to do
384 // Does this one more time because removeChild() fires a MutationEvent.
385 if (!checkReplaceChild(this, newChild.get(), oldChild, ec))
389 collectChildrenAndRemoveFromOldParent(newChild.get(), targets, ec);
393 // Does this yet another check because collectChildrenAndRemoveFromOldParent() fires a MutationEvent.
394 if (!checkReplaceChild(this, newChild.get(), oldChild, ec))
397 InspectorInstrumentation::willInsertDOMNode(document(), this);
399 // Add the new child(ren)
400 for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); ++it) {
401 Node* child = it->get();
403 // Due to arbitrary code running in response to a DOM mutation event it's
404 // possible that "next" is no longer a child of "this".
405 // It's also possible that "child" has been inserted elsewhere.
406 // In either of those cases, we'll just stop.
407 if (next && next->parentNode() != this)
409 if (child->parentNode())
412 treeScope()->adoptIfNeeded(child);
414 // Add child before "next".
416 NoEventDispatchAssertion assertNoEventDispatch;
418 insertBeforeCommon(next.get(), child);
420 appendChildToContainer(child, this);
423 updateTreeAfterInsertion(this, child, shouldLazyAttach);
426 dispatchSubtreeModifiedEvent();
430 static void willRemoveChild(Node* child)
432 #if ENABLE(MUTATION_OBSERVERS)
433 ASSERT(child->parentNode());
434 ChildListMutationScope(child->parentNode()).willRemoveChild(child);
435 child->notifyMutationObserversNodeWillDetach();
438 dispatchChildRemovalEvents(child);
439 child->document()->nodeWillBeRemoved(child); // e.g. mutation event listener can create a new range.
440 ChildFrameDisconnector(child).disconnect();
443 static void willRemoveChildren(ContainerNode* container)
446 getChildNodes(container, children);
448 container->document()->nodeChildrenWillBeRemoved(container);
450 #if ENABLE(MUTATION_OBSERVERS)
451 ChildListMutationScope mutation(container);
454 for (NodeVector::const_iterator it = children.begin(); it != children.end(); it++) {
455 Node* child = it->get();
457 #if ENABLE(MUTATION_OBSERVERS)
458 mutation.willRemoveChild(child);
459 child->notifyMutationObserversNodeWillDetach();
462 // fire removed from document mutation events.
463 dispatchChildRemovalEvents(child);
466 ChildFrameDisconnector(container, ChildFrameDisconnector::DoNotIncludeRoot).disconnect();
469 void ContainerNode::disconnectDescendantFrames()
471 ChildFrameDisconnector(this).disconnect();
474 bool ContainerNode::removeChild(Node* oldChild, ExceptionCode& ec)
476 // Check that this node is not "floating".
477 // If it is, it can be deleted as a side effect of sending mutation events.
478 ASSERT(refCount() || parentOrHostNode());
480 RefPtr<Node> protect(this);
484 // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
485 if (isReadOnlyNode()) {
486 ec = NO_MODIFICATION_ALLOWED_ERR;
490 // NOT_FOUND_ERR: Raised if oldChild is not a child of this node.
491 if (!oldChild || oldChild->parentNode() != this) {
496 RefPtr<Node> child = oldChild;
498 document()->removeFocusedNodeOfSubtree(child.get());
500 #if ENABLE(FULLSCREEN_API)
501 document()->removeFullScreenElementOfSubtree(child.get());
504 // Events fired when blurring currently focused node might have moved this
505 // child into a different parent.
506 if (child->parentNode() != this) {
511 willRemoveChild(child.get());
513 // Mutation events might have moved this child into a different parent.
514 if (child->parentNode() != this) {
520 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
522 Node* prev = child->previousSibling();
523 Node* next = child->nextSibling();
524 removeBetween(prev, next, child.get());
525 childrenChanged(false, prev, next, -1);
526 ChildNodeRemovalNotifier(this).notify(child.get());
528 dispatchSubtreeModifiedEvent();
533 void ContainerNode::removeBetween(Node* previousChild, Node* nextChild, Node* oldChild)
535 NoEventDispatchAssertion assertNoEventDispatch;
538 ASSERT(oldChild->parentNode() == this);
540 // Remove from rendering tree
541 if (oldChild->attached())
545 nextChild->setPreviousSibling(previousChild);
547 previousChild->setNextSibling(nextChild);
548 if (m_firstChild == oldChild)
549 m_firstChild = nextChild;
550 if (m_lastChild == oldChild)
551 m_lastChild = previousChild;
553 oldChild->setPreviousSibling(0);
554 oldChild->setNextSibling(0);
555 oldChild->setParentOrHostNode(0);
557 document()->adoptIfNeeded(oldChild);
560 void ContainerNode::parserRemoveChild(Node* oldChild)
563 ASSERT(oldChild->parentNode() == this);
564 ASSERT(!oldChild->isDocumentFragment());
566 Node* prev = oldChild->previousSibling();
567 Node* next = oldChild->nextSibling();
569 removeBetween(prev, next, oldChild);
571 childrenChanged(true, prev, next, -1);
572 ChildNodeRemovalNotifier(this).notify(oldChild);
575 // this differs from other remove functions because it forcibly removes all the children,
576 // regardless of read-only status or event exceptions, e.g.
577 void ContainerNode::removeChildren()
582 // The container node can be removed from event handlers.
583 RefPtr<ContainerNode> protect(this);
585 // exclude this node when looking for removed focusedNode since only children will be removed
586 document()->removeFocusedNodeOfSubtree(this, true);
588 #if ENABLE(FULLSCREEN_API)
589 document()->removeFullScreenElementOfSubtree(this, true);
592 // Do any prep work needed before actually starting to detach
593 // and remove... e.g. stop loading frames, fire unload events.
594 willRemoveChildren(protect.get());
596 Vector<RefPtr<Node>, 10> removedChildren;
598 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
599 NoEventDispatchAssertion assertNoEventDispatch;
600 removedChildren.reserveInitialCapacity(childNodeCount());
601 while (RefPtr<Node> n = m_firstChild) {
602 Node* next = n->nextSibling();
604 // Remove the node from the tree before calling detach or removedFromDocument (4427024, 4129744).
605 // removeChild() does this after calling detach(). There is no explanation for
606 // this discrepancy between removeChild() and its optimized version removeChildren().
607 n->setPreviousSibling(0);
608 n->setNextSibling(0);
609 n->setParentOrHostNode(0);
610 document()->adoptIfNeeded(n.get());
613 if (n == m_lastChild)
615 removedChildren.append(n.release());
618 size_t removedChildrenCount = removedChildren.size();
621 // Detach the nodes only after properly removed from the tree because
622 // a. detaching requires a proper DOM tree (for counters and quotes for
623 // example) and during the previous loop the next sibling still points to
624 // the node being removed while the node being removed does not point back
625 // and does not point to the same parent as its next sibling.
626 // b. destroying Renderers of standalone nodes is sometimes faster.
627 for (i = 0; i < removedChildrenCount; ++i) {
628 Node* removedChild = removedChildren[i].get();
629 if (removedChild->attached())
630 removedChild->detach();
633 childrenChanged(false, 0, 0, -static_cast<int>(removedChildrenCount));
635 for (i = 0; i < removedChildrenCount; ++i)
636 ChildNodeRemovalNotifier(this).notify(removedChildren[i].get());
639 dispatchSubtreeModifiedEvent();
642 bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, bool shouldLazyAttach)
644 RefPtr<ContainerNode> protect(this);
646 // Check that this node is not "floating".
647 // If it is, it can be deleted as a side effect of sending mutation events.
648 ASSERT(refCount() || parentOrHostNode());
652 // Make sure adding the new child is ok
653 if (!checkAddChild(this, newChild.get(), ec))
656 if (newChild == m_lastChild) // nothing to do
660 collectChildrenAndRemoveFromOldParent(newChild.get(), targets, ec);
664 if (targets.isEmpty())
667 // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events.
668 if (!checkAcceptChildGuaranteedNodeTypes(this, newChild.get(), ec))
671 InspectorInstrumentation::willInsertDOMNode(document(), this);
673 #if ENABLE(MUTATION_OBSERVERS)
674 ChildListMutationScope mutation(this);
677 // Now actually add the child(ren)
678 for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); ++it) {
679 Node* child = it->get();
681 // If the child has a parent again, just stop what we're doing, because
682 // that means someone is doing something with DOM mutation -- can't re-parent
683 // a child that already has a parent.
684 if (child->parentNode())
687 treeScope()->adoptIfNeeded(child);
689 // Append child to the end of the list
691 NoEventDispatchAssertion assertNoEventDispatch;
692 appendChildToContainer(child, this);
695 updateTreeAfterInsertion(this, child, shouldLazyAttach);
698 dispatchSubtreeModifiedEvent();
702 void ContainerNode::parserAppendChild(PassRefPtr<Node> newChild)
705 ASSERT(!newChild->parentNode()); // Use appendChild if you need to handle reparenting (and want DOM mutation events).
706 ASSERT(!newChild->isDocumentFragment());
707 ASSERT(document() == newChild->document());
709 Node* last = m_lastChild;
711 NoEventDispatchAssertion assertNoEventDispatch;
712 // FIXME: This method should take a PassRefPtr.
713 appendChildToContainer(newChild.get(), this);
714 treeScope()->adoptIfNeeded(newChild.get());
717 childrenChanged(true, last, 0, 1);
718 ChildNodeInsertionNotifier(this).notify(newChild.get());
721 void ContainerNode::suspendPostAttachCallbacks()
723 if (!s_attachDepth) {
724 ASSERT(!s_shouldReEnableMemoryCacheCallsAfterAttach);
725 if (Page* page = document()->page()) {
726 // FIXME: How can this call be specific to one Page, while the
727 // s_attachDepth is a global? Doesn't make sense.
728 if (page->areMemoryCacheClientCallsEnabled()) {
729 page->setMemoryCacheClientCallsEnabled(false);
730 s_shouldReEnableMemoryCacheCallsAfterAttach = true;
733 #if USE(PLATFORM_STRATEGIES)
734 platformStrategies()->loaderStrategy()->resourceLoadScheduler()->suspendPendingRequests();
736 resourceLoadScheduler()->suspendPendingRequests();
742 void ContainerNode::resumePostAttachCallbacks()
744 if (s_attachDepth == 1) {
745 RefPtr<ContainerNode> protect(this);
747 if (s_postAttachCallbackQueue)
748 dispatchPostAttachCallbacks();
749 if (s_shouldReEnableMemoryCacheCallsAfterAttach) {
750 s_shouldReEnableMemoryCacheCallsAfterAttach = false;
751 if (Page* page = document()->page())
752 page->setMemoryCacheClientCallsEnabled(true);
754 #if USE(PLATFORM_STRATEGIES)
755 platformStrategies()->loaderStrategy()->resourceLoadScheduler()->resumePendingRequests();
757 resourceLoadScheduler()->resumePendingRequests();
763 void ContainerNode::queuePostAttachCallback(NodeCallback callback, Node* node, unsigned callbackData)
765 if (!s_postAttachCallbackQueue)
766 s_postAttachCallbackQueue = new NodeCallbackQueue;
768 s_postAttachCallbackQueue->append(CallbackInfo(callback, CallbackParameters(node, callbackData)));
771 bool ContainerNode::postAttachCallbacksAreSuspended()
773 return s_attachDepth;
776 void ContainerNode::dispatchPostAttachCallbacks()
778 // We recalculate size() each time through the loop because a callback
779 // can add more callbacks to the end of the queue.
780 for (size_t i = 0; i < s_postAttachCallbackQueue->size(); ++i) {
781 const CallbackInfo& info = (*s_postAttachCallbackQueue)[i];
782 NodeCallback callback = info.first;
783 CallbackParameters params = info.second;
785 callback(params.first.get(), params.second);
787 s_postAttachCallbackQueue->clear();
790 static void needsStyleRecalcCallback(Node* node, unsigned data)
792 node->setNeedsStyleRecalc(static_cast<StyleChangeType>(data));
795 void ContainerNode::scheduleSetNeedsStyleRecalc(StyleChangeType changeType)
797 if (postAttachCallbacksAreSuspended())
798 queuePostAttachCallback(needsStyleRecalcCallback, this, static_cast<unsigned>(changeType));
800 setNeedsStyleRecalc(changeType);
803 void ContainerNode::attach()
809 void ContainerNode::detach()
813 clearChildNeedsStyleRecalc();
816 void ContainerNode::childrenChanged(bool changedByParser, Node*, Node*, int childCountDelta)
818 document()->incDOMTreeVersion();
819 if (!changedByParser && childCountDelta)
820 document()->updateRangesAfterChildrenChanged(this);
821 invalidateNodeListCachesInAncestors();
824 void ContainerNode::cloneChildNodes(ContainerNode *clone)
826 HTMLElement* deleteButtonContainerElement = 0;
827 if (Frame* frame = document()->frame())
828 deleteButtonContainerElement = frame->editor()->deleteButtonController()->containerElement();
830 ExceptionCode ec = 0;
831 for (Node* n = firstChild(); n && !ec; n = n->nextSibling()) {
832 if (n == deleteButtonContainerElement)
834 clone->appendChild(n->cloneNode(true), ec);
838 bool ContainerNode::getUpperLeftCorner(FloatPoint& point) const
842 // What is this code really trying to do?
843 RenderObject* o = renderer();
846 if (!o->isInline() || o->isReplaced()) {
847 point = o->localToAbsolute(FloatPoint(), UseTransforms);
851 // find the next text/image child, to get a position
856 else if (o->nextSibling())
857 o = o->nextSibling();
859 RenderObject* next = 0;
860 while (!next && o->parent()) {
862 next = o->nextSibling();
871 if (!o->isInline() || o->isReplaced()) {
872 point = o->localToAbsolute(FloatPoint(), UseTransforms);
876 if (p->node() && p->node() == this && o->isText() && !o->isBR() && !toRenderText(o)->firstTextBox()) {
877 // do nothing - skip unrendered whitespace that is a child or next sibling of the anchor
878 } else if ((o->isText() && !o->isBR()) || o->isReplaced()) {
879 point = FloatPoint();
880 if (o->isText() && toRenderText(o)->firstTextBox()) {
881 point.move(toRenderText(o)->linesBoundingBox().x(), toRenderText(o)->firstTextBox()->root()->lineTop());
882 } else if (o->isBox()) {
883 RenderBox* box = toRenderBox(o);
884 point.moveBy(box->location());
886 point = o->container()->localToAbsolute(point, UseTransforms);
891 // If the target doesn't have any children or siblings that could be used to calculate the scroll position, we must be
892 // at the end of the document. Scroll to the bottom. FIXME: who said anything about scrolling?
893 if (!o && document()->view()) {
894 point = FloatPoint(0, document()->view()->contentsHeight());
900 bool ContainerNode::getLowerRightCorner(FloatPoint& point) const
905 RenderObject* o = renderer();
906 if (!o->isInline() || o->isReplaced()) {
907 RenderBox* box = toRenderBox(o);
908 point = o->localToAbsolute(LayoutPoint(box->size()), UseTransforms);
912 // find the last text/image child, to get a position
916 else if (o->previousSibling())
917 o = o->previousSibling();
919 RenderObject* prev = 0;
924 prev = o->previousSibling();
929 if (o->isText() || o->isReplaced()) {
930 point = FloatPoint();
932 RenderText* text = toRenderText(o);
933 IntRect linesBox = text->linesBoundingBox();
934 if (!linesBox.maxX() && !linesBox.maxY())
936 point.moveBy(linesBox.maxXMaxYCorner());
938 RenderBox* box = toRenderBox(o);
939 point.moveBy(box->frameRect().maxXMaxYCorner());
941 point = o->container()->localToAbsolute(point, UseTransforms);
948 LayoutRect ContainerNode::boundingBox() const
950 FloatPoint upperLeft, lowerRight;
951 bool foundUpperLeft = getUpperLeftCorner(upperLeft);
952 bool foundLowerRight = getLowerRightCorner(lowerRight);
954 // If we've found one corner, but not the other,
955 // then we should just return a point at the corner that we did find.
956 if (foundUpperLeft != foundLowerRight) {
958 lowerRight = upperLeft;
960 upperLeft = lowerRight;
963 return enclosingLayoutRect(FloatRect(upperLeft, lowerRight.expandedTo(upperLeft) - upperLeft));
966 void ContainerNode::setFocus(bool received)
968 if (focused() == received)
971 Node::setFocus(received);
973 // note that we need to recalc the style
974 setNeedsStyleRecalc();
977 void ContainerNode::setActive(bool down, bool pause)
979 if (down == active()) return;
981 Node::setActive(down);
983 // note that we need to recalc the style
984 // FIXME: Move to Element
986 bool reactsToPress = renderStyle()->affectedByActive() || (isElementNode() && toElement(this)->childrenAffectedByActive());
988 setNeedsStyleRecalc();
989 if (renderStyle()->hasAppearance()) {
990 if (renderer()->theme()->stateChanged(renderer(), PressedState))
991 reactsToPress = true;
993 if (reactsToPress && pause) {
994 // The delay here is subtle. It relies on an assumption, namely that the amount of time it takes
995 // to repaint the "down" state of the control is about the same time as it would take to repaint the
996 // "up" state. Once you assume this, you can just delay for 100ms - that time (assuming that after you
997 // leave this method, it will be about that long before the flush of the up state happens again).
998 #ifdef HAVE_FUNC_USLEEP
999 double startTime = currentTime();
1002 // Ensure there are no pending changes
1003 Document::updateStyleForAllDocuments();
1004 // Do an immediate repaint.
1006 renderer()->repaint(true);
1008 // FIXME: Find a substitute for usleep for Win32.
1009 // Better yet, come up with a way of doing this that doesn't use this sort of thing at all.
1010 #ifdef HAVE_FUNC_USLEEP
1011 // Now pause for a small amount of time (1/10th of a second from before we repainted in the pressed state)
1012 double remainingTime = 0.1 - (currentTime() - startTime);
1013 if (remainingTime > 0)
1014 usleep(static_cast<useconds_t>(remainingTime * 1000000.0));
1020 void ContainerNode::setHovered(bool over)
1022 if (over == hovered()) return;
1024 Node::setHovered(over);
1026 // note that we need to recalc the style
1027 // FIXME: Move to Element
1029 if (renderStyle()->affectedByHover() || (isElementNode() && toElement(this)->childrenAffectedByHover()))
1030 setNeedsStyleRecalc();
1031 if (renderer() && renderer()->style()->hasAppearance())
1032 renderer()->theme()->stateChanged(renderer(), HoverState);
1036 unsigned ContainerNode::childNodeCount() const
1040 for (n = firstChild(); n; n = n->nextSibling())
1045 Node *ContainerNode::childNode(unsigned index) const
1048 Node *n = firstChild();
1049 for (i = 0; n != 0 && i < index; i++)
1050 n = n->nextSibling();
1055 static void dispatchChildInsertionEvents(Node* child)
1057 if (child->isInShadowTree())
1060 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
1062 RefPtr<Node> c = child;
1063 RefPtr<Document> document = child->document();
1065 if (c->parentNode() && document->hasListenerType(Document::DOMNODEINSERTED_LISTENER))
1066 c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeInsertedEvent, true, c->parentNode()));
1068 // dispatch the DOMNodeInsertedIntoDocument event to all descendants
1069 if (c->inDocument() && document->hasListenerType(Document::DOMNODEINSERTEDINTODOCUMENT_LISTENER)) {
1070 for (; c; c = NodeTraversal::next(c.get(), child))
1071 c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeInsertedIntoDocumentEvent, false));
1075 static void dispatchChildRemovalEvents(Node* child)
1077 if (child->isInShadowTree()) {
1078 InspectorInstrumentation::willRemoveDOMNode(child->document(), child);
1082 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
1085 willCreatePossiblyOrphanedTreeByRemoval(child);
1087 InspectorInstrumentation::willRemoveDOMNode(child->document(), child);
1089 RefPtr<Node> c = child;
1090 RefPtr<Document> document = child->document();
1092 // dispatch pre-removal mutation events
1093 if (c->parentNode() && document->hasListenerType(Document::DOMNODEREMOVED_LISTENER))
1094 c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeRemovedEvent, true, c->parentNode()));
1096 // dispatch the DOMNodeRemovedFromDocument event to all descendants
1097 if (c->inDocument() && document->hasListenerType(Document::DOMNODEREMOVEDFROMDOCUMENT_LISTENER)) {
1098 for (; c; c = NodeTraversal::next(c.get(), child))
1099 c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeRemovedFromDocumentEvent, false));
1103 static void updateTreeAfterInsertion(ContainerNode* parent, Node* child, bool shouldLazyAttach)
1105 ASSERT(parent->refCount());
1106 ASSERT(child->refCount());
1108 #if ENABLE(MUTATION_OBSERVERS)
1109 ChildListMutationScope(parent).childAdded(child);
1112 parent->childrenChanged(false, child->previousSibling(), child->nextSibling(), 1);
1114 ChildNodeInsertionNotifier(parent).notify(child);
1116 // FIXME: Attachment should be the first operation in this function, but some code
1117 // (for example, HTMLFormControlElement's autofocus support) requires this ordering.
1118 if (parent->attached() && !child->attached() && child->parentNode() == parent) {
1119 if (shouldLazyAttach)
1120 child->lazyAttach();
1125 dispatchChildInsertionEvents(child);
1129 bool childAttachedAllowedWhenAttachingChildren(ContainerNode* node)
1131 if (node->isShadowRoot())
1134 if (node->isInsertionPoint())
1137 if (node->isElementNode() && toElement(node)->shadow())
1144 } // namespace WebCore