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