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