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
37namespace blink {
38
39void RenderObjectChildList::trace(Visitor* visitor)
40{
41    visitor->trace(m_firstChild);
42    visitor->trace(m_lastChild);
43}
44
45void 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
59RenderObject* 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
122void 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
172void 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