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 "RenderStyle.h"
40 #include "RenderTextFragment.h"
41 #include "RenderView.h"
45 void RenderObjectChildList::destroyLeftoverChildren()
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 if (firstChild()->isRunIn() && firstChild()->node()) {
51 firstChild()->node()->setRenderer(0);
52 firstChild()->node()->setNeedsStyleRecalc();
53 firstChild()->destroy();
55 // 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.
56 if (firstChild()->node())
57 firstChild()->node()->setRenderer(0);
58 firstChild()->destroy();
63 RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, RenderObject* oldChild, bool fullRemove)
65 ASSERT(oldChild->parent() == owner);
67 // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or
68 // that a positioned child got yanked). We also repaint, so that the area exposed when the child
69 // disappears gets repainted properly.
70 if (!owner->documentBeingDestroyed() && fullRemove && oldChild->m_everHadLayout) {
71 oldChild->setNeedsLayoutAndPrefWidthsRecalc();
72 if (oldChild->isBody())
73 owner->view()->repaint();
78 // If we have a line box wrapper, delete it.
79 if (oldChild->isBox())
80 toRenderBox(oldChild)->deleteLineBoxWrapper();
82 if (!owner->documentBeingDestroyed() && fullRemove) {
83 // if we remove visible child from an invisible parent, we don't know the layer visibility any more
84 RenderLayer* layer = 0;
85 if (owner->style()->visibility() != VISIBLE && oldChild->style()->visibility() == VISIBLE && !oldChild->hasLayer()) {
86 layer = owner->enclosingLayer();
87 layer->dirtyVisibleContentStatus();
90 // Keep our layer hierarchy updated.
91 if (oldChild->firstChild() || oldChild->hasLayer()) {
93 layer = owner->enclosingLayer();
94 oldChild->removeLayers(layer);
97 if (oldChild->isListItem())
98 toRenderListItem(oldChild)->updateListMarkerNumbers();
100 if (oldChild->isPositioned() && owner->childrenInline())
101 owner->dirtyLinesFromChangedChild(oldChild);
104 // Update cached boundaries in SVG renderers, if a child is removed.
105 owner->setNeedsBoundariesUpdate();
109 // If oldChild is the start or end of the selection, then clear the selection to
110 // avoid problems of invalid pointers.
111 // FIXME: The SelectionController should be responsible for this when it
112 // is notified of DOM mutations.
113 if (!owner->documentBeingDestroyed() && oldChild->isSelectionBorder())
114 owner->view()->clearSelection();
117 if (oldChild->previousSibling())
118 oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
119 if (oldChild->nextSibling())
120 oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
122 if (firstChild() == oldChild)
123 setFirstChild(oldChild->nextSibling());
124 if (lastChild() == oldChild)
125 setLastChild(oldChild->previousSibling());
127 oldChild->setPreviousSibling(0);
128 oldChild->setNextSibling(0);
129 oldChild->setParent(0);
131 if (AXObjectCache::accessibilityEnabled())
132 owner->document()->axObjectCache()->childrenChanged(owner);
137 void RenderObjectChildList::appendChildNode(RenderObject* owner, RenderObject* newChild, bool fullAppend)
139 ASSERT(newChild->parent() == 0);
140 ASSERT(!owner->isBlockFlow() || (!newChild->isTableSection() && !newChild->isTableRow() && !newChild->isTableCell()));
142 newChild->setParent(owner);
143 RenderObject* lChild = lastChild();
146 newChild->setPreviousSibling(lChild);
147 lChild->setNextSibling(newChild);
149 setFirstChild(newChild);
151 setLastChild(newChild);
154 // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children
155 // and don't have a layer attached to ourselves.
156 RenderLayer* layer = 0;
157 if (newChild->firstChild() || newChild->hasLayer()) {
158 layer = owner->enclosingLayer();
159 newChild->addLayers(layer, newChild);
162 // if the new child is visible but this object was not, tell the layer it has some visible content
163 // that needs to be drawn and layer visibility optimization can't be used
164 if (owner->style()->visibility() != VISIBLE && newChild->style()->visibility() == VISIBLE && !newChild->hasLayer()) {
166 layer = owner->enclosingLayer();
168 layer->setHasVisibleContent(true);
171 if (newChild->isListItem())
172 toRenderListItem(newChild)->updateListMarkerNumbers();
174 if (!newChild->isFloatingOrPositioned() && owner->childrenInline())
175 owner->dirtyLinesFromChangedChild(newChild);
178 newChild->setNeedsLayoutAndPrefWidthsRecalc(); // Goes up the containing block hierarchy.
179 if (!owner->normalChildNeedsLayout())
180 owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
182 if (AXObjectCache::accessibilityEnabled())
183 owner->document()->axObjectCache()->childrenChanged(owner);
186 void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* child, RenderObject* beforeChild, bool fullInsert)
189 appendChildNode(owner, child, fullInsert);
193 ASSERT(!child->parent());
194 while (beforeChild->parent() != owner && beforeChild->parent()->isAnonymousBlock())
195 beforeChild = beforeChild->parent();
196 ASSERT(beforeChild->parent() == owner);
198 ASSERT(!owner->isBlockFlow() || (!child->isTableSection() && !child->isTableRow() && !child->isTableCell()));
200 if (beforeChild == firstChild())
201 setFirstChild(child);
203 RenderObject* prev = beforeChild->previousSibling();
204 child->setNextSibling(beforeChild);
205 beforeChild->setPreviousSibling(child);
207 prev->setNextSibling(child);
208 child->setPreviousSibling(prev);
210 child->setParent(owner);
213 // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children
214 // and don't have a layer attached to ourselves.
215 RenderLayer* layer = 0;
216 if (child->firstChild() || child->hasLayer()) {
217 layer = owner->enclosingLayer();
218 child->addLayers(layer, child);
221 // if the new child is visible but this object was not, tell the layer it has some visible content
222 // that needs to be drawn and layer visibility optimization can't be used
223 if (owner->style()->visibility() != VISIBLE && child->style()->visibility() == VISIBLE && !child->hasLayer()) {
225 layer = owner->enclosingLayer();
227 layer->setHasVisibleContent(true);
230 if (child->isListItem())
231 toRenderListItem(child)->updateListMarkerNumbers();
233 if (!child->isFloating() && owner->childrenInline())
234 owner->dirtyLinesFromChangedChild(child);
237 child->setNeedsLayoutAndPrefWidthsRecalc();
238 if (!owner->normalChildNeedsLayout())
239 owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
241 if (AXObjectCache::accessibilityEnabled())
242 owner->document()->axObjectCache()->childrenChanged(owner);
245 static RenderObject* beforeAfterContainer(RenderObject* container, PseudoId type)
247 if (type == BEFORE) {
248 // An anonymous (generated) inline run-in that has PseudoId BEFORE must come from a grandparent.
249 // Therefore we should skip these generated run-ins when checking our immediate children.
250 // If we don't find our :before child immediately, then we should check if we own a
251 // generated inline run-in in the next level of children.
252 RenderObject* first = container;
254 // Skip list markers and generated run-ins
255 first = first->firstChild();
256 while (first && (first->isListMarker() || (first->isRenderInline() && first->isRunIn() && first->isAnonymous())))
257 first = first->nextSibling();
258 } while (first && first->isAnonymous() && first->style()->styleType() == NOPSEUDO);
263 if (first->style()->styleType() == type)
266 // Check for a possible generated run-in, using run-in positioning rules.
267 // Skip inlines and floating / positioned blocks, and place as the first child.
268 first = container->firstChild();
269 if (!first->isRenderBlock())
271 while (first && first->isFloatingOrPositioned())
272 first = first->nextSibling();
274 first = first->firstChild();
275 // We still need to skip any list markers that could exist before the run-in.
276 while (first && first->isListMarker())
277 first = first->nextSibling();
278 if (first && first->style()->styleType() == type && first->isRenderInline() && first->isRunIn() && first->isAnonymous())
285 RenderObject* last = container;
287 last = last->lastChild();
288 } while (last && last->isAnonymous() && last->style()->styleType() == NOPSEUDO && !last->isListMarker());
289 if (last && last->style()->styleType() != type)
294 ASSERT_NOT_REACHED();
298 static RenderObject* findBeforeAfterParent(RenderObject* object)
300 // Only table parts need to search for the :before or :after parent
301 if (!(object->isTable() || object->isTableSection() || object->isTableRow()))
304 RenderObject* beforeAfterParent = object;
305 while (beforeAfterParent && !(beforeAfterParent->isText() || beforeAfterParent->isImage()))
306 beforeAfterParent = beforeAfterParent->firstChild();
307 return beforeAfterParent;
310 static void invalidateCountersInContainer(RenderObject* container, const AtomicString& identifier)
314 container = findBeforeAfterParent(container);
317 // Sometimes the counter is attached directly on the container.
318 if (container->isCounter()) {
319 toRenderCounter(container)->invalidate(identifier);
322 for (RenderObject* content = container->firstChild(); content; content = content->nextSibling()) {
323 if (content->isCounter())
324 toRenderCounter(content)->invalidate(identifier);
328 void RenderObjectChildList::invalidateCounters(RenderObject* owner, const AtomicString& identifier)
330 ASSERT(!owner->documentBeingDestroyed());
331 invalidateCountersInContainer(beforeAfterContainer(owner, BEFORE), identifier);
332 invalidateCountersInContainer(beforeAfterContainer(owner, AFTER), identifier);
335 void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, PseudoId type, RenderObject* styledObject)
337 // Double check that the document did in fact use generated content rules. Otherwise we should not have been called.
338 ASSERT(owner->document()->usesBeforeAfterRules());
340 // In CSS2, before/after pseudo-content cannot nest. Check this first.
341 if (owner->style()->styleType() == BEFORE || owner->style()->styleType() == AFTER)
345 styledObject = owner;
347 RenderStyle* pseudoElementStyle = styledObject->getCachedPseudoStyle(type);
348 RenderObject* child = beforeAfterContainer(owner, type);
350 // Whether or not we currently have generated content attached.
351 bool oldContentPresent = child;
353 // Whether or not we now want generated content.
354 bool newContentWanted = pseudoElementStyle && pseudoElementStyle->display() != NONE;
356 // For <q><p/></q>, if this object is the inline continuation of the <q>, we only want to generate
357 // :after content and not :before content.
358 if (newContentWanted && type == BEFORE && owner->isElementContinuation())
359 newContentWanted = false;
361 // Similarly, if we're the beginning of a <q>, and there's an inline continuation for our object,
362 // then we don't generate the :after content.
363 if (newContentWanted && type == AFTER && owner->virtualContinuation())
364 newContentWanted = false;
366 // If we don't want generated content any longer, or if we have generated content, but it's no longer
367 // identical to the new content data we want to build render objects for, then we nuke all
368 // of the old generated content.
369 if (oldContentPresent && (!newContentWanted || Node::diff(child->style(), pseudoElementStyle) == Node::Detach)) {
371 if (child->style()->styleType() == type) {
372 oldContentPresent = false;
374 child = (type == BEFORE) ? owner->virtualChildren()->firstChild() : owner->virtualChildren()->lastChild();
378 // If we have no pseudo-element style or if the pseudo-element style's display type is NONE, then we
379 // have no generated content and can now return.
380 if (!newContentWanted)
383 if (owner->isRenderInline() && !pseudoElementStyle->isDisplayInlineType() && pseudoElementStyle->floating() == FNONE &&
384 !(pseudoElementStyle->position() == AbsolutePosition || pseudoElementStyle->position() == FixedPosition))
385 // According to the CSS2 spec (the end of section 12.1), the only allowed
386 // display values for the pseudo style are NONE and INLINE for inline flows.
387 // FIXME: CSS2.1 lifted this restriction, but block display types will crash.
388 // For now we at least relax the restriction to allow all inline types like inline-block
390 pseudoElementStyle->setDisplay(INLINE);
392 if (oldContentPresent) {
393 if (child && child->style()->styleType() == type) {
394 // We have generated content present still. We want to walk this content and update our
395 // style information with the new pseudo-element style.
396 child->setStyle(pseudoElementStyle);
398 RenderObject* beforeAfterParent = findBeforeAfterParent(child);
399 if (!beforeAfterParent)
402 // Note that if we ever support additional types of generated content (which should be way off
403 // in the future), this code will need to be patched.
404 for (RenderObject* genChild = beforeAfterParent->firstChild(); genChild; genChild = genChild->nextSibling()) {
405 if (genChild->isText())
406 // Generated text content is a child whose style also needs to be set to the pseudo-element style.
407 genChild->setStyle(pseudoElementStyle);
408 else if (genChild->isImage()) {
409 // Images get an empty style that inherits from the pseudo.
410 RefPtr<RenderStyle> style = RenderStyle::create();
411 style->inheritFrom(pseudoElementStyle);
412 genChild->setStyle(style.release());
414 // RenderListItem may insert a list marker here. We do not need to care about this case.
415 // Otherwise, genChild must be a first-letter container. updateFirstLetter() will take care of it.
416 ASSERT(genChild->isListMarker() || genChild->style()->styleType() == FIRST_LETTER);
420 return; // We've updated the generated content. That's all we needed to do.
423 RenderObject* insertBefore = (type == BEFORE) ? owner->virtualChildren()->firstChild() : 0;
425 // Generated content consists of a single container that houses multiple children (specified
426 // by the content property). This generated content container gets the pseudo-element style set on it.
427 RenderObject* generatedContentContainer = 0;
429 // Walk our list of generated content and create render objects for each.
430 for (const ContentData* content = pseudoElementStyle->contentData(); content; content = content->next()) {
431 RenderObject* renderer = 0;
432 switch (content->type()) {
436 renderer = new (owner->renderArena()) RenderTextFragment(owner->document() /* anonymous object */, content->text());
437 renderer->setStyle(pseudoElementStyle);
439 case CONTENT_OBJECT: {
440 RenderImage* image = new (owner->renderArena()) RenderImage(owner->document()); // anonymous object
441 RefPtr<RenderStyle> style = RenderStyle::create();
442 style->inheritFrom(pseudoElementStyle);
443 image->setStyle(style.release());
444 if (StyleImage* styleImage = content->image())
445 image->setImageResource(RenderImageResourceStyleImage::create(styleImage));
447 image->setImageResource(RenderImageResource::create());
451 case CONTENT_COUNTER:
452 renderer = new (owner->renderArena()) RenderCounter(owner->document(), *content->counter());
453 renderer->setStyle(pseudoElementStyle);
458 if (!generatedContentContainer) {
459 // Make a generated box that might be any display type now that we are able to drill down into children
460 // to find the original content properly.
461 generatedContentContainer = RenderObject::createObject(owner->document(), pseudoElementStyle);
462 generatedContentContainer->setStyle(pseudoElementStyle);
463 owner->addChild(generatedContentContainer, insertBefore);
465 if (generatedContentContainer->isChildAllowed(renderer, pseudoElementStyle))
466 generatedContentContainer->addChild(renderer);
473 } // namespace WebCore