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 39 void RenderObjectChildList::trace(Visitor* visitor) 40 { 41 visitor->trace(m_firstChild); 42 visitor->trace(m_lastChild); 43 } 44 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 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 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 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