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

Side by Side Diff: Source/core/dom/ContainerNode.cpp

Issue 418133003: Call insertedInto or removedFrom before childrenChanged (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 6 years, 5 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org) 4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2013 Apple Inc. All rights reserved. 5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2013 Apple Inc. All rights reserved.
6 * 6 *
7 * This library is free software; you can redistribute it and/or 7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public 8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either 9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version. 10 * version 2 of the License, or (at your option) any later version.
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after
296 void ContainerNode::parserInsertBefore(PassRefPtrWillBeRawPtr<Node> newChild, No de& nextChild) 296 void ContainerNode::parserInsertBefore(PassRefPtrWillBeRawPtr<Node> newChild, No de& nextChild)
297 { 297 {
298 ASSERT(newChild); 298 ASSERT(newChild);
299 ASSERT(nextChild.parentNode() == this); 299 ASSERT(nextChild.parentNode() == this);
300 ASSERT(!newChild->isDocumentFragment()); 300 ASSERT(!newChild->isDocumentFragment());
301 ASSERT(!isHTMLTemplateElement(this)); 301 ASSERT(!isHTMLTemplateElement(this));
302 302
303 if (nextChild.previousSibling() == newChild || &nextChild == newChild) // no thing to do 303 if (nextChild.previousSibling() == newChild || &nextChild == newChild) // no thing to do
304 return; 304 return;
305 305
306 RefPtrWillBeRawPtr<Node> protect(this);
307
306 if (document() != newChild->document()) 308 if (document() != newChild->document())
307 document().adoptNode(newChild.get(), ASSERT_NO_EXCEPTION); 309 document().adoptNode(newChild.get(), ASSERT_NO_EXCEPTION);
308 310
309 insertBeforeCommon(nextChild, *newChild); 311 insertBeforeCommon(nextChild, *newChild);
310 312
311 newChild->updateAncestorConnectedSubframeCountForInsertion(); 313 newChild->updateAncestorConnectedSubframeCountForInsertion();
312 314
313 ChildListMutationScope(*this).childAdded(*newChild); 315 ChildListMutationScope(*this).childAdded(*newChild);
314 316
315 ChildrenChange change = {ChildInserted, newChild->previousSibling(), &nextCh ild, ChildrenChangeSourceParser}; 317 notifyNodeInserted(*newChild, ChildrenChangeSourceParser);
316 childrenChanged(change);
317
318 notifyNodeInserted(*newChild);
319 } 318 }
320 319
321 PassRefPtrWillBeRawPtr<Node> ContainerNode::replaceChild(PassRefPtrWillBeRawPtr< Node> newChild, PassRefPtrWillBeRawPtr<Node> oldChild, ExceptionState& exception State) 320 PassRefPtrWillBeRawPtr<Node> ContainerNode::replaceChild(PassRefPtrWillBeRawPtr< Node> newChild, PassRefPtrWillBeRawPtr<Node> oldChild, ExceptionState& exception State)
322 { 321 {
323 #if !ENABLE(OILPAN) 322 #if !ENABLE(OILPAN)
324 // Check that this node is not "floating". 323 // Check that this node is not "floating".
325 // If it is, it can be deleted as a side effect of sending mutation events. 324 // If it is, it can be deleted as a side effect of sending mutation events.
326 ASSERT(refCount() || parentOrShadowHostNode()); 325 ASSERT(refCount() || parentOrShadowHostNode());
327 #endif 326 #endif
328 327
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after
561 exceptionState.throwDOMException(NotFoundError, "The node to be removed is no longer a child of this node. Perhaps it was moved in response to a mutatio n?"); 560 exceptionState.throwDOMException(NotFoundError, "The node to be removed is no longer a child of this node. Perhaps it was moved in response to a mutatio n?");
562 return nullptr; 561 return nullptr;
563 } 562 }
564 563
565 { 564 {
566 HTMLFrameOwnerElement::UpdateSuspendScope suspendWidgetHierarchyUpdates; 565 HTMLFrameOwnerElement::UpdateSuspendScope suspendWidgetHierarchyUpdates;
567 566
568 Node* prev = child->previousSibling(); 567 Node* prev = child->previousSibling();
569 Node* next = child->nextSibling(); 568 Node* next = child->nextSibling();
570 removeBetween(prev, next, *child); 569 removeBetween(prev, next, *child);
570 notifyNodeRemoved(*child);
571 ChildrenChange change = {ChildRemoved, prev, next, ChildrenChangeSourceA PI}; 571 ChildrenChange change = {ChildRemoved, prev, next, ChildrenChangeSourceA PI};
572 childrenChanged(change); 572 childrenChanged(change);
573 notifyNodeRemoved(*child);
574 } 573 }
575 dispatchSubtreeModifiedEvent(); 574 dispatchSubtreeModifiedEvent();
576 return child; 575 return child;
577 } 576 }
578 577
579 void ContainerNode::removeBetween(Node* previousChild, Node* nextChild, Node& ol dChild) 578 void ContainerNode::removeBetween(Node* previousChild, Node* nextChild, Node& ol dChild)
580 { 579 {
581 NoEventDispatchAssertion assertNoEventDispatch; 580 NoEventDispatchAssertion assertNoEventDispatch;
582 581
583 ASSERT(oldChild.parentNode() == this); 582 ASSERT(oldChild.parentNode() == this);
(...skipping 26 matching lines...) Expand all
610 Node* next = oldChild.nextSibling(); 609 Node* next = oldChild.nextSibling();
611 610
612 oldChild.updateAncestorConnectedSubframeCountForRemoval(); 611 oldChild.updateAncestorConnectedSubframeCountForRemoval();
613 612
614 ChildListMutationScope(*this).willRemoveChild(oldChild); 613 ChildListMutationScope(*this).willRemoveChild(oldChild);
615 oldChild.notifyMutationObserversNodeWillDetach(); 614 oldChild.notifyMutationObserversNodeWillDetach();
616 615
617 removeBetween(prev, next, oldChild); 616 removeBetween(prev, next, oldChild);
618 617
619 ChildrenChange change = {ChildRemoved, prev, next, ChildrenChangeSourceParse r}; 618 ChildrenChange change = {ChildRemoved, prev, next, ChildrenChangeSourceParse r};
619 notifyNodeRemoved(oldChild);
620 childrenChanged(change); 620 childrenChanged(change);
621 notifyNodeRemoved(oldChild);
622 } 621 }
623 622
624 // this differs from other remove functions because it forcibly removes all the children, 623 // this differs from other remove functions because it forcibly removes all the children,
625 // regardless of read-only status or event exceptions, e.g. 624 // regardless of read-only status or event exceptions, e.g.
626 void ContainerNode::removeChildren() 625 void ContainerNode::removeChildren()
627 { 626 {
628 if (!m_firstChild) 627 if (!m_firstChild)
629 return; 628 return;
630 629
631 // The container node can be removed from event handlers. 630 // The container node can be removed from event handlers.
(...skipping 14 matching lines...) Expand all
646 // Exclude this node when looking for removed focusedElement since only 645 // Exclude this node when looking for removed focusedElement since only
647 // children will be removed. 646 // children will be removed.
648 // This must be later than willRemoveChildren, which might change focus 647 // This must be later than willRemoveChildren, which might change focus
649 // state of a child. 648 // state of a child.
650 document().removeFocusedElementOfSubtree(this, true); 649 document().removeFocusedElementOfSubtree(this, true);
651 650
652 // Removing a node from a selection can cause widget updates. 651 // Removing a node from a selection can cause widget updates.
653 document().nodeChildrenWillBeRemoved(*this); 652 document().nodeChildrenWillBeRemoved(*this);
654 } 653 }
655 654
656 655 // FIXME: Remove this NodeVector. Right now WebPluginContainerImpl::m_elemen t is a
656 // raw ptr which means the code below can drop the last ref to a plugin elem ent and
657 // then the code in UpdateSuspendScope::performDeferredWidgetTreeOperations will
658 // try to destroy the plugin which will be a use-after-free. We should use a RefPtr
659 // in the WebPluginContainerImpl instead.
657 NodeVector removedChildren; 660 NodeVector removedChildren;
658 { 661 {
659 HTMLFrameOwnerElement::UpdateSuspendScope suspendWidgetHierarchyUpdates; 662 HTMLFrameOwnerElement::UpdateSuspendScope suspendWidgetHierarchyUpdates;
663
660 { 664 {
661 NoEventDispatchAssertion assertNoEventDispatch; 665 NoEventDispatchAssertion assertNoEventDispatch;
662 removedChildren.reserveInitialCapacity(countChildren()); 666 ScriptForbiddenScope forbidScript;
663 while (m_firstChild) { 667
664 removedChildren.append(m_firstChild); 668 removedChildren.reserveInitialCapacity(childNodeCount());
665 removeBetween(0, m_firstChild->nextSibling(), *m_firstChild); 669
670 while (RefPtrWillBeRawPtr<Node> child = m_firstChild) {
671 removeBetween(0, child->nextSibling(), *child);
672 removedChildren.append(child.get());
673 notifyNodeRemoved(*child);
666 } 674 }
667 } 675 }
668 676
669 ChildrenChange change = {AllChildrenRemoved, nullptr, nullptr, ChildrenC hangeSourceAPI}; 677 ChildrenChange change = {AllChildrenRemoved, nullptr, nullptr, ChildrenC hangeSourceAPI};
670 childrenChanged(change); 678 childrenChanged(change);
671
672 for (size_t i = 0; i < removedChildren.size(); ++i)
673 notifyNodeRemoved(*removedChildren[i]);
674 } 679 }
675 680
676 dispatchSubtreeModifiedEvent(); 681 dispatchSubtreeModifiedEvent();
677 } 682 }
678 683
679 PassRefPtrWillBeRawPtr<Node> ContainerNode::appendChild(PassRefPtrWillBeRawPtr<N ode> newChild, ExceptionState& exceptionState) 684 PassRefPtrWillBeRawPtr<Node> ContainerNode::appendChild(PassRefPtrWillBeRawPtr<N ode> newChild, ExceptionState& exceptionState)
680 { 685 {
681 RefPtrWillBeRawPtr<ContainerNode> protect(this); 686 RefPtrWillBeRawPtr<ContainerNode> protect(this);
682 687
683 #if !ENABLE(OILPAN) 688 #if !ENABLE(OILPAN)
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
741 return newChild; 746 return newChild;
742 } 747 }
743 748
744 void ContainerNode::parserAppendChild(PassRefPtrWillBeRawPtr<Node> newChild) 749 void ContainerNode::parserAppendChild(PassRefPtrWillBeRawPtr<Node> newChild)
745 { 750 {
746 ASSERT(newChild); 751 ASSERT(newChild);
747 ASSERT(!newChild->parentNode()); // Use appendChild if you need to handle re parenting (and want DOM mutation events). 752 ASSERT(!newChild->parentNode()); // Use appendChild if you need to handle re parenting (and want DOM mutation events).
748 ASSERT(!newChild->isDocumentFragment()); 753 ASSERT(!newChild->isDocumentFragment());
749 ASSERT(!isHTMLTemplateElement(this)); 754 ASSERT(!isHTMLTemplateElement(this));
750 755
756 RefPtrWillBeRawPtr<Node> protect(this);
adamk 2014/07/24 21:35:59 What's this about?
esprehn 2014/07/24 22:50:18 Nothing is protecting |this| in these parser metho
757
751 if (document() != newChild->document()) 758 if (document() != newChild->document())
752 document().adoptNode(newChild.get(), ASSERT_NO_EXCEPTION); 759 document().adoptNode(newChild.get(), ASSERT_NO_EXCEPTION);
753 760
754 Node* last = m_lastChild;
755
756 { 761 {
757 NoEventDispatchAssertion assertNoEventDispatch; 762 NoEventDispatchAssertion assertNoEventDispatch;
758 ScriptForbiddenScope forbidScript; 763 ScriptForbiddenScope forbidScript;
759 764
760 treeScope().adoptIfNeeded(*newChild); 765 treeScope().adoptIfNeeded(*newChild);
761 appendChildCommon(*newChild); 766 appendChildCommon(*newChild);
762 newChild->updateAncestorConnectedSubframeCountForInsertion(); 767 newChild->updateAncestorConnectedSubframeCountForInsertion();
763 ChildListMutationScope(*this).childAdded(*newChild); 768 ChildListMutationScope(*this).childAdded(*newChild);
764 } 769 }
765 770
766 ChildrenChange change = {ChildInserted, last, nullptr, ChildrenChangeSourceP arser}; 771 notifyNodeInserted(*newChild, ChildrenChangeSourceParser);
767 childrenChanged(change);
768 notifyNodeInserted(*newChild);
769 } 772 }
770 773
771 void ContainerNode::notifyNodeInserted(Node& root) 774 void ContainerNode::notifyNodeInserted(Node& root, ChildrenChangeSource source)
772 { 775 {
773 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden()); 776 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
774 777
775 InspectorInstrumentation::didInsertDOMNode(&root); 778 InspectorInstrumentation::didInsertDOMNode(&root);
776 779
777 RefPtrWillBeRawPtr<Node> protect(this); 780 RefPtrWillBeRawPtr<Node> protect(this);
778 RefPtrWillBeRawPtr<Node> protectNode(root); 781 RefPtrWillBeRawPtr<Node> protectNode(root);
779 782
780 NodeVector postInsertionNotificationTargets; 783 NodeVector postInsertionNotificationTargets;
781 notifyNodeInsertedInternal(root, postInsertionNotificationTargets); 784 notifyNodeInsertedInternal(root, postInsertionNotificationTargets);
782 785
786 // ShadowRoots are not real children, we don't need to tell host that it's
adamk 2014/07/24 21:35:59 Why are you changing this behavior in this patch?
esprehn 2014/07/24 22:50:18 I'm not changing any behavior, I moved childrenCha
787 // children changed when one is added.
788 // FIXME: We should have a separate code path for ShadowRoot since it only
789 // needs to call insertedInto and the rest of this logic is not needed.
790 if (!root.isShadowRoot()) {
791 ChildrenChange change = {ChildInserted, root.previousSibling(), root.nex tSibling(), source};
792 childrenChanged(change);
793 }
794
783 for (size_t i = 0; i < postInsertionNotificationTargets.size(); ++i) { 795 for (size_t i = 0; i < postInsertionNotificationTargets.size(); ++i) {
784 Node* targetNode = postInsertionNotificationTargets[i].get(); 796 Node* targetNode = postInsertionNotificationTargets[i].get();
785 if (targetNode->inDocument()) 797 if (targetNode->inDocument())
786 targetNode->didNotifySubtreeInsertionsToDocument(); 798 targetNode->didNotifySubtreeInsertionsToDocument();
787 } 799 }
788 } 800 }
789 801
790 void ContainerNode::notifyNodeInsertedInternal(Node& root, NodeVector& postInser tionNotificationTargets) 802 void ContainerNode::notifyNodeInsertedInternal(Node& root, NodeVector& postInser tionNotificationTargets)
791 { 803 {
792 NoEventDispatchAssertion assertNoEventDispatch; 804 NoEventDispatchAssertion assertNoEventDispatch;
(...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after
1184 1196
1185 void ContainerNode::updateTreeAfterInsertion(Node& child) 1197 void ContainerNode::updateTreeAfterInsertion(Node& child)
1186 { 1198 {
1187 #if !ENABLE(OILPAN) 1199 #if !ENABLE(OILPAN)
1188 ASSERT(refCount()); 1200 ASSERT(refCount());
1189 ASSERT(child.refCount()); 1201 ASSERT(child.refCount());
1190 #endif 1202 #endif
1191 1203
1192 ChildListMutationScope(*this).childAdded(child); 1204 ChildListMutationScope(*this).childAdded(child);
1193 1205
1194 ChildrenChange change = {ChildInserted, child.previousSibling(), child.nextS ibling(), ChildrenChangeSourceAPI};
1195 childrenChanged(change);
1196
1197 notifyNodeInserted(child); 1206 notifyNodeInserted(child);
1198 1207
1199 dispatchChildInsertionEvents(child); 1208 dispatchChildInsertionEvents(child);
1200 } 1209 }
1201 1210
1202 bool ContainerNode::hasRestyleFlagInternal(DynamicRestyleFlags mask) const 1211 bool ContainerNode::hasRestyleFlagInternal(DynamicRestyleFlags mask) const
1203 { 1212 {
1204 return rareData()->hasRestyleFlag(mask); 1213 return rareData()->hasRestyleFlag(mask);
1205 } 1214 }
1206 1215
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
1387 return true; 1396 return true;
1388 1397
1389 if (node->isElementNode() && toElement(node)->shadow()) 1398 if (node->isElementNode() && toElement(node)->shadow())
1390 return true; 1399 return true;
1391 1400
1392 return false; 1401 return false;
1393 } 1402 }
1394 #endif 1403 #endif
1395 1404
1396 } // namespace blink 1405 } // namespace blink
OLDNEW
« LayoutTests/fast/dom/script-remove-child-id-map.html ('K') | « Source/core/dom/ContainerNode.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698