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 "ContainerNode.h" 25 26 #include "BeforeLoadEvent.h" 27 #include "Cache.h" 28 #include "ContainerNodeAlgorithms.h" 29 #include "DeleteButtonController.h" 30 #include "EventNames.h" 31 #include "ExceptionCode.h" 32 #include "FloatRect.h" 33 #include "Frame.h" 34 #include "FrameView.h" 35 #include "InlineTextBox.h" 36 #include "InspectorController.h" 37 #include "MutationEvent.h" 38 #include "Page.h" 39 #include "RenderTheme.h" 40 #include "RootInlineBox.h" 41 #include "loader.h" 42 #include <wtf/CurrentTime.h> 43 44 namespace WebCore { 45 46 static void dispatchChildInsertionEvents(Node*); 47 static void dispatchChildRemovalEvents(Node*); 48 49 typedef Vector<std::pair<NodeCallback, RefPtr<Node> > > NodeCallbackQueue; 50 static NodeCallbackQueue* s_postAttachCallbackQueue; 51 52 static size_t s_attachDepth; 53 static bool s_shouldReEnableMemoryCacheCallsAfterAttach; 54 55 void ContainerNode::removeAllChildren() 56 { 57 removeAllChildrenInContainer<Node, ContainerNode>(this); 58 } 59 60 ContainerNode::~ContainerNode() 61 { 62 removeAllChildren(); 63 } 64 65 bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode& ec, bool shouldLazyAttach) 66 { 67 // Check that this node is not "floating". 68 // If it is, it can be deleted as a side effect of sending mutation events. 69 ASSERT(refCount() || parent()); 70 71 ec = 0; 72 73 // insertBefore(node, 0) is equivalent to appendChild(node) 74 if (!refChild) 75 return appendChild(newChild, ec, shouldLazyAttach); 76 77 // Make sure adding the new child is OK. 78 checkAddChild(newChild.get(), ec); 79 if (ec) 80 return false; 81 82 // NOT_FOUND_ERR: Raised if refChild is not a child of this node 83 if (refChild->parentNode() != this) { 84 ec = NOT_FOUND_ERR; 85 return false; 86 } 87 88 bool isFragment = newChild->nodeType() == DOCUMENT_FRAGMENT_NODE; 89 90 // If newChild is a DocumentFragment with no children; there's nothing to do. 91 // Just return true 92 if (isFragment && !newChild->firstChild()) 93 return true; 94 95 // Now actually add the child(ren) 96 if (refChild->previousSibling() == newChild || refChild == newChild) // nothing to do 97 return true; 98 99 RefPtr<Node> next = refChild; 100 RefPtr<Node> refChildPreviousSibling = refChild->previousSibling(); 101 102 RefPtr<Node> child = isFragment ? newChild->firstChild() : newChild; 103 while (child) { 104 RefPtr<Node> nextChild = isFragment ? child->nextSibling() : 0; 105 106 // If child is already present in the tree, first remove it from the old location. 107 if (Node* oldParent = child->parentNode()) 108 oldParent->removeChild(child.get(), ec); 109 if (ec) 110 return 0; 111 112 // FIXME: After sending the mutation events, "this" could be destroyed. 113 // We can prevent that by doing a "ref", but first we have to make sure 114 // that no callers call with ref count == 0 and parent = 0 (as of this 115 // writing, there are definitely callers who call that way). 116 117 // Due to arbitrary code running in response to a DOM mutation event it's 118 // possible that "next" is no longer a child of "this". 119 // It's also possible that "child" has been inserted elsewhere. 120 // In either of those cases, we'll just stop. 121 if (next->parentNode() != this) 122 break; 123 if (child->parentNode()) 124 break; 125 126 ASSERT(!child->nextSibling()); 127 ASSERT(!child->previousSibling()); 128 129 // Add child before "next". 130 forbidEventDispatch(); 131 Node* prev = next->previousSibling(); 132 ASSERT(m_lastChild != prev); 133 next->setPreviousSibling(child.get()); 134 if (prev) { 135 ASSERT(m_firstChild != next); 136 ASSERT(prev->nextSibling() == next); 137 prev->setNextSibling(child.get()); 138 } else { 139 ASSERT(m_firstChild == next); 140 m_firstChild = child.get(); 141 } 142 child->setParent(this); 143 child->setPreviousSibling(prev); 144 child->setNextSibling(next.get()); 145 allowEventDispatch(); 146 147 // Dispatch the mutation events. 148 childrenChanged(false, refChildPreviousSibling.get(), next.get(), 1); 149 dispatchChildInsertionEvents(child.get()); 150 151 // Add child to the rendering tree. 152 if (attached() && !child->attached() && child->parent() == this) { 153 if (shouldLazyAttach) 154 child->lazyAttach(); 155 else 156 child->attach(); 157 } 158 159 child = nextChild.release(); 160 } 161 162 dispatchSubtreeModifiedEvent(); 163 return true; 164 } 165 166 bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode& ec, bool shouldLazyAttach) 167 { 168 // Check that this node is not "floating". 169 // If it is, it can be deleted as a side effect of sending mutation events. 170 ASSERT(refCount() || parent()); 171 172 ec = 0; 173 174 if (oldChild == newChild) // nothing to do 175 return true; 176 177 // Make sure replacing the old child with the new is ok 178 checkReplaceChild(newChild.get(), oldChild, ec); 179 if (ec) 180 return false; 181 182 // NOT_FOUND_ERR: Raised if oldChild is not a child of this node. 183 if (!oldChild || oldChild->parentNode() != this) { 184 ec = NOT_FOUND_ERR; 185 return false; 186 } 187 188 RefPtr<Node> prev = oldChild->previousSibling(); 189 RefPtr<Node> next = oldChild->nextSibling(); 190 191 // Remove the node we're replacing 192 RefPtr<Node> removedChild = oldChild; 193 removeChild(oldChild, ec); 194 if (ec) 195 return false; 196 197 // FIXME: After sending the mutation events, "this" could be destroyed. 198 // We can prevent that by doing a "ref", but first we have to make sure 199 // that no callers call with ref count == 0 and parent = 0 (as of this 200 // writing, there are definitely callers who call that way). 201 202 bool isFragment = newChild->nodeType() == DOCUMENT_FRAGMENT_NODE; 203 204 // Add the new child(ren) 205 int childCountDelta = 0; 206 RefPtr<Node> child = isFragment ? newChild->firstChild() : newChild; 207 while (child) { 208 // If the new child is already in the right place, we're done. 209 if (prev && (prev == child || prev == child->previousSibling())) 210 break; 211 212 // For a fragment we have more children to do. 213 RefPtr<Node> nextChild = isFragment ? child->nextSibling() : 0; 214 215 // Remove child from its old position. 216 if (Node* oldParent = child->parentNode()) 217 oldParent->removeChild(child.get(), ec); 218 if (ec) 219 return false; 220 221 // Due to arbitrary code running in response to a DOM mutation event it's 222 // possible that "prev" is no longer a child of "this". 223 // It's also possible that "child" has been inserted elsewhere. 224 // In either of those cases, we'll just stop. 225 if (prev && prev->parentNode() != this) 226 break; 227 if (child->parentNode()) 228 break; 229 230 childCountDelta++; 231 232 ASSERT(!child->nextSibling()); 233 ASSERT(!child->previousSibling()); 234 235 // Add child after "prev". 236 forbidEventDispatch(); 237 Node* next; 238 if (prev) { 239 next = prev->nextSibling(); 240 ASSERT(m_firstChild != next); 241 prev->setNextSibling(child.get()); 242 } else { 243 next = m_firstChild; 244 m_firstChild = child.get(); 245 } 246 if (next) { 247 ASSERT(m_lastChild != prev); 248 ASSERT(next->previousSibling() == prev); 249 next->setPreviousSibling(child.get()); 250 } else { 251 ASSERT(m_lastChild == prev); 252 m_lastChild = child.get(); 253 } 254 child->setParent(this); 255 child->setPreviousSibling(prev.get()); 256 child->setNextSibling(next); 257 allowEventDispatch(); 258 259 // Dispatch the mutation events 260 dispatchChildInsertionEvents(child.get()); 261 262 // Add child to the rendering tree 263 if (attached() && !child->attached() && child->parent() == this) { 264 if (shouldLazyAttach) 265 child->lazyAttach(); 266 else 267 child->attach(); 268 } 269 270 prev = child; 271 child = nextChild.release(); 272 } 273 274 if (childCountDelta) 275 childrenChanged(false, prev.get(), next.get(), childCountDelta); 276 dispatchSubtreeModifiedEvent(); 277 return true; 278 } 279 280 void ContainerNode::willRemove() 281 { 282 for (Node *n = m_firstChild; n != 0; n = n->nextSibling()) 283 n->willRemove(); 284 Node::willRemove(); 285 } 286 287 static ExceptionCode willRemoveChild(Node *child) 288 { 289 ExceptionCode ec = 0; 290 291 // fire removed from document mutation events. 292 dispatchChildRemovalEvents(child); 293 if (ec) 294 return ec; 295 296 if (child->attached()) 297 child->willRemove(); 298 299 return 0; 300 } 301 302 bool ContainerNode::removeChild(Node* oldChild, ExceptionCode& ec) 303 { 304 // Check that this node is not "floating". 305 // If it is, it can be deleted as a side effect of sending mutation events. 306 ASSERT(refCount() || parent()); 307 308 ec = 0; 309 310 // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. 311 if (isReadOnlyNode()) { 312 ec = NO_MODIFICATION_ALLOWED_ERR; 313 return false; 314 } 315 316 // NOT_FOUND_ERR: Raised if oldChild is not a child of this node. 317 if (!oldChild || oldChild->parentNode() != this) { 318 ec = NOT_FOUND_ERR; 319 return false; 320 } 321 322 RefPtr<Node> child = oldChild; 323 324 ec = willRemoveChild(child.get()); 325 if (ec) 326 return false; 327 328 // Mutation events might have moved this child into a different parent. 329 if (child->parentNode() != this) { 330 ec = NOT_FOUND_ERR; 331 return false; 332 } 333 334 document()->removeFocusedNodeOfSubtree(child.get()); 335 336 // FIXME: After sending the mutation events, "this" could be destroyed. 337 // We can prevent that by doing a "ref", but first we have to make sure 338 // that no callers call with ref count == 0 and parent = 0 (as of this 339 // writing, there are definitely callers who call that way). 340 341 forbidEventDispatch(); 342 343 // Remove from rendering tree 344 if (child->attached()) 345 child->detach(); 346 347 // Remove the child 348 Node *prev, *next; 349 prev = child->previousSibling(); 350 next = child->nextSibling(); 351 352 if (next) 353 next->setPreviousSibling(prev); 354 if (prev) 355 prev->setNextSibling(next); 356 if (m_firstChild == child) 357 m_firstChild = next; 358 if (m_lastChild == child) 359 m_lastChild = prev; 360 361 child->setPreviousSibling(0); 362 child->setNextSibling(0); 363 child->setParent(0); 364 365 allowEventDispatch(); 366 367 // Dispatch post-removal mutation events 368 childrenChanged(false, prev, next, -1); 369 dispatchSubtreeModifiedEvent(); 370 371 if (child->inDocument()) 372 child->removedFromDocument(); 373 else 374 child->removedFromTree(true); 375 376 return child; 377 } 378 379 // this differs from other remove functions because it forcibly removes all the children, 380 // regardless of read-only status or event exceptions, e.g. 381 bool ContainerNode::removeChildren() 382 { 383 if (!m_firstChild) 384 return false; 385 386 // The container node can be removed from event handlers. 387 RefPtr<Node> protect(this); 388 389 // Do any prep work needed before actually starting to detach 390 // and remove... e.g. stop loading frames, fire unload events. 391 // FIXME: Adding new children from event handlers can cause an infinite loop here. 392 for (RefPtr<Node> n = m_firstChild; n; n = n->nextSibling()) 393 willRemoveChild(n.get()); 394 395 // exclude this node when looking for removed focusedNode since only children will be removed 396 document()->removeFocusedNodeOfSubtree(this, true); 397 398 forbidEventDispatch(); 399 int childCountDelta = 0; 400 while (RefPtr<Node> n = m_firstChild) { 401 childCountDelta--; 402 403 Node* next = n->nextSibling(); 404 405 // Remove the node from the tree before calling detach or removedFromDocument (4427024, 4129744) 406 n->setPreviousSibling(0); 407 n->setNextSibling(0); 408 n->setParent(0); 409 410 m_firstChild = next; 411 if (n == m_lastChild) 412 m_lastChild = 0; 413 414 if (n->attached()) 415 n->detach(); 416 417 if (n->inDocument()) 418 n->removedFromDocument(); 419 } 420 allowEventDispatch(); 421 422 // Dispatch a single post-removal mutation event denoting a modified subtree. 423 childrenChanged(false, 0, 0, childCountDelta); 424 dispatchSubtreeModifiedEvent(); 425 426 return true; 427 } 428 429 bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, bool shouldLazyAttach) 430 { 431 // Check that this node is not "floating". 432 // If it is, it can be deleted as a side effect of sending mutation events. 433 ASSERT(refCount() || parent()); 434 435 ec = 0; 436 437 // Make sure adding the new child is ok 438 checkAddChild(newChild.get(), ec); 439 if (ec) 440 return 0; 441 442 if (newChild == m_lastChild) // nothing to do 443 return newChild; 444 445 bool isFragment = newChild->nodeType() == DOCUMENT_FRAGMENT_NODE; 446 447 // If newChild is a DocumentFragment with no children.... there's nothing to do. 448 // Just return the document fragment 449 if (isFragment && !newChild->firstChild()) 450 return true; 451 452 // Now actually add the child(ren) 453 RefPtr<Node> prev = lastChild(); 454 RefPtr<Node> child = isFragment ? newChild->firstChild() : newChild; 455 while (child) { 456 // For a fragment we have more children to do. 457 RefPtr<Node> nextChild = isFragment ? child->nextSibling() : 0; 458 459 // If child is already present in the tree, first remove it 460 if (Node* oldParent = child->parentNode()) { 461 oldParent->removeChild(child.get(), ec); 462 if (ec) 463 return 0; 464 465 // If the child has a parent again, just stop what we're doing, because 466 // that means someone is doing something with DOM mutation -- can't re-parent 467 // a child that already has a parent. 468 if (child->parentNode()) 469 break; 470 } 471 472 // Append child to the end of the list 473 forbidEventDispatch(); 474 child->setParent(this); 475 if (m_lastChild) { 476 child->setPreviousSibling(m_lastChild); 477 m_lastChild->setNextSibling(child.get()); 478 } else 479 m_firstChild = child.get(); 480 m_lastChild = child.get(); 481 allowEventDispatch(); 482 483 // Dispatch the mutation events 484 childrenChanged(false, prev.get(), 0, 1); 485 dispatchChildInsertionEvents(child.get()); 486 487 // Add child to the rendering tree 488 if (attached() && !child->attached() && child->parent() == this) { 489 if (shouldLazyAttach) 490 child->lazyAttach(); 491 else 492 child->attach(); 493 } 494 495 child = nextChild.release(); 496 } 497 498 dispatchSubtreeModifiedEvent(); 499 return true; 500 } 501 502 ContainerNode* ContainerNode::addChild(PassRefPtr<Node> newChild) 503 { 504 ASSERT(newChild); 505 // This function is only used during parsing. 506 // It does not send any DOM mutation events. 507 508 // Check for consistency with DTD, but only when parsing HTML. 509 if (document()->isHTMLDocument() && !childAllowed(newChild.get())) 510 return 0; 511 512 forbidEventDispatch(); 513 Node* last = m_lastChild; 514 appendChildToContainer<Node, ContainerNode>(newChild.get(), this); 515 allowEventDispatch(); 516 517 document()->incDOMTreeVersion(); 518 if (inDocument()) 519 newChild->insertedIntoDocument(); 520 childrenChanged(true, last, 0, 1); 521 522 if (newChild->isElementNode()) 523 return static_cast<ContainerNode*>(newChild.get()); 524 return this; 525 } 526 527 void ContainerNode::suspendPostAttachCallbacks() 528 { 529 if (!s_attachDepth) { 530 ASSERT(!s_shouldReEnableMemoryCacheCallsAfterAttach); 531 if (Page* page = document()->page()) { 532 if (page->areMemoryCacheClientCallsEnabled()) { 533 page->setMemoryCacheClientCallsEnabled(false); 534 s_shouldReEnableMemoryCacheCallsAfterAttach = true; 535 } 536 } 537 cache()->loader()->suspendPendingRequests(); 538 } 539 ++s_attachDepth; 540 } 541 542 void ContainerNode::resumePostAttachCallbacks() 543 { 544 if (s_attachDepth == 1) { 545 if (s_postAttachCallbackQueue) 546 dispatchPostAttachCallbacks(); 547 if (s_shouldReEnableMemoryCacheCallsAfterAttach) { 548 s_shouldReEnableMemoryCacheCallsAfterAttach = false; 549 if (Page* page = document()->page()) 550 page->setMemoryCacheClientCallsEnabled(true); 551 } 552 cache()->loader()->resumePendingRequests(); 553 } 554 --s_attachDepth; 555 } 556 557 void ContainerNode::queuePostAttachCallback(NodeCallback callback, Node* node) 558 { 559 if (!s_postAttachCallbackQueue) 560 s_postAttachCallbackQueue = new NodeCallbackQueue; 561 562 s_postAttachCallbackQueue->append(std::pair<NodeCallback, RefPtr<Node> >(callback, node)); 563 } 564 565 void ContainerNode::dispatchPostAttachCallbacks() 566 { 567 // We recalculate size() each time through the loop because a callback 568 // can add more callbacks to the end of the queue. 569 for (size_t i = 0; i < s_postAttachCallbackQueue->size(); ++i) { 570 std::pair<NodeCallback, RefPtr<Node> >& pair = (*s_postAttachCallbackQueue)[i]; 571 NodeCallback callback = pair.first; 572 Node* node = pair.second.get(); 573 574 callback(node); 575 } 576 s_postAttachCallbackQueue->clear(); 577 } 578 579 void ContainerNode::attach() 580 { 581 for (Node* child = m_firstChild; child; child = child->nextSibling()) 582 child->attach(); 583 Node::attach(); 584 } 585 586 void ContainerNode::detach() 587 { 588 for (Node* child = m_firstChild; child; child = child->nextSibling()) 589 child->detach(); 590 setChildNeedsStyleRecalc(false); 591 Node::detach(); 592 } 593 594 void ContainerNode::insertedIntoDocument() 595 { 596 Node::insertedIntoDocument(); 597 insertedIntoTree(false); 598 for (Node* child = m_firstChild; child; child = child->nextSibling()) 599 child->insertedIntoDocument(); 600 } 601 602 void ContainerNode::removedFromDocument() 603 { 604 Node::removedFromDocument(); 605 if (document()->cssTarget() == this) 606 document()->setCSSTarget(0); 607 setInDocument(false); 608 removedFromTree(false); 609 for (Node* child = m_firstChild; child; child = child->nextSibling()) 610 child->removedFromDocument(); 611 } 612 613 void ContainerNode::insertedIntoTree(bool deep) 614 { 615 if (!deep) 616 return; 617 for (Node* child = m_firstChild; child; child = child->nextSibling()) 618 child->insertedIntoTree(true); 619 } 620 621 void ContainerNode::removedFromTree(bool deep) 622 { 623 if (!deep) 624 return; 625 for (Node* child = m_firstChild; child; child = child->nextSibling()) 626 child->removedFromTree(true); 627 } 628 629 void ContainerNode::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) 630 { 631 Node::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); 632 if (!changedByParser && childCountDelta) 633 document()->nodeChildrenChanged(this); 634 if (document()->hasNodeListCaches()) 635 notifyNodeListsChildrenChanged(); 636 } 637 638 void ContainerNode::cloneChildNodes(ContainerNode *clone) 639 { 640 // disable the delete button so it's elements are not serialized into the markup 641 if (document()->frame()) 642 document()->frame()->editor()->deleteButtonController()->disable(); 643 ExceptionCode ec = 0; 644 for (Node* n = firstChild(); n && !ec; n = n->nextSibling()) 645 clone->appendChild(n->cloneNode(true), ec); 646 if (document()->frame()) 647 document()->frame()->editor()->deleteButtonController()->enable(); 648 } 649 650 // FIXME: This doesn't work correctly with transforms. 651 bool ContainerNode::getUpperLeftCorner(FloatPoint& point) const 652 { 653 if (!renderer()) 654 return false; 655 // What is this code really trying to do? 656 RenderObject *o = renderer(); 657 RenderObject *p = o; 658 659 if (!o->isInline() || o->isReplaced()) { 660 point = o->localToAbsolute(); 661 return true; 662 } 663 664 // find the next text/image child, to get a position 665 while (o) { 666 p = o; 667 if (o->firstChild()) 668 o = o->firstChild(); 669 else if (o->nextSibling()) 670 o = o->nextSibling(); 671 else { 672 RenderObject *next = 0; 673 while (!next && o->parent()) { 674 o = o->parent(); 675 next = o->nextSibling(); 676 } 677 o = next; 678 679 if (!o) 680 break; 681 } 682 ASSERT(o); 683 684 if (!o->isInline() || o->isReplaced()) { 685 point = o->localToAbsolute(); 686 return true; 687 } 688 689 if (p->node() && p->node() == this && o->isText() && !o->isBR() && !toRenderText(o)->firstTextBox()) { 690 // do nothing - skip unrendered whitespace that is a child or next sibling of the anchor 691 } else if ((o->isText() && !o->isBR()) || o->isReplaced()) { 692 point = o->container()->localToAbsolute(); 693 if (o->isText() && toRenderText(o)->firstTextBox()) { 694 point.move(toRenderText(o)->linesBoundingBox().x(), 695 toRenderText(o)->firstTextBox()->root()->lineTop()); 696 } else if (o->isBox()) { 697 RenderBox* box = toRenderBox(o); 698 point.move(box->x(), box->y()); 699 } 700 return true; 701 } 702 } 703 704 // If the target doesn't have any children or siblings that could be used to calculate the scroll position, we must be 705 // at the end of the document. Scroll to the bottom. FIXME: who said anything about scrolling? 706 if (!o && document()->view()) { 707 point = FloatPoint(0, document()->view()->contentsHeight()); 708 return true; 709 } 710 return false; 711 } 712 713 // FIXME: This doesn't work correctly with transforms. 714 bool ContainerNode::getLowerRightCorner(FloatPoint& point) const 715 { 716 if (!renderer()) 717 return false; 718 719 RenderObject* o = renderer(); 720 if (!o->isInline() || o->isReplaced()) { 721 RenderBox* box = toRenderBox(o); 722 point = o->localToAbsolute(); 723 point.move(box->width(), box->height()); 724 return true; 725 } 726 727 // find the last text/image child, to get a position 728 while (o) { 729 if (o->lastChild()) 730 o = o->lastChild(); 731 else if (o->previousSibling()) 732 o = o->previousSibling(); 733 else { 734 RenderObject* prev = 0; 735 while (!prev) { 736 o = o->parent(); 737 if (!o) 738 return false; 739 prev = o->previousSibling(); 740 } 741 o = prev; 742 } 743 ASSERT(o); 744 if (o->isText() || o->isReplaced()) { 745 point = o->container()->localToAbsolute(); 746 if (o->isText()) { 747 RenderText* text = toRenderText(o); 748 IntRect linesBox = text->linesBoundingBox(); 749 point.move(linesBox.x() + linesBox.width(), linesBox.y() + linesBox.height()); 750 } else { 751 RenderBox* box = toRenderBox(o); 752 point.move(box->x() + box->width(), box->y() + box->height()); 753 } 754 return true; 755 } 756 } 757 return true; 758 } 759 760 IntRect ContainerNode::getRect() const 761 { 762 FloatPoint upperLeft, lowerRight; 763 bool foundUpperLeft = getUpperLeftCorner(upperLeft); 764 bool foundLowerRight = getLowerRightCorner(lowerRight); 765 766 // If we've found one corner, but not the other, 767 // then we should just return a point at the corner that we did find. 768 if (foundUpperLeft != foundLowerRight) { 769 if (foundUpperLeft) 770 lowerRight = upperLeft; 771 else 772 upperLeft = lowerRight; 773 } 774 775 lowerRight.setX(max(upperLeft.x(), lowerRight.x())); 776 lowerRight.setY(max(upperLeft.y(), lowerRight.y())); 777 778 return enclosingIntRect(FloatRect(upperLeft, lowerRight - upperLeft)); 779 } 780 781 void ContainerNode::setFocus(bool received) 782 { 783 if (focused() == received) 784 return; 785 786 Node::setFocus(received); 787 788 // note that we need to recalc the style 789 setNeedsStyleRecalc(); 790 } 791 792 void ContainerNode::setActive(bool down, bool pause) 793 { 794 if (down == active()) return; 795 796 Node::setActive(down); 797 798 // note that we need to recalc the style 799 // FIXME: Move to Element 800 if (renderer()) { 801 bool reactsToPress = renderer()->style()->affectedByActiveRules(); 802 if (reactsToPress) 803 setNeedsStyleRecalc(); 804 if (renderer() && renderer()->style()->hasAppearance()) { 805 if (renderer()->theme()->stateChanged(renderer(), PressedState)) 806 reactsToPress = true; 807 } 808 if (reactsToPress && pause) { 809 // The delay here is subtle. It relies on an assumption, namely that the amount of time it takes 810 // to repaint the "down" state of the control is about the same time as it would take to repaint the 811 // "up" state. Once you assume this, you can just delay for 100ms - that time (assuming that after you 812 // leave this method, it will be about that long before the flush of the up state happens again). 813 #ifdef HAVE_FUNC_USLEEP 814 double startTime = currentTime(); 815 #endif 816 817 // Ensure there are no pending changes 818 Document::updateStyleForAllDocuments(); 819 // Do an immediate repaint. 820 if (renderer()) 821 renderer()->repaint(true); 822 823 // FIXME: Find a substitute for usleep for Win32. 824 // Better yet, come up with a way of doing this that doesn't use this sort of thing at all. 825 #ifdef HAVE_FUNC_USLEEP 826 // Now pause for a small amount of time (1/10th of a second from before we repainted in the pressed state) 827 double remainingTime = 0.1 - (currentTime() - startTime); 828 if (remainingTime > 0) 829 usleep(static_cast<useconds_t>(remainingTime * 1000000.0)); 830 #endif 831 } 832 } 833 } 834 835 void ContainerNode::setHovered(bool over) 836 { 837 if (over == hovered()) return; 838 839 Node::setHovered(over); 840 841 // note that we need to recalc the style 842 // FIXME: Move to Element 843 if (renderer()) { 844 if (renderer()->style()->affectedByHoverRules()) 845 setNeedsStyleRecalc(); 846 if (renderer() && renderer()->style()->hasAppearance()) 847 renderer()->theme()->stateChanged(renderer(), HoverState); 848 } 849 } 850 851 unsigned ContainerNode::childNodeCount() const 852 { 853 unsigned count = 0; 854 Node *n; 855 for (n = firstChild(); n; n = n->nextSibling()) 856 count++; 857 return count; 858 } 859 860 Node *ContainerNode::childNode(unsigned index) const 861 { 862 unsigned i; 863 Node *n = firstChild(); 864 for (i = 0; n != 0 && i < index; i++) 865 n = n->nextSibling(); 866 return n; 867 } 868 869 static void dispatchChildInsertionEvents(Node* child) 870 { 871 ASSERT(!eventDispatchForbidden()); 872 873 #if ENABLE(INSPECTOR) 874 if (Page* page = child->document()->page()) { 875 if (InspectorController* inspectorController = page->inspectorController()) 876 inspectorController->didInsertDOMNode(child); 877 } 878 #endif 879 880 RefPtr<Node> c = child; 881 RefPtr<Document> document = child->document(); 882 883 if (c->parentNode() && c->parentNode()->inDocument()) 884 c->insertedIntoDocument(); 885 else 886 c->insertedIntoTree(true); 887 888 document->incDOMTreeVersion(); 889 890 if (c->parentNode() && document->hasListenerType(Document::DOMNODEINSERTED_LISTENER)) 891 c->dispatchEvent(MutationEvent::create(eventNames().DOMNodeInsertedEvent, true, c->parentNode())); 892 893 // dispatch the DOMNodeInsertedIntoDocument event to all descendants 894 if (c->inDocument() && document->hasListenerType(Document::DOMNODEINSERTEDINTODOCUMENT_LISTENER)) { 895 for (; c; c = c->traverseNextNode(child)) 896 c->dispatchEvent(MutationEvent::create(eventNames().DOMNodeInsertedIntoDocumentEvent, false)); 897 } 898 } 899 900 static void dispatchChildRemovalEvents(Node* child) 901 { 902 #if ENABLE(INSPECTOR) 903 if (Page* page = child->document()->page()) { 904 if (InspectorController* inspectorController = page->inspectorController()) 905 inspectorController->didRemoveDOMNode(child); 906 } 907 #endif 908 909 RefPtr<Node> c = child; 910 RefPtr<Document> document = child->document(); 911 912 // update auxiliary doc info (e.g. iterators) to note that node is being removed 913 document->nodeWillBeRemoved(child); 914 915 document->incDOMTreeVersion(); 916 917 // dispatch pre-removal mutation events 918 if (c->parentNode() && document->hasListenerType(Document::DOMNODEREMOVED_LISTENER)) 919 c->dispatchEvent(MutationEvent::create(eventNames().DOMNodeRemovedEvent, true, c->parentNode())); 920 921 // dispatch the DOMNodeRemovedFromDocument event to all descendants 922 if (c->inDocument() && document->hasListenerType(Document::DOMNODEREMOVEDFROMDOCUMENT_LISTENER)) { 923 for (; c; c = c->traverseNextNode(child)) 924 c->dispatchEvent(MutationEvent::create(eventNames().DOMNodeRemovedFromDocumentEvent, false)); 925 } 926 } 927 928 bool ContainerNode::dispatchBeforeLoadEvent(const String& sourceURL) 929 { 930 if (!document()->hasListenerType(Document::BEFORELOAD_LISTENER)) 931 return true; 932 933 RefPtr<ContainerNode> protector(this); 934 RefPtr<BeforeLoadEvent> beforeLoadEvent = BeforeLoadEvent::create(sourceURL); 935 dispatchEvent(beforeLoadEvent.get()); 936 return !beforeLoadEvent->defaultPrevented(); 937 } 938 939 } // namespace WebCore 940