2 * Copyright (C) 2009 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "RenderObjectChildList.h"
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"
42 static void updateListMarkerNumbers(RenderObject* child)
44 for (RenderObject* sibling = child; sibling; sibling = sibling->nextSibling()) {
45 if (sibling->isListItem())
46 toRenderListItem(sibling)->updateValue();
50 void RenderObjectChildList::destroyLeftoverChildren()
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.
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();
64 RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, RenderObject* oldChild, bool fullRemove)
66 ASSERT(oldChild->parent() == owner);
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();
76 // If we have a line box wrapper, delete it.
77 if (oldChild->isBox())
78 toRenderBox(oldChild)->deleteLineBoxWrapper();
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();
88 // Keep our layer hierarchy updated.
89 if (oldChild->firstChild() || oldChild->hasLayer()) {
91 layer = owner->enclosingLayer();
92 oldChild->removeLayers(layer);
95 // renumber ordered lists
96 if (oldChild->isListItem())
97 updateListMarkerNumbers(oldChild->nextSibling());
99 if (oldChild->isPositioned() && owner->childrenInline())
100 owner->dirtyLinesFromChangedChild(oldChild);
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();
111 if (oldChild->previousSibling())
112 oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
113 if (oldChild->nextSibling())
114 oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
116 if (firstChild() == oldChild)
117 setFirstChild(oldChild->nextSibling());
118 if (lastChild() == oldChild)
119 setLastChild(oldChild->previousSibling());
121 oldChild->setPreviousSibling(0);
122 oldChild->setNextSibling(0);
123 oldChild->setParent(0);
125 if (AXObjectCache::accessibilityEnabled())
126 owner->document()->axObjectCache()->childrenChanged(owner);
131 void RenderObjectChildList::appendChildNode(RenderObject* owner, RenderObject* newChild, bool fullAppend)
133 ASSERT(newChild->parent() == 0);
134 ASSERT(!owner->isBlockFlow() || (!newChild->isTableSection() && !newChild->isTableRow() && !newChild->isTableCell()));
136 newChild->setParent(owner);
137 RenderObject* lChild = lastChild();
140 newChild->setPreviousSibling(lChild);
141 lChild->setNextSibling(newChild);
143 setFirstChild(newChild);
145 setLastChild(newChild);
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);
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()) {
160 layer = owner->enclosingLayer();
162 layer->setHasVisibleContent(true);
165 if (!newChild->isFloatingOrPositioned() && owner->childrenInline())
166 owner->dirtyLinesFromChangedChild(newChild);
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.
173 if (AXObjectCache::accessibilityEnabled())
174 owner->document()->axObjectCache()->childrenChanged(owner);
177 void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* child, RenderObject* beforeChild, bool fullInsert)
180 appendChildNode(owner, child);
184 ASSERT(!child->parent());
185 while (beforeChild->parent() != owner && beforeChild->parent()->isAnonymousBlock())
186 beforeChild = beforeChild->parent();
187 ASSERT(beforeChild->parent() == owner);
189 ASSERT(!owner->isBlockFlow() || (!child->isTableSection() && !child->isTableRow() && !child->isTableCell()));
191 if (beforeChild == firstChild())
192 setFirstChild(child);
194 RenderObject* prev = beforeChild->previousSibling();
195 child->setNextSibling(beforeChild);
196 beforeChild->setPreviousSibling(child);
198 prev->setNextSibling(child);
199 child->setPreviousSibling(prev);
201 child->setParent(owner);
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);
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()) {
216 layer = owner->enclosingLayer();
218 layer->setHasVisibleContent(true);
222 if (!child->isFloating() && owner->childrenInline())
223 owner->dirtyLinesFromChangedChild(child);
226 child->setNeedsLayoutAndPrefWidthsRecalc();
227 if (!owner->normalChildNeedsLayout())
228 owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
230 if (AXObjectCache::accessibilityEnabled())
231 owner->document()->axObjectCache()->childrenChanged(owner);
234 static RenderObject* beforeAfterContainer(RenderObject* container, PseudoId type)
236 if (type == BEFORE) {
237 RenderObject* first = container;
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)
249 RenderObject* last = container;
251 last = last->lastChild();
252 } while (last && last->isAnonymous() && last->style()->styleType() == NOPSEUDO && !last->isListMarker());
253 if (last && last->style()->styleType() != type)
258 ASSERT_NOT_REACHED();
262 static RenderObject* findBeforeAfterParent(RenderObject* object)
264 // Only table parts need to search for the :before or :after parent
265 if (!(object->isTable() || object->isTableSection() || object->isTableRow()))
268 RenderObject* beforeAfterParent = object;
269 while (beforeAfterParent && !(beforeAfterParent->isText() || beforeAfterParent->isImage()))
270 beforeAfterParent = beforeAfterParent->firstChild();
271 return beforeAfterParent;
274 static void invalidateCountersInContainer(RenderObject* container, const AtomicString& identifier)
278 container = findBeforeAfterParent(container);
281 // Sometimes the counter is attached directly on the container.
282 if (container->isCounter()) {
283 toRenderCounter(container)->invalidate(identifier);
286 for (RenderObject* content = container->firstChild(); content; content = content->nextSibling()) {
287 if (content->isCounter())
288 toRenderCounter(content)->invalidate(identifier);
292 void RenderObjectChildList::invalidateCounters(RenderObject* owner, const AtomicString& identifier)
294 ASSERT(!owner->documentBeingDestroyed());
295 invalidateCountersInContainer(beforeAfterContainer(owner, BEFORE), identifier);
296 invalidateCountersInContainer(beforeAfterContainer(owner, AFTER), identifier);
299 void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, PseudoId type, RenderObject* styledObject)
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());
304 // In CSS2, before/after pseudo-content cannot nest. Check this first.
305 if (owner->style()->styleType() == BEFORE || owner->style()->styleType() == AFTER)
309 styledObject = owner;
311 RenderStyle* pseudoElementStyle = styledObject->getCachedPseudoStyle(type);
312 RenderObject* child = beforeAfterContainer(owner, type);
314 // Whether or not we currently have generated content attached.
315 bool oldContentPresent = child;
317 // Whether or not we now want generated content.
318 bool newContentWanted = pseudoElementStyle && pseudoElementStyle->display() != NONE;
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;
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;
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)) {
335 if (child && child->style()->styleType() == type) {
336 oldContentPresent = false;
338 child = (type == BEFORE) ? owner->virtualChildren()->firstChild() : owner->virtualChildren()->lastChild();
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)
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
354 pseudoElementStyle->setDisplay(INLINE);
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);
362 RenderObject* beforeAfterParent = findBeforeAfterParent(child);
363 if (!beforeAfterParent)
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());
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);
384 return; // We've updated the generated content. That's all we needed to do.
387 RenderObject* insertBefore = (type == BEFORE) ? owner->virtualChildren()->firstChild() : 0;
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;
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()) {
400 renderer = new (owner->renderArena()) RenderTextFragment(owner->document() /* anonymous object */, content->text());
401 renderer->setStyle(pseudoElementStyle);
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);
413 case CONTENT_COUNTER:
414 renderer = new (owner->renderArena()) RenderCounter(owner->document(), *content->counter());
415 renderer->setStyle(pseudoElementStyle);
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);
427 generatedContentContainer->addChild(renderer);
432 } // namespace WebCore