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