• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 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 "RenderBlock.h"
32 #include "RenderCounter.h"
33 #include "RenderImageGeneratedContent.h"
34 #include "RenderInline.h"
35 #include "RenderLayer.h"
36 #include "RenderListItem.h"
37 #include "RenderStyle.h"
38 #include "RenderTextFragment.h"
39 #include "RenderView.h"
40 
41 namespace WebCore {
42 
updateListMarkerNumbers(RenderObject * child)43 static void updateListMarkerNumbers(RenderObject* child)
44 {
45     for (RenderObject* sibling = child; sibling; sibling = sibling->nextSibling()) {
46         if (sibling->isListItem())
47             toRenderListItem(sibling)->updateValue();
48     }
49 }
50 
destroyLeftoverChildren()51 void RenderObjectChildList::destroyLeftoverChildren()
52 {
53     while (firstChild()) {
54         if (firstChild()->isListMarker() || (firstChild()->style()->styleType() == FIRST_LETTER && !firstChild()->isText()))
55             firstChild()->remove();  // List markers are owned by their enclosing list and so don't get destroyed by this container. Similarly, first letters are destroyed by their remaining text fragment.
56         else if (firstChild()->isRunIn() && firstChild()->node()) {
57             firstChild()->node()->setRenderer(0);
58             firstChild()->node()->setNeedsStyleRecalc();
59             firstChild()->destroy();
60         } else {
61             // 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.
62             if (firstChild()->node())
63                 firstChild()->node()->setRenderer(0);
64             firstChild()->destroy();
65         }
66     }
67 }
68 
removeChildNode(RenderObject * owner,RenderObject * oldChild,bool fullRemove)69 RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, RenderObject* oldChild, bool fullRemove)
70 {
71     ASSERT(oldChild->parent() == owner);
72 
73     // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or
74     // that a positioned child got yanked).  We also repaint, so that the area exposed when the child
75     // disappears gets repainted properly.
76     if (!owner->documentBeingDestroyed() && fullRemove && oldChild->m_everHadLayout) {
77         oldChild->setNeedsLayoutAndPrefWidthsRecalc();
78         oldChild->repaint();
79     }
80 
81     // If we have a line box wrapper, delete it.
82     if (oldChild->isBox())
83         toRenderBox(oldChild)->deleteLineBoxWrapper();
84 
85     if (!owner->documentBeingDestroyed() && fullRemove) {
86         // if we remove visible child from an invisible parent, we don't know the layer visibility any more
87         RenderLayer* layer = 0;
88         if (owner->style()->visibility() != VISIBLE && oldChild->style()->visibility() == VISIBLE && !oldChild->hasLayer()) {
89             layer = owner->enclosingLayer();
90             layer->dirtyVisibleContentStatus();
91         }
92 
93          // Keep our layer hierarchy updated.
94         if (oldChild->firstChild() || oldChild->hasLayer()) {
95             if (!layer)
96                 layer = owner->enclosingLayer();
97             oldChild->removeLayers(layer);
98         }
99 
100         // renumber ordered lists
101         if (oldChild->isListItem())
102             updateListMarkerNumbers(oldChild->nextSibling());
103 
104         if (oldChild->isPositioned() && owner->childrenInline())
105             owner->dirtyLinesFromChangedChild(oldChild);
106     }
107 
108     // If oldChild is the start or end of the selection, then clear the selection to
109     // avoid problems of invalid pointers.
110     // FIXME: The SelectionController should be responsible for this when it
111     // is notified of DOM mutations.
112     if (!owner->documentBeingDestroyed() && oldChild->isSelectionBorder())
113         owner->view()->clearSelection();
114 
115     // remove the child
116     if (oldChild->previousSibling())
117         oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
118     if (oldChild->nextSibling())
119         oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
120 
121     if (firstChild() == oldChild)
122         setFirstChild(oldChild->nextSibling());
123     if (lastChild() == oldChild)
124         setLastChild(oldChild->previousSibling());
125 
126     oldChild->setPreviousSibling(0);
127     oldChild->setNextSibling(0);
128     oldChild->setParent(0);
129 
130     if (AXObjectCache::accessibilityEnabled())
131         owner->document()->axObjectCache()->childrenChanged(owner);
132 
133     return oldChild;
134 }
135 
appendChildNode(RenderObject * owner,RenderObject * newChild,bool fullAppend)136 void RenderObjectChildList::appendChildNode(RenderObject* owner, RenderObject* newChild, bool fullAppend)
137 {
138     ASSERT(newChild->parent() == 0);
139     ASSERT(!owner->isBlockFlow() || (!newChild->isTableSection() && !newChild->isTableRow() && !newChild->isTableCell()));
140 
141     newChild->setParent(owner);
142     RenderObject* lChild = lastChild();
143 
144     if (lChild) {
145         newChild->setPreviousSibling(lChild);
146         lChild->setNextSibling(newChild);
147     } else
148         setFirstChild(newChild);
149 
150     setLastChild(newChild);
151 
152     if (fullAppend) {
153         // Keep our layer hierarchy updated.  Optimize for the common case where we don't have any children
154         // and don't have a layer attached to ourselves.
155         RenderLayer* layer = 0;
156         if (newChild->firstChild() || newChild->hasLayer()) {
157             layer = owner->enclosingLayer();
158             newChild->addLayers(layer, newChild);
159         }
160 
161         // if the new child is visible but this object was not, tell the layer it has some visible content
162         // that needs to be drawn and layer visibility optimization can't be used
163         if (owner->style()->visibility() != VISIBLE && newChild->style()->visibility() == VISIBLE && !newChild->hasLayer()) {
164             if (!layer)
165                 layer = owner->enclosingLayer();
166             if (layer)
167                 layer->setHasVisibleContent(true);
168         }
169 
170         if (!newChild->isFloatingOrPositioned() && owner->childrenInline())
171             owner->dirtyLinesFromChangedChild(newChild);
172     }
173 
174     newChild->setNeedsLayoutAndPrefWidthsRecalc(); // Goes up the containing block hierarchy.
175     if (!owner->normalChildNeedsLayout())
176         owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
177 
178     if (AXObjectCache::accessibilityEnabled())
179         owner->document()->axObjectCache()->childrenChanged(owner);
180 }
181 
insertChildNode(RenderObject * owner,RenderObject * child,RenderObject * beforeChild,bool fullInsert)182 void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* child, RenderObject* beforeChild, bool fullInsert)
183 {
184     if (!beforeChild) {
185         appendChildNode(owner, child);
186         return;
187     }
188 
189     ASSERT(!child->parent());
190     while (beforeChild->parent() != owner && beforeChild->parent()->isAnonymousBlock())
191         beforeChild = beforeChild->parent();
192     ASSERT(beforeChild->parent() == owner);
193 
194     ASSERT(!owner->isBlockFlow() || (!child->isTableSection() && !child->isTableRow() && !child->isTableCell()));
195 
196     if (beforeChild == firstChild())
197         setFirstChild(child);
198 
199     RenderObject* prev = beforeChild->previousSibling();
200     child->setNextSibling(beforeChild);
201     beforeChild->setPreviousSibling(child);
202     if (prev)
203         prev->setNextSibling(child);
204     child->setPreviousSibling(prev);
205 
206     child->setParent(owner);
207 
208     if (fullInsert) {
209         // Keep our layer hierarchy updated.  Optimize for the common case where we don't have any children
210         // and don't have a layer attached to ourselves.
211         RenderLayer* layer = 0;
212         if (child->firstChild() || child->hasLayer()) {
213             layer = owner->enclosingLayer();
214             child->addLayers(layer, child);
215         }
216 
217         // if the new child is visible but this object was not, tell the layer it has some visible content
218         // that needs to be drawn and layer visibility optimization can't be used
219         if (owner->style()->visibility() != VISIBLE && child->style()->visibility() == VISIBLE && !child->hasLayer()) {
220             if (!layer)
221                 layer = owner->enclosingLayer();
222             if (layer)
223                 layer->setHasVisibleContent(true);
224         }
225 
226 
227         if (!child->isFloating() && owner->childrenInline())
228             owner->dirtyLinesFromChangedChild(child);
229     }
230 
231     child->setNeedsLayoutAndPrefWidthsRecalc();
232     if (!owner->normalChildNeedsLayout())
233         owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
234 
235     if (AXObjectCache::accessibilityEnabled())
236         owner->document()->axObjectCache()->childrenChanged(owner);
237 }
238 
beforeAfterContainer(RenderObject * container,PseudoId type)239 static RenderObject* beforeAfterContainer(RenderObject* container, PseudoId type)
240 {
241     if (type == BEFORE) {
242         RenderObject* first = container;
243         do {
244             // Skip list markers.
245             first = first->firstChild();
246             while (first && first->isListMarker())
247                 first = first->nextSibling();
248         } while (first && first->isAnonymous() && first->style()->styleType() == NOPSEUDO);
249         if (first && first->style()->styleType() != type)
250             return 0;
251         return first;
252     }
253     if (type == AFTER) {
254         RenderObject* last = container;
255         do {
256             last = last->lastChild();
257         } while (last && last->isAnonymous() && last->style()->styleType() == NOPSEUDO && !last->isListMarker());
258         if (last && last->style()->styleType() != type)
259             return 0;
260         return last;
261     }
262 
263     ASSERT_NOT_REACHED();
264     return 0;
265 }
266 
findBeforeAfterParent(RenderObject * object)267 static RenderObject* findBeforeAfterParent(RenderObject* object)
268 {
269     // Only table parts need to search for the :before or :after parent
270     if (!(object->isTable() || object->isTableSection() || object->isTableRow()))
271         return object;
272 
273     RenderObject* beforeAfterParent = object;
274     while (beforeAfterParent && !(beforeAfterParent->isText() || beforeAfterParent->isImage()))
275         beforeAfterParent = beforeAfterParent->firstChild();
276     return beforeAfterParent;
277 }
278 
invalidateCountersInContainer(RenderObject * container,const AtomicString & identifier)279 static void invalidateCountersInContainer(RenderObject* container, const AtomicString& identifier)
280 {
281     if (!container)
282         return;
283     container = findBeforeAfterParent(container);
284     if (!container)
285         return;
286     // Sometimes the counter is attached directly on the container.
287     if (container->isCounter()) {
288         toRenderCounter(container)->invalidate(identifier);
289         return;
290     }
291     for (RenderObject* content = container->firstChild(); content; content = content->nextSibling()) {
292         if (content->isCounter())
293             toRenderCounter(content)->invalidate(identifier);
294     }
295 }
296 
invalidateCounters(RenderObject * owner,const AtomicString & identifier)297 void RenderObjectChildList::invalidateCounters(RenderObject* owner, const AtomicString& identifier)
298 {
299     ASSERT(!owner->documentBeingDestroyed());
300     invalidateCountersInContainer(beforeAfterContainer(owner, BEFORE), identifier);
301     invalidateCountersInContainer(beforeAfterContainer(owner, AFTER), identifier);
302 }
303 
updateBeforeAfterContent(RenderObject * owner,PseudoId type,RenderObject * styledObject)304 void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, PseudoId type, RenderObject* styledObject)
305 {
306     // Double check that the document did in fact use generated content rules.  Otherwise we should not have been called.
307     ASSERT(owner->document()->usesBeforeAfterRules());
308 
309     // In CSS2, before/after pseudo-content cannot nest.  Check this first.
310     if (owner->style()->styleType() == BEFORE || owner->style()->styleType() == AFTER)
311         return;
312 
313     if (!styledObject)
314         styledObject = owner;
315 
316     RenderStyle* pseudoElementStyle = styledObject->getCachedPseudoStyle(type);
317     RenderObject* child = beforeAfterContainer(owner, type);
318 
319     // Whether or not we currently have generated content attached.
320     bool oldContentPresent = child;
321 
322     // Whether or not we now want generated content.
323     bool newContentWanted = pseudoElementStyle && pseudoElementStyle->display() != NONE;
324 
325     // For <q><p/></q>, if this object is the inline continuation of the <q>, we only want to generate
326     // :after content and not :before content.
327     if (newContentWanted && type == BEFORE && owner->isRenderInline() && toRenderInline(owner)->isInlineContinuation())
328         newContentWanted = false;
329 
330     // Similarly, if we're the beginning of a <q>, and there's an inline continuation for our object,
331     // then we don't generate the :after content.
332     if (newContentWanted && type == AFTER && owner->isRenderInline() && toRenderInline(owner)->continuation())
333         newContentWanted = false;
334 
335     // If we don't want generated content any longer, or if we have generated content, but it's no longer
336     // identical to the new content data we want to build render objects for, then we nuke all
337     // of the old generated content.
338     if (!newContentWanted || (oldContentPresent && Node::diff(child->style(), pseudoElementStyle) == Node::Detach)) {
339         // Nuke the child.
340         if (child && child->style()->styleType() == type) {
341             oldContentPresent = false;
342             child->destroy();
343             child = (type == BEFORE) ? owner->virtualChildren()->firstChild() : owner->virtualChildren()->lastChild();
344         }
345     }
346 
347     // If we have no pseudo-element style or if the pseudo-element style's display type is NONE, then we
348     // have no generated content and can now return.
349     if (!newContentWanted)
350         return;
351 
352     if (owner->isRenderInline() && !pseudoElementStyle->isDisplayInlineType() && pseudoElementStyle->floating() == FNONE &&
353         !(pseudoElementStyle->position() == AbsolutePosition || pseudoElementStyle->position() == FixedPosition))
354         // According to the CSS2 spec (the end of section 12.1), the only allowed
355         // display values for the pseudo style are NONE and INLINE for inline flows.
356         // FIXME: CSS2.1 lifted this restriction, but block display types will crash.
357         // For now we at least relax the restriction to allow all inline types like inline-block
358         // and inline-table.
359         pseudoElementStyle->setDisplay(INLINE);
360 
361     if (oldContentPresent) {
362         if (child && child->style()->styleType() == type) {
363             // We have generated content present still.  We want to walk this content and update our
364             // style information with the new pseudo-element style.
365             child->setStyle(pseudoElementStyle);
366 
367             RenderObject* beforeAfterParent = findBeforeAfterParent(child);
368             if (!beforeAfterParent)
369                 return;
370 
371             // Note that if we ever support additional types of generated content (which should be way off
372             // in the future), this code will need to be patched.
373             for (RenderObject* genChild = beforeAfterParent->firstChild(); genChild; genChild = genChild->nextSibling()) {
374                 if (genChild->isText())
375                     // Generated text content is a child whose style also needs to be set to the pseudo-element style.
376                     genChild->setStyle(pseudoElementStyle);
377                 else if (genChild->isImage()) {
378                     // Images get an empty style that inherits from the pseudo.
379                     RefPtr<RenderStyle> style = RenderStyle::create();
380                     style->inheritFrom(pseudoElementStyle);
381                     genChild->setStyle(style.release());
382                 } else {
383                     // RenderListItem may insert a list marker here. We do not need to care about this case.
384                     // Otherwise, genChild must be a first-letter container. updateFirstLetter() will take care of it.
385                     ASSERT(genChild->isListMarker() || genChild->style()->styleType() == FIRST_LETTER);
386                 }
387             }
388         }
389         return; // We've updated the generated content. That's all we needed to do.
390     }
391 
392     RenderObject* insertBefore = (type == BEFORE) ? owner->virtualChildren()->firstChild() : 0;
393 
394     // Generated content consists of a single container that houses multiple children (specified
395     // by the content property).  This generated content container gets the pseudo-element style set on it.
396     RenderObject* generatedContentContainer = 0;
397 
398     // Walk our list of generated content and create render objects for each.
399     for (const ContentData* content = pseudoElementStyle->contentData(); content; content = content->next()) {
400         RenderObject* renderer = 0;
401         switch (content->type()) {
402             case CONTENT_NONE:
403                 break;
404             case CONTENT_TEXT:
405                 renderer = new (owner->renderArena()) RenderTextFragment(owner->document() /* anonymous object */, content->text());
406                 renderer->setStyle(pseudoElementStyle);
407                 break;
408             case CONTENT_OBJECT: {
409                 RenderImageGeneratedContent* image = new (owner->renderArena()) RenderImageGeneratedContent(owner->document()); // anonymous object
410                 RefPtr<RenderStyle> style = RenderStyle::create();
411                 style->inheritFrom(pseudoElementStyle);
412                 image->setStyle(style.release());
413                 if (StyleImage* styleImage = content->image())
414                     image->setStyleImage(styleImage);
415                 renderer = image;
416                 break;
417             }
418             case CONTENT_COUNTER:
419                 renderer = new (owner->renderArena()) RenderCounter(owner->document(), *content->counter());
420                 renderer->setStyle(pseudoElementStyle);
421                 break;
422         }
423 
424         if (renderer) {
425             if (!generatedContentContainer) {
426                 // Make a generated box that might be any display type now that we are able to drill down into children
427                 // to find the original content properly.
428                 generatedContentContainer = RenderObject::createObject(owner->document(), pseudoElementStyle);
429                 generatedContentContainer->setStyle(pseudoElementStyle);
430                 owner->addChild(generatedContentContainer, insertBefore);
431             }
432             if (generatedContentContainer->isChildAllowed(renderer, pseudoElementStyle))
433                 generatedContentContainer->addChild(renderer);
434             else
435                 renderer->destroy();
436         }
437     }
438 }
439 
440 } // namespace WebCore
441