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