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 "RenderObjectChildList.h" 29 30 #include "AXObjectCache.h" 31 #include "ContentData.h" 32 #include "RenderBlock.h" 33 #include "RenderCounter.h" 34 #include "RenderImage.h" 35 #include "RenderImageResourceStyleImage.h" 36 #include "RenderInline.h" 37 #include "RenderLayer.h" 38 #include "RenderListItem.h" 39 #include "RenderQuote.h" 40 #include "RenderStyle.h" 41 #include "RenderTextFragment.h" 42 #include "RenderView.h" 43 44 namespace WebCore { 45 46 void RenderObjectChildList::destroyLeftoverChildren() 47 { 48 while (firstChild()) { 49 if (firstChild()->isListMarker() || (firstChild()->style()->styleType() == FIRST_LETTER && !firstChild()->isText())) 50 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. 51 else if (firstChild()->isRunIn() && firstChild()->node()) { 52 firstChild()->node()->setRenderer(0); 53 firstChild()->node()->setNeedsStyleRecalc(); 54 firstChild()->destroy(); 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 64 RenderObject* 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 if (oldChild->isBody()) 74 owner->view()->repaint(); 75 else 76 oldChild->repaint(); 77 } 78 79 // If we have a line box wrapper, delete it. 80 if (oldChild->isBox()) 81 toRenderBox(oldChild)->deleteLineBoxWrapper(); 82 83 if (!owner->documentBeingDestroyed() && fullRemove) { 84 // if we remove visible child from an invisible parent, we don't know the layer visibility any more 85 RenderLayer* layer = 0; 86 if (owner->style()->visibility() != VISIBLE && oldChild->style()->visibility() == VISIBLE && !oldChild->hasLayer()) { 87 layer = owner->enclosingLayer(); 88 layer->dirtyVisibleContentStatus(); 89 } 90 91 // Keep our layer hierarchy updated. 92 if (oldChild->firstChild() || oldChild->hasLayer()) { 93 if (!layer) 94 layer = owner->enclosingLayer(); 95 oldChild->removeLayers(layer); 96 } 97 98 if (oldChild->isListItem()) 99 toRenderListItem(oldChild)->updateListMarkerNumbers(); 100 101 if (oldChild->isPositioned() && owner->childrenInline()) 102 owner->dirtyLinesFromChangedChild(oldChild); 103 104 #if ENABLE(SVG) 105 // Update cached boundaries in SVG renderers, if a child is removed. 106 owner->setNeedsBoundariesUpdate(); 107 #endif 108 } 109 110 // If oldChild is the start or end of the selection, then clear the selection to 111 // avoid problems of invalid pointers. 112 // FIXME: The SelectionController should be responsible for this when it 113 // is notified of DOM mutations. 114 if (!owner->documentBeingDestroyed() && oldChild->isSelectionBorder()) 115 owner->view()->clearSelection(); 116 117 // remove the child 118 if (oldChild->previousSibling()) 119 oldChild->previousSibling()->setNextSibling(oldChild->nextSibling()); 120 if (oldChild->nextSibling()) 121 oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling()); 122 123 if (firstChild() == oldChild) 124 setFirstChild(oldChild->nextSibling()); 125 if (lastChild() == oldChild) 126 setLastChild(oldChild->previousSibling()); 127 128 oldChild->setPreviousSibling(0); 129 oldChild->setNextSibling(0); 130 oldChild->setParent(0); 131 132 RenderCounter::rendererRemovedFromTree(oldChild); 133 RenderQuote::rendererRemovedFromTree(oldChild); 134 135 if (AXObjectCache::accessibilityEnabled()) 136 owner->document()->axObjectCache()->childrenChanged(owner); 137 138 return oldChild; 139 } 140 141 void RenderObjectChildList::appendChildNode(RenderObject* owner, RenderObject* newChild, bool fullAppend) 142 { 143 ASSERT(newChild->parent() == 0); 144 ASSERT(!owner->isBlockFlow() || (!newChild->isTableSection() && !newChild->isTableRow() && !newChild->isTableCell())); 145 146 newChild->setParent(owner); 147 RenderObject* lChild = lastChild(); 148 149 if (lChild) { 150 newChild->setPreviousSibling(lChild); 151 lChild->setNextSibling(newChild); 152 } else 153 setFirstChild(newChild); 154 155 setLastChild(newChild); 156 157 if (fullAppend) { 158 // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children 159 // and don't have a layer attached to ourselves. 160 RenderLayer* layer = 0; 161 if (newChild->firstChild() || newChild->hasLayer()) { 162 layer = owner->enclosingLayer(); 163 newChild->addLayers(layer, newChild); 164 } 165 166 // if the new child is visible but this object was not, tell the layer it has some visible content 167 // that needs to be drawn and layer visibility optimization can't be used 168 if (owner->style()->visibility() != VISIBLE && newChild->style()->visibility() == VISIBLE && !newChild->hasLayer()) { 169 if (!layer) 170 layer = owner->enclosingLayer(); 171 if (layer) 172 layer->setHasVisibleContent(true); 173 } 174 175 if (newChild->isListItem()) 176 toRenderListItem(newChild)->updateListMarkerNumbers(); 177 178 if (!newChild->isFloatingOrPositioned() && owner->childrenInline()) 179 owner->dirtyLinesFromChangedChild(newChild); 180 } 181 RenderCounter::rendererSubtreeAttached(newChild); 182 RenderQuote::rendererSubtreeAttached(newChild); 183 newChild->setNeedsLayoutAndPrefWidthsRecalc(); // Goes up the containing block hierarchy. 184 if (!owner->normalChildNeedsLayout()) 185 owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child. 186 187 if (AXObjectCache::accessibilityEnabled()) 188 owner->document()->axObjectCache()->childrenChanged(owner); 189 } 190 191 void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* child, RenderObject* beforeChild, bool fullInsert) 192 { 193 if (!beforeChild) { 194 appendChildNode(owner, child, fullInsert); 195 return; 196 } 197 198 ASSERT(!child->parent()); 199 while (beforeChild->parent() != owner && beforeChild->parent()->isAnonymousBlock()) 200 beforeChild = beforeChild->parent(); 201 ASSERT(beforeChild->parent() == owner); 202 203 ASSERT(!owner->isBlockFlow() || (!child->isTableSection() && !child->isTableRow() && !child->isTableCell())); 204 205 if (beforeChild == firstChild()) 206 setFirstChild(child); 207 208 RenderObject* prev = beforeChild->previousSibling(); 209 child->setNextSibling(beforeChild); 210 beforeChild->setPreviousSibling(child); 211 if (prev) 212 prev->setNextSibling(child); 213 child->setPreviousSibling(prev); 214 215 child->setParent(owner); 216 217 if (fullInsert) { 218 // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children 219 // and don't have a layer attached to ourselves. 220 RenderLayer* layer = 0; 221 if (child->firstChild() || child->hasLayer()) { 222 layer = owner->enclosingLayer(); 223 child->addLayers(layer, child); 224 } 225 226 // if the new child is visible but this object was not, tell the layer it has some visible content 227 // that needs to be drawn and layer visibility optimization can't be used 228 if (owner->style()->visibility() != VISIBLE && child->style()->visibility() == VISIBLE && !child->hasLayer()) { 229 if (!layer) 230 layer = owner->enclosingLayer(); 231 if (layer) 232 layer->setHasVisibleContent(true); 233 } 234 235 if (child->isListItem()) 236 toRenderListItem(child)->updateListMarkerNumbers(); 237 238 if (!child->isFloating() && owner->childrenInline()) 239 owner->dirtyLinesFromChangedChild(child); 240 } 241 242 RenderCounter::rendererSubtreeAttached(child); 243 RenderQuote::rendererSubtreeAttached(child); 244 child->setNeedsLayoutAndPrefWidthsRecalc(); 245 if (!owner->normalChildNeedsLayout()) 246 owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child. 247 248 if (AXObjectCache::accessibilityEnabled()) 249 owner->document()->axObjectCache()->childrenChanged(owner); 250 } 251 252 static RenderObject* findBeforeAfterParent(RenderObject* object) 253 { 254 // Only table parts need to search for the :before or :after parent 255 if (!(object->isTable() || object->isTableSection() || object->isTableRow())) 256 return object; 257 258 RenderObject* beforeAfterParent = object; 259 while (beforeAfterParent && !(beforeAfterParent->isText() || beforeAfterParent->isImage())) 260 beforeAfterParent = beforeAfterParent->firstChild(); 261 return beforeAfterParent ? beforeAfterParent->parent() : 0; 262 } 263 264 RenderObject* RenderObjectChildList::beforePseudoElementRenderer(const RenderObject* owner) const 265 { 266 // An anonymous (generated) inline run-in that has PseudoId BEFORE must come from a grandparent. 267 // Therefore we should skip these generated run-ins when checking our immediate children. 268 // If we don't find our :before child immediately, then we should check if we own a 269 // generated inline run-in in the next level of children. 270 RenderObject* first = const_cast<RenderObject*>(owner); 271 do { 272 first = first->firstChild(); 273 // Skip list markers and generated run-ins. 274 while (first && (first->isListMarker() || (first->isRenderInline() && first->isRunIn()))) 275 first = first->nextInPreOrderAfterChildren(owner); 276 } while (first && first->isAnonymous() && first->style()->styleType() == NOPSEUDO); 277 278 if (!first) 279 return 0; 280 281 if (first->style()->styleType() == BEFORE) 282 return first; 283 284 // Check for a possible generated run-in, using run-in positioning rules. 285 first = owner->firstChild(); 286 if (!first->isRenderBlock()) 287 return 0; 288 289 first = first->firstChild(); 290 // We still need to skip any list markers that could exist before the run-in. 291 while (first && first->isListMarker()) 292 first = first->nextSibling(); 293 if (first && first->style()->styleType() == BEFORE && first->isRenderInline() && first->isRunIn()) 294 return first; 295 296 return 0; 297 } 298 299 RenderObject* RenderObjectChildList::afterPseudoElementRenderer(const RenderObject* owner) const 300 { 301 RenderObject* last = const_cast<RenderObject*>(owner); 302 do { 303 last = last->lastChild(); 304 } while (last && last->isAnonymous() && last->style()->styleType() == NOPSEUDO && !last->isListMarker()); 305 if (last && last->style()->styleType() != AFTER) 306 return 0; 307 return last; 308 } 309 310 void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, PseudoId type, const RenderObject* styledObject) 311 { 312 // Double check that the document did in fact use generated content rules. Otherwise we should not have been called. 313 ASSERT(owner->document()->usesBeforeAfterRules()); 314 315 // In CSS2, before/after pseudo-content cannot nest. Check this first. 316 if (owner->style()->styleType() == BEFORE || owner->style()->styleType() == AFTER) 317 return; 318 319 if (!styledObject) 320 styledObject = owner; 321 322 RenderStyle* pseudoElementStyle = styledObject->getCachedPseudoStyle(type); 323 RenderObject* child; 324 switch (type) { 325 case BEFORE: 326 child = beforePseudoElementRenderer(owner); 327 break; 328 case AFTER: 329 child = afterPseudoElementRenderer(owner); 330 break; 331 default: 332 ASSERT_NOT_REACHED(); 333 return; 334 } 335 336 // Whether or not we currently have generated content attached. 337 bool oldContentPresent = child; 338 339 // Whether or not we now want generated content. 340 bool newContentWanted = pseudoElementStyle && pseudoElementStyle->display() != NONE; 341 342 // For <q><p/></q>, if this object is the inline continuation of the <q>, we only want to generate 343 // :after content and not :before content. 344 if (newContentWanted && type == BEFORE && owner->isElementContinuation()) 345 newContentWanted = false; 346 347 // Similarly, if we're the beginning of a <q>, and there's an inline continuation for our object, 348 // then we don't generate the :after content. 349 if (newContentWanted && type == AFTER && owner->virtualContinuation()) 350 newContentWanted = false; 351 352 // If we don't want generated content any longer, or if we have generated content, but it's no longer 353 // identical to the new content data we want to build render objects for, then we nuke all 354 // of the old generated content. 355 if (oldContentPresent && (!newContentWanted || Node::diff(child->style(), pseudoElementStyle) == Node::Detach)) { 356 // Nuke the child. 357 if (child->style()->styleType() == type) { 358 oldContentPresent = false; 359 child->destroy(); 360 child = (type == BEFORE) ? owner->virtualChildren()->firstChild() : owner->virtualChildren()->lastChild(); 361 } 362 } 363 364 // If we have no pseudo-element style or if the pseudo-element style's display type is NONE, then we 365 // have no generated content and can now return. 366 if (!newContentWanted) 367 return; 368 369 if (owner->isRenderInline() && !pseudoElementStyle->isDisplayInlineType() && pseudoElementStyle->floating() == FNONE && 370 !(pseudoElementStyle->position() == AbsolutePosition || pseudoElementStyle->position() == FixedPosition)) 371 // According to the CSS2 spec (the end of section 12.1), the only allowed 372 // display values for the pseudo style are NONE and INLINE for inline flows. 373 // FIXME: CSS2.1 lifted this restriction, but block display types will crash. 374 // For now we at least relax the restriction to allow all inline types like inline-block 375 // and inline-table. 376 pseudoElementStyle->setDisplay(INLINE); 377 378 if (oldContentPresent) { 379 if (child && child->style()->styleType() == type) { 380 // We have generated content present still. We want to walk this content and update our 381 // style information with the new pseudo-element style. 382 child->setStyle(pseudoElementStyle); 383 384 RenderObject* beforeAfterParent = findBeforeAfterParent(child); 385 if (!beforeAfterParent) 386 return; 387 388 // Note that if we ever support additional types of generated content (which should be way off 389 // in the future), this code will need to be patched. 390 for (RenderObject* genChild = beforeAfterParent->firstChild(); genChild; genChild = genChild->nextSibling()) { 391 if (genChild->isText()) 392 // Generated text content is a child whose style also needs to be set to the pseudo-element style. 393 genChild->setStyle(pseudoElementStyle); 394 else if (genChild->isImage()) { 395 // Images get an empty style that inherits from the pseudo. 396 RefPtr<RenderStyle> style = RenderStyle::create(); 397 style->inheritFrom(pseudoElementStyle); 398 genChild->setStyle(style.release()); 399 } else { 400 // RenderListItem may insert a list marker here. We do not need to care about this case. 401 // Otherwise, genChild must be a first-letter container. updateFirstLetter() will take care of it. 402 ASSERT(genChild->isListMarker() || genChild->style()->styleType() == FIRST_LETTER); 403 } 404 } 405 } 406 return; // We've updated the generated content. That's all we needed to do. 407 } 408 409 RenderObject* insertBefore = (type == BEFORE) ? owner->virtualChildren()->firstChild() : 0; 410 411 // Generated content consists of a single container that houses multiple children (specified 412 // by the content property). This generated content container gets the pseudo-element style set on it. 413 RenderObject* generatedContentContainer = 0; 414 415 // Walk our list of generated content and create render objects for each. 416 for (const ContentData* content = pseudoElementStyle->contentData(); content; content = content->next()) { 417 RenderObject* renderer = 0; 418 switch (content->type()) { 419 case CONTENT_NONE: 420 break; 421 case CONTENT_TEXT: 422 renderer = new (owner->renderArena()) RenderTextFragment(owner->document() /* anonymous object */, content->text()); 423 renderer->setStyle(pseudoElementStyle); 424 break; 425 case CONTENT_OBJECT: { 426 RenderImage* image = new (owner->renderArena()) RenderImage(owner->document()); // anonymous object 427 RefPtr<RenderStyle> style = RenderStyle::create(); 428 style->inheritFrom(pseudoElementStyle); 429 image->setStyle(style.release()); 430 if (StyleImage* styleImage = content->image()) 431 image->setImageResource(RenderImageResourceStyleImage::create(styleImage)); 432 else 433 image->setImageResource(RenderImageResource::create()); 434 renderer = image; 435 break; 436 } 437 case CONTENT_COUNTER: 438 renderer = new (owner->renderArena()) RenderCounter(owner->document(), *content->counter()); 439 renderer->setStyle(pseudoElementStyle); 440 break; 441 case CONTENT_QUOTE: 442 renderer = new (owner->renderArena()) RenderQuote(owner->document(), content->quote()); 443 renderer->setStyle(pseudoElementStyle); 444 break; 445 } 446 447 if (renderer) { 448 if (!generatedContentContainer) { 449 // Make a generated box that might be any display type now that we are able to drill down into children 450 // to find the original content properly. 451 generatedContentContainer = RenderObject::createObject(owner->document(), pseudoElementStyle); 452 ASSERT(styledObject->node()); // The styled object cannot be anonymous or else it could not have ':before' or ':after' pseudo elements. 453 generatedContentContainer->setNode(styledObject->node()); // This allows access to the generatingNode. 454 generatedContentContainer->setStyle(pseudoElementStyle); 455 if (!owner->isChildAllowed(generatedContentContainer, pseudoElementStyle)) { 456 // The generated content container is not allowed here -> abort. 457 generatedContentContainer->destroy(); 458 renderer->destroy(); 459 return; 460 } 461 owner->addChild(generatedContentContainer, insertBefore); 462 } 463 if (generatedContentContainer->isChildAllowed(renderer, pseudoElementStyle)) 464 generatedContentContainer->addChild(renderer); 465 else 466 renderer->destroy(); 467 } 468 } 469 } 470 471 } // namespace WebCore 472