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