1/*
2 * Copyright (C) 2009 Apple Inc.  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
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.
12 *
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.
24 */
25
26#include "config.h"
27#include "RenderObjectChildList.h"
28
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"
39
40namespace WebCore {
41
42static void updateListMarkerNumbers(RenderObject* child)
43{
44    for (RenderObject* sibling = child; sibling; sibling = sibling->nextSibling()) {
45        if (sibling->isListItem())
46            toRenderListItem(sibling)->updateValue();
47    }
48}
49
50void RenderObjectChildList::destroyLeftoverChildren()
51{
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.
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
64RenderObject* 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        oldChild->repaint();
74    }
75
76    // If we have a line box wrapper, delete it.
77    if (oldChild->isBox())
78        toRenderBox(oldChild)->deleteLineBoxWrapper();
79
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();
86        }
87
88         // Keep our layer hierarchy updated.
89        if (oldChild->firstChild() || oldChild->hasLayer()) {
90            if (!layer)
91                layer = owner->enclosingLayer();
92            oldChild->removeLayers(layer);
93        }
94
95        // renumber ordered lists
96        if (oldChild->isListItem())
97            updateListMarkerNumbers(oldChild->nextSibling());
98
99        if (oldChild->isPositioned() && owner->childrenInline())
100            owner->dirtyLinesFromChangedChild(oldChild);
101    }
102
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();
109
110    // remove the child
111    if (oldChild->previousSibling())
112        oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
113    if (oldChild->nextSibling())
114        oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
115
116    if (firstChild() == oldChild)
117        setFirstChild(oldChild->nextSibling());
118    if (lastChild() == oldChild)
119        setLastChild(oldChild->previousSibling());
120
121    oldChild->setPreviousSibling(0);
122    oldChild->setNextSibling(0);
123    oldChild->setParent(0);
124
125    if (AXObjectCache::accessibilityEnabled())
126        owner->document()->axObjectCache()->childrenChanged(owner);
127
128    return oldChild;
129}
130
131void RenderObjectChildList::appendChildNode(RenderObject* owner, RenderObject* newChild, bool fullAppend)
132{
133    ASSERT(newChild->parent() == 0);
134    ASSERT(!owner->isBlockFlow() || (!newChild->isTableSection() && !newChild->isTableRow() && !newChild->isTableCell()));
135
136    newChild->setParent(owner);
137    RenderObject* lChild = lastChild();
138
139    if (lChild) {
140        newChild->setPreviousSibling(lChild);
141        lChild->setNextSibling(newChild);
142    } else
143        setFirstChild(newChild);
144
145    setLastChild(newChild);
146
147    if (fullAppend) {
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);
154        }
155
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()) {
159            if (!layer)
160                layer = owner->enclosingLayer();
161            if (layer)
162                layer->setHasVisibleContent(true);
163        }
164
165        if (!newChild->isFloatingOrPositioned() && owner->childrenInline())
166            owner->dirtyLinesFromChangedChild(newChild);
167    }
168
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.
172
173    if (AXObjectCache::accessibilityEnabled())
174        owner->document()->axObjectCache()->childrenChanged(owner);
175}
176
177void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* child, RenderObject* beforeChild, bool fullInsert)
178{
179    if (!beforeChild) {
180        appendChildNode(owner, child);
181        return;
182    }
183
184    ASSERT(!child->parent());
185    while (beforeChild->parent() != owner && beforeChild->parent()->isAnonymousBlock())
186        beforeChild = beforeChild->parent();
187    ASSERT(beforeChild->parent() == owner);
188
189    ASSERT(!owner->isBlockFlow() || (!child->isTableSection() && !child->isTableRow() && !child->isTableCell()));
190
191    if (beforeChild == firstChild())
192        setFirstChild(child);
193
194    RenderObject* prev = beforeChild->previousSibling();
195    child->setNextSibling(beforeChild);
196    beforeChild->setPreviousSibling(child);
197    if (prev)
198        prev->setNextSibling(child);
199    child->setPreviousSibling(prev);
200
201    child->setParent(owner);
202
203    if (fullInsert) {
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);
210        }
211
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()) {
215            if (!layer)
216                layer = owner->enclosingLayer();
217            if (layer)
218                layer->setHasVisibleContent(true);
219        }
220
221
222        if (!child->isFloating() && owner->childrenInline())
223            owner->dirtyLinesFromChangedChild(child);
224    }
225
226    child->setNeedsLayoutAndPrefWidthsRecalc();
227    if (!owner->normalChildNeedsLayout())
228        owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
229
230    if (AXObjectCache::accessibilityEnabled())
231        owner->document()->axObjectCache()->childrenChanged(owner);
232}
233
234static RenderObject* beforeAfterContainer(RenderObject* container, PseudoId type)
235{
236    if (type == BEFORE) {
237        RenderObject* first = container;
238        do {
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)
245            return 0;
246        return first;
247    }
248    if (type == AFTER) {
249        RenderObject* last = container;
250        do {
251            last = last->lastChild();
252        } while (last && last->isAnonymous() && last->style()->styleType() == NOPSEUDO && !last->isListMarker());
253        if (last && last->style()->styleType() != type)
254            return 0;
255        return last;
256    }
257
258    ASSERT_NOT_REACHED();
259    return 0;
260}
261
262static RenderObject* findBeforeAfterParent(RenderObject* object)
263{
264    // Only table parts need to search for the :before or :after parent
265    if (!(object->isTable() || object->isTableSection() || object->isTableRow()))
266        return object;
267
268    RenderObject* beforeAfterParent = object;
269    while (beforeAfterParent && !(beforeAfterParent->isText() || beforeAfterParent->isImage()))
270        beforeAfterParent = beforeAfterParent->firstChild();
271    return beforeAfterParent;
272}
273
274static void invalidateCountersInContainer(RenderObject* container, const AtomicString& identifier)
275{
276    if (!container)
277        return;
278    container = findBeforeAfterParent(container);
279    if (!container)
280        return;
281    // Sometimes the counter is attached directly on the container.
282    if (container->isCounter()) {
283        toRenderCounter(container)->invalidate(identifier);
284        return;
285    }
286    for (RenderObject* content = container->firstChild(); content; content = content->nextSibling()) {
287        if (content->isCounter())
288            toRenderCounter(content)->invalidate(identifier);
289    }
290}
291
292void RenderObjectChildList::invalidateCounters(RenderObject* owner, const AtomicString& identifier)
293{
294    ASSERT(!owner->documentBeingDestroyed());
295    invalidateCountersInContainer(beforeAfterContainer(owner, BEFORE), identifier);
296    invalidateCountersInContainer(beforeAfterContainer(owner, AFTER), identifier);
297}
298
299void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, PseudoId type, RenderObject* styledObject)
300{
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());
303
304    // In CSS2, before/after pseudo-content cannot nest.  Check this first.
305    if (owner->style()->styleType() == BEFORE || owner->style()->styleType() == AFTER)
306        return;
307
308    if (!styledObject)
309        styledObject = owner;
310
311    RenderStyle* pseudoElementStyle = styledObject->getCachedPseudoStyle(type);
312    RenderObject* child = beforeAfterContainer(owner, type);
313
314    // Whether or not we currently have generated content attached.
315    bool oldContentPresent = child;
316
317    // Whether or not we now want generated content.
318    bool newContentWanted = pseudoElementStyle && pseudoElementStyle->display() != NONE;
319
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;
324
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;
329
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)) {
334        // Nuke the child.
335        if (child && child->style()->styleType() == type) {
336            oldContentPresent = false;
337            child->destroy();
338            child = (type == BEFORE) ? owner->virtualChildren()->firstChild() : owner->virtualChildren()->lastChild();
339        }
340    }
341
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)
345        return;
346
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
353        // and inline-table.
354        pseudoElementStyle->setDisplay(INLINE);
355
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);
361
362            RenderObject* beforeAfterParent = findBeforeAfterParent(child);
363            if (!beforeAfterParent)
364                return;
365
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());
377                } else {
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);
381                }
382            }
383        }
384        return; // We've updated the generated content. That's all we needed to do.
385    }
386
387    RenderObject* insertBefore = (type == BEFORE) ? owner->virtualChildren()->firstChild() : 0;
388
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;
392
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()) {
397            case CONTENT_NONE:
398                break;
399            case CONTENT_TEXT:
400                renderer = new (owner->renderArena()) RenderTextFragment(owner->document() /* anonymous object */, content->text());
401                renderer->setStyle(pseudoElementStyle);
402                break;
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);
410                renderer = image;
411                break;
412            }
413            case CONTENT_COUNTER:
414                renderer = new (owner->renderArena()) RenderCounter(owner->document(), *content->counter());
415                renderer->setStyle(pseudoElementStyle);
416                break;
417        }
418
419        if (renderer) {
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);
426            }
427            generatedContentContainer->addChild(renderer);
428        }
429    }
430}
431
432} // namespace WebCore
433