2 * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
3 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
28 #include "RenderObjectChildList.h"
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 "RenderNamedFlowThread.h"
40 #include "RenderQuote.h"
41 #include "RenderRegion.h"
42 #include "RenderStyle.h"
43 #include "RenderTextFragment.h"
44 #include "RenderView.h"
48 void RenderObjectChildList::destroyLeftoverChildren()
50 while (firstChild()) {
51 if (firstChild()->isListMarker() || (firstChild()->style()->styleType() == FIRST_LETTER && !firstChild()->isText()))
52 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.
53 else if (firstChild()->isRunIn() && firstChild()->node()) {
54 firstChild()->node()->setRenderer(0);
55 firstChild()->node()->setNeedsStyleRecalc();
56 firstChild()->destroy();
58 // 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.
59 if (firstChild()->node())
60 firstChild()->node()->setRenderer(0);
61 firstChild()->destroy();
66 static RenderNamedFlowThread* renderNamedFlowThreadContainer(RenderObject* object)
68 while (object && object->isAnonymousBlock() && !object->isRenderNamedFlowThread())
69 object = object->parent();
71 return object && object->isRenderNamedFlowThread() ? toRenderNamedFlowThread(object) : 0;
74 RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, RenderObject* oldChild, bool fullRemove)
76 ASSERT(oldChild->parent() == owner);
78 if (oldChild->isFloatingOrOutOfFlowPositioned())
79 toRenderBox(oldChild)->removeFloatingOrPositionedChildFromBlockLists();
81 // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or
82 // that a positioned child got yanked). We also repaint, so that the area exposed when the child
83 // disappears gets repainted properly.
84 if (!owner->documentBeingDestroyed() && fullRemove && oldChild->everHadLayout()) {
85 oldChild->setNeedsLayoutAndPrefWidthsRecalc();
86 if (oldChild->isBody())
87 owner->view()->repaint();
92 // If we have a line box wrapper, delete it.
93 if (oldChild->isBox())
94 toRenderBox(oldChild)->deleteLineBoxWrapper();
96 if (!owner->documentBeingDestroyed() && fullRemove) {
97 // if we remove visible child from an invisible parent, we don't know the layer visibility any more
98 RenderLayer* layer = 0;
99 if (owner->style()->visibility() != VISIBLE && oldChild->style()->visibility() == VISIBLE && !oldChild->hasLayer()) {
100 if ((layer = owner->enclosingLayer()))
101 layer->dirtyVisibleContentStatus();
104 // Keep our layer hierarchy updated.
105 if (oldChild->firstChild() || oldChild->hasLayer()) {
107 layer = owner->enclosingLayer();
108 oldChild->removeLayers(layer);
111 if (oldChild->isListItem())
112 toRenderListItem(oldChild)->updateListMarkerNumbers();
114 if (oldChild->isOutOfFlowPositioned() && owner->childrenInline())
115 owner->dirtyLinesFromChangedChild(oldChild);
117 if (oldChild->isRenderRegion())
118 toRenderRegion(oldChild)->detachRegion();
120 if (oldChild->inRenderFlowThread()) {
121 if (oldChild->isBox())
122 oldChild->enclosingRenderFlowThread()->removeRenderBoxRegionInfo(toRenderBox(oldChild));
123 oldChild->enclosingRenderFlowThread()->clearRenderObjectCustomStyle(oldChild);
126 if (RenderNamedFlowThread* containerFlowThread = renderNamedFlowThreadContainer(owner))
127 containerFlowThread->removeFlowChild(oldChild);
130 // Update cached boundaries in SVG renderers, if a child is removed.
131 owner->setNeedsBoundariesUpdate();
135 // If oldChild is the start or end of the selection, then clear the selection to
136 // avoid problems of invalid pointers.
137 // FIXME: The FrameSelection should be responsible for this when it
138 // is notified of DOM mutations.
139 if (!owner->documentBeingDestroyed() && oldChild->isSelectionBorder())
140 owner->view()->clearSelection();
143 if (oldChild->previousSibling())
144 oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
145 if (oldChild->nextSibling())
146 oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
148 if (firstChild() == oldChild)
149 setFirstChild(oldChild->nextSibling());
150 if (lastChild() == oldChild)
151 setLastChild(oldChild->previousSibling());
153 oldChild->setPreviousSibling(0);
154 oldChild->setNextSibling(0);
155 oldChild->setParent(0);
157 // rendererRemovedFromTree walks the whole subtree. We can improve performance
158 // by skipping this step when destroying the entire tree.
159 if (!owner->documentBeingDestroyed()) {
160 RenderCounter::rendererRemovedFromTree(oldChild);
161 RenderQuote::rendererRemovedFromTree(oldChild);
164 if (AXObjectCache::accessibilityEnabled())
165 owner->document()->axObjectCache()->childrenChanged(owner);
170 void RenderObjectChildList::appendChildNode(RenderObject* owner, RenderObject* newChild, bool fullAppend)
172 ASSERT(newChild->parent() == 0);
173 ASSERT(!owner->isBlockFlow() || (!newChild->isTableSection() && !newChild->isTableRow() && !newChild->isTableCell()));
175 newChild->setParent(owner);
176 RenderObject* lChild = lastChild();
179 newChild->setPreviousSibling(lChild);
180 lChild->setNextSibling(newChild);
182 setFirstChild(newChild);
184 setLastChild(newChild);
187 // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children
188 // and don't have a layer attached to ourselves.
189 RenderLayer* layer = 0;
190 if (newChild->firstChild() || newChild->hasLayer()) {
191 layer = owner->enclosingLayer();
192 newChild->addLayers(layer);
195 // if the new child is visible but this object was not, tell the layer it has some visible content
196 // that needs to be drawn and layer visibility optimization can't be used
197 if (owner->style()->visibility() != VISIBLE && newChild->style()->visibility() == VISIBLE && !newChild->hasLayer()) {
199 layer = owner->enclosingLayer();
201 layer->setHasVisibleContent();
204 if (newChild->isListItem())
205 toRenderListItem(newChild)->updateListMarkerNumbers();
207 if (!newChild->isFloating() && owner->childrenInline())
208 owner->dirtyLinesFromChangedChild(newChild);
210 if (newChild->isRenderRegion())
211 toRenderRegion(newChild)->attachRegion();
213 if (RenderNamedFlowThread* containerFlowThread = renderNamedFlowThreadContainer(owner))
214 containerFlowThread->addFlowChild(newChild);
217 if (!owner->documentBeingDestroyed()) {
218 RenderCounter::rendererSubtreeAttached(newChild);
219 RenderQuote::rendererSubtreeAttached(newChild);
221 newChild->setNeedsLayoutAndPrefWidthsRecalc(); // Goes up the containing block hierarchy.
222 if (!owner->normalChildNeedsLayout())
223 owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
225 if (AXObjectCache::accessibilityEnabled())
226 owner->document()->axObjectCache()->childrenChanged(owner);
229 void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* child, RenderObject* beforeChild, bool fullInsert)
232 appendChildNode(owner, child, fullInsert);
236 ASSERT(!child->parent());
237 while (beforeChild->parent() != owner && beforeChild->parent()->isAnonymousBlock())
238 beforeChild = beforeChild->parent();
239 ASSERT(beforeChild->parent() == owner);
241 ASSERT(!owner->isBlockFlow() || (!child->isTableSection() && !child->isTableRow() && !child->isTableCell()));
243 if (beforeChild == firstChild())
244 setFirstChild(child);
246 RenderObject* prev = beforeChild->previousSibling();
247 child->setNextSibling(beforeChild);
248 beforeChild->setPreviousSibling(child);
250 prev->setNextSibling(child);
251 child->setPreviousSibling(prev);
253 child->setParent(owner);
256 // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children
257 // and don't have a layer attached to ourselves.
258 RenderLayer* layer = 0;
259 if (child->firstChild() || child->hasLayer()) {
260 layer = owner->enclosingLayer();
261 child->addLayers(layer);
264 // if the new child is visible but this object was not, tell the layer it has some visible content
265 // that needs to be drawn and layer visibility optimization can't be used
266 if (owner->style()->visibility() != VISIBLE && child->style()->visibility() == VISIBLE && !child->hasLayer()) {
268 layer = owner->enclosingLayer();
270 layer->setHasVisibleContent();
273 if (child->isListItem())
274 toRenderListItem(child)->updateListMarkerNumbers();
276 if (!child->isFloating() && owner->childrenInline())
277 owner->dirtyLinesFromChangedChild(child);
279 if (child->isRenderRegion())
280 toRenderRegion(child)->attachRegion();
282 if (RenderNamedFlowThread* containerFlowThread = renderNamedFlowThreadContainer(owner))
283 containerFlowThread->addFlowChild(child, beforeChild);
286 if (!owner->documentBeingDestroyed()) {
287 RenderCounter::rendererSubtreeAttached(child);
288 RenderQuote::rendererSubtreeAttached(child);
290 child->setNeedsLayoutAndPrefWidthsRecalc();
291 if (!owner->normalChildNeedsLayout())
292 owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
294 if (AXObjectCache::accessibilityEnabled())
295 owner->document()->axObjectCache()->childrenChanged(owner);
298 static RenderObject* findBeforeAfterParent(RenderObject* object)
300 // Only table parts and flex-boxes need to search for the :before or :after parent
301 // FIXME: We could likely get away without this check and always look for the right parent.
302 if (!(object->isTable() || object->isTableSection() || object->isTableRow() || object->isFlexibleBoxIncludingDeprecated()))
305 // If there is a :first-letter style applied on the :before or :after content,
306 // then we want the parent of the first-letter block
307 RenderObject* beforeAfterParent = object;
308 while (beforeAfterParent && !(beforeAfterParent->isText() || beforeAfterParent->isImage())
309 && (beforeAfterParent->style()->styleType() != FIRST_LETTER))
310 beforeAfterParent = beforeAfterParent->firstChild();
312 return beforeAfterParent ? beforeAfterParent->parent() : 0;
315 RenderObject* RenderObjectChildList::beforePseudoElementRenderer(const RenderObject* owner) const
317 // An anonymous (generated) inline run-in that has PseudoId BEFORE must come from a grandparent.
318 // Therefore we should skip these generated run-ins when checking our immediate children.
319 // If we don't find our :before child immediately, then we should check if we own a
320 // generated inline run-in in the next level of children.
321 RenderObject* first = const_cast<RenderObject*>(owner);
323 first = first->firstChild();
324 // Skip list markers and generated run-ins.
325 while (first && (first->isListMarker() || (first->isRenderInline() && first->isRunIn())))
326 first = first->nextInPreOrderAfterChildren(owner);
327 } while (first && first->isAnonymous() && first->style()->styleType() == NOPSEUDO);
332 if (first->isBeforeContent())
335 // Check for a possible generated run-in, using run-in positioning rules.
336 first = owner->firstChild();
337 if (!first->isRenderBlock())
340 first = first->firstChild();
341 // We still need to skip any list markers that could exist before the run-in.
342 while (first && first->isListMarker())
343 first = first->nextSibling();
344 if (first && first->isBeforeContent() && first->isRenderInline() && first->isRunIn())
350 RenderObject* RenderObjectChildList::afterPseudoElementRenderer(const RenderObject* owner) const
352 RenderObject* last = const_cast<RenderObject*>(owner);
354 last = last->lastChild();
355 } while (last && last->isAnonymous() && last->style()->styleType() == NOPSEUDO && !last->isListMarker());
356 if (last && !last->isAfterContent())
361 void RenderObjectChildList::updateBeforeAfterStyle(RenderObject* child, PseudoId type, RenderStyle* pseudoElementStyle)
363 if (!child || child->style()->styleType() != type)
366 // We have generated content present still. We want to walk this content and update our
367 // style information with the new pseudo-element style.
368 child->setStyle(pseudoElementStyle);
370 RenderObject* beforeAfterParent = findBeforeAfterParent(child);
371 if (!beforeAfterParent)
374 // When beforeAfterParent is not equal to child (e.g. in tables),
375 // we need to create new styles inheriting from pseudoElementStyle
376 // on all the intermediate parents (leaving their display same).
377 if (beforeAfterParent != child) {
378 RenderObject* curr = beforeAfterParent;
379 while (curr && curr != child) {
380 ASSERT(curr->isAnonymous());
381 RefPtr<RenderStyle> newStyle = RenderStyle::create();
382 newStyle->inheritFrom(pseudoElementStyle);
383 newStyle->setDisplay(curr->style()->display());
384 newStyle->setStyleType(curr->style()->styleType());
385 curr->setStyle(newStyle);
386 curr = curr->parent();
390 // Note that if we ever support additional types of generated content (which should be way off
391 // in the future), this code will need to be patched.
392 for (RenderObject* genChild = beforeAfterParent->firstChild(); genChild; genChild = genChild->nextSibling()) {
393 if (genChild->isText())
394 // Generated text content is a child whose style also needs to be set to the pseudo-element style.
395 genChild->setStyle(pseudoElementStyle);
396 else if (genChild->isImage()) {
397 // Images get an empty style that inherits from the pseudo.
398 RefPtr<RenderStyle> style = RenderStyle::create();
399 style->inheritFrom(pseudoElementStyle);
400 genChild->setStyle(style.release());
402 // RenderListItem may insert a list marker here. We do not need to care about this case.
403 // Otherwise, genChild must be a first-letter container. updateFirstLetter() will take care of it.
404 ASSERT(genChild->isListMarker() || genChild->style()->styleType() == FIRST_LETTER);
409 static RenderObject* createRendererForBeforeAfterContent(RenderObject* owner, const ContentData* content, RenderStyle* pseudoElementStyle)
411 RenderObject* renderer = 0;
412 switch (content->type()) {
416 renderer = new (owner->renderArena()) RenderTextFragment(owner->document() /* anonymous object */, static_cast<const TextContentData*>(content)->text().impl());
417 renderer->setStyle(pseudoElementStyle);
419 case CONTENT_OBJECT: {
420 RenderImage* image = new (owner->renderArena()) RenderImage(owner->document()); // anonymous object
421 RefPtr<RenderStyle> style = RenderStyle::create();
422 style->inheritFrom(pseudoElementStyle);
423 image->setStyle(style.release());
424 if (const StyleImage* styleImage = static_cast<const ImageContentData*>(content)->image())
425 image->setImageResource(RenderImageResourceStyleImage::create(const_cast<StyleImage*>(styleImage)));
427 image->setImageResource(RenderImageResource::create());
431 case CONTENT_COUNTER:
432 renderer = new (owner->renderArena()) RenderCounter(owner->document(), *static_cast<const CounterContentData*>(content)->counter());
433 renderer->setStyle(pseudoElementStyle);
436 renderer = new (owner->renderArena()) RenderQuote(owner->document(), static_cast<const QuoteContentData*>(content)->quote());
437 renderer->setStyle(pseudoElementStyle);
443 void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, PseudoId type, const RenderObject* styledObject)
445 // Double check that the document did in fact use generated content rules. Otherwise we should not have been called.
446 ASSERT(owner->document()->usesBeforeAfterRules());
448 // In CSS2, before/after pseudo-content cannot nest. Check this first.
449 if (owner->style()->styleType() == BEFORE || owner->style()->styleType() == AFTER)
453 styledObject = owner;
455 RenderStyle* pseudoElementStyle = styledObject->getCachedPseudoStyle(type);
459 child = beforePseudoElementRenderer(owner);
462 child = afterPseudoElementRenderer(owner);
465 ASSERT_NOT_REACHED();
469 // Whether or not we currently have generated content attached.
470 bool oldContentPresent = child;
472 // Whether or not we now want generated content.
473 bool newContentWanted = pseudoElementStyle && pseudoElementStyle->display() != NONE;
475 // For <q><p/></q>, if this object is the inline continuation of the <q>, we only want to generate
476 // :after content and not :before content.
477 if (newContentWanted && type == BEFORE && owner->isElementContinuation())
478 newContentWanted = false;
480 // Similarly, if we're the beginning of a <q>, and there's an inline continuation for our object,
481 // then we don't generate the :after content.
482 if (newContentWanted && type == AFTER && owner->virtualContinuation())
483 newContentWanted = false;
485 // If we don't want generated content any longer, or if we have generated content, but it's no longer
486 // identical to the new content data we want to build render objects for, then we nuke all
487 // of the old generated content.
488 if (oldContentPresent && (!newContentWanted || Node::diff(child->style(), pseudoElementStyle, owner->document()) == Node::Detach)) {
490 if (child->style()->styleType() == type) {
491 oldContentPresent = false;
493 child = (type == BEFORE) ? owner->virtualChildren()->firstChild() : owner->virtualChildren()->lastChild();
497 // If we have no pseudo-element style or if the pseudo-element style's display type is NONE, then we
498 // have no generated content and can now return.
499 if (!newContentWanted)
502 if (owner->isRenderInline() && !pseudoElementStyle->isDisplayInlineType() && !pseudoElementStyle->isFloating() &&
503 !(pseudoElementStyle->position() == AbsolutePosition || pseudoElementStyle->position() == FixedPosition))
504 // According to the CSS2 spec (the end of section 12.1), the only allowed
505 // display values for the pseudo style are NONE and INLINE for inline flows.
506 // FIXME: CSS2.1 lifted this restriction, but block display types will crash.
507 // For now we at least relax the restriction to allow all inline types like inline-block
509 pseudoElementStyle->setDisplay(INLINE);
511 if (oldContentPresent) {
512 updateBeforeAfterStyle(child, type, pseudoElementStyle);
513 return; // We've updated the generated content. That's all we needed to do.
516 RenderObject* insertBefore = (type == BEFORE) ? owner->virtualChildren()->firstChild() : 0;
517 if (insertBefore && insertBefore->isAnonymousBlock() && insertBefore->childrenInline() && !insertBefore->isEmpty()) {
518 // We are going to add the "before" element. We have to check whether the "insertBefore" element
519 // is an anonymous block with inline children. If it is, then we should insert the "before" element
520 // before the first inline child of the anonymous block, otherwise we will end up with the "before"
521 // element in a different block. We do this only when the anonymous block has children, otherwise
522 // we end up with the before element in a wrong block.
523 insertBefore = insertBefore->firstChild();
526 // Nothing goes before the intruded run-in, not even generated content.
527 if (insertBefore && insertBefore->isRunIn() && owner->isRenderBlock()
528 && toRenderBlock(owner)->runInIsPlacedIntoSiblingBlock(insertBefore))
529 insertBefore = insertBefore->nextSibling();
531 // Generated content consists of a single container that houses multiple children (specified
532 // by the content property). This generated content container gets the pseudo-element style set on it.
533 RenderObject* generatedContentContainer = 0;
535 // Walk our list of generated content and create render objects for each.
536 for (const ContentData* content = pseudoElementStyle->contentData(); content; content = content->next()) {
537 RenderObject* renderer = createRendererForBeforeAfterContent(owner, content, pseudoElementStyle);
540 if (!generatedContentContainer) {
541 // Make a generated box that might be any display type now that we are able to drill down into children
542 // to find the original content properly.
543 generatedContentContainer = RenderObject::createObject(owner->document(), pseudoElementStyle);
544 ASSERT(styledObject->node()); // The styled object cannot be anonymous or else it could not have ':before' or ':after' pseudo elements.
545 generatedContentContainer->setNode(styledObject->node()); // This allows access to the generatingNode.
546 generatedContentContainer->setStyle(pseudoElementStyle);
547 if (!owner->isChildAllowed(generatedContentContainer, pseudoElementStyle)) {
548 // The generated content container is not allowed here -> abort.
549 generatedContentContainer->destroy();
554 // When we don't have a first child and are part of a continuation chain,
555 // insertBefore is incorrectly set to zero above, which causes the :before
556 // child to end up at the end of continuation chain.
557 // See https://bugs.webkit.org/show_bug.cgi?id=78380.
558 if (!insertBefore && type == BEFORE && owner->virtualContinuation())
559 owner->addChildIgnoringContinuation(generatedContentContainer, 0);
561 owner->addChild(generatedContentContainer, insertBefore);
563 if (generatedContentContainer->isChildAllowed(renderer, pseudoElementStyle))
564 generatedContentContainer->addChild(renderer);
570 if (!generatedContentContainer)
573 // Handle placement of run-ins. We do the run-in placement at the end since generatedContentContainer can get destroyed.
574 RenderObject* generatedContentContainerImmediateParent = generatedContentContainer->parent();
575 if (generatedContentContainerImmediateParent->isRenderBlock())
576 toRenderBlock(generatedContentContainerImmediateParent)->placeRunInIfNeeded(generatedContentContainer, PlaceGeneratedRunIn);
579 } // namespace WebCore