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