1/* 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, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved. 6 * 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. 11 * 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. 16 * 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. 21 */ 22 23#include "config.h" 24#include "ContainerNode.h" 25 26#include "AXObjectCache.h" 27#include "ChildListMutationScope.h" 28#include "Chrome.h" 29#include "ChromeClient.h" 30#include "ContainerNodeAlgorithms.h" 31#include "Editor.h" 32#include "EventNames.h" 33#include "ExceptionCode.h" 34#include "FloatRect.h" 35#include "Frame.h" 36#include "FrameView.h" 37#include "HTMLNames.h" 38#include "InlineTextBox.h" 39#include "InsertionPoint.h" 40#include "InspectorInstrumentation.h" 41#include "JSNode.h" 42#include "LoaderStrategy.h" 43#include "MemoryCache.h" 44#include "MutationEvent.h" 45#include "NodeRenderStyle.h" 46#include "NodeTraversal.h" 47#include "Page.h" 48#include "PlatformStrategies.h" 49#include "RenderBox.h" 50#include "RenderTheme.h" 51#include "RenderWidget.h" 52#include "ResourceLoadScheduler.h" 53#include "RootInlineBox.h" 54#include "TemplateContentDocumentFragment.h" 55#include <wtf/CurrentTime.h> 56#include <wtf/Vector.h> 57 58#if ENABLE(DELETION_UI) 59#include "DeleteButtonController.h" 60#endif 61 62using namespace std; 63 64namespace WebCore { 65 66static void dispatchChildInsertionEvents(Node*); 67static void dispatchChildRemovalEvents(Node*); 68static void updateTreeAfterInsertion(ContainerNode*, Node*, AttachBehavior); 69 70typedef pair<RefPtr<Node>, unsigned> CallbackParameters; 71typedef pair<NodeCallback, CallbackParameters> CallbackInfo; 72typedef Vector<CallbackInfo> NodeCallbackQueue; 73 74static NodeCallbackQueue* s_postAttachCallbackQueue; 75 76static size_t s_attachDepth; 77static bool s_shouldReEnableMemoryCacheCallsAfterAttach; 78 79ChildNodesLazySnapshot* ChildNodesLazySnapshot::latestSnapshot = 0; 80 81#ifndef NDEBUG 82unsigned NoEventDispatchAssertion::s_count = 0; 83#endif 84 85static void collectChildrenAndRemoveFromOldParent(Node* node, NodeVector& nodes, ExceptionCode& ec) 86{ 87 if (node->nodeType() != Node::DOCUMENT_FRAGMENT_NODE) { 88 nodes.append(node); 89 if (ContainerNode* oldParent = node->parentNode()) 90 oldParent->removeChild(node, ec); 91 return; 92 } 93 getChildNodes(node, nodes); 94 toContainerNode(node)->removeChildren(); 95} 96 97void ContainerNode::removeDetachedChildren() 98{ 99 if (connectedSubframeCount()) { 100 for (Node* child = firstChild(); child; child = child->nextSibling()) 101 child->updateAncestorConnectedSubframeCountForRemoval(); 102 } 103 // FIXME: We should be able to ASSERT(!attached()) here: https://bugs.webkit.org/show_bug.cgi?id=107801 104 removeDetachedChildrenInContainer<Node, ContainerNode>(this); 105} 106 107void ContainerNode::takeAllChildrenFrom(ContainerNode* oldParent) 108{ 109 NodeVector children; 110 getChildNodes(oldParent, children); 111 112 if (oldParent->document()->hasMutationObserversOfType(MutationObserver::ChildList)) { 113 ChildListMutationScope mutation(oldParent); 114 for (unsigned i = 0; i < children.size(); ++i) 115 mutation.willRemoveChild(children[i].get()); 116 } 117 118 // FIXME: We need to do notifyMutationObserversNodeWillDetach() for each child, 119 // probably inside removeDetachedChildrenInContainer. 120 121 oldParent->removeDetachedChildren(); 122 123 for (unsigned i = 0; i < children.size(); ++i) { 124 if (children[i]->attached()) 125 children[i]->detach(); 126 // FIXME: We need a no mutation event version of adoptNode. 127 RefPtr<Node> child = document()->adoptNode(children[i].release(), ASSERT_NO_EXCEPTION); 128 parserAppendChild(child.get()); 129 // FIXME: Together with adoptNode above, the tree scope might get updated recursively twice 130 // (if the document changed or oldParent was in a shadow tree, AND *this is in a shadow tree). 131 // Can we do better? 132 treeScope()->adoptIfNeeded(child.get()); 133 if (attached() && !child->attached()) 134 child->attach(); 135 } 136} 137 138ContainerNode::~ContainerNode() 139{ 140 if (Document* document = documentInternal()) 141 willBeDeletedFrom(document); 142 removeDetachedChildren(); 143} 144 145static inline bool isChildTypeAllowed(ContainerNode* newParent, Node* child) 146{ 147 if (!child->isDocumentFragment()) 148 return newParent->childTypeAllowed(child->nodeType()); 149 150 for (Node* node = child->firstChild(); node; node = node->nextSibling()) { 151 if (!newParent->childTypeAllowed(node->nodeType())) 152 return false; 153 } 154 return true; 155} 156 157static inline bool isInTemplateContent(const Node* node) 158{ 159#if ENABLE(TEMPLATE_ELEMENT) 160 Document* document = node->document(); 161 return document && document == document->templateDocument(); 162#else 163 UNUSED_PARAM(node); 164 return false; 165#endif 166} 167 168static inline bool containsConsideringHostElements(const Node* newChild, const Node* newParent) 169{ 170 return (newParent->isInShadowTree() || isInTemplateContent(newParent)) 171 ? newChild->containsIncludingHostElements(newParent) 172 : newChild->contains(newParent); 173} 174 175static inline ExceptionCode checkAcceptChild(ContainerNode* newParent, Node* newChild, Node* oldChild) 176{ 177 // Not mentioned in spec: throw NOT_FOUND_ERR if newChild is null 178 if (!newChild) 179 return NOT_FOUND_ERR; 180 181 // Use common case fast path if possible. 182 if ((newChild->isElementNode() || newChild->isTextNode()) && newParent->isElementNode()) { 183 ASSERT(!newParent->isReadOnlyNode()); 184 ASSERT(!newParent->isDocumentTypeNode()); 185 ASSERT(isChildTypeAllowed(newParent, newChild)); 186 if (containsConsideringHostElements(newChild, newParent)) 187 return HIERARCHY_REQUEST_ERR; 188 return 0; 189 } 190 191 // This should never happen, but also protect release builds from tree corruption. 192 ASSERT(!newChild->isPseudoElement()); 193 if (newChild->isPseudoElement()) 194 return HIERARCHY_REQUEST_ERR; 195 196 if (newParent->isReadOnlyNode()) 197 return NO_MODIFICATION_ALLOWED_ERR; 198 if (newChild->inDocument() && newChild->isDocumentTypeNode()) 199 return HIERARCHY_REQUEST_ERR; 200 if (containsConsideringHostElements(newChild, newParent)) 201 return HIERARCHY_REQUEST_ERR; 202 203 if (oldChild && newParent->isDocumentNode()) { 204 if (!toDocument(newParent)->canReplaceChild(newChild, oldChild)) 205 return HIERARCHY_REQUEST_ERR; 206 } else if (!isChildTypeAllowed(newParent, newChild)) 207 return HIERARCHY_REQUEST_ERR; 208 209 return 0; 210} 211 212static inline bool checkAcceptChildGuaranteedNodeTypes(ContainerNode* newParent, Node* newChild, ExceptionCode& ec) 213{ 214 ASSERT(!newParent->isReadOnlyNode()); 215 ASSERT(!newParent->isDocumentTypeNode()); 216 ASSERT(isChildTypeAllowed(newParent, newChild)); 217 if (newChild->contains(newParent)) { 218 ec = HIERARCHY_REQUEST_ERR; 219 return false; 220 } 221 222 return true; 223} 224 225static inline bool checkAddChild(ContainerNode* newParent, Node* newChild, ExceptionCode& ec) 226{ 227 ec = checkAcceptChild(newParent, newChild, 0); 228 if (ec) 229 return false; 230 231 return true; 232} 233 234static inline bool checkReplaceChild(ContainerNode* newParent, Node* newChild, Node* oldChild, ExceptionCode& ec) 235{ 236 ec = checkAcceptChild(newParent, newChild, oldChild); 237 if (ec) 238 return false; 239 240 return true; 241} 242 243bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode& ec, AttachBehavior attachBehavior) 244{ 245 // Check that this node is not "floating". 246 // If it is, it can be deleted as a side effect of sending mutation events. 247 ASSERT(refCount() || parentOrShadowHostNode()); 248 249 RefPtr<Node> protect(this); 250 251 ec = 0; 252 253 // insertBefore(node, 0) is equivalent to appendChild(node) 254 if (!refChild) 255 return appendChild(newChild, ec, attachBehavior); 256 257 // Make sure adding the new child is OK. 258 if (!checkAddChild(this, newChild.get(), ec)) 259 return false; 260 261 // NOT_FOUND_ERR: Raised if refChild is not a child of this node 262 if (refChild->parentNode() != this) { 263 ec = NOT_FOUND_ERR; 264 return false; 265 } 266 267 if (refChild->previousSibling() == newChild || refChild == newChild) // nothing to do 268 return true; 269 270 RefPtr<Node> next = refChild; 271 272 NodeVector targets; 273 collectChildrenAndRemoveFromOldParent(newChild.get(), targets, ec); 274 if (ec) 275 return false; 276 if (targets.isEmpty()) 277 return true; 278 279 // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events. 280 if (!checkAcceptChildGuaranteedNodeTypes(this, newChild.get(), ec)) 281 return false; 282 283 InspectorInstrumentation::willInsertDOMNode(document(), this); 284 285 ChildListMutationScope mutation(this); 286 for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); ++it) { 287 Node* child = it->get(); 288 289 // Due to arbitrary code running in response to a DOM mutation event it's 290 // possible that "next" is no longer a child of "this". 291 // It's also possible that "child" has been inserted elsewhere. 292 // In either of those cases, we'll just stop. 293 if (next->parentNode() != this) 294 break; 295 if (child->parentNode()) 296 break; 297 298 treeScope()->adoptIfNeeded(child); 299 300 insertBeforeCommon(next.get(), child); 301 302 updateTreeAfterInsertion(this, child, attachBehavior); 303 } 304 305 dispatchSubtreeModifiedEvent(); 306 return true; 307} 308 309void ContainerNode::insertBeforeCommon(Node* nextChild, Node* newChild) 310{ 311 NoEventDispatchAssertion assertNoEventDispatch; 312 313 ASSERT(newChild); 314 ASSERT(!newChild->parentNode()); // Use insertBefore if you need to handle reparenting (and want DOM mutation events). 315 ASSERT(!newChild->nextSibling()); 316 ASSERT(!newChild->previousSibling()); 317 ASSERT(!newChild->isShadowRoot()); 318 319 Node* prev = nextChild->previousSibling(); 320 ASSERT(m_lastChild != prev); 321 nextChild->setPreviousSibling(newChild); 322 if (prev) { 323 ASSERT(m_firstChild != nextChild); 324 ASSERT(prev->nextSibling() == nextChild); 325 prev->setNextSibling(newChild); 326 } else { 327 ASSERT(m_firstChild == nextChild); 328 m_firstChild = newChild; 329 } 330 newChild->setParentOrShadowHostNode(this); 331 newChild->setPreviousSibling(prev); 332 newChild->setNextSibling(nextChild); 333} 334 335void ContainerNode::parserInsertBefore(PassRefPtr<Node> newChild, Node* nextChild) 336{ 337 ASSERT(newChild); 338 ASSERT(nextChild); 339 ASSERT(nextChild->parentNode() == this); 340 ASSERT(!newChild->isDocumentFragment()); 341#if ENABLE(TEMPLATE_ELEMENT) 342 ASSERT(!hasTagName(HTMLNames::templateTag)); 343#endif 344 345 if (nextChild->previousSibling() == newChild || nextChild == newChild) // nothing to do 346 return; 347 348 if (document() != newChild->document()) 349 document()->adoptNode(newChild.get(), ASSERT_NO_EXCEPTION); 350 351 insertBeforeCommon(nextChild, newChild.get()); 352 353 newChild->updateAncestorConnectedSubframeCountForInsertion(); 354 355 ChildListMutationScope(this).childAdded(newChild.get()); 356 357 childrenChanged(true, newChild->previousSibling(), nextChild, 1); 358 ChildNodeInsertionNotifier(this).notify(newChild.get()); 359} 360 361bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode& ec, AttachBehavior attachBehavior) 362{ 363 // Check that this node is not "floating". 364 // If it is, it can be deleted as a side effect of sending mutation events. 365 ASSERT(refCount() || parentOrShadowHostNode()); 366 367 RefPtr<Node> protect(this); 368 369 ec = 0; 370 371 if (oldChild == newChild) // nothing to do 372 return true; 373 374 if (!oldChild) { 375 ec = NOT_FOUND_ERR; 376 return false; 377 } 378 379 // Make sure replacing the old child with the new is ok 380 if (!checkReplaceChild(this, newChild.get(), oldChild, ec)) 381 return false; 382 383 // NOT_FOUND_ERR: Raised if oldChild is not a child of this node. 384 if (oldChild->parentNode() != this) { 385 ec = NOT_FOUND_ERR; 386 return false; 387 } 388 389 ChildListMutationScope mutation(this); 390 391 RefPtr<Node> next = oldChild->nextSibling(); 392 393 // Remove the node we're replacing 394 RefPtr<Node> removedChild = oldChild; 395 removeChild(oldChild, ec); 396 if (ec) 397 return false; 398 399 if (next && (next->previousSibling() == newChild || next == newChild)) // nothing to do 400 return true; 401 402 // Does this one more time because removeChild() fires a MutationEvent. 403 if (!checkReplaceChild(this, newChild.get(), oldChild, ec)) 404 return false; 405 406 NodeVector targets; 407 collectChildrenAndRemoveFromOldParent(newChild.get(), targets, ec); 408 if (ec) 409 return false; 410 411 // Does this yet another check because collectChildrenAndRemoveFromOldParent() fires a MutationEvent. 412 if (!checkReplaceChild(this, newChild.get(), oldChild, ec)) 413 return false; 414 415 InspectorInstrumentation::willInsertDOMNode(document(), this); 416 417 // Add the new child(ren) 418 for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); ++it) { 419 Node* child = it->get(); 420 421 // Due to arbitrary code running in response to a DOM mutation event it's 422 // possible that "next" is no longer a child of "this". 423 // It's also possible that "child" has been inserted elsewhere. 424 // In either of those cases, we'll just stop. 425 if (next && next->parentNode() != this) 426 break; 427 if (child->parentNode()) 428 break; 429 430 treeScope()->adoptIfNeeded(child); 431 432 // Add child before "next". 433 { 434 NoEventDispatchAssertion assertNoEventDispatch; 435 if (next) 436 insertBeforeCommon(next.get(), child); 437 else 438 appendChildToContainer(child, this); 439 } 440 441 updateTreeAfterInsertion(this, child, attachBehavior); 442 } 443 444 dispatchSubtreeModifiedEvent(); 445 return true; 446} 447 448static void willRemoveChild(Node* child) 449{ 450 ASSERT(child->parentNode()); 451 ChildListMutationScope(child->parentNode()).willRemoveChild(child); 452 child->notifyMutationObserversNodeWillDetach(); 453 dispatchChildRemovalEvents(child); 454 child->document()->nodeWillBeRemoved(child); // e.g. mutation event listener can create a new range. 455 ChildFrameDisconnector(child).disconnect(); 456} 457 458static void willRemoveChildren(ContainerNode* container) 459{ 460 NodeVector children; 461 getChildNodes(container, children); 462 463 ChildListMutationScope mutation(container); 464 for (NodeVector::const_iterator it = children.begin(); it != children.end(); ++it) { 465 Node* child = it->get(); 466 mutation.willRemoveChild(child); 467 child->notifyMutationObserversNodeWillDetach(); 468 469 // fire removed from document mutation events. 470 dispatchChildRemovalEvents(child); 471 } 472 473 container->document()->nodeChildrenWillBeRemoved(container); 474 475 ChildFrameDisconnector(container).disconnect(ChildFrameDisconnector::DescendantsOnly); 476} 477 478void ContainerNode::disconnectDescendantFrames() 479{ 480 ChildFrameDisconnector(this).disconnect(); 481} 482 483bool ContainerNode::removeChild(Node* oldChild, ExceptionCode& ec) 484{ 485 // Check that this node is not "floating". 486 // If it is, it can be deleted as a side effect of sending mutation events. 487 ASSERT(refCount() || parentOrShadowHostNode()); 488 489 RefPtr<Node> protect(this); 490 491 ec = 0; 492 493 // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. 494 if (isReadOnlyNode()) { 495 ec = NO_MODIFICATION_ALLOWED_ERR; 496 return false; 497 } 498 499 // NOT_FOUND_ERR: Raised if oldChild is not a child of this node. 500 if (!oldChild || oldChild->parentNode() != this) { 501 ec = NOT_FOUND_ERR; 502 return false; 503 } 504 505 RefPtr<Node> child = oldChild; 506 507 document()->removeFocusedNodeOfSubtree(child.get()); 508 509#if ENABLE(FULLSCREEN_API) 510 document()->removeFullScreenElementOfSubtree(child.get()); 511#endif 512 513 // Events fired when blurring currently focused node might have moved this 514 // child into a different parent. 515 if (child->parentNode() != this) { 516 ec = NOT_FOUND_ERR; 517 return false; 518 } 519 520 willRemoveChild(child.get()); 521 522 // Mutation events might have moved this child into a different parent. 523 if (child->parentNode() != this) { 524 ec = NOT_FOUND_ERR; 525 return false; 526 } 527 528 { 529 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates; 530 531 Node* prev = child->previousSibling(); 532 Node* next = child->nextSibling(); 533 removeBetween(prev, next, child.get()); 534 childrenChanged(false, prev, next, -1); 535 ChildNodeRemovalNotifier(this).notify(child.get()); 536 } 537 dispatchSubtreeModifiedEvent(); 538 539 return child; 540} 541 542void ContainerNode::removeBetween(Node* previousChild, Node* nextChild, Node* oldChild) 543{ 544 NoEventDispatchAssertion assertNoEventDispatch; 545 546 ASSERT(oldChild); 547 ASSERT(oldChild->parentNode() == this); 548 549 // Remove from rendering tree 550 if (oldChild->attached()) 551 oldChild->detach(); 552 553 if (nextChild) 554 nextChild->setPreviousSibling(previousChild); 555 if (previousChild) 556 previousChild->setNextSibling(nextChild); 557 if (m_firstChild == oldChild) 558 m_firstChild = nextChild; 559 if (m_lastChild == oldChild) 560 m_lastChild = previousChild; 561 562 oldChild->setPreviousSibling(0); 563 oldChild->setNextSibling(0); 564 oldChild->setParentOrShadowHostNode(0); 565 566 document()->adoptIfNeeded(oldChild); 567} 568 569void ContainerNode::parserRemoveChild(Node* oldChild) 570{ 571 ASSERT(oldChild); 572 ASSERT(oldChild->parentNode() == this); 573 ASSERT(!oldChild->isDocumentFragment()); 574 575 Node* prev = oldChild->previousSibling(); 576 Node* next = oldChild->nextSibling(); 577 578 oldChild->updateAncestorConnectedSubframeCountForRemoval(); 579 580 ChildListMutationScope(this).willRemoveChild(oldChild); 581 oldChild->notifyMutationObserversNodeWillDetach(); 582 583 removeBetween(prev, next, oldChild); 584 585 childrenChanged(true, prev, next, -1); 586 ChildNodeRemovalNotifier(this).notify(oldChild); 587} 588 589// this differs from other remove functions because it forcibly removes all the children, 590// regardless of read-only status or event exceptions, e.g. 591void ContainerNode::removeChildren() 592{ 593 if (!m_firstChild) 594 return; 595 596 // The container node can be removed from event handlers. 597 RefPtr<ContainerNode> protect(this); 598 599 // exclude this node when looking for removed focusedNode since only children will be removed 600 document()->removeFocusedNodeOfSubtree(this, true); 601 602#if ENABLE(FULLSCREEN_API) 603 document()->removeFullScreenElementOfSubtree(this, true); 604#endif 605 606 // Do any prep work needed before actually starting to detach 607 // and remove... e.g. stop loading frames, fire unload events. 608 willRemoveChildren(protect.get()); 609 610 NodeVector removedChildren; 611 { 612 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates; 613 { 614 NoEventDispatchAssertion assertNoEventDispatch; 615 removedChildren.reserveInitialCapacity(childNodeCount()); 616 while (RefPtr<Node> n = m_firstChild) { 617 removedChildren.append(m_firstChild); 618 removeBetween(0, m_firstChild->nextSibling(), m_firstChild); 619 } 620 } 621 622 childrenChanged(false, 0, 0, -static_cast<int>(removedChildren.size())); 623 624 for (size_t i = 0; i < removedChildren.size(); ++i) 625 ChildNodeRemovalNotifier(this).notify(removedChildren[i].get()); 626 } 627 628 dispatchSubtreeModifiedEvent(); 629} 630 631bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, AttachBehavior attachBehavior) 632{ 633 RefPtr<ContainerNode> protect(this); 634 635 // Check that this node is not "floating". 636 // If it is, it can be deleted as a side effect of sending mutation events. 637 ASSERT(refCount() || parentOrShadowHostNode()); 638 639 ec = 0; 640 641 // Make sure adding the new child is ok 642 if (!checkAddChild(this, newChild.get(), ec)) 643 return false; 644 645 if (newChild == m_lastChild) // nothing to do 646 return newChild; 647 648 NodeVector targets; 649 collectChildrenAndRemoveFromOldParent(newChild.get(), targets, ec); 650 if (ec) 651 return false; 652 653 if (targets.isEmpty()) 654 return true; 655 656 // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events. 657 if (!checkAcceptChildGuaranteedNodeTypes(this, newChild.get(), ec)) 658 return false; 659 660 InspectorInstrumentation::willInsertDOMNode(document(), this); 661 662 // Now actually add the child(ren) 663 ChildListMutationScope mutation(this); 664 for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); ++it) { 665 Node* child = it->get(); 666 667 // If the child has a parent again, just stop what we're doing, because 668 // that means someone is doing something with DOM mutation -- can't re-parent 669 // a child that already has a parent. 670 if (child->parentNode()) 671 break; 672 673 treeScope()->adoptIfNeeded(child); 674 675 // Append child to the end of the list 676 { 677 NoEventDispatchAssertion assertNoEventDispatch; 678 appendChildToContainer(child, this); 679 } 680 681 updateTreeAfterInsertion(this, child, attachBehavior); 682 } 683 684 dispatchSubtreeModifiedEvent(); 685 return true; 686} 687 688void ContainerNode::parserAppendChild(PassRefPtr<Node> newChild) 689{ 690 ASSERT(newChild); 691 ASSERT(!newChild->parentNode()); // Use appendChild if you need to handle reparenting (and want DOM mutation events). 692 ASSERT(!newChild->isDocumentFragment()); 693#if ENABLE(TEMPLATE_ELEMENT) 694 ASSERT(!hasTagName(HTMLNames::templateTag)); 695#endif 696 697 if (document() != newChild->document()) 698 document()->adoptNode(newChild.get(), ASSERT_NO_EXCEPTION); 699 700 Node* last = m_lastChild; 701 { 702 NoEventDispatchAssertion assertNoEventDispatch; 703 // FIXME: This method should take a PassRefPtr. 704 appendChildToContainer(newChild.get(), this); 705 treeScope()->adoptIfNeeded(newChild.get()); 706 } 707 708 newChild->updateAncestorConnectedSubframeCountForInsertion(); 709 710 ChildListMutationScope(this).childAdded(newChild.get()); 711 712 childrenChanged(true, last, 0, 1); 713 ChildNodeInsertionNotifier(this).notify(newChild.get()); 714} 715 716void ContainerNode::suspendPostAttachCallbacks() 717{ 718 if (!s_attachDepth) { 719 ASSERT(!s_shouldReEnableMemoryCacheCallsAfterAttach); 720 if (Page* page = document()->page()) { 721 // FIXME: How can this call be specific to one Page, while the 722 // s_attachDepth is a global? Doesn't make sense. 723 if (page->areMemoryCacheClientCallsEnabled()) { 724 page->setMemoryCacheClientCallsEnabled(false); 725 s_shouldReEnableMemoryCacheCallsAfterAttach = true; 726 } 727 } 728 platformStrategies()->loaderStrategy()->resourceLoadScheduler()->suspendPendingRequests(); 729 } 730 ++s_attachDepth; 731} 732 733void ContainerNode::resumePostAttachCallbacks() 734{ 735 if (s_attachDepth == 1) { 736 RefPtr<ContainerNode> protect(this); 737 738 if (s_postAttachCallbackQueue) 739 dispatchPostAttachCallbacks(); 740 if (s_shouldReEnableMemoryCacheCallsAfterAttach) { 741 s_shouldReEnableMemoryCacheCallsAfterAttach = false; 742 if (Page* page = document()->page()) 743 page->setMemoryCacheClientCallsEnabled(true); 744 } 745 platformStrategies()->loaderStrategy()->resourceLoadScheduler()->resumePendingRequests(); 746 } 747 --s_attachDepth; 748} 749 750void ContainerNode::queuePostAttachCallback(NodeCallback callback, Node* node, unsigned callbackData) 751{ 752 if (!s_postAttachCallbackQueue) 753 s_postAttachCallbackQueue = new NodeCallbackQueue; 754 755 s_postAttachCallbackQueue->append(CallbackInfo(callback, CallbackParameters(node, callbackData))); 756} 757 758bool ContainerNode::postAttachCallbacksAreSuspended() 759{ 760 return s_attachDepth; 761} 762 763void ContainerNode::dispatchPostAttachCallbacks() 764{ 765 // We recalculate size() each time through the loop because a callback 766 // can add more callbacks to the end of the queue. 767 for (size_t i = 0; i < s_postAttachCallbackQueue->size(); ++i) { 768 const CallbackInfo& info = (*s_postAttachCallbackQueue)[i]; 769 NodeCallback callback = info.first; 770 CallbackParameters params = info.second; 771 772 callback(params.first.get(), params.second); 773 } 774 s_postAttachCallbackQueue->clear(); 775} 776 777static void needsStyleRecalcCallback(Node* node, unsigned data) 778{ 779 node->setNeedsStyleRecalc(static_cast<StyleChangeType>(data)); 780} 781 782void ContainerNode::scheduleSetNeedsStyleRecalc(StyleChangeType changeType) 783{ 784 if (postAttachCallbacksAreSuspended()) 785 queuePostAttachCallback(needsStyleRecalcCallback, this, static_cast<unsigned>(changeType)); 786 else 787 setNeedsStyleRecalc(changeType); 788} 789 790void ContainerNode::attach(const AttachContext& context) 791{ 792 attachChildren(); 793 Node::attach(context); 794} 795 796void ContainerNode::detach(const AttachContext& context) 797{ 798 detachChildren(); 799 clearChildNeedsStyleRecalc(); 800 Node::detach(context); 801} 802 803void ContainerNode::childrenChanged(bool changedByParser, Node*, Node*, int childCountDelta) 804{ 805 document()->incDOMTreeVersion(); 806 if (!changedByParser && childCountDelta) 807 document()->updateRangesAfterChildrenChanged(this); 808 invalidateNodeListCachesInAncestors(); 809} 810 811inline static void cloneChildNodesAvoidingDeleteButton(ContainerNode* parent, ContainerNode* clonedParent, HTMLElement* deleteButtonContainerElement) 812{ 813 ExceptionCode ec = 0; 814 for (Node* child = parent->firstChild(); child && !ec; child = child->nextSibling()) { 815 816#if ENABLE(DELETION_UI) 817 if (child == deleteButtonContainerElement) 818 continue; 819#else 820 UNUSED_PARAM(deleteButtonContainerElement); 821#endif 822 823 RefPtr<Node> clonedChild = child->cloneNode(false); 824 clonedParent->appendChild(clonedChild, ec); 825 826 if (!ec && child->isContainerNode()) 827 cloneChildNodesAvoidingDeleteButton(toContainerNode(child), toContainerNode(clonedChild.get()), deleteButtonContainerElement); 828 } 829} 830 831void ContainerNode::cloneChildNodes(ContainerNode *clone) 832{ 833#if ENABLE(DELETION_UI) 834 HTMLElement* deleteButtonContainerElement = 0; 835 if (Frame* frame = document()->frame()) 836 deleteButtonContainerElement = frame->editor().deleteButtonController()->containerElement(); 837 cloneChildNodesAvoidingDeleteButton(this, clone, deleteButtonContainerElement); 838#else 839 cloneChildNodesAvoidingDeleteButton(this, clone, 0); 840#endif 841} 842 843bool ContainerNode::getUpperLeftCorner(FloatPoint& point) const 844{ 845 if (!renderer()) 846 return false; 847 // What is this code really trying to do? 848 RenderObject* o = renderer(); 849 RenderObject* p = o; 850 851 if (!o->isInline() || o->isReplaced()) { 852 point = o->localToAbsolute(FloatPoint(), UseTransforms); 853 return true; 854 } 855 856 // find the next text/image child, to get a position 857 while (o) { 858 p = o; 859 if (o->firstChild()) 860 o = o->firstChild(); 861 else if (o->nextSibling()) 862 o = o->nextSibling(); 863 else { 864 RenderObject* next = 0; 865 while (!next && o->parent()) { 866 o = o->parent(); 867 next = o->nextSibling(); 868 } 869 o = next; 870 871 if (!o) 872 break; 873 } 874 ASSERT(o); 875 876 if (!o->isInline() || o->isReplaced()) { 877 point = o->localToAbsolute(FloatPoint(), UseTransforms); 878 return true; 879 } 880 881 if (p->node() && p->node() == this && o->isText() && !o->isBR() && !toRenderText(o)->firstTextBox()) { 882 // do nothing - skip unrendered whitespace that is a child or next sibling of the anchor 883 } else if ((o->isText() && !o->isBR()) || o->isReplaced()) { 884 point = FloatPoint(); 885 if (o->isText() && toRenderText(o)->firstTextBox()) { 886 point.move(toRenderText(o)->linesBoundingBox().x(), toRenderText(o)->firstTextBox()->root()->lineTop()); 887 } else if (o->isBox()) { 888 RenderBox* box = toRenderBox(o); 889 point.moveBy(box->location()); 890 } 891 point = o->container()->localToAbsolute(point, UseTransforms); 892 return true; 893 } 894 } 895 896 // If the target doesn't have any children or siblings that could be used to calculate the scroll position, we must be 897 // at the end of the document. Scroll to the bottom. FIXME: who said anything about scrolling? 898 if (!o && document()->view()) { 899 point = FloatPoint(0, document()->view()->contentsHeight()); 900 return true; 901 } 902 return false; 903} 904 905bool ContainerNode::getLowerRightCorner(FloatPoint& point) const 906{ 907 if (!renderer()) 908 return false; 909 910 RenderObject* o = renderer(); 911 if (!o->isInline() || o->isReplaced()) { 912 RenderBox* box = toRenderBox(o); 913 point = o->localToAbsolute(LayoutPoint(box->size()), UseTransforms); 914 return true; 915 } 916 917 // find the last text/image child, to get a position 918 while (o) { 919 if (o->lastChild()) 920 o = o->lastChild(); 921 else if (o->previousSibling()) 922 o = o->previousSibling(); 923 else { 924 RenderObject* prev = 0; 925 while (!prev) { 926 o = o->parent(); 927 if (!o) 928 return false; 929 prev = o->previousSibling(); 930 } 931 o = prev; 932 } 933 ASSERT(o); 934 if (o->isText() || o->isReplaced()) { 935 point = FloatPoint(); 936 if (o->isText()) { 937 RenderText* text = toRenderText(o); 938 IntRect linesBox = text->linesBoundingBox(); 939 if (!linesBox.maxX() && !linesBox.maxY()) 940 continue; 941 point.moveBy(linesBox.maxXMaxYCorner()); 942 } else { 943 RenderBox* box = toRenderBox(o); 944 point.moveBy(box->frameRect().maxXMaxYCorner()); 945 } 946 point = o->container()->localToAbsolute(point, UseTransforms); 947 return true; 948 } 949 } 950 return true; 951} 952 953LayoutRect ContainerNode::boundingBox() const 954{ 955 FloatPoint upperLeft, lowerRight; 956 bool foundUpperLeft = getUpperLeftCorner(upperLeft); 957 bool foundLowerRight = getLowerRightCorner(lowerRight); 958 959 // If we've found one corner, but not the other, 960 // then we should just return a point at the corner that we did find. 961 if (foundUpperLeft != foundLowerRight) { 962 if (foundUpperLeft) 963 lowerRight = upperLeft; 964 else 965 upperLeft = lowerRight; 966 } 967 968 return enclosingLayoutRect(FloatRect(upperLeft, lowerRight.expandedTo(upperLeft) - upperLeft)); 969} 970 971unsigned ContainerNode::childNodeCount() const 972{ 973 unsigned count = 0; 974 Node *n; 975 for (n = firstChild(); n; n = n->nextSibling()) 976 count++; 977 return count; 978} 979 980Node *ContainerNode::childNode(unsigned index) const 981{ 982 unsigned i; 983 Node *n = firstChild(); 984 for (i = 0; n != 0 && i < index; i++) 985 n = n->nextSibling(); 986 return n; 987} 988 989static void dispatchChildInsertionEvents(Node* child) 990{ 991 if (child->isInShadowTree()) 992 return; 993 994 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden()); 995 996 RefPtr<Node> c = child; 997 RefPtr<Document> document = child->document(); 998 999 if (c->parentNode() && document->hasListenerType(Document::DOMNODEINSERTED_LISTENER)) 1000 c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeInsertedEvent, true, c->parentNode())); 1001 1002 // dispatch the DOMNodeInsertedIntoDocument event to all descendants 1003 if (c->inDocument() && document->hasListenerType(Document::DOMNODEINSERTEDINTODOCUMENT_LISTENER)) { 1004 for (; c; c = NodeTraversal::next(c.get(), child)) 1005 c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeInsertedIntoDocumentEvent, false)); 1006 } 1007} 1008 1009static void dispatchChildRemovalEvents(Node* child) 1010{ 1011 if (child->isInShadowTree()) { 1012 InspectorInstrumentation::willRemoveDOMNode(child->document(), child); 1013 return; 1014 } 1015 1016 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden()); 1017 1018 willCreatePossiblyOrphanedTreeByRemoval(child); 1019 InspectorInstrumentation::willRemoveDOMNode(child->document(), child); 1020 1021 RefPtr<Node> c = child; 1022 RefPtr<Document> document = child->document(); 1023 1024 // dispatch pre-removal mutation events 1025 if (c->parentNode() && document->hasListenerType(Document::DOMNODEREMOVED_LISTENER)) 1026 c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeRemovedEvent, true, c->parentNode())); 1027 1028 // dispatch the DOMNodeRemovedFromDocument event to all descendants 1029 if (c->inDocument() && document->hasListenerType(Document::DOMNODEREMOVEDFROMDOCUMENT_LISTENER)) { 1030 for (; c; c = NodeTraversal::next(c.get(), child)) 1031 c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeRemovedFromDocumentEvent, false)); 1032 } 1033} 1034 1035static void updateTreeAfterInsertion(ContainerNode* parent, Node* child, AttachBehavior attachBehavior) 1036{ 1037 ASSERT(parent->refCount()); 1038 ASSERT(child->refCount()); 1039 1040 ChildListMutationScope(parent).childAdded(child); 1041 1042 parent->childrenChanged(false, child->previousSibling(), child->nextSibling(), 1); 1043 1044 ChildNodeInsertionNotifier(parent).notify(child); 1045 1046 // FIXME: Attachment should be the first operation in this function, but some code 1047 // (for example, HTMLFormControlElement's autofocus support) requires this ordering. 1048 if (parent->attached() && !child->attached() && child->parentNode() == parent) { 1049 if (attachBehavior == AttachLazily) 1050 child->lazyAttach(); 1051 else 1052 child->attach(); 1053 } 1054 1055 dispatchChildInsertionEvents(child); 1056} 1057 1058#ifndef NDEBUG 1059bool childAttachedAllowedWhenAttachingChildren(ContainerNode* node) 1060{ 1061 if (node->isShadowRoot()) 1062 return true; 1063 1064 if (node->isInsertionPoint()) 1065 return true; 1066 1067 if (node->isElementNode() && toElement(node)->shadow()) 1068 return true; 1069 1070 return false; 1071} 1072#endif 1073 1074} // namespace WebCore 1075