<rdar://problem/10208291> first-letter in generated before content with display:...
[WebKit-https.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 "RenderFlowThread.h"
35 #include "RenderImage.h"
36 #include "RenderImageResourceStyleImage.h"
37 #include "RenderInline.h"
38 #include "RenderLayer.h"
39 #include "RenderListItem.h"
40 #include "RenderQuote.h"
41 #include "RenderRegion.h"
42 #include "RenderStyle.h"
43 #include "RenderTextFragment.h"
44 #include "RenderView.h"
45
46 namespace WebCore {
47
48 void RenderObjectChildList::destroyLeftoverChildren()
49 {
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();
57         } else {
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();
62         }
63     }
64 }
65
66 static RenderFlowThread* renderFlowThreadContainer(RenderObject* object)
67 {
68     while (object && object->isAnonymousBlock() && !object->isRenderFlowThread())
69         object = object->parent();
70
71     return object && object->isRenderFlowThread() ? toRenderFlowThread(object) : 0;
72 }
73
74 RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, RenderObject* oldChild, bool fullRemove)
75 {
76     ASSERT(oldChild->parent() == owner);
77
78     // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or
79     // that a positioned child got yanked).  We also repaint, so that the area exposed when the child
80     // disappears gets repainted properly.
81     if (!owner->documentBeingDestroyed() && fullRemove && oldChild->m_everHadLayout) {
82         oldChild->setNeedsLayoutAndPrefWidthsRecalc();
83         if (oldChild->isBody())
84             owner->view()->repaint();
85         else
86             oldChild->repaint();
87     }
88
89     // If we have a line box wrapper, delete it.
90     if (oldChild->isBox())
91         toRenderBox(oldChild)->deleteLineBoxWrapper();
92
93     if (!owner->documentBeingDestroyed() && fullRemove) {
94         // if we remove visible child from an invisible parent, we don't know the layer visibility any more
95         RenderLayer* layer = 0;
96         if (owner->style()->visibility() != VISIBLE && oldChild->style()->visibility() == VISIBLE && !oldChild->hasLayer()) {
97             if ((layer = owner->enclosingLayer()))
98                 layer->dirtyVisibleContentStatus();
99         }
100
101          // Keep our layer hierarchy updated.
102         if (oldChild->firstChild() || oldChild->hasLayer()) {
103             if (!layer)
104                 layer = owner->enclosingLayer();
105             oldChild->removeLayers(layer);
106         }
107
108         if (oldChild->isListItem())
109             toRenderListItem(oldChild)->updateListMarkerNumbers();
110
111         if (oldChild->isPositioned() && owner->childrenInline())
112             owner->dirtyLinesFromChangedChild(oldChild);
113
114         if (oldChild->isRenderRegion())
115             toRenderRegion(oldChild)->detachRegion();
116
117         if (oldChild->inRenderFlowThread() && oldChild->isBox())
118             oldChild->enclosingRenderFlowThread()->removeRenderBoxRegionInfo(toRenderBox(oldChild));
119
120         if (RenderFlowThread* containerFlowThread = renderFlowThreadContainer(owner))
121             containerFlowThread->removeFlowChild(oldChild);
122
123 #if ENABLE(SVG)
124         // Update cached boundaries in SVG renderers, if a child is removed.
125         owner->setNeedsBoundariesUpdate();
126 #endif
127     }
128     
129     // If oldChild is the start or end of the selection, then clear the selection to
130     // avoid problems of invalid pointers.
131     // FIXME: The FrameSelection should be responsible for this when it
132     // is notified of DOM mutations.
133     if (!owner->documentBeingDestroyed() && oldChild->isSelectionBorder())
134         owner->view()->clearSelection();
135
136     // remove the child
137     if (oldChild->previousSibling())
138         oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
139     if (oldChild->nextSibling())
140         oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
141
142     if (firstChild() == oldChild)
143         setFirstChild(oldChild->nextSibling());
144     if (lastChild() == oldChild)
145         setLastChild(oldChild->previousSibling());
146
147     oldChild->setPreviousSibling(0);
148     oldChild->setNextSibling(0);
149     oldChild->setParent(0);
150
151     RenderCounter::rendererRemovedFromTree(oldChild);
152     RenderQuote::rendererRemovedFromTree(oldChild);
153
154     if (AXObjectCache::accessibilityEnabled())
155         owner->document()->axObjectCache()->childrenChanged(owner);
156
157     return oldChild;
158 }
159
160 void RenderObjectChildList::appendChildNode(RenderObject* owner, RenderObject* newChild, bool fullAppend)
161 {
162     ASSERT(newChild->parent() == 0);
163     ASSERT(!owner->isBlockFlow() || (!newChild->isTableSection() && !newChild->isTableRow() && !newChild->isTableCell()));
164
165     newChild->setParent(owner);
166     RenderObject* lChild = lastChild();
167
168     if (lChild) {
169         newChild->setPreviousSibling(lChild);
170         lChild->setNextSibling(newChild);
171     } else
172         setFirstChild(newChild);
173
174     setLastChild(newChild);
175     
176     if (fullAppend) {
177         // Keep our layer hierarchy updated.  Optimize for the common case where we don't have any children
178         // and don't have a layer attached to ourselves.
179         RenderLayer* layer = 0;
180         if (newChild->firstChild() || newChild->hasLayer()) {
181             layer = owner->enclosingLayer();
182             newChild->addLayers(layer);
183         }
184
185         // if the new child is visible but this object was not, tell the layer it has some visible content
186         // that needs to be drawn and layer visibility optimization can't be used
187         if (owner->style()->visibility() != VISIBLE && newChild->style()->visibility() == VISIBLE && !newChild->hasLayer()) {
188             if (!layer)
189                 layer = owner->enclosingLayer();
190             if (layer)
191                 layer->setHasVisibleContent(true);
192         }
193
194         if (newChild->isListItem())
195             toRenderListItem(newChild)->updateListMarkerNumbers();
196
197         if (!newChild->isFloating() && owner->childrenInline())
198             owner->dirtyLinesFromChangedChild(newChild);
199
200         if (newChild->isRenderRegion())
201             toRenderRegion(newChild)->attachRegion();
202
203         if (RenderFlowThread* containerFlowThread = renderFlowThreadContainer(owner))
204             containerFlowThread->addFlowChild(newChild);
205     }
206     RenderCounter::rendererSubtreeAttached(newChild);
207     RenderQuote::rendererSubtreeAttached(newChild);
208     newChild->setNeedsLayoutAndPrefWidthsRecalc(); // Goes up the containing block hierarchy.
209     if (!owner->normalChildNeedsLayout())
210         owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
211     
212     if (AXObjectCache::accessibilityEnabled())
213         owner->document()->axObjectCache()->childrenChanged(owner);
214 }
215
216 void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* child, RenderObject* beforeChild, bool fullInsert)
217 {
218     if (!beforeChild) {
219         appendChildNode(owner, child, fullInsert);
220         return;
221     }
222
223     ASSERT(!child->parent());
224     while (beforeChild->parent() != owner && beforeChild->parent()->isAnonymousBlock())
225         beforeChild = beforeChild->parent();
226     ASSERT(beforeChild->parent() == owner);
227
228     ASSERT(!owner->isBlockFlow() || (!child->isTableSection() && !child->isTableRow() && !child->isTableCell()));
229
230     if (beforeChild == firstChild())
231         setFirstChild(child);
232
233     RenderObject* prev = beforeChild->previousSibling();
234     child->setNextSibling(beforeChild);
235     beforeChild->setPreviousSibling(child);
236     if (prev)
237         prev->setNextSibling(child);
238     child->setPreviousSibling(prev);
239
240     child->setParent(owner);
241     
242     if (fullInsert) {
243         // Keep our layer hierarchy updated.  Optimize for the common case where we don't have any children
244         // and don't have a layer attached to ourselves.
245         RenderLayer* layer = 0;
246         if (child->firstChild() || child->hasLayer()) {
247             layer = owner->enclosingLayer();
248             child->addLayers(layer);
249         }
250
251         // if the new child is visible but this object was not, tell the layer it has some visible content
252         // that needs to be drawn and layer visibility optimization can't be used
253         if (owner->style()->visibility() != VISIBLE && child->style()->visibility() == VISIBLE && !child->hasLayer()) {
254             if (!layer)
255                 layer = owner->enclosingLayer();
256             if (layer)
257                 layer->setHasVisibleContent(true);
258         }
259
260         if (child->isListItem())
261             toRenderListItem(child)->updateListMarkerNumbers();
262
263         if (!child->isFloating() && owner->childrenInline())
264             owner->dirtyLinesFromChangedChild(child);
265
266         if (child->isRenderRegion())
267             toRenderRegion(child)->attachRegion();
268
269         if (RenderFlowThread* containerFlowThread = renderFlowThreadContainer(owner))
270             containerFlowThread->addFlowChild(child, beforeChild);
271     }
272
273     RenderCounter::rendererSubtreeAttached(child);
274     RenderQuote::rendererSubtreeAttached(child);
275     child->setNeedsLayoutAndPrefWidthsRecalc();
276     if (!owner->normalChildNeedsLayout())
277         owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
278     
279     if (AXObjectCache::accessibilityEnabled())
280         owner->document()->axObjectCache()->childrenChanged(owner);
281 }
282
283 static RenderObject* findBeforeAfterParent(RenderObject* object)
284 {
285     // Only table parts need to search for the :before or :after parent
286     if (!(object->isTable() || object->isTableSection() || object->isTableRow()))
287         return object;
288
289     RenderObject* beforeAfterParent = object;
290     while (beforeAfterParent && !(beforeAfterParent->isText() || beforeAfterParent->isImage()))
291         beforeAfterParent = beforeAfterParent->firstChild();
292     return beforeAfterParent ? beforeAfterParent->parent() : 0;
293 }
294
295 RenderObject* RenderObjectChildList::beforePseudoElementRenderer(const RenderObject* owner) const
296 {
297     // An anonymous (generated) inline run-in that has PseudoId BEFORE must come from a grandparent.
298     // Therefore we should skip these generated run-ins when checking our immediate children.
299     // If we don't find our :before child immediately, then we should check if we own a
300     // generated inline run-in in the next level of children.
301     RenderObject* first = const_cast<RenderObject*>(owner);
302     do {
303         // Skip list markers and generated run-ins
304         first = first->firstChild();
305         while (first && first->isListMarker()) {
306             if (first->parent() != owner && first->parent()->isAnonymousBlock())
307                 first = first->parent();
308             first = first->nextSibling();
309         }
310         while (first && first->isRenderInline() && first->isRunIn())
311             first = first->nextSibling();
312     } while (first && first->isAnonymous() && first->style()->styleType() == NOPSEUDO);
313
314     if (!first)
315         return 0;
316
317     if (first->style()->styleType() == BEFORE)
318         return first;
319
320     // Check for a possible generated run-in, using run-in positioning rules.
321     // Skip inlines and floating / positioned blocks, and place as the first child.
322     first = owner->firstChild();
323     if (!first->isRenderBlock())
324         return 0;
325     while (first && first->isFloatingOrPositioned())
326         first = first->nextSibling();
327     if (first) {
328         first = first->firstChild();
329         // We still need to skip any list markers that could exist before the run-in.
330         while (first && first->isListMarker())
331             first = first->nextSibling();
332         if (first && first->style()->styleType() == BEFORE && first->isRenderInline() && first->isRunIn())
333             return first;
334     }
335     return 0;
336 }
337
338 RenderObject* RenderObjectChildList::afterPseudoElementRenderer(const RenderObject* owner) const
339 {
340     RenderObject* last = const_cast<RenderObject*>(owner);
341     do {
342         last = last->lastChild();
343     } while (last && last->isAnonymous() && last->style()->styleType() == NOPSEUDO && !last->isListMarker());
344     if (last && last->style()->styleType() != AFTER)
345         return 0;
346     return last;
347 }
348
349 void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, PseudoId type, const RenderObject* styledObject)
350 {
351     // Double check that the document did in fact use generated content rules.  Otherwise we should not have been called.
352     ASSERT(owner->document()->usesBeforeAfterRules());
353
354     // In CSS2, before/after pseudo-content cannot nest.  Check this first.
355     if (owner->style()->styleType() == BEFORE || owner->style()->styleType() == AFTER)
356         return;
357     
358     if (!styledObject)
359         styledObject = owner;
360
361     RenderStyle* pseudoElementStyle = styledObject->getCachedPseudoStyle(type);
362     RenderObject* child;
363     switch (type) {
364     case BEFORE:
365         child = beforePseudoElementRenderer(owner);
366         break;
367     case AFTER:
368         child = afterPseudoElementRenderer(owner);
369         break;
370     default:
371         ASSERT_NOT_REACHED();
372         return;
373     }
374
375     // Whether or not we currently have generated content attached.
376     bool oldContentPresent = child;
377
378     // Whether or not we now want generated content.
379     bool newContentWanted = pseudoElementStyle && pseudoElementStyle->display() != NONE;
380
381     // For <q><p/></q>, if this object is the inline continuation of the <q>, we only want to generate
382     // :after content and not :before content.
383     if (newContentWanted && type == BEFORE && owner->isElementContinuation())
384         newContentWanted = false;
385
386     // Similarly, if we're the beginning of a <q>, and there's an inline continuation for our object,
387     // then we don't generate the :after content.
388     if (newContentWanted && type == AFTER && owner->virtualContinuation())
389         newContentWanted = false;
390     
391     // If we don't want generated content any longer, or if we have generated content, but it's no longer
392     // identical to the new content data we want to build render objects for, then we nuke all
393     // of the old generated content.
394     if (oldContentPresent && (!newContentWanted || Node::diff(child->style(), pseudoElementStyle) == Node::Detach)) {
395         // Nuke the child. 
396         if (child->style()->styleType() == type) {
397             oldContentPresent = false;
398             child->destroy();
399             child = (type == BEFORE) ? owner->virtualChildren()->firstChild() : owner->virtualChildren()->lastChild();
400         }
401     }
402
403     // If we have no pseudo-element style or if the pseudo-element style's display type is NONE, then we
404     // have no generated content and can now return.
405     if (!newContentWanted)
406         return;
407
408     if (owner->isRenderInline() && !pseudoElementStyle->isDisplayInlineType() && !pseudoElementStyle->isFloating() &&
409         !(pseudoElementStyle->position() == AbsolutePosition || pseudoElementStyle->position() == FixedPosition))
410         // According to the CSS2 spec (the end of section 12.1), the only allowed
411         // display values for the pseudo style are NONE and INLINE for inline flows.
412         // FIXME: CSS2.1 lifted this restriction, but block display types will crash.
413         // For now we at least relax the restriction to allow all inline types like inline-block
414         // and inline-table.
415         pseudoElementStyle->setDisplay(INLINE);
416
417     if (oldContentPresent) {
418         if (child && child->style()->styleType() == type) {
419             // We have generated content present still.  We want to walk this content and update our
420             // style information with the new pseudo-element style.
421             child->setStyle(pseudoElementStyle);
422
423             RenderObject* beforeAfterParent = findBeforeAfterParent(child);
424             if (!beforeAfterParent)
425                 return;
426
427             // When beforeAfterParent is not equal to child (e.g. in tables),
428             // we need to create new styles inheriting from pseudoElementStyle 
429             // on all the intermediate parents (leaving their display same).
430             if (beforeAfterParent != child) {
431                 RenderObject* curr = beforeAfterParent;
432                 while (curr && curr != child) {
433                     ASSERT(curr->isAnonymous());
434                     RefPtr<RenderStyle> newStyle = RenderStyle::create();
435                     newStyle->inheritFrom(pseudoElementStyle);
436                     newStyle->setDisplay(curr->style()->display());
437                     newStyle->setStyleType(curr->style()->styleType());
438                     curr->setStyle(newStyle);
439                     curr = curr->parent();
440                 }
441             }
442
443             // Note that if we ever support additional types of generated content (which should be way off
444             // in the future), this code will need to be patched.
445             for (RenderObject* genChild = beforeAfterParent->firstChild(); genChild; genChild = genChild->nextSibling()) {
446                 if (genChild->isText())
447                     // Generated text content is a child whose style also needs to be set to the pseudo-element style.
448                     genChild->setStyle(pseudoElementStyle);
449                 else if (genChild->isImage()) {
450                     // Images get an empty style that inherits from the pseudo.
451                     RefPtr<RenderStyle> style = RenderStyle::create();
452                     style->inheritFrom(pseudoElementStyle);
453                     genChild->setStyle(style.release());
454                 } else {
455                     // RenderListItem may insert a list marker here. We do not need to care about this case.
456                     // Otherwise, genChild must be a first-letter container. updateFirstLetter() will take care of it.
457                     ASSERT(genChild->isListMarker() || genChild->style()->styleType() == FIRST_LETTER);
458                 }
459             }
460         }
461         return; // We've updated the generated content. That's all we needed to do.
462     }
463     
464     RenderObject* insertBefore = (type == BEFORE) ? owner->virtualChildren()->firstChild() : 0;
465     if (insertBefore && insertBefore->isAnonymousBlock() && insertBefore->childrenInline() && !insertBefore->isEmpty()) {
466         // We are going to add the "before" element. We have to check whether the "insertBefore" element
467         // is an anonymous block with inline children. If it is, then we should insert the "before" element
468         // before the first inline child of the anonymous block, otherwise we will end up with the "before"
469         // element in a different block. We do this only when the anonymous block has children, otherwise
470         // we end up with the before element in a wrong block.
471         insertBefore = insertBefore->firstChild();
472     }
473
474     // Generated content consists of a single container that houses multiple children (specified
475     // by the content property).  This generated content container gets the pseudo-element style set on it.
476     RenderObject* generatedContentContainer = 0;
477     
478     // Walk our list of generated content and create render objects for each.
479     for (const ContentData* content = pseudoElementStyle->contentData(); content; content = content->next()) {
480         RenderObject* renderer = 0;
481         switch (content->type()) {
482             case CONTENT_NONE:
483                 break;
484             case CONTENT_TEXT:
485                 renderer = new (owner->renderArena()) RenderTextFragment(owner->document() /* anonymous object */, static_cast<const TextContentData*>(content)->text().impl());
486                 renderer->setStyle(pseudoElementStyle);
487                 break;
488             case CONTENT_OBJECT: {
489                 RenderImage* image = new (owner->renderArena()) RenderImage(owner->document()); // anonymous object
490                 RefPtr<RenderStyle> style = RenderStyle::create();
491                 style->inheritFrom(pseudoElementStyle);
492                 image->setStyle(style.release());
493                 if (const StyleImage* styleImage = static_cast<const ImageContentData*>(content)->image())
494                     image->setImageResource(RenderImageResourceStyleImage::create(const_cast<StyleImage*>(styleImage)));
495                 else
496                     image->setImageResource(RenderImageResource::create());
497                 renderer = image;
498                 break;
499             }
500         case CONTENT_COUNTER:
501             renderer = new (owner->renderArena()) RenderCounter(owner->document(), *static_cast<const CounterContentData*>(content)->counter());
502             renderer->setStyle(pseudoElementStyle);
503             break;
504         case CONTENT_QUOTE:
505             renderer = new (owner->renderArena()) RenderQuote(owner->document(), static_cast<const QuoteContentData*>(content)->quote());
506             renderer->setStyle(pseudoElementStyle);
507             break;
508         }
509
510         if (renderer) {
511             if (!generatedContentContainer) {
512                 // Make a generated box that might be any display type now that we are able to drill down into children
513                 // to find the original content properly.
514                 generatedContentContainer = RenderObject::createObject(owner->document(), pseudoElementStyle);
515                 ASSERT(styledObject->node()); // The styled object cannot be anonymous or else it could not have ':before' or ':after' pseudo elements.
516                 generatedContentContainer->setNode(styledObject->node()); // This allows access to the generatingNode.
517                 generatedContentContainer->setStyle(pseudoElementStyle);
518                 if (!owner->isChildAllowed(generatedContentContainer, pseudoElementStyle)) {
519                     // The generated content container is not allowed here -> abort.
520                     generatedContentContainer->destroy();
521                     renderer->destroy();
522                     return;
523                 }
524                 owner->addChild(generatedContentContainer, insertBefore);
525             }
526             if (generatedContentContainer->isChildAllowed(renderer, pseudoElementStyle))
527                 generatedContentContainer->addChild(renderer);
528             else
529                 renderer->destroy();
530         }
531     }
532 }
533
534 } // namespace WebCore