LayoutTests:
[WebKit-https.git] / WebCore / rendering / RenderContainer.cpp
1 /**
2  * This file is part of the html renderer for KDE.
3  *
4  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
6  *           (C) 2000 Dirk Mueller (mueller@kde.org)
7  * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
8  * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net)
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public License
21  * along with this library; see the file COPYING.LIB.  If not, write to
22  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23  * Boston, MA 02111-1307, USA.
24  *
25  */
26
27 #include "config.h"
28 #include "htmlediting.h"
29 #include "RenderContainer.h"
30 #include "RenderListItem.h"
31 #include "RenderTable.h"
32 #include "RenderTextFragment.h"
33 #include "RenderImage.h"
34 #include "RenderView.h"
35 #include "Document.h"
36
37 // For accessibility
38 #include "AccessibilityObjectCache.h" 
39
40 namespace WebCore {
41
42 RenderContainer::RenderContainer(WebCore::Node* node)
43     : RenderBox(node)
44 {
45     m_first = 0;
46     m_last = 0;
47 }
48
49
50 RenderContainer::~RenderContainer()
51 {
52 }
53
54 void RenderContainer::destroy()
55 {
56     destroyLeftoverChildren();
57     RenderBox::destroy();
58 }
59
60 void RenderContainer::destroyLeftoverChildren()
61 {
62     while (m_first) {
63         if (m_first->isListMarker() || (m_first->style()->styleType() == RenderStyle::FIRST_LETTER && !m_first->isText()))
64             m_first->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.
65         else {
66         // 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.
67             if (m_first->element())
68                 m_first->element()->setRenderer(0);
69             m_first->destroy();
70         }
71     }
72 }
73
74 bool RenderContainer::canHaveChildren() const
75 {
76     return true;
77 }
78
79 static void updateListMarkerNumbers(RenderObject* child)
80 {
81     for (RenderObject* r = child; r; r = r->nextSibling()) {
82         if (r->isListItem())
83             static_cast<RenderListItem*>(r)->resetValue();
84     }
85 }
86
87 void RenderContainer::addChild(RenderObject* newChild, RenderObject* beforeChild)
88 {
89     bool needsTable = false;
90
91     if(!newChild->isText() && !newChild->isReplaced()) {
92         switch(newChild->style()->display()) {
93         case LIST_ITEM:
94             updateListMarkerNumbers(beforeChild ? beforeChild : lastChild());
95             break;
96         case INLINE:
97         case BLOCK:
98         case INLINE_BLOCK:
99         case RUN_IN:
100         case COMPACT:
101         case BOX:
102         case INLINE_BOX:
103         case TABLE:
104         case INLINE_TABLE:
105         case TABLE_COLUMN:
106             break;
107         case TABLE_COLUMN_GROUP:
108         case TABLE_CAPTION:
109         case TABLE_ROW_GROUP:
110         case TABLE_HEADER_GROUP:
111         case TABLE_FOOTER_GROUP:
112             if (!isTable())
113                 needsTable = true;
114             break;
115         case TABLE_ROW:
116             if (!isTableSection())
117                 needsTable = true;
118             break;
119         case TABLE_CELL:
120             if (!isTableRow())
121                 needsTable = true;
122             // I'm not 100% sure this is the best way to fix this, but without this
123             // change we recurse infinitely when trying to render the CSS2 test page:
124             // http://www.bath.ac.uk/%7Epy8ieh/internet/eviltests/htmlbodyheadrendering2.html.
125             // See Radar 2925291.
126             if (isTableCell() && !firstChild() && !newChild->isTableCell())
127                 needsTable = false;
128             break;
129         case NONE:
130             break;
131         }
132     }
133
134     if (needsTable) {
135         RenderTable *table;
136         if(!beforeChild)
137             beforeChild = lastChild();
138         if(beforeChild && beforeChild->isAnonymous() && beforeChild->isTable())
139             table = static_cast<RenderTable*>(beforeChild);
140         else {
141             table = new (renderArena()) RenderTable(document() /* is anonymous */);
142             RenderStyle *newStyle = new (renderArena()) RenderStyle();
143             newStyle->inheritFrom(style());
144             newStyle->setDisplay(TABLE);
145             table->setStyle(newStyle);
146             addChild(table, beforeChild);
147         }
148         table->addChild(newChild);
149     } else {
150         // just add it...
151         insertChildNode(newChild, beforeChild);
152     }
153     
154     if (newChild->isText() && newChild->style()->textTransform() == CAPITALIZE) {
155         RefPtr<StringImpl> textToTransform =  static_cast<RenderText*>(newChild)->originalString();
156         if (textToTransform)
157             static_cast<RenderText*>(newChild)->setText(textToTransform.get(), true);
158     }
159 }
160
161 RenderObject* RenderContainer::removeChildNode(RenderObject* oldChild)
162 {
163     KHTMLAssert(oldChild->parent() == this);
164
165     // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or
166     // that a positioned child got yanked).  We also repaint, so that the area exposed when the child
167     // disappears gets repainted properly.
168     if (!documentBeingDestroyed()) {
169         oldChild->setNeedsLayoutAndMinMaxRecalc();
170         oldChild->repaint();
171         
172         // Keep our layer hierarchy updated.
173         oldChild->removeLayers(enclosingLayer());
174         
175         // If oldChild is the start or end of the selection, then clear the selection to
176         // avoid problems of invalid pointers.
177         // FIXME: The SelectionController should be responsible for this when it
178         // is notified of DOM mutations.
179         if (oldChild->isSelectionBorder())
180             view()->clearSelection();
181
182         // renumber ordered lists
183         if (oldChild->isListItem())
184             updateListMarkerNumbers(oldChild->nextSibling());
185         
186         if (oldChild->isPositioned() && childrenInline())
187             dirtyLinesFromChangedChild(oldChild);
188     }
189     
190     // remove the child
191     if (oldChild->previousSibling())
192         oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
193     if (oldChild->nextSibling())
194         oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
195
196     if (m_first == oldChild)
197         m_first = oldChild->nextSibling();
198     if (m_last == oldChild)
199         m_last = oldChild->previousSibling();
200
201     oldChild->setPreviousSibling(0);
202     oldChild->setNextSibling(0);
203     oldChild->setParent(0);
204
205     if (AccessibilityObjectCache::accessibilityEnabled())
206         document()->getAccObjectCache()->childrenChanged(this);
207
208     return oldChild;
209 }
210
211 void RenderContainer::removeChild(RenderObject* oldChild)
212 {
213     removeChildNode(oldChild);
214 }
215
216 void RenderContainer::updatePseudoChild(RenderStyle::PseudoId type, RenderObject* child)
217 {
218     // In CSS2, before/after pseudo-content cannot nest.  Check this first.
219     if (style()->styleType() == RenderStyle::BEFORE || style()->styleType() == RenderStyle::AFTER)
220         return;
221     
222     RenderStyle* pseudo = getPseudoStyle(type);
223
224     // Whether or not we currently have generated content attached.
225     bool oldContentPresent = child && (child->style()->styleType() == type);
226
227     // Whether or not we now want generated content.  
228     bool newContentWanted = pseudo && pseudo->display() != NONE;
229
230     // For <q><p/></q>, if this object is the inline continuation of the <q>, we only want to generate
231     // :after content and not :before content.
232     if (newContentWanted && type == RenderStyle::BEFORE && isInlineContinuation())
233         newContentWanted = false;
234
235     // Similarly, if we're the beginning of a <q>, and there's an inline continuation for our object,
236     // then we don't generate the :after content.
237     if (newContentWanted && type == RenderStyle::AFTER && isRenderInline() && continuation())
238         newContentWanted = false;
239     
240     // If we don't want generated content any longer, or if we have generated content, but it's no longer
241     // identical to the new content data we want to build render objects for, then we nuke all
242     // of the old generated content.
243     if (!newContentWanted ||
244         (oldContentPresent && !child->style()->contentDataEquivalent(pseudo))) {
245         // Nuke the child. 
246         if (child && child->style()->styleType() == type) {
247             oldContentPresent = false;
248             child->destroy();
249             child = (type == RenderStyle::BEFORE) ? firstChild() : lastChild();
250         }
251     }
252
253     // If we have no pseudo-style or if the pseudo's display type is NONE, then we
254     // have no generated content and can now return.
255     if (!newContentWanted)
256         return;
257
258     if (isInlineFlow() && pseudo->display() != INLINE)
259         // According to the CSS2 spec (the end of section 12.1), the only allowed
260         // display values for the pseudo style are NONE and INLINE.  Since we already
261         // determined that the pseudo is not display NONE, any display other than
262         // inline should be mutated to INLINE.
263         pseudo->setDisplay(INLINE);
264     
265     if (oldContentPresent) {
266         if (child && child->style()->styleType() == type) {
267             // We have generated content present still.  We want to walk this content and update our
268             // style information with the new pseudo style.
269             child->setStyle(pseudo);
270
271             // Note that if we ever support additional types of generated content (which should be way off
272             // in the future), this code will need to be patched.
273             for (RenderObject* genChild = child->firstChild(); genChild; genChild = genChild->nextSibling()) {
274                 if (genChild->isText())
275                     // Generated text content is a child whose style also needs to be set to the pseudo
276                     // style.
277                     genChild->setStyle(pseudo);
278                 else {
279                     // Images get an empty style that inherits from the pseudo.
280                     RenderStyle* style = new (renderArena()) RenderStyle();
281                     style->inheritFrom(pseudo);
282                     genChild->setStyle(style);
283                 }
284             }
285         }
286         return; // We've updated the generated content. That's all we needed to do.
287     }
288     
289     RenderObject* insertBefore = (type == RenderStyle::BEFORE) ? child : 0;
290
291     // Generated content consists of a single container that houses multiple children (specified
292     // by the content property).  This pseudo container gets the pseudo style set on it.
293     RenderObject* pseudoContainer = 0;
294     
295     // Now walk our list of generated content and create render objects for every type
296     // we encounter.
297     for (ContentData* contentData = pseudo->contentData();
298          contentData; contentData = contentData->_nextContent) {
299         if (!pseudoContainer)
300             pseudoContainer = RenderFlow::createAnonymousFlow(document(), pseudo); /* anonymous box */
301         
302         if (contentData->contentType() == CONTENT_TEXT)
303         {
304             RenderText* t = new (renderArena()) RenderTextFragment(document() /*anonymous object */, contentData->contentText());
305             t->setStyle(pseudo);
306             pseudoContainer->addChild(t);
307         }
308         else if (contentData->contentType() == CONTENT_OBJECT)
309         {
310             RenderImage* img = new (renderArena()) RenderImage(document()); /* Anonymous object */
311             RenderStyle* style = new (renderArena()) RenderStyle();
312             style->inheritFrom(pseudo);
313             img->setStyle(style);
314             img->setContentObject(contentData->contentObject());
315             pseudoContainer->addChild(img);
316         }
317     }
318
319     if (pseudoContainer) {
320         // Add the pseudo after we've installed all our content, so that addChild will be able to find the text
321         // inside the inline for e.g., first-letter styling.
322         addChild(pseudoContainer, insertBefore);
323     }
324 }
325
326
327 void RenderContainer::appendChildNode(RenderObject* newChild)
328 {
329     KHTMLAssert(newChild->parent() == 0);
330     KHTMLAssert(!isBlockFlow() || (!newChild->isTableSection() && !newChild->isTableRow() && !newChild->isTableCell()));
331
332     newChild->setParent(this);
333     RenderObject* lChild = lastChild();
334
335     if(lChild)
336     {
337         newChild->setPreviousSibling(lChild);
338         lChild->setNextSibling(newChild);
339     }
340     else
341         setFirstChild(newChild);
342
343     setLastChild(newChild);
344     
345     // Keep our layer hierarchy updated.  Optimize for the common case where we don't have any children
346     // and don't have a layer attached to ourselves.
347     if (newChild->firstChild() || newChild->layer()) {
348         RenderLayer* layer = enclosingLayer();
349         newChild->addLayers(layer, newChild);
350     }
351     
352     newChild->setNeedsLayoutAndMinMaxRecalc(); // Goes up the containing block hierarchy.
353     if (!normalChildNeedsLayout())
354         setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
355     
356     if (!newChild->isFloatingOrPositioned() && childrenInline())
357         dirtyLinesFromChangedChild(newChild);
358     
359     if (AccessibilityObjectCache::accessibilityEnabled())
360         document()->getAccObjectCache()->childrenChanged(this);
361 }
362
363 void RenderContainer::insertChildNode(RenderObject* child, RenderObject* beforeChild)
364 {
365     if(!beforeChild) {
366         appendChildNode(child);
367         return;
368     }
369
370     KHTMLAssert(!child->parent());
371     while ( beforeChild->parent() != this && beforeChild->parent()->isAnonymousBlock() )
372         beforeChild = beforeChild->parent();
373     KHTMLAssert(beforeChild->parent() == this);
374
375     KHTMLAssert(!isBlockFlow() || (!child->isTableSection() && !child->isTableRow() && !child->isTableCell()));
376
377     if(beforeChild == firstChild())
378         setFirstChild(child);
379
380     RenderObject* prev = beforeChild->previousSibling();
381     child->setNextSibling(beforeChild);
382     beforeChild->setPreviousSibling(child);
383     if(prev) prev->setNextSibling(child);
384     child->setPreviousSibling(prev);
385
386     child->setParent(this);
387     
388     // Keep our layer hierarchy updated.
389     RenderLayer* layer = enclosingLayer();
390     child->addLayers(layer, child);
391
392     child->setNeedsLayoutAndMinMaxRecalc();
393     if (!normalChildNeedsLayout())
394         setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
395     
396     if (!child->isFloating() && childrenInline())
397         dirtyLinesFromChangedChild(child);
398     
399     if (AccessibilityObjectCache::accessibilityEnabled())
400         document()->getAccObjectCache()->childrenChanged(this);
401 }
402
403 void RenderContainer::layout()
404 {
405     KHTMLAssert( needsLayout() );
406     KHTMLAssert( minMaxKnown() );
407
408     RenderObject* child = firstChild();
409     while( child ) {
410         child->layoutIfNeeded();
411         child = child->nextSibling();
412     }
413     setNeedsLayout(false);
414 }
415
416 void RenderContainer::removeLeftoverAnonymousBoxes()
417 {
418     // we have to go over all child nodes and remove anonymous boxes, that do _not_
419     // have inline children to keep the tree flat
420     RenderObject* child = firstChild();
421     while( child ) {
422         RenderObject* next = child->nextSibling();
423         
424         if ( child->isRenderBlock() && child->isAnonymousBlock() && !child->continuation() && !child->childrenInline() && !child->isTableCell() ) {
425             RenderObject* firstAnChild = child->firstChild();
426             RenderObject* lastAnChild = child->lastChild();
427             if ( firstAnChild ) {
428                 RenderObject* o = firstAnChild;
429                 while( o ) {
430                     o->setParent( this );
431                     o = o->nextSibling();
432                 }
433                 firstAnChild->setPreviousSibling( child->previousSibling() );
434                 lastAnChild->setNextSibling( child->nextSibling() );
435                 if ( child->previousSibling() )
436                     child->previousSibling()->setNextSibling( firstAnChild );
437                 if ( child->nextSibling() )
438                     child->nextSibling()->setPreviousSibling( lastAnChild );
439             } else {
440                 if ( child->previousSibling() )
441                     child->previousSibling()->setNextSibling( child->nextSibling() );
442                 if ( child->nextSibling() )
443                     child->nextSibling()->setPreviousSibling( child->previousSibling() );
444                 
445             }
446             if ( child == firstChild() )
447                 m_first = firstAnChild;
448             if ( child == lastChild() )
449                 m_last = lastAnChild;
450             child->setParent( 0 );
451             child->setPreviousSibling( 0 );
452             child->setNextSibling( 0 );
453             if ( !child->isText() ) {
454                 RenderContainer *c = static_cast<RenderContainer*>(child);
455                 c->m_first = 0;
456                 c->m_next = 0;
457             }
458             child->destroy();
459         }
460         child = next;
461     }
462
463     if (parent()) // && isAnonymousBlock() && !continuation() && !childrenInline() && !isTableCell())
464         parent()->removeLeftoverAnonymousBoxes();
465 }
466
467 VisiblePosition RenderContainer::positionForCoordinates(int x, int y)
468 {
469     // no children...return this render object's element, if there is one, and offset 0
470     if (!firstChild())
471         return VisiblePosition(element(), 0, DOWNSTREAM);
472         
473     if (isTable()) {
474         int absx, absy;
475         absolutePositionForContent(absx, absy);
476         
477         int left = absx;
478         int right = left + contentWidth() + borderRight() + paddingRight() + borderLeft() + paddingLeft();
479         int top = absy;
480         int bottom = top + contentHeight() + borderTop() + paddingTop() + borderBottom() + paddingBottom();
481         
482         if (x < left || x > right || y < top || y > bottom) {
483             if (x <= (left + right) / 2)
484                 return VisiblePosition(Position(element(), 0));
485             else
486                 return VisiblePosition(Position(element(), maxDeepOffset(element())));
487         }
488     }
489
490     // Pass off to the closest child.
491     int minDist = INT_MAX;
492     RenderObject* closestRenderer = 0;
493     for (RenderObject* renderer = firstChild(); renderer; renderer = renderer->nextSibling()) {
494         if (!renderer->firstChild() && !renderer->isInline() && !renderer->isBlockFlow() 
495             || renderer->height() == 0 || renderer->style()->visibility() != VISIBLE)
496             continue;
497
498         int absx, absy;
499         renderer->absolutePositionForContent(absx, absy);
500         
501         int top = absy + borderTop() + paddingTop();
502         int bottom = top + renderer->contentHeight();
503         int left = absx + borderLeft() + paddingLeft();
504         int right = left + renderer->contentWidth();
505         
506         if (x <= right && x >= left && y <= top && y >= bottom)
507             return renderer->positionForCoordinates(x, y);
508         
509         // Find the distance from (x, y) to the box.  Split the space around the box into 8 pieces
510         // and use a different compare depending on which piece (x, y) is in.
511         IntPoint cmp;
512         if (x > right) {
513             if (y < top)
514                 cmp = IntPoint(right, top);
515             else if (y > bottom)
516                 cmp = IntPoint(right, bottom);
517             else
518                 cmp = IntPoint(right, y);
519         } else if (x < left) {
520             if (y < top)
521                 cmp = IntPoint(left, top);
522             else if (y > bottom)
523                 cmp = IntPoint(left, bottom);
524             else
525                 cmp = IntPoint(left, y);
526         } else {
527             if (y < top)
528                 cmp = IntPoint(x, top);
529             else
530                 cmp = IntPoint(x, bottom);
531         }
532         
533         int x1minusx2 = cmp.x() - x;
534         int y1minusy2 = cmp.y() - y;
535         
536         int dist = x1minusx2 * x1minusx2 + y1minusy2 * y1minusy2;
537         if (dist < minDist) {
538             closestRenderer = renderer;
539             minDist = dist;
540         }
541     }
542     
543     if (closestRenderer)
544         return closestRenderer->positionForCoordinates(x, y);
545     
546     return VisiblePosition(element(), 0, DOWNSTREAM);
547 }
548
549 DeprecatedValueList<IntRect> RenderContainer::lineBoxRects()
550 {
551     if (!firstChild() && (isInline() || isAnonymousBlock())) {
552         DeprecatedValueList<IntRect> rects;
553         int x = 0, y = 0;
554         absolutePositionForContent(x, y);
555         absoluteRects(rects, x, y);
556         return rects;
557     }
558
559     if (!firstChild())
560         return DeprecatedValueList<IntRect>();
561
562     DeprecatedValueList<IntRect> rects;
563     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
564         if (child->isText() || child->isInline() || child->isAnonymousBlock()) {
565             int x = 0, y = 0;
566             child->absolutePositionForContent(x, y);
567             child->absoluteRects(rects, x, y);
568         }
569     }
570
571     return rects;
572 }
573
574 #undef DEBUG_LAYOUT
575
576 }