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

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

Issue 306233005: Call insertedInto or removedFrom before childrenChanged (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Pass right flags, don't notify on ShadowRoot Created 6 years, 6 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
« no previous file with comments | « Source/core/dom/ContainerNode.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 Apple Inc. All rights reserv ed. 5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserv ed.
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 260 matching lines...) Expand 10 before | Expand all | Expand 10 after
271 newChild.setNextSibling(&nextChild); 271 newChild.setNextSibling(&nextChild);
272 } 272 }
273 273
274 void ContainerNode::parserInsertBefore(PassRefPtr<Node> newChild, Node& nextChil d) 274 void ContainerNode::parserInsertBefore(PassRefPtr<Node> newChild, Node& nextChil d)
275 { 275 {
276 ASSERT(newChild); 276 ASSERT(newChild);
277 ASSERT(nextChild.parentNode() == this); 277 ASSERT(nextChild.parentNode() == this);
278 ASSERT(!newChild->isDocumentFragment()); 278 ASSERT(!newChild->isDocumentFragment());
279 ASSERT(!isHTMLTemplateElement(this)); 279 ASSERT(!isHTMLTemplateElement(this));
280 280
281 RefPtr<Node> protect(this);
282
281 if (nextChild.previousSibling() == newChild || nextChild == newChild) // not hing to do 283 if (nextChild.previousSibling() == newChild || nextChild == newChild) // not hing to do
282 return; 284 return;
283 285
284 if (document() != newChild->document()) 286 if (document() != newChild->document())
285 document().adoptNode(newChild.get(), ASSERT_NO_EXCEPTION); 287 document().adoptNode(newChild.get(), ASSERT_NO_EXCEPTION);
286 288
287 insertBeforeCommon(nextChild, *newChild); 289 insertBeforeCommon(nextChild, *newChild);
288 290
289 newChild->updateAncestorConnectedSubframeCountForInsertion(); 291 newChild->updateAncestorConnectedSubframeCountForInsertion();
290 292
291 ChildListMutationScope(*this).childAdded(*newChild); 293 ChildListMutationScope(*this).childAdded(*newChild);
292 294
293 childrenChanged(true, newChild->previousSibling(), &nextChild, 1); 295 notifyNodeInserted(*newChild, true);
294
295 notifyNodeInserted(*newChild);
296 } 296 }
297 297
298 void ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce ptionState& exceptionState) 298 void ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce ptionState& exceptionState)
299 { 299 {
300 #if !ENABLE(OILPAN) 300 #if !ENABLE(OILPAN)
301 // Check that this node is not "floating". 301 // Check that this node is not "floating".
302 // If it is, it can be deleted as a side effect of sending mutation events. 302 // If it is, it can be deleted as a side effect of sending mutation events.
303 ASSERT(refCount() || parentOrShadowHostNode()); 303 ASSERT(refCount() || parentOrShadowHostNode());
304 #endif 304 #endif
305 305
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
461 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?"); 461 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?");
462 return; 462 return;
463 } 463 }
464 464
465 { 465 {
466 HTMLFrameOwnerElement::UpdateSuspendScope suspendWidgetHierarchyUpdates; 466 HTMLFrameOwnerElement::UpdateSuspendScope suspendWidgetHierarchyUpdates;
467 467
468 Node* prev = child->previousSibling(); 468 Node* prev = child->previousSibling();
469 Node* next = child->nextSibling(); 469 Node* next = child->nextSibling();
470 removeBetween(prev, next, *child); 470 removeBetween(prev, next, *child);
471 notifyNodeRemoved(*child);
471 childrenChanged(false, prev, next, -1); 472 childrenChanged(false, prev, next, -1);
472 notifyNodeRemoved(*child);
473 } 473 }
474 dispatchSubtreeModifiedEvent(); 474 dispatchSubtreeModifiedEvent();
475 } 475 }
476 476
477 void ContainerNode::removeBetween(Node* previousChild, Node* nextChild, Node& ol dChild) 477 void ContainerNode::removeBetween(Node* previousChild, Node* nextChild, Node& ol dChild)
478 { 478 {
479 NoEventDispatchAssertion assertNoEventDispatch; 479 NoEventDispatchAssertion assertNoEventDispatch;
480 480
481 ASSERT(oldChild.parentNode() == this); 481 ASSERT(oldChild.parentNode() == this);
482 482
(...skipping 14 matching lines...) Expand all
497 oldChild.setParentOrShadowHostNode(0); 497 oldChild.setParentOrShadowHostNode(0);
498 498
499 document().adoptIfNeeded(oldChild); 499 document().adoptIfNeeded(oldChild);
500 } 500 }
501 501
502 void ContainerNode::parserRemoveChild(Node& oldChild) 502 void ContainerNode::parserRemoveChild(Node& oldChild)
503 { 503 {
504 ASSERT(oldChild.parentNode() == this); 504 ASSERT(oldChild.parentNode() == this);
505 ASSERT(!oldChild.isDocumentFragment()); 505 ASSERT(!oldChild.isDocumentFragment());
506 506
507 ScriptForbiddenScope forbidScript;
508
509 RefPtr<Node> protect(this);
ojan 2014/06/04 00:38:46 Don't need this if script can't execute.
510
507 Node* prev = oldChild.previousSibling(); 511 Node* prev = oldChild.previousSibling();
508 Node* next = oldChild.nextSibling(); 512 Node* next = oldChild.nextSibling();
509 513
510 oldChild.updateAncestorConnectedSubframeCountForRemoval(); 514 oldChild.updateAncestorConnectedSubframeCountForRemoval();
511 515
512 ChildListMutationScope(*this).willRemoveChild(oldChild); 516 ChildListMutationScope(*this).willRemoveChild(oldChild);
513 oldChild.notifyMutationObserversNodeWillDetach(); 517 oldChild.notifyMutationObserversNodeWillDetach();
514 518
515 removeBetween(prev, next, oldChild); 519 removeBetween(prev, next, oldChild);
516 520 notifyNodeRemoved(oldChild);
517 childrenChanged(true, prev, next, -1); 521 childrenChanged(true, prev, next, -1);
518 notifyNodeRemoved(oldChild);
519 } 522 }
520 523
521 // this differs from other remove functions because it forcibly removes all the children, 524 // this differs from other remove functions because it forcibly removes all the children,
522 // regardless of read-only status or event exceptions, e.g. 525 // regardless of read-only status or event exceptions, e.g.
523 void ContainerNode::removeChildren() 526 void ContainerNode::removeChildren()
524 { 527 {
525 if (!m_firstChild) 528 if (!m_firstChild)
526 return; 529 return;
527 530
528 // The container node can be removed from event handlers. 531 // The container node can be removed from event handlers.
(...skipping 14 matching lines...) Expand all
543 // Exclude this node when looking for removed focusedElement since only 546 // Exclude this node when looking for removed focusedElement since only
544 // children will be removed. 547 // children will be removed.
545 // This must be later than willRemoveChildren, which might change focus 548 // This must be later than willRemoveChildren, which might change focus
546 // state of a child. 549 // state of a child.
547 document().removeFocusedElementOfSubtree(this, true); 550 document().removeFocusedElementOfSubtree(this, true);
548 551
549 // Removing a node from a selection can cause widget updates. 552 // Removing a node from a selection can cause widget updates.
550 document().nodeChildrenWillBeRemoved(*this); 553 document().nodeChildrenWillBeRemoved(*this);
551 } 554 }
552 555
553
554 NodeVector removedChildren;
555 { 556 {
556 HTMLFrameOwnerElement::UpdateSuspendScope suspendWidgetHierarchyUpdates; 557 HTMLFrameOwnerElement::UpdateSuspendScope suspendWidgetHierarchyUpdates;
557 { 558 ScriptForbiddenScope forbidScript;
559
560 // FIXME: We can't have a top level NoEventDispatchAssertion since
561 // SVGElement::invalidateInstances() is called inside ::childrenChanged
562 // and will stamp out new <use> shadow trees which mutates the DOM and
563 // hits the event dispatching assert in ::notifyNodeInserted. We should
564 // figure out how to make ths work async.
565
566 int childCount = 0;
567 while (RefPtr<Node> child = m_firstChild) {
558 NoEventDispatchAssertion assertNoEventDispatch; 568 NoEventDispatchAssertion assertNoEventDispatch;
559 removedChildren.reserveInitialCapacity(countChildren()); 569 ++childCount;
560 while (m_firstChild) { 570 removeBetween(0, child->nextSibling(), *child);
561 removedChildren.append(m_firstChild); 571 notifyNodeRemoved(*child);
562 removeBetween(0, m_firstChild->nextSibling(), *m_firstChild);
563 }
564 } 572 }
565 573
566 childrenChanged(false, 0, 0, -static_cast<int>(removedChildren.size())); 574 childrenChanged(false, 0, 0, -childCount);
567
568 for (size_t i = 0; i < removedChildren.size(); ++i)
569 notifyNodeRemoved(*removedChildren[i]);
570 } 575 }
571 576
572 dispatchSubtreeModifiedEvent(); 577 dispatchSubtreeModifiedEvent();
573 } 578 }
574 579
575 void ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionState& excep tionState) 580 void ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionState& excep tionState)
576 { 581 {
577 RefPtr<ContainerNode> protect(this); 582 RefPtr<ContainerNode> protect(this);
578 583
579 #if !ENABLE(OILPAN) 584 #if !ENABLE(OILPAN)
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
630 dispatchSubtreeModifiedEvent(); 635 dispatchSubtreeModifiedEvent();
631 } 636 }
632 637
633 void ContainerNode::parserAppendChild(PassRefPtr<Node> newChild) 638 void ContainerNode::parserAppendChild(PassRefPtr<Node> newChild)
634 { 639 {
635 ASSERT(newChild); 640 ASSERT(newChild);
636 ASSERT(!newChild->parentNode()); // Use appendChild if you need to handle re parenting (and want DOM mutation events). 641 ASSERT(!newChild->parentNode()); // Use appendChild if you need to handle re parenting (and want DOM mutation events).
637 ASSERT(!newChild->isDocumentFragment()); 642 ASSERT(!newChild->isDocumentFragment());
638 ASSERT(!isHTMLTemplateElement(this)); 643 ASSERT(!isHTMLTemplateElement(this));
639 644
645 RefPtr<Node> protect(this);
646
640 if (document() != newChild->document()) 647 if (document() != newChild->document())
641 document().adoptNode(newChild.get(), ASSERT_NO_EXCEPTION); 648 document().adoptNode(newChild.get(), ASSERT_NO_EXCEPTION);
642 649
643 Node* last = m_lastChild;
644
645 { 650 {
646 NoEventDispatchAssertion assertNoEventDispatch; 651 NoEventDispatchAssertion assertNoEventDispatch;
647 ScriptForbiddenScope forbidScript; 652 ScriptForbiddenScope forbidScript;
648 653
649 treeScope().adoptIfNeeded(*newChild); 654 treeScope().adoptIfNeeded(*newChild);
650 // FIXME: This method should take a PassRefPtr. 655 // FIXME: This method should take a PassRefPtr.
651 appendChildToContainer(*newChild, *this); 656 appendChildToContainer(*newChild, *this);
652 newChild->updateAncestorConnectedSubframeCountForInsertion(); 657 newChild->updateAncestorConnectedSubframeCountForInsertion();
653 ChildListMutationScope(*this).childAdded(*newChild); 658 ChildListMutationScope(*this).childAdded(*newChild);
654 } 659 }
655 660
656 childrenChanged(true, last, 0, 1); 661 notifyNodeInserted(*newChild, true);
ojan 2014/06/04 00:38:46 Bool arguments!!
657 notifyNodeInserted(*newChild);
658 } 662 }
659 663
660 void ContainerNode::notifyNodeInserted(Node& root) 664 void ContainerNode::notifyNodeInserted(Node& root, bool createdByParser)
661 { 665 {
662 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden()); 666 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
663 667
664 InspectorInstrumentation::didInsertDOMNode(&root); 668 InspectorInstrumentation::didInsertDOMNode(&root);
665 669
666 RefPtr<Node> protect(this); 670 RefPtr<Node> protect(this);
667 RefPtr<Node> protectNode(root); 671 RefPtr<Node> protectRoot(root);
668 672
669 NodeVector postInsertionNotificationTargets; 673 NodeVector postInsertionNotificationTargets;
670 notifyNodeInsertedInternal(root, postInsertionNotificationTargets); 674 notifyNodeInsertedInternal(root, postInsertionNotificationTargets);
671 675
676 // ShadowRoots are not real children, we don't need to tell host that it's
677 // children changed when one is added.
678 if (!root.isShadowRoot())
ojan 2014/06/04 00:38:46 As per discussion in person, this is a little goof
679 childrenChanged(createdByParser, root.previousSibling(), root.nextSiblin g(), 1);
680
672 for (size_t i = 0; i < postInsertionNotificationTargets.size(); ++i) { 681 for (size_t i = 0; i < postInsertionNotificationTargets.size(); ++i) {
673 Node* targetNode = postInsertionNotificationTargets[i].get(); 682 Node* targetNode = postInsertionNotificationTargets[i].get();
674 if (targetNode->inDocument()) 683 if (targetNode->inDocument())
675 targetNode->didNotifySubtreeInsertionsToDocument(); 684 targetNode->didNotifySubtreeInsertionsToDocument();
676 } 685 }
677 } 686 }
678 687
679 void ContainerNode::notifyNodeInsertedInternal(Node& root, NodeVector& postInser tionNotificationTargets) 688 void ContainerNode::notifyNodeInsertedInternal(Node& root, NodeVector& postInser tionNotificationTargets)
680 { 689 {
681 NoEventDispatchAssertion assertNoEventDispatch; 690 NoEventDispatchAssertion assertNoEventDispatch;
(...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after
1072 1081
1073 void ContainerNode::updateTreeAfterInsertion(Node& child) 1082 void ContainerNode::updateTreeAfterInsertion(Node& child)
1074 { 1083 {
1075 #if !ENABLE(OILPAN) 1084 #if !ENABLE(OILPAN)
1076 ASSERT(refCount()); 1085 ASSERT(refCount());
1077 ASSERT(child.refCount()); 1086 ASSERT(child.refCount());
1078 #endif 1087 #endif
1079 1088
1080 ChildListMutationScope(*this).childAdded(child); 1089 ChildListMutationScope(*this).childAdded(child);
1081 1090
1082 childrenChanged(false, child.previousSibling(), child.nextSibling(), 1);
1083
1084 notifyNodeInserted(child); 1091 notifyNodeInserted(child);
1085 1092
1086 dispatchChildInsertionEvents(child); 1093 dispatchChildInsertionEvents(child);
1087 } 1094 }
1088 1095
1089 bool ContainerNode::hasRestyleFlagInternal(DynamicRestyleFlags mask) const 1096 bool ContainerNode::hasRestyleFlagInternal(DynamicRestyleFlags mask) const
1090 { 1097 {
1091 return rareData()->hasRestyleFlag(mask); 1098 return rareData()->hasRestyleFlag(mask);
1092 } 1099 }
1093 1100
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
1276 return true; 1283 return true;
1277 1284
1278 if (node->isElementNode() && toElement(node)->shadow()) 1285 if (node->isElementNode() && toElement(node)->shadow())
1279 return true; 1286 return true;
1280 1287
1281 return false; 1288 return false;
1282 } 1289 }
1283 #endif 1290 #endif
1284 1291
1285 } // namespace WebCore 1292 } // namespace WebCore
OLDNEW
« no previous file with comments | « Source/core/dom/ContainerNode.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698