1/* 2 * Copyright (C) 2009 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "RenderObjectChildList.h" 28 29#include "AXObjectCache.h" 30#include "RenderBlock.h" 31#include "RenderCounter.h" 32#include "RenderImageGeneratedContent.h" 33#include "RenderInline.h" 34#include "RenderLayer.h" 35#include "RenderListItem.h" 36#include "RenderStyle.h" 37#include "RenderTextFragment.h" 38#include "RenderView.h" 39 40namespace WebCore { 41 42static void updateListMarkerNumbers(RenderObject* child) 43{ 44 for (RenderObject* sibling = child; sibling; sibling = sibling->nextSibling()) { 45 if (sibling->isListItem()) 46 toRenderListItem(sibling)->updateValue(); 47 } 48} 49 50void RenderObjectChildList::destroyLeftoverChildren() 51{ 52 while (firstChild()) { 53 if (firstChild()->isListMarker() || (firstChild()->style()->styleType() == FIRST_LETTER && !firstChild()->isText())) 54 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. 55 else { 56 // 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. 57 if (firstChild()->node()) 58 firstChild()->node()->setRenderer(0); 59 firstChild()->destroy(); 60 } 61 } 62} 63 64RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, RenderObject* oldChild, bool fullRemove) 65{ 66 ASSERT(oldChild->parent() == owner); 67 68 // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or 69 // that a positioned child got yanked). We also repaint, so that the area exposed when the child 70 // disappears gets repainted properly. 71 if (!owner->documentBeingDestroyed() && fullRemove && oldChild->m_everHadLayout) { 72 oldChild->setNeedsLayoutAndPrefWidthsRecalc(); 73 oldChild->repaint(); 74 } 75 76 // If we have a line box wrapper, delete it. 77 if (oldChild->isBox()) 78 toRenderBox(oldChild)->deleteLineBoxWrapper(); 79 80 if (!owner->documentBeingDestroyed() && fullRemove) { 81 // if we remove visible child from an invisible parent, we don't know the layer visibility any more 82 RenderLayer* layer = 0; 83 if (owner->style()->visibility() != VISIBLE && oldChild->style()->visibility() == VISIBLE && !oldChild->hasLayer()) { 84 layer = owner->enclosingLayer(); 85 layer->dirtyVisibleContentStatus(); 86 } 87 88 // Keep our layer hierarchy updated. 89 if (oldChild->firstChild() || oldChild->hasLayer()) { 90 if (!layer) 91 layer = owner->enclosingLayer(); 92 oldChild->removeLayers(layer); 93 } 94 95 // renumber ordered lists 96 if (oldChild->isListItem()) 97 updateListMarkerNumbers(oldChild->nextSibling()); 98 99 if (oldChild->isPositioned() && owner->childrenInline()) 100 owner->dirtyLinesFromChangedChild(oldChild); 101 } 102 103 // If oldChild is the start or end of the selection, then clear the selection to 104 // avoid problems of invalid pointers. 105 // FIXME: The SelectionController should be responsible for this when it 106 // is notified of DOM mutations. 107 if (!owner->documentBeingDestroyed() && oldChild->isSelectionBorder()) 108 owner->view()->clearSelection(); 109 110 // remove the child 111 if (oldChild->previousSibling()) 112 oldChild->previousSibling()->setNextSibling(oldChild->nextSibling()); 113 if (oldChild->nextSibling()) 114 oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling()); 115 116 if (firstChild() == oldChild) 117 setFirstChild(oldChild->nextSibling()); 118 if (lastChild() == oldChild) 119 setLastChild(oldChild->previousSibling()); 120 121 oldChild->setPreviousSibling(0); 122 oldChild->setNextSibling(0); 123 oldChild->setParent(0); 124 125 if (AXObjectCache::accessibilityEnabled()) 126 owner->document()->axObjectCache()->childrenChanged(owner); 127 128 return oldChild; 129} 130 131void RenderObjectChildList::appendChildNode(RenderObject* owner, RenderObject* newChild, bool fullAppend) 132{ 133 ASSERT(newChild->parent() == 0); 134 ASSERT(!owner->isBlockFlow() || (!newChild->isTableSection() && !newChild->isTableRow() && !newChild->isTableCell())); 135 136 newChild->setParent(owner); 137 RenderObject* lChild = lastChild(); 138 139 if (lChild) { 140 newChild->setPreviousSibling(lChild); 141 lChild->setNextSibling(newChild); 142 } else 143 setFirstChild(newChild); 144 145 setLastChild(newChild); 146 147 if (fullAppend) { 148 // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children 149 // and don't have a layer attached to ourselves. 150 RenderLayer* layer = 0; 151 if (newChild->firstChild() || newChild->hasLayer()) { 152 layer = owner->enclosingLayer(); 153 newChild->addLayers(layer, newChild); 154 } 155 156 // if the new child is visible but this object was not, tell the layer it has some visible content 157 // that needs to be drawn and layer visibility optimization can't be used 158 if (owner->style()->visibility() != VISIBLE && newChild->style()->visibility() == VISIBLE && !newChild->hasLayer()) { 159 if (!layer) 160 layer = owner->enclosingLayer(); 161 if (layer) 162 layer->setHasVisibleContent(true); 163 } 164 165 if (!newChild->isFloatingOrPositioned() && owner->childrenInline()) 166 owner->dirtyLinesFromChangedChild(newChild); 167 } 168 169 newChild->setNeedsLayoutAndPrefWidthsRecalc(); // Goes up the containing block hierarchy. 170 if (!owner->normalChildNeedsLayout()) 171 owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child. 172 173 if (AXObjectCache::accessibilityEnabled()) 174 owner->document()->axObjectCache()->childrenChanged(owner); 175} 176 177void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* child, RenderObject* beforeChild, bool fullInsert) 178{ 179 if (!beforeChild) { 180 appendChildNode(owner, child); 181 return; 182 } 183 184 ASSERT(!child->parent()); 185 while (beforeChild->parent() != owner && beforeChild->parent()->isAnonymousBlock()) 186 beforeChild = beforeChild->parent(); 187 ASSERT(beforeChild->parent() == owner); 188 189 ASSERT(!owner->isBlockFlow() || (!child->isTableSection() && !child->isTableRow() && !child->isTableCell())); 190 191 if (beforeChild == firstChild()) 192 setFirstChild(child); 193 194 RenderObject* prev = beforeChild->previousSibling(); 195 child->setNextSibling(beforeChild); 196 beforeChild->setPreviousSibling(child); 197 if (prev) 198 prev->setNextSibling(child); 199 child->setPreviousSibling(prev); 200 201 child->setParent(owner); 202 203 if (fullInsert) { 204 // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children 205 // and don't have a layer attached to ourselves. 206 RenderLayer* layer = 0; 207 if (child->firstChild() || child->hasLayer()) { 208 layer = owner->enclosingLayer(); 209 child->addLayers(layer, child); 210 } 211 212 // if the new child is visible but this object was not, tell the layer it has some visible content 213 // that needs to be drawn and layer visibility optimization can't be used 214 if (owner->style()->visibility() != VISIBLE && child->style()->visibility() == VISIBLE && !child->hasLayer()) { 215 if (!layer) 216 layer = owner->enclosingLayer(); 217 if (layer) 218 layer->setHasVisibleContent(true); 219 } 220 221 222 if (!child->isFloating() && owner->childrenInline()) 223 owner->dirtyLinesFromChangedChild(child); 224 } 225 226 child->setNeedsLayoutAndPrefWidthsRecalc(); 227 if (!owner->normalChildNeedsLayout()) 228 owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child. 229 230 if (AXObjectCache::accessibilityEnabled()) 231 owner->document()->axObjectCache()->childrenChanged(owner); 232} 233 234static RenderObject* beforeAfterContainer(RenderObject* container, PseudoId type) 235{ 236 if (type == BEFORE) { 237 RenderObject* first = container; 238 do { 239 // Skip list markers. 240 first = first->firstChild(); 241 while (first && first->isListMarker()) 242 first = first->nextSibling(); 243 } while (first && first->isAnonymous() && first->style()->styleType() == NOPSEUDO); 244 if (first && first->style()->styleType() != type) 245 return 0; 246 return first; 247 } 248 if (type == AFTER) { 249 RenderObject* last = container; 250 do { 251 last = last->lastChild(); 252 } while (last && last->isAnonymous() && last->style()->styleType() == NOPSEUDO && !last->isListMarker()); 253 if (last && last->style()->styleType() != type) 254 return 0; 255 return last; 256 } 257 258 ASSERT_NOT_REACHED(); 259 return 0; 260} 261 262static RenderObject* findBeforeAfterParent(RenderObject* object) 263{ 264 // Only table parts need to search for the :before or :after parent 265 if (!(object->isTable() || object->isTableSection() || object->isTableRow())) 266 return object; 267 268 RenderObject* beforeAfterParent = object; 269 while (beforeAfterParent && !(beforeAfterParent->isText() || beforeAfterParent->isImage())) 270 beforeAfterParent = beforeAfterParent->firstChild(); 271 return beforeAfterParent; 272} 273 274static void invalidateCountersInContainer(RenderObject* container, const AtomicString& identifier) 275{ 276 if (!container) 277 return; 278 container = findBeforeAfterParent(container); 279 if (!container) 280 return; 281 // Sometimes the counter is attached directly on the container. 282 if (container->isCounter()) { 283 toRenderCounter(container)->invalidate(identifier); 284 return; 285 } 286 for (RenderObject* content = container->firstChild(); content; content = content->nextSibling()) { 287 if (content->isCounter()) 288 toRenderCounter(content)->invalidate(identifier); 289 } 290} 291 292void RenderObjectChildList::invalidateCounters(RenderObject* owner, const AtomicString& identifier) 293{ 294 ASSERT(!owner->documentBeingDestroyed()); 295 invalidateCountersInContainer(beforeAfterContainer(owner, BEFORE), identifier); 296 invalidateCountersInContainer(beforeAfterContainer(owner, AFTER), identifier); 297} 298 299void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, PseudoId type, RenderObject* styledObject) 300{ 301 // Double check that the document did in fact use generated content rules. Otherwise we should not have been called. 302 ASSERT(owner->document()->usesBeforeAfterRules()); 303 304 // In CSS2, before/after pseudo-content cannot nest. Check this first. 305 if (owner->style()->styleType() == BEFORE || owner->style()->styleType() == AFTER) 306 return; 307 308 if (!styledObject) 309 styledObject = owner; 310 311 RenderStyle* pseudoElementStyle = styledObject->getCachedPseudoStyle(type); 312 RenderObject* child = beforeAfterContainer(owner, type); 313 314 // Whether or not we currently have generated content attached. 315 bool oldContentPresent = child; 316 317 // Whether or not we now want generated content. 318 bool newContentWanted = pseudoElementStyle && pseudoElementStyle->display() != NONE; 319 320 // For <q><p/></q>, if this object is the inline continuation of the <q>, we only want to generate 321 // :after content and not :before content. 322 if (newContentWanted && type == BEFORE && owner->isRenderInline() && toRenderInline(owner)->isInlineContinuation()) 323 newContentWanted = false; 324 325 // Similarly, if we're the beginning of a <q>, and there's an inline continuation for our object, 326 // then we don't generate the :after content. 327 if (newContentWanted && type == AFTER && owner->isRenderInline() && toRenderInline(owner)->continuation()) 328 newContentWanted = false; 329 330 // If we don't want generated content any longer, or if we have generated content, but it's no longer 331 // identical to the new content data we want to build render objects for, then we nuke all 332 // of the old generated content. 333 if (!newContentWanted || (oldContentPresent && Node::diff(child->style(), pseudoElementStyle) == Node::Detach)) { 334 // Nuke the child. 335 if (child && child->style()->styleType() == type) { 336 oldContentPresent = false; 337 child->destroy(); 338 child = (type == BEFORE) ? owner->virtualChildren()->firstChild() : owner->virtualChildren()->lastChild(); 339 } 340 } 341 342 // If we have no pseudo-element style or if the pseudo-element style's display type is NONE, then we 343 // have no generated content and can now return. 344 if (!newContentWanted) 345 return; 346 347 if (owner->isRenderInline() && !pseudoElementStyle->isDisplayInlineType() && pseudoElementStyle->floating() == FNONE && 348 !(pseudoElementStyle->position() == AbsolutePosition || pseudoElementStyle->position() == FixedPosition)) 349 // According to the CSS2 spec (the end of section 12.1), the only allowed 350 // display values for the pseudo style are NONE and INLINE for inline flows. 351 // FIXME: CSS2.1 lifted this restriction, but block display types will crash. 352 // For now we at least relax the restriction to allow all inline types like inline-block 353 // and inline-table. 354 pseudoElementStyle->setDisplay(INLINE); 355 356 if (oldContentPresent) { 357 if (child && child->style()->styleType() == type) { 358 // We have generated content present still. We want to walk this content and update our 359 // style information with the new pseudo-element style. 360 child->setStyle(pseudoElementStyle); 361 362 RenderObject* beforeAfterParent = findBeforeAfterParent(child); 363 if (!beforeAfterParent) 364 return; 365 366 // Note that if we ever support additional types of generated content (which should be way off 367 // in the future), this code will need to be patched. 368 for (RenderObject* genChild = beforeAfterParent->firstChild(); genChild; genChild = genChild->nextSibling()) { 369 if (genChild->isText()) 370 // Generated text content is a child whose style also needs to be set to the pseudo-element style. 371 genChild->setStyle(pseudoElementStyle); 372 else if (genChild->isImage()) { 373 // Images get an empty style that inherits from the pseudo. 374 RefPtr<RenderStyle> style = RenderStyle::create(); 375 style->inheritFrom(pseudoElementStyle); 376 genChild->setStyle(style.release()); 377 } else { 378 // RenderListItem may insert a list marker here. We do not need to care about this case. 379 // Otherwise, genChild must be a first-letter container. updateFirstLetter() will take care of it. 380 ASSERT(genChild->isListMarker() || genChild->style()->styleType() == FIRST_LETTER); 381 } 382 } 383 } 384 return; // We've updated the generated content. That's all we needed to do. 385 } 386 387 RenderObject* insertBefore = (type == BEFORE) ? owner->virtualChildren()->firstChild() : 0; 388 389 // Generated content consists of a single container that houses multiple children (specified 390 // by the content property). This generated content container gets the pseudo-element style set on it. 391 RenderObject* generatedContentContainer = 0; 392 393 // Walk our list of generated content and create render objects for each. 394 for (const ContentData* content = pseudoElementStyle->contentData(); content; content = content->next()) { 395 RenderObject* renderer = 0; 396 switch (content->type()) { 397 case CONTENT_NONE: 398 break; 399 case CONTENT_TEXT: 400 renderer = new (owner->renderArena()) RenderTextFragment(owner->document() /* anonymous object */, content->text()); 401 renderer->setStyle(pseudoElementStyle); 402 break; 403 case CONTENT_OBJECT: { 404 RenderImageGeneratedContent* image = new (owner->renderArena()) RenderImageGeneratedContent(owner->document()); // anonymous object 405 RefPtr<RenderStyle> style = RenderStyle::create(); 406 style->inheritFrom(pseudoElementStyle); 407 image->setStyle(style.release()); 408 if (StyleImage* styleImage = content->image()) 409 image->setStyleImage(styleImage); 410 renderer = image; 411 break; 412 } 413 case CONTENT_COUNTER: 414 renderer = new (owner->renderArena()) RenderCounter(owner->document(), *content->counter()); 415 renderer->setStyle(pseudoElementStyle); 416 break; 417 } 418 419 if (renderer) { 420 if (!generatedContentContainer) { 421 // Make a generated box that might be any display type now that we are able to drill down into children 422 // to find the original content properly. 423 generatedContentContainer = RenderObject::createObject(owner->document(), pseudoElementStyle); 424 generatedContentContainer->setStyle(pseudoElementStyle); 425 owner->addChild(generatedContentContainer, insertBefore); 426 } 427 generatedContentContainer->addChild(renderer); 428 } 429 } 430} 431 432} // namespace WebCore 433