2008-11-04 Anders Carlsson <andersca@apple.com>
[webkit/qt.git] / WebCore / dom / ContainerNode.cpp
blob0f46ae67106374faecbc8beff13849722a10eccc
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 Apple Inc. All rights reserved.
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.
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.
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.
23 #include "config.h"
24 #include "ContainerNode.h"
26 #include "ContainerNodeAlgorithms.h"
27 #include "DeleteButtonController.h"
28 #include "Document.h"
29 #include "Editor.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 "MutationEvent.h"
37 #include "RenderTheme.h"
38 #include "RootInlineBox.h"
39 #include "SystemTime.h"
40 #include <wtf/Vector.h>
42 namespace WebCore {
44 static void dispatchChildInsertionEvents(Node*, ExceptionCode&);
45 static void dispatchChildRemovalEvents(Node*, ExceptionCode&);
47 typedef Vector<std::pair<NodeCallback, RefPtr<Node> > > NodeCallbackQueue;
48 static NodeCallbackQueue* s_postAttachCallbackQueue = 0;
50 static size_t s_attachDepth = 0;
52 ContainerNode::ContainerNode(Document* doc, bool isElement)
53 : EventTargetNode(doc, isElement, true)
54 , m_firstChild(0)
55 , m_lastChild(0)
59 void ContainerNode::removeAllChildren()
61 removeAllChildrenInContainer<Node, ContainerNode>(this);
64 ContainerNode::~ContainerNode()
66 removeAllChildren();
69 bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode& ec, bool shouldLazyAttach)
71 // Check that this node is not "floating".
72 // If it is, it can be deleted as a side effect of sending mutation events.
73 ASSERT(refCount() || parent());
75 ec = 0;
77 // insertBefore(node, 0) is equivalent to appendChild(node)
78 if (!refChild)
79 return appendChild(newChild, ec, shouldLazyAttach);
81 // Make sure adding the new child is OK.
82 checkAddChild(newChild.get(), ec);
83 if (ec)
84 return false;
86 // NOT_FOUND_ERR: Raised if refChild is not a child of this node
87 if (refChild->parentNode() != this) {
88 ec = NOT_FOUND_ERR;
89 return false;
92 bool isFragment = newChild->nodeType() == DOCUMENT_FRAGMENT_NODE;
94 // If newChild is a DocumentFragment with no children; there's nothing to do.
95 // Just return true
96 if (isFragment && !newChild->firstChild())
97 return true;
99 // Now actually add the child(ren)
100 if (refChild->previousSibling() == newChild || refChild == newChild) // nothing to do
101 return true;
103 RefPtr<Node> next = refChild;
104 RefPtr<Node> prev = refChild->previousSibling();
106 int childCountDelta = 0;
107 RefPtr<Node> child = isFragment ? newChild->firstChild() : newChild;
108 while (child) {
109 RefPtr<Node> nextChild = isFragment ? child->nextSibling() : 0;
111 // If child is already present in the tree, first remove it from the old location.
112 if (Node* oldParent = child->parentNode())
113 oldParent->removeChild(child.get(), ec);
114 if (ec)
115 return 0;
117 // FIXME: After sending the mutation events, "this" could be destroyed.
118 // We can prevent that by doing a "ref", but first we have to make sure
119 // that no callers call with ref count == 0 and parent = 0 (as of this
120 // writing, there are definitely callers who call that way).
122 // Due to arbitrary code running in response to a DOM mutation event it's
123 // possible that "next" is no longer a child of "this".
124 // It's also possible that "child" has been inserted elsewhere.
125 // In either of those cases, we'll just stop.
126 if (next->parentNode() != this)
127 break;
128 if (child->parentNode())
129 break;
131 ASSERT(!child->nextSibling());
132 ASSERT(!child->previousSibling());
134 childCountDelta++;
136 // Add child before "next".
137 forbidEventDispatch();
138 Node* prev = next->previousSibling();
139 ASSERT(m_lastChild != prev);
140 next->setPreviousSibling(child.get());
141 if (prev) {
142 ASSERT(m_firstChild != next);
143 ASSERT(prev->nextSibling() == next);
144 prev->setNextSibling(child.get());
145 } else {
146 ASSERT(m_firstChild == next);
147 m_firstChild = child.get();
149 child->setParent(this);
150 child->setPreviousSibling(prev);
151 child->setNextSibling(next.get());
152 allowEventDispatch();
154 // Dispatch the mutation events.
155 dispatchChildInsertionEvents(child.get(), ec);
157 // Add child to the rendering tree.
158 if (attached() && !child->attached() && child->parent() == this) {
159 if (shouldLazyAttach)
160 child->lazyAttach();
161 else
162 child->attach();
165 child = nextChild.release();
168 document()->setDocumentChanged(true);
169 if (childCountDelta)
170 childrenChanged(false, prev.get(), next.get(), childCountDelta);
171 dispatchSubtreeModifiedEvent();
172 return true;
175 bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode& ec, bool shouldLazyAttach)
177 // Check that this node is not "floating".
178 // If it is, it can be deleted as a side effect of sending mutation events.
179 ASSERT(refCount() || parent());
181 ec = 0;
183 if (oldChild == newChild) // nothing to do
184 return true;
186 // Make sure replacing the old child with the new is ok
187 checkReplaceChild(newChild.get(), oldChild, ec);
188 if (ec)
189 return false;
191 // NOT_FOUND_ERR: Raised if oldChild is not a child of this node.
192 if (!oldChild || oldChild->parentNode() != this) {
193 ec = NOT_FOUND_ERR;
194 return false;
197 RefPtr<Node> prev = oldChild->previousSibling();
198 RefPtr<Node> next = oldChild->nextSibling();
200 // Remove the node we're replacing
201 RefPtr<Node> removedChild = oldChild;
202 removeChild(oldChild, ec);
203 if (ec)
204 return false;
206 // FIXME: After sending the mutation events, "this" could be destroyed.
207 // We can prevent that by doing a "ref", but first we have to make sure
208 // that no callers call with ref count == 0 and parent = 0 (as of this
209 // writing, there are definitely callers who call that way).
211 bool isFragment = newChild->nodeType() == DOCUMENT_FRAGMENT_NODE;
213 // Add the new child(ren)
214 int childCountDelta = 0;
215 RefPtr<Node> child = isFragment ? newChild->firstChild() : newChild;
216 while (child) {
217 // If the new child is already in the right place, we're done.
218 if (prev && (prev == child || prev == child->previousSibling()))
219 break;
221 // For a fragment we have more children to do.
222 RefPtr<Node> nextChild = isFragment ? child->nextSibling() : 0;
224 // Remove child from its old position.
225 if (Node* oldParent = child->parentNode())
226 oldParent->removeChild(child.get(), ec);
227 if (ec)
228 return 0;
230 // Due to arbitrary code running in response to a DOM mutation event it's
231 // possible that "prev" is no longer a child of "this".
232 // It's also possible that "child" has been inserted elsewhere.
233 // In either of those cases, we'll just stop.
234 if (prev && prev->parentNode() != this)
235 break;
236 if (child->parentNode())
237 break;
239 childCountDelta++;
241 ASSERT(!child->nextSibling());
242 ASSERT(!child->previousSibling());
244 // Add child after "prev".
245 forbidEventDispatch();
246 Node* next;
247 if (prev) {
248 next = prev->nextSibling();
249 ASSERT(m_firstChild != next);
250 prev->setNextSibling(child.get());
251 } else {
252 next = m_firstChild;
253 m_firstChild = child.get();
255 if (next) {
256 ASSERT(m_lastChild != prev);
257 ASSERT(next->previousSibling() == prev);
258 next->setPreviousSibling(child.get());
259 } else {
260 ASSERT(m_lastChild == prev);
261 m_lastChild = child.get();
263 child->setParent(this);
264 child->setPreviousSibling(prev.get());
265 child->setNextSibling(next);
266 allowEventDispatch();
268 // Dispatch the mutation events
269 dispatchChildInsertionEvents(child.get(), ec);
271 // Add child to the rendering tree
272 if (attached() && !child->attached() && child->parent() == this) {
273 if (shouldLazyAttach)
274 child->lazyAttach();
275 else
276 child->attach();
279 prev = child;
280 child = nextChild.release();
283 document()->setDocumentChanged(true);
284 if (childCountDelta)
285 childrenChanged(false, prev.get(), next.get(), childCountDelta);
286 dispatchSubtreeModifiedEvent();
287 return true;
290 void ContainerNode::willRemove()
292 for (Node *n = m_firstChild; n != 0; n = n->nextSibling())
293 n->willRemove();
294 EventTargetNode::willRemove();
297 static ExceptionCode willRemoveChild(Node *child)
299 ExceptionCode ec = 0;
301 // fire removed from document mutation events.
302 dispatchChildRemovalEvents(child, ec);
303 if (ec)
304 return ec;
306 if (child->attached())
307 child->willRemove();
309 return 0;
312 bool ContainerNode::removeChild(Node* oldChild, ExceptionCode& ec)
314 // Check that this node is not "floating".
315 // If it is, it can be deleted as a side effect of sending mutation events.
316 ASSERT(refCount() || parent());
318 ec = 0;
320 // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
321 if (isReadOnlyNode()) {
322 ec = NO_MODIFICATION_ALLOWED_ERR;
323 return false;
326 // NOT_FOUND_ERR: Raised if oldChild is not a child of this node.
327 if (!oldChild || oldChild->parentNode() != this) {
328 ec = NOT_FOUND_ERR;
329 return false;
332 RefPtr<Node> child = oldChild;
334 ec = willRemoveChild(child.get());
335 if (ec)
336 return false;
338 // Mutation events might have moved this child into a different parent.
339 if (child->parentNode() != this) {
340 ec = NOT_FOUND_ERR;
341 return false;
344 document()->removeFocusedNodeOfSubtree(child.get());
346 // FIXME: After sending the mutation events, "this" could be destroyed.
347 // We can prevent that by doing a "ref", but first we have to make sure
348 // that no callers call with ref count == 0 and parent = 0 (as of this
349 // writing, there are definitely callers who call that way).
351 forbidEventDispatch();
353 // Remove from rendering tree
354 if (child->attached())
355 child->detach();
357 // Remove the child
358 Node *prev, *next;
359 prev = child->previousSibling();
360 next = child->nextSibling();
362 if (next)
363 next->setPreviousSibling(prev);
364 if (prev)
365 prev->setNextSibling(next);
366 if (m_firstChild == child)
367 m_firstChild = next;
368 if (m_lastChild == child)
369 m_lastChild = prev;
371 child->setPreviousSibling(0);
372 child->setNextSibling(0);
373 child->setParent(0);
375 allowEventDispatch();
377 document()->setDocumentChanged(true);
379 // Dispatch post-removal mutation events
380 childrenChanged(false, prev, next, -1);
381 dispatchSubtreeModifiedEvent();
383 if (child->inDocument())
384 child->removedFromDocument();
385 else
386 child->removedFromTree(true);
388 return child;
391 // this differs from other remove functions because it forcibly removes all the children,
392 // regardless of read-only status or event exceptions, e.g.
393 bool ContainerNode::removeChildren()
395 if (!m_firstChild)
396 return false;
398 Node* n;
400 // do any prep work needed before actually starting to detach
401 // and remove... e.g. stop loading frames, fire unload events
402 for (n = m_firstChild; n; n = n->nextSibling())
403 willRemoveChild(n);
405 // exclude this node when looking for removed focusedNode since only children will be removed
406 document()->removeFocusedNodeOfSubtree(this, true);
408 forbidEventDispatch();
409 int childCountDelta = 0;
410 while ((n = m_firstChild) != 0) {
411 childCountDelta--;
413 Node *next = n->nextSibling();
415 n->ref();
417 // Remove the node from the tree before calling detach or removedFromDocument (4427024, 4129744)
418 n->setPreviousSibling(0);
419 n->setNextSibling(0);
420 n->setParent(0);
422 m_firstChild = next;
423 if (n == m_lastChild)
424 m_lastChild = 0;
426 if (n->attached())
427 n->detach();
429 if (n->inDocument())
430 n->removedFromDocument();
432 n->deref();
434 allowEventDispatch();
436 // Dispatch a single post-removal mutation event denoting a modified subtree.
437 childrenChanged(false, 0, 0, childCountDelta);
438 dispatchSubtreeModifiedEvent();
440 return true;
443 bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, bool shouldLazyAttach)
445 // Check that this node is not "floating".
446 // If it is, it can be deleted as a side effect of sending mutation events.
447 ASSERT(refCount() || parent());
449 ec = 0;
451 // Make sure adding the new child is ok
452 checkAddChild(newChild.get(), ec);
453 if (ec)
454 return 0;
456 if (newChild == m_lastChild) // nothing to do
457 return newChild;
459 bool isFragment = newChild->nodeType() == DOCUMENT_FRAGMENT_NODE;
461 // If newChild is a DocumentFragment with no children.... there's nothing to do.
462 // Just return the document fragment
463 if (isFragment && !newChild->firstChild())
464 return true;
466 // Now actually add the child(ren)
467 int childCountDelta = 0;
468 RefPtr<Node> prev = lastChild();
469 RefPtr<Node> child = isFragment ? newChild->firstChild() : newChild;
470 while (child) {
471 // For a fragment we have more children to do.
472 RefPtr<Node> nextChild = isFragment ? child->nextSibling() : 0;
474 // If child is already present in the tree, first remove it
475 if (Node* oldParent = child->parentNode()) {
476 oldParent->removeChild(child.get(), ec);
477 if (ec)
478 return 0;
480 // If the child has a parent again, just stop what we're doing, because
481 // that means someone is doing something with DOM mutation -- can't re-parent
482 // a child that already has a parent.
483 if (child->parentNode())
484 break;
487 // Append child to the end of the list
488 childCountDelta++;
489 forbidEventDispatch();
490 child->setParent(this);
491 if (m_lastChild) {
492 child->setPreviousSibling(m_lastChild);
493 m_lastChild->setNextSibling(child.get());
494 } else
495 m_firstChild = child.get();
496 m_lastChild = child.get();
497 allowEventDispatch();
499 // Dispatch the mutation events
500 dispatchChildInsertionEvents(child.get(), ec);
502 // Add child to the rendering tree
503 if (attached() && !child->attached() && child->parent() == this) {
504 if (shouldLazyAttach)
505 child->lazyAttach();
506 else
507 child->attach();
510 child = nextChild.release();
513 document()->setDocumentChanged(true);
514 childrenChanged(false, prev.get(), 0, childCountDelta);
515 dispatchSubtreeModifiedEvent();
516 return true;
519 ContainerNode* ContainerNode::addChild(PassRefPtr<Node> newChild)
521 // This function is only used during parsing.
522 // It does not send any DOM mutation events.
524 // Check for consistency with DTD, but only when parsing HTML.
525 if (document()->isHTMLDocument() && !childAllowed(newChild.get()))
526 return 0;
528 forbidEventDispatch();
529 Node* last = m_lastChild;
530 appendChildToContainer<Node, ContainerNode>(newChild.get(), this);
531 allowEventDispatch();
533 document()->incDOMTreeVersion();
534 if (inDocument())
535 newChild->insertedIntoDocument();
536 childrenChanged(true, last, 0, 1);
538 if (newChild->isElementNode())
539 return static_cast<ContainerNode*>(newChild.get());
540 return this;
543 void ContainerNode::suspendPostAttachCallbacks()
545 ++s_attachDepth;
548 void ContainerNode::resumePostAttachCallbacks()
550 if (s_attachDepth == 1 && s_postAttachCallbackQueue)
551 dispatchPostAttachCallbacks();
552 --s_attachDepth;
555 void ContainerNode::queuePostAttachCallback(NodeCallback callback, Node* node)
557 if (!s_postAttachCallbackQueue)
558 s_postAttachCallbackQueue = new NodeCallbackQueue;
560 s_postAttachCallbackQueue->append(std::pair<NodeCallback, RefPtr<Node> >(callback, node));
563 void ContainerNode::dispatchPostAttachCallbacks()
565 // We recalculate size() each time through the loop because a callback
566 // can add more callbacks to the end of the queue.
567 for (size_t i = 0; i < s_postAttachCallbackQueue->size(); ++i) {
568 std::pair<NodeCallback, RefPtr<Node> >& pair = (*s_postAttachCallbackQueue)[i];
569 NodeCallback callback = pair.first;
570 Node* node = pair.second.get();
572 callback(node);
574 s_postAttachCallbackQueue->clear();
577 void ContainerNode::attach()
579 ++s_attachDepth;
581 for (Node* child = m_firstChild; child; child = child->nextSibling())
582 child->attach();
583 EventTargetNode::attach();
585 if (s_attachDepth == 1 && s_postAttachCallbackQueue)
586 dispatchPostAttachCallbacks();
587 --s_attachDepth;
590 void ContainerNode::detach()
592 for (Node* child = m_firstChild; child; child = child->nextSibling())
593 child->detach();
594 setHasChangedChild(false);
595 EventTargetNode::detach();
598 void ContainerNode::insertedIntoDocument()
600 EventTargetNode::insertedIntoDocument();
601 for (Node *child = m_firstChild; child; child = child->nextSibling())
602 child->insertedIntoDocument();
605 void ContainerNode::removedFromDocument()
607 EventTargetNode::removedFromDocument();
608 for (Node *child = m_firstChild; child; child = child->nextSibling())
609 child->removedFromDocument();
612 void ContainerNode::insertedIntoTree(bool deep)
614 EventTargetNode::insertedIntoTree(deep);
615 if (deep) {
616 for (Node *child = m_firstChild; child; child = child->nextSibling())
617 child->insertedIntoTree(deep);
621 void ContainerNode::removedFromTree(bool deep)
623 EventTargetNode::removedFromTree(deep);
624 if (deep) {
625 for (Node *child = m_firstChild; child; child = child->nextSibling())
626 child->removedFromTree(deep);
630 void ContainerNode::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
632 Node::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
633 if (!changedByParser && childCountDelta)
634 document()->nodeChildrenChanged(this);
635 if (document()->hasNodeListCaches())
636 notifyNodeListsChildrenChanged();
639 void ContainerNode::cloneChildNodes(ContainerNode *clone)
641 // disable the delete button so it's elements are not serialized into the markup
642 if (document()->frame())
643 document()->frame()->editor()->deleteButtonController()->disable();
644 ExceptionCode ec = 0;
645 for (Node* n = firstChild(); n && !ec; n = n->nextSibling())
646 clone->appendChild(n->cloneNode(true), ec);
647 if (document()->frame())
648 document()->frame()->editor()->deleteButtonController()->enable();
651 // FIXME: This doesn't work correctly with transforms.
652 bool ContainerNode::getUpperLeftCorner(FloatPoint& point) const
654 if (!renderer())
655 return false;
656 // What is this code really trying to do?
657 RenderObject *o = renderer();
658 RenderObject *p = o;
660 if (!o->isInline() || o->isReplaced()) {
661 point = o->localToAbsolute();
662 return true;
665 // find the next text/image child, to get a position
666 while (o) {
667 p = o;
668 if (o->firstChild())
669 o = o->firstChild();
670 else if (o->nextSibling())
671 o = o->nextSibling();
672 else {
673 RenderObject *next = 0;
674 while (!next && o->parent()) {
675 o = o->parent();
676 next = o->nextSibling();
678 o = next;
680 if (!o)
681 break;
684 if (!o->isInline() || o->isReplaced()) {
685 point = o->localToAbsolute();
686 return true;
689 if (p->element() && p->element() == this && o->isText() && !o->isBR() && !static_cast<RenderText*>(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() && static_cast<RenderText *>(o)->firstTextBox()) {
694 point.move(static_cast<RenderText *>(o)->minXPos(),
695 static_cast<RenderText *>(o)->firstTextBox()->root()->topOverflow());
696 } else
697 point.move(o->xPos(), o->yPos());
698 return true;
702 // If the target doesn't have any children or siblings that could be used to calculate the scroll position, we must be
703 // at the end of the document. Scroll to the bottom. FIXME: who said anything about scrolling?
704 if (!o && document()->view()) {
705 point = FloatPoint(0, document()->view()->contentsHeight());
706 return true;
708 return false;
711 // FIXME: This doesn't work correctly with transforms.
712 bool ContainerNode::getLowerRightCorner(FloatPoint& point) const
714 if (!renderer())
715 return false;
717 RenderObject *o = renderer();
718 if (!o->isInline() || o->isReplaced())
720 point = o->localToAbsolute();
721 point.move(o->width(),
722 o->height() + o->borderTopExtra() + o->borderBottomExtra());
723 return true;
726 // find the last text/image child, to get a position
727 while (o) {
728 if (o->lastChild())
729 o = o->lastChild();
730 else if (o->previousSibling())
731 o = o->previousSibling();
732 else {
733 RenderObject *prev = 0;
734 while(!prev) {
735 o = o->parent();
736 if (!o)
737 return false;
738 prev = o->previousSibling();
740 o = prev;
742 if (o->isText() || o->isReplaced()) {
743 point = o->container()->localToAbsolute();
744 int xOffset;
745 if (o->isText())
746 xOffset = static_cast<RenderText *>(o)->minXPos() + o->width();
747 else
748 xOffset = o->xPos() + o->width();
750 point.move(xOffset, o->yPos() + o->height());
751 return true;
754 return true;
757 IntRect ContainerNode::getRect() const
759 FloatPoint upperLeft, lowerRight;
760 bool foundUpperLeft = getUpperLeftCorner(upperLeft);
761 bool foundLowerRight = getLowerRightCorner(lowerRight);
763 // If we've found one corner, but not the other,
764 // then we should just return a point at the corner that we did find.
765 if (foundUpperLeft != foundLowerRight)
767 if (foundUpperLeft)
768 lowerRight = upperLeft;
769 else
770 upperLeft = lowerRight;
773 lowerRight.setX(max(upperLeft.x(), lowerRight.x()));
774 lowerRight.setY(max(upperLeft.y(), lowerRight.y()));
776 return enclosingIntRect(FloatRect(upperLeft, lowerRight - upperLeft));
779 void ContainerNode::setFocus(bool received)
781 if (focused() == received)
782 return;
784 EventTargetNode::setFocus(received);
786 // note that we need to recalc the style
787 setChanged();
790 void ContainerNode::setActive(bool down, bool pause)
792 if (down == active()) return;
794 EventTargetNode::setActive(down);
796 // note that we need to recalc the style
797 // FIXME: Move to Element
798 if (renderer()) {
799 bool reactsToPress = renderer()->style()->affectedByActiveRules();
800 if (reactsToPress)
801 setChanged();
802 if (renderer() && renderer()->style()->hasAppearance()) {
803 if (theme()->stateChanged(renderer(), PressedState))
804 reactsToPress = true;
806 if (reactsToPress && pause) {
807 // The delay here is subtle. It relies on an assumption, namely that the amount of time it takes
808 // to repaint the "down" state of the control is about the same time as it would take to repaint the
809 // "up" state. Once you assume this, you can just delay for 100ms - that time (assuming that after you
810 // leave this method, it will be about that long before the flush of the up state happens again).
811 #ifdef HAVE_FUNC_USLEEP
812 double startTime = currentTime();
813 #endif
815 // Ensure there are no pending changes
816 Document::updateDocumentsRendering();
817 // Do an immediate repaint.
818 if (renderer())
819 renderer()->repaint(true);
821 // FIXME: Find a substitute for usleep for Win32.
822 // Better yet, come up with a way of doing this that doesn't use this sort of thing at all.
823 #ifdef HAVE_FUNC_USLEEP
824 // Now pause for a small amount of time (1/10th of a second from before we repainted in the pressed state)
825 double remainingTime = 0.1 - (currentTime() - startTime);
826 if (remainingTime > 0)
827 usleep(static_cast<useconds_t>(remainingTime * 1000000.0));
828 #endif
833 void ContainerNode::setHovered(bool over)
835 if (over == hovered()) return;
837 EventTargetNode::setHovered(over);
839 // note that we need to recalc the style
840 // FIXME: Move to Element
841 if (renderer()) {
842 if (renderer()->style()->affectedByHoverRules())
843 setChanged();
844 if (renderer() && renderer()->style()->hasAppearance())
845 theme()->stateChanged(renderer(), HoverState);
849 unsigned ContainerNode::childNodeCount() const
851 unsigned count = 0;
852 Node *n;
853 for (n = firstChild(); n; n = n->nextSibling())
854 count++;
855 return count;
858 Node *ContainerNode::childNode(unsigned index) const
860 unsigned i;
861 Node *n = firstChild();
862 for (i = 0; n != 0 && i < index; i++)
863 n = n->nextSibling();
864 return n;
867 static void dispatchChildInsertionEvents(Node* child, ExceptionCode& ec)
869 ASSERT(!eventDispatchForbidden());
871 RefPtr<Node> c = child;
872 DocPtr<Document> doc = child->document();
874 if (c->parentNode() && c->parentNode()->inDocument())
875 c->insertedIntoDocument();
876 else
877 c->insertedIntoTree(true);
879 if (c->parentNode() &&
880 doc->hasListenerType(Document::DOMNODEINSERTED_LISTENER) &&
881 c->isEventTargetNode()) {
882 ec = 0;
883 EventTargetNodeCast(c.get())->dispatchEvent(MutationEvent::create(eventNames().DOMNodeInsertedEvent, true, false,
884 c->parentNode(), String(), String(), String(), 0), ec);
885 if (ec)
886 return;
889 // dispatch the DOMNodeInsertedIntoDocument event to all descendants
890 if (c->inDocument() && doc->hasListenerType(Document::DOMNODEINSERTEDINTODOCUMENT_LISTENER))
891 for (; c; c = c->traverseNextNode(child)) {
892 if (!c->isEventTargetNode())
893 continue;
895 ec = 0;
896 EventTargetNodeCast(c.get())->dispatchEvent(MutationEvent::create(eventNames().DOMNodeInsertedIntoDocumentEvent, false, false,
897 0, String(), String(), String(), 0), ec);
898 if (ec)
899 return;
903 static void dispatchChildRemovalEvents(Node* child, ExceptionCode& ec)
905 RefPtr<Node> c = child;
906 DocPtr<Document> doc = child->document();
908 // update auxiliary doc info (e.g. iterators) to note that node is being removed
909 doc->nodeWillBeRemoved(child);
911 // dispatch pre-removal mutation events
912 if (c->parentNode() &&
913 doc->hasListenerType(Document::DOMNODEREMOVED_LISTENER) &&
914 c->isEventTargetNode()) {
915 ec = 0;
916 EventTargetNodeCast(c.get())->dispatchEvent(MutationEvent::create(eventNames().DOMNodeRemovedEvent, true, false,
917 c->parentNode(), String(), String(), String(), 0), ec);
918 if (ec)
919 return;
922 // dispatch the DOMNodeRemovedFromDocument event to all descendants
923 if (c->inDocument() && doc->hasListenerType(Document::DOMNODEREMOVEDFROMDOCUMENT_LISTENER))
924 for (; c; c = c->traverseNextNode(child)) {
925 if (!c->isEventTargetNode())
926 continue;
927 ec = 0;
928 EventTargetNodeCast(c.get())->dispatchEvent(MutationEvent::create(eventNames().DOMNodeRemovedFromDocumentEvent, false, false,
929 0, String(), String(), String(), 0), ec);
930 if (ec)
931 return;