OSDN Git Service

Merge WebKit at r75993: Initial merge by git.
[android-x86/external-webkit.git] / Source / WebCore / rendering / RenderObjectChildList.cpp
1 /*
2  * Copyright (C) 2009, 2010 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 "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"
42
43 namespace WebCore {
44
45 void RenderObjectChildList::destroyLeftoverChildren()
46 {
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();
54         } else {
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();
59         }
60     }
61 }
62
63 RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, RenderObject* oldChild, bool fullRemove)
64 {
65     ASSERT(oldChild->parent() == owner);
66
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();
74         else
75             oldChild->repaint();
76     }
77
78     // If we have a line box wrapper, delete it.
79     if (oldChild->isBox())
80         toRenderBox(oldChild)->deleteLineBoxWrapper();
81
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();
88         }
89
90          // Keep our layer hierarchy updated.
91         if (oldChild->firstChild() || oldChild->hasLayer()) {
92             if (!layer)
93                 layer = owner->enclosingLayer();
94             oldChild->removeLayers(layer);
95         }
96
97         if (oldChild->isListItem())
98             toRenderListItem(oldChild)->updateListMarkerNumbers();
99
100         if (oldChild->isPositioned() && owner->childrenInline())
101             owner->dirtyLinesFromChangedChild(oldChild);
102
103 #if ENABLE(SVG)
104         // Update cached boundaries in SVG renderers, if a child is removed.
105         owner->setNeedsBoundariesUpdate();
106 #endif
107     }
108     
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();
115
116     // remove the child
117     if (oldChild->previousSibling())
118         oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
119     if (oldChild->nextSibling())
120         oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
121
122     if (firstChild() == oldChild)
123         setFirstChild(oldChild->nextSibling());
124     if (lastChild() == oldChild)
125         setLastChild(oldChild->previousSibling());
126
127     oldChild->setPreviousSibling(0);
128     oldChild->setNextSibling(0);
129     oldChild->setParent(0);
130
131     if (AXObjectCache::accessibilityEnabled())
132         owner->document()->axObjectCache()->childrenChanged(owner);
133
134     return oldChild;
135 }
136
137 void RenderObjectChildList::appendChildNode(RenderObject* owner, RenderObject* newChild, bool fullAppend)
138 {
139     ASSERT(newChild->parent() == 0);
140     ASSERT(!owner->isBlockFlow() || (!newChild->isTableSection() && !newChild->isTableRow() && !newChild->isTableCell()));
141
142     newChild->setParent(owner);
143     RenderObject* lChild = lastChild();
144
145     if (lChild) {
146         newChild->setPreviousSibling(lChild);
147         lChild->setNextSibling(newChild);
148     } else
149         setFirstChild(newChild);
150
151     setLastChild(newChild);
152     
153     if (fullAppend) {
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);
160         }
161
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()) {
165             if (!layer)
166                 layer = owner->enclosingLayer();
167             if (layer)
168                 layer->setHasVisibleContent(true);
169         }
170
171         if (newChild->isListItem())
172             toRenderListItem(newChild)->updateListMarkerNumbers();
173
174         if (!newChild->isFloatingOrPositioned() && owner->childrenInline())
175             owner->dirtyLinesFromChangedChild(newChild);
176     }
177
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.
181     
182     if (AXObjectCache::accessibilityEnabled())
183         owner->document()->axObjectCache()->childrenChanged(owner);
184 }
185
186 void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* child, RenderObject* beforeChild, bool fullInsert)
187 {
188     if (!beforeChild) {
189         appendChildNode(owner, child, fullInsert);
190         return;
191     }
192
193     ASSERT(!child->parent());
194     while (beforeChild->parent() != owner && beforeChild->parent()->isAnonymousBlock())
195         beforeChild = beforeChild->parent();
196     ASSERT(beforeChild->parent() == owner);
197
198     ASSERT(!owner->isBlockFlow() || (!child->isTableSection() && !child->isTableRow() && !child->isTableCell()));
199
200     if (beforeChild == firstChild())
201         setFirstChild(child);
202
203     RenderObject* prev = beforeChild->previousSibling();
204     child->setNextSibling(beforeChild);
205     beforeChild->setPreviousSibling(child);
206     if (prev)
207         prev->setNextSibling(child);
208     child->setPreviousSibling(prev);
209
210     child->setParent(owner);
211     
212     if (fullInsert) {
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);
219         }
220
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()) {
224             if (!layer)
225                 layer = owner->enclosingLayer();
226             if (layer)
227                 layer->setHasVisibleContent(true);
228         }
229
230         if (child->isListItem())
231             toRenderListItem(child)->updateListMarkerNumbers();
232
233         if (!child->isFloating() && owner->childrenInline())
234             owner->dirtyLinesFromChangedChild(child);
235     }
236
237     child->setNeedsLayoutAndPrefWidthsRecalc();
238     if (!owner->normalChildNeedsLayout())
239         owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
240     
241     if (AXObjectCache::accessibilityEnabled())
242         owner->document()->axObjectCache()->childrenChanged(owner);
243 }
244
245 static RenderObject* beforeAfterContainer(RenderObject* container, PseudoId type)
246 {
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;
253         do {
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);
259
260         if (!first)
261             return 0;
262
263         if (first->style()->styleType() == type)
264             return first;
265
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())
270             return 0;
271         while (first && first->isFloatingOrPositioned())
272             first = first->nextSibling();
273         if (first) {
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())
279                 return first;
280         }
281         return 0;
282     }
283
284     if (type == AFTER) {
285         RenderObject* last = container;
286         do {
287             last = last->lastChild();
288         } while (last && last->isAnonymous() && last->style()->styleType() == NOPSEUDO && !last->isListMarker());
289         if (last && last->style()->styleType() != type)
290             return 0;
291         return last;
292     }
293
294     ASSERT_NOT_REACHED();
295     return 0;
296 }
297
298 static RenderObject* findBeforeAfterParent(RenderObject* object)
299 {
300     // Only table parts need to search for the :before or :after parent
301     if (!(object->isTable() || object->isTableSection() || object->isTableRow()))
302         return object;
303
304     RenderObject* beforeAfterParent = object;
305     while (beforeAfterParent && !(beforeAfterParent->isText() || beforeAfterParent->isImage()))
306         beforeAfterParent = beforeAfterParent->firstChild();
307     return beforeAfterParent;
308 }
309
310 static void invalidateCountersInContainer(RenderObject* container, const AtomicString& identifier)
311 {
312     if (!container)
313         return;
314     container = findBeforeAfterParent(container);
315     if (!container)
316         return;
317     // Sometimes the counter is attached directly on the container.
318     if (container->isCounter()) {
319         toRenderCounter(container)->invalidate(identifier);
320         return;
321     }
322     for (RenderObject* content = container->firstChild(); content; content = content->nextSibling()) {
323         if (content->isCounter())
324             toRenderCounter(content)->invalidate(identifier);
325     }
326 }
327
328 void RenderObjectChildList::invalidateCounters(RenderObject* owner, const AtomicString& identifier)
329 {
330     ASSERT(!owner->documentBeingDestroyed());
331     invalidateCountersInContainer(beforeAfterContainer(owner, BEFORE), identifier);
332     invalidateCountersInContainer(beforeAfterContainer(owner, AFTER), identifier);
333 }
334
335 void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, PseudoId type, RenderObject* styledObject)
336 {
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());
339
340     // In CSS2, before/after pseudo-content cannot nest.  Check this first.
341     if (owner->style()->styleType() == BEFORE || owner->style()->styleType() == AFTER)
342         return;
343     
344     if (!styledObject)
345         styledObject = owner;
346
347     RenderStyle* pseudoElementStyle = styledObject->getCachedPseudoStyle(type);
348     RenderObject* child = beforeAfterContainer(owner, type);
349
350     // Whether or not we currently have generated content attached.
351     bool oldContentPresent = child;
352
353     // Whether or not we now want generated content.
354     bool newContentWanted = pseudoElementStyle && pseudoElementStyle->display() != NONE;
355
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;
360
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;
365     
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)) {
370         // Nuke the child. 
371         if (child->style()->styleType() == type) {
372             oldContentPresent = false;
373             child->destroy();
374             child = (type == BEFORE) ? owner->virtualChildren()->firstChild() : owner->virtualChildren()->lastChild();
375         }
376     }
377
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)
381         return;
382
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
389         // and inline-table.
390         pseudoElementStyle->setDisplay(INLINE);
391
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);
397
398             RenderObject* beforeAfterParent = findBeforeAfterParent(child);
399             if (!beforeAfterParent)
400                 return;
401
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());
413                 } else {
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);
417                 }
418             }
419         }
420         return; // We've updated the generated content. That's all we needed to do.
421     }
422     
423     RenderObject* insertBefore = (type == BEFORE) ? owner->virtualChildren()->firstChild() : 0;
424
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;
428     
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()) {
433             case CONTENT_NONE:
434                 break;
435             case CONTENT_TEXT:
436                 renderer = new (owner->renderArena()) RenderTextFragment(owner->document() /* anonymous object */, content->text());
437                 renderer->setStyle(pseudoElementStyle);
438                 break;
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));
446                 else
447                     image->setImageResource(RenderImageResource::create());
448                 renderer = image;
449                 break;
450             }
451             case CONTENT_COUNTER:
452                 renderer = new (owner->renderArena()) RenderCounter(owner->document(), *content->counter());
453                 renderer->setStyle(pseudoElementStyle);
454                 break;
455         }
456
457         if (renderer) {
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);
464             }
465             if (generatedContentContainer->isChildAllowed(renderer, pseudoElementStyle))
466                 generatedContentContainer->addChild(renderer);
467             else
468                 renderer->destroy();
469         }
470     }
471 }
472
473 } // namespace WebCore