1 /*
2 * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
3 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include "config.h"
28 #include "core/rendering/RenderObjectChildList.h"
29
30 #include "core/accessibility/AXObjectCache.h"
31 #include "core/rendering/RenderCounter.h"
32 #include "core/rendering/RenderLayer.h"
33 #include "core/rendering/RenderObject.h"
34 #include "core/rendering/RenderView.h"
35 #include "core/rendering/style/RenderStyle.h"
36
37 namespace blink {
38
trace(Visitor * visitor)39 void RenderObjectChildList::trace(Visitor* visitor)
40 {
41 visitor->trace(m_firstChild);
42 visitor->trace(m_lastChild);
43 }
44
destroyLeftoverChildren()45 void RenderObjectChildList::destroyLeftoverChildren()
46 {
47 while (firstChild()) {
48 if (firstChild()->isListMarker() || (firstChild()->style()->styleType() == FIRST_LETTER && !firstChild()->isText())) {
49 firstChild()->remove(); // List markers are owned by their enclosing list and so don't get destroyed by this container. Similarly, first letters are destroyed by their remaining text fragment.
50 } else {
51 // Destroy any anonymous children remaining in the render tree, as well as implicit (shadow) DOM elements like those used in the engine-based text fields.
52 if (firstChild()->node())
53 firstChild()->node()->setRenderer(0);
54 firstChild()->destroy();
55 }
56 }
57 }
58
removeChildNode(RenderObject * owner,RenderObject * oldChild,bool notifyRenderer)59 RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, RenderObject* oldChild, bool notifyRenderer)
60 {
61 ASSERT(oldChild->parent() == owner);
62
63 if (oldChild->isFloatingOrOutOfFlowPositioned())
64 toRenderBox(oldChild)->removeFloatingOrPositionedChildFromBlockLists();
65
66 {
67 // FIXME: We should not be allowing paint invalidation during layout. crbug.com/336250
68 AllowPaintInvalidationScope scoper(owner->frameView());
69
70 // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or
71 // that a positioned child got yanked). We also issue paint invalidations, so that the area exposed when the child
72 // disappears gets paint invalidated properly.
73 if (!owner->documentBeingDestroyed() && notifyRenderer && oldChild->everHadLayout()) {
74 oldChild->setNeedsLayoutAndPrefWidthsRecalc();
75 invalidatePaintOnRemoval(*oldChild);
76 }
77 }
78
79 // If we have a line box wrapper, delete it.
80 if (oldChild->isBox())
81 toRenderBox(oldChild)->deleteLineBoxWrapper();
82
83 // If oldChild is the start or end of the selection, then clear the selection to
84 // avoid problems of invalid pointers.
85 // FIXME: The FrameSelection should be responsible for this when it
86 // is notified of DOM mutations.
87 if (!owner->documentBeingDestroyed() && oldChild->isSelectionBorder())
88 owner->view()->clearSelection();
89
90 if (!owner->documentBeingDestroyed() && notifyRenderer)
91 oldChild->willBeRemovedFromTree();
92
93 // WARNING: There should be no code running between willBeRemovedFromTree and the actual removal below.
94 // This is needed to avoid race conditions where willBeRemovedFromTree would dirty the tree's structure
95 // and the code running here would force an untimely rebuilding, leaving |oldChild| dangling.
96
97 if (oldChild->previousSibling())
98 oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
99 if (oldChild->nextSibling())
100 oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
101
102 if (firstChild() == oldChild)
103 setFirstChild(oldChild->nextSibling());
104 if (lastChild() == oldChild)
105 setLastChild(oldChild->previousSibling());
106
107 oldChild->setPreviousSibling(0);
108 oldChild->setNextSibling(0);
109 oldChild->setParent(0);
110
111 // rendererRemovedFromTree walks the whole subtree. We can improve performance
112 // by skipping this step when destroying the entire tree.
113 if (!owner->documentBeingDestroyed())
114 RenderCounter::rendererRemovedFromTree(oldChild);
115
116 if (AXObjectCache* cache = owner->document().existingAXObjectCache())
117 cache->childrenChanged(owner);
118
119 return oldChild;
120 }
121
insertChildNode(RenderObject * owner,RenderObject * newChild,RenderObject * beforeChild,bool notifyRenderer)122 void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* newChild, RenderObject* beforeChild, bool notifyRenderer)
123 {
124 ASSERT(!newChild->parent());
125 ASSERT(!owner->isRenderBlockFlow() || (!newChild->isTableSection() && !newChild->isTableRow() && !newChild->isTableCell()));
126
127 while (beforeChild && beforeChild->parent() && beforeChild->parent() != owner)
128 beforeChild = beforeChild->parent();
129
130 // This should never happen, but if it does prevent render tree corruption
131 // where child->parent() ends up being owner but child->nextSibling()->parent()
132 // is not owner.
133 if (beforeChild && beforeChild->parent() != owner) {
134 ASSERT_NOT_REACHED();
135 return;
136 }
137
138 newChild->setParent(owner);
139
140 if (firstChild() == beforeChild)
141 setFirstChild(newChild);
142
143 if (beforeChild) {
144 RenderObject* previousSibling = beforeChild->previousSibling();
145 if (previousSibling)
146 previousSibling->setNextSibling(newChild);
147 newChild->setPreviousSibling(previousSibling);
148 newChild->setNextSibling(beforeChild);
149 beforeChild->setPreviousSibling(newChild);
150 } else {
151 if (lastChild())
152 lastChild()->setNextSibling(newChild);
153 newChild->setPreviousSibling(lastChild());
154 setLastChild(newChild);
155 }
156
157 if (!owner->documentBeingDestroyed() && notifyRenderer)
158 newChild->insertedIntoTree();
159
160 if (!owner->documentBeingDestroyed()) {
161 RenderCounter::rendererSubtreeAttached(newChild);
162 }
163
164 newChild->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
165 if (!owner->normalChildNeedsLayout())
166 owner->setChildNeedsLayout(); // We may supply the static position for an absolute positioned child.
167
168 if (AXObjectCache* cache = owner->document().axObjectCache())
169 cache->childrenChanged(owner);
170 }
171
invalidatePaintOnRemoval(const RenderObject & oldChild)172 void RenderObjectChildList::invalidatePaintOnRemoval(const RenderObject& oldChild)
173 {
174 if (!oldChild.isRooted())
175 return;
176 if (oldChild.isBody()) {
177 oldChild.view()->setShouldDoFullPaintInvalidation(true);
178 return;
179 }
180 if (oldChild.isText()) {
181 oldChild.parent()->setShouldDoFullPaintInvalidation(true);
182 return;
183 }
184 DisableCompositingQueryAsserts disabler;
185 oldChild.invalidatePaintUsingContainer(oldChild.containerForPaintInvalidation(), oldChild.previousPaintInvalidationRect(), InvalidationRendererRemoval);
186 }
187
188 } // namespace blink
189