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