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