LayoutTests:
[WebKit-https.git] / WebCore / rendering / RenderTable.cpp
1 /**
2  * Copyright (C) 1997 Martin Jones (mjones@kde.org)
3  *           (C) 1997 Torben Weis (weis@kde.org)
4  *           (C) 1998 Waldo Bastian (bastian@kde.org)
5  *           (C) 1999 Lars Knoll (knoll@kde.org)
6  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
7  * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
8  * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
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 #include "config.h"
27 #include "RenderTable.h"
28
29 #include "AutoTableLayout.h"
30 #include "DeleteButtonController.h"
31 #include "Document.h"
32 #include "FixedTableLayout.h"
33 #include "FrameView.h"
34 #include "HTMLNames.h"
35 #include "RenderTableCell.h"
36 #include "RenderTableCol.h"
37 #include "RenderTableSection.h"
38 #include "RenderView.h"
39 #include "TextStream.h"
40
41 using namespace std;
42
43 namespace WebCore {
44
45 using namespace HTMLNames;
46
47 RenderTable::RenderTable(Node* node)
48     : RenderBlock(node)
49     , m_caption(0)
50     , m_head(0)
51     , m_foot(0)
52     , m_firstBody(0)
53     , m_tableLayout(0)
54     , m_currentBorder(0)
55     , m_frame(Void)
56     , m_rules(None)
57     , m_hasColElements(false)
58     , m_padding(0)
59     , m_needsSectionRecalc(0)
60     , m_hSpacing(0)
61     , m_vSpacing(0)
62     , m_borderLeft(0)
63     , m_borderRight(0)
64 {
65     m_columnPos.fill(0, 2);
66     m_columns.fill(ColumnStruct(), 1);
67 }
68
69 RenderTable::~RenderTable()
70 {
71     delete m_tableLayout;
72 }
73
74 void RenderTable::setStyle(RenderStyle* newStyle)
75 {
76     ETableLayout oldTableLayout = style() ? style()->tableLayout() : TAUTO;
77     RenderBlock::setStyle(newStyle);
78
79     // In the collapsed border model, there is no cell spacing.
80     m_hSpacing = collapseBorders() ? 0 : style()->horizontalBorderSpacing();
81     m_vSpacing = collapseBorders() ? 0 : style()->verticalBorderSpacing();
82     m_columnPos[0] = m_hSpacing;
83
84     if (!m_tableLayout || style()->tableLayout() != oldTableLayout) {
85         delete m_tableLayout;
86
87         // According to the CSS2 spec, you only use fixed table layout if an
88         // explicit width is specified on the table.  Auto width implies auto table layout.
89         if (style()->tableLayout() == TFIXED && !style()->width().isAuto())
90             m_tableLayout = new FixedTableLayout(this);
91         else
92             m_tableLayout = new AutoTableLayout(this);
93     }
94 }
95
96 static inline void resetSectionPointerIfNotBefore(RenderTableSection*& ptr, RenderObject* before)
97 {
98     if (!before || !ptr)
99         return;
100     RenderObject* o = before->previousSibling();
101     while (o && o != ptr)
102         o = o->previousSibling();
103     if (!o)
104         ptr = 0;
105 }
106
107 void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild)
108 {
109     bool wrapInAnonymousSection = true;
110     bool isTableElement = element() && element()->hasTagName(tableTag);
111
112     switch (child->style()->display()) {
113         case TABLE_CAPTION:
114             if (child->isRenderBlock()) {
115                 // First caption wins.
116                 if (beforeChild && m_caption) {
117                     RenderObject* o = beforeChild->previousSibling();
118                     while (o && o != m_caption)
119                         o = o->previousSibling();
120                     if (!o)
121                         m_caption = 0;
122                 }
123                 if (!m_caption)
124                     m_caption = static_cast<RenderBlock*>(child);
125             }
126             wrapInAnonymousSection = false;
127             break;
128         case TABLE_COLUMN:
129         case TABLE_COLUMN_GROUP:
130             m_hasColElements = true;
131             wrapInAnonymousSection = false;
132             break;
133         case TABLE_HEADER_GROUP:
134             if (child->isTableSection()) {
135                 resetSectionPointerIfNotBefore(m_head, beforeChild);
136                 if (!m_head) {
137                     m_head = static_cast<RenderTableSection*>(child);
138                 } else {
139                     resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
140                     if (!m_firstBody) 
141                         m_firstBody = static_cast<RenderTableSection*>(child);
142                 }
143             }
144             wrapInAnonymousSection = false;
145             break;
146         case TABLE_FOOTER_GROUP:
147             if (child->isTableSection()) {
148                 resetSectionPointerIfNotBefore(m_foot, beforeChild);
149                 if (!m_foot) {
150                     m_foot = static_cast<RenderTableSection*>(child);
151                     wrapInAnonymousSection = false;
152                     break;
153                 }
154             }
155             // Fall through.
156         case TABLE_ROW_GROUP:
157             if (child->isTableSection()) {
158                 resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
159                 if (!m_firstBody)
160                     m_firstBody = static_cast<RenderTableSection*>(child);
161             }
162             wrapInAnonymousSection = false;
163             break;
164         case TABLE_CELL:
165         case TABLE_ROW:
166             wrapInAnonymousSection = true;
167             break;
168         case BLOCK:
169         case BOX:
170         case COMPACT:
171         case INLINE:
172         case INLINE_BLOCK:
173         case INLINE_BOX:
174         case INLINE_TABLE:
175         case LIST_ITEM:
176         case NONE:
177         case RUN_IN:
178         case TABLE:
179             // Allow a form to just sit at the top level.
180             wrapInAnonymousSection = !isTableElement || !child->element() || !(child->element()->hasTagName(formTag) && document()->isHTMLDocument());
181
182             // FIXME: Allow the delete button container element to sit at the top level. This is needed until http://bugs.webkit.org/show_bug.cgi?id=11363 is fixed.
183             if (wrapInAnonymousSection && child->element() && child->element()->isHTMLElement() && static_cast<HTMLElement*>(child->element())->id() == DeleteButtonController::containerElementIdentifier)
184                 wrapInAnonymousSection = false;
185             break;
186         }
187
188     if (!wrapInAnonymousSection) {
189         // If the next renderer is actually wrapped in an anonymous table section, we need to go up and find that.
190         while (beforeChild && !beforeChild->isTableSection() && !beforeChild->isTableCol())
191             beforeChild = beforeChild->parent();
192
193         RenderContainer::addChild(child, beforeChild);
194         return;
195     }
196
197     if (!beforeChild && lastChild() && lastChild()->isTableSection() && lastChild()->isAnonymous()) {
198         lastChild()->addChild(child);
199         return;
200     }
201
202     RenderObject* lastBox = beforeChild;
203     RenderObject* nextToLastBox = beforeChild;
204     while (lastBox && lastBox->parent()->isAnonymous() && !lastBox->isTableSection() && lastBox->style()->display() != TABLE_CAPTION) {
205         nextToLastBox = lastBox;
206         lastBox = lastBox->parent();
207     }
208     if (lastBox && lastBox->isAnonymous()) {
209         lastBox->addChild(child, nextToLastBox);
210         return;
211     }
212
213     if (beforeChild && !beforeChild->isTableSection())
214         beforeChild = 0;
215     RenderTableSection* section = new (renderArena()) RenderTableSection(document() /* anonymous */);
216     RenderStyle* newStyle = new (renderArena()) RenderStyle();
217     newStyle->inheritFrom(style());
218     newStyle->setDisplay(TABLE_ROW_GROUP);
219     section->setStyle(newStyle);
220     addChild(section, beforeChild);
221     section->addChild(child);
222 }
223
224 void RenderTable::calcWidth()
225 {
226     if (isPositioned())
227         calcAbsoluteHorizontal();
228
229     RenderBlock* cb = containingBlock();
230     int availableWidth = cb->availableWidth();
231
232     LengthType widthType = style()->width().type();
233     if (widthType > Relative && style()->width().isPositive()) {
234         // Percent or fixed table
235         m_width = style()->width().calcMinValue(availableWidth);
236         if (m_minWidth > m_width)
237             m_width = m_minWidth;
238     } else {
239         // An auto width table should shrink to fit within the line width if necessary in order to 
240         // avoid overlapping floats.
241         availableWidth = cb->lineWidth(m_y);
242         
243         // Subtract out any fixed margins from our available width for auto width tables.
244         int marginTotal = 0;
245         if (!style()->marginLeft().isAuto())
246             marginTotal += style()->marginLeft().calcValue(availableWidth);
247         if (!style()->marginRight().isAuto())
248             marginTotal += style()->marginRight().calcValue(availableWidth);
249             
250         // Subtract out our margins to get the available content width.
251         int availContentWidth = max(0, availableWidth - marginTotal);
252         
253         // Ensure we aren't bigger than our max width or smaller than our min width.
254         m_width = min(availContentWidth, m_maxWidth);
255     }
256     
257     m_width = max(m_width, m_minWidth);
258
259     // Finally, with our true width determined, compute our margins for real.
260     m_marginRight = 0;
261     m_marginLeft = 0;
262     calcHorizontalMargins(style()->marginLeft(), style()->marginRight(), availableWidth);
263 }
264
265 void RenderTable::layout()
266 {
267     ASSERT(needsLayout());
268     ASSERT(minMaxKnown());
269     ASSERT(!m_needsSectionRecalc);
270
271     if (posChildNeedsLayout() && !normalChildNeedsLayout() && !selfNeedsLayout()) {
272         // All we have to do is lay out our positioned objects.
273         layoutPositionedObjects(false);
274         setNeedsLayout(false);
275         return;
276     }
277
278     IntRect oldBounds;
279     bool checkForRepaint = checkForRepaintDuringLayout();
280     if (checkForRepaint) {
281         oldBounds = getAbsoluteRepaintRect();
282         oldBounds.move(view()->layoutDelta());
283     }
284     
285     m_height = 0;
286     m_overflowHeight = 0;
287     m_overflowTop = 0;
288     initMaxMarginValues();
289     
290     //int oldWidth = m_width;
291     calcWidth();
292
293     // FIXME: The optimisation below doesn't work since the internal table
294     // layout could have changed.  we need to add a flag to the table
295     // layout that tells us if something has changed in the min max
296     // calculations to do it correctly.
297 //     if ( oldWidth != m_width || columns.size() + 1 != columnPos.size() )
298     m_tableLayout->layout();
299
300     setCellWidths();
301
302     // layout child objects
303     int calculatedHeight = 0;
304     int oldTableTop = m_caption ? m_caption->height() + m_caption->marginTop() + m_caption->marginBottom() : 0;
305
306     RenderObject* child = firstChild();
307     while (child) {
308         // FIXME: What about a form that has a display value that makes it a table section?
309         if (child->needsLayout() && !(child->element() && child->element()->hasTagName(formTag)))
310             child->layout();
311         if (child->isTableSection()) {
312             static_cast<RenderTableSection*>(child)->calcRowHeight();
313             calculatedHeight += static_cast<RenderTableSection*>(child)->layoutRows(0);
314         }
315         child = child->nextSibling();
316     }
317
318     m_overflowWidth = m_width + (collapseBorders() ? outerBorderRight() - borderRight() : 0);
319     m_overflowLeft = collapseBorders() ? borderLeft() - outerBorderLeft() : 0;
320
321     // If any table section moved vertically, we will just repaint everything from that
322     // section down (it is quite unlikely that any of the following sections
323     // did not shift).
324     bool sectionMoved = false;
325     int movedSectionTop = 0;
326
327     // FIXME: Collapse caption margin.
328     if (m_caption && m_caption->style()->captionSide() != CAPBOTTOM) {
329         IntRect captionRect(m_caption->xPos(), m_caption->yPos(), m_caption->width(), m_caption->height());
330
331         m_caption->setPos(m_caption->marginLeft(), m_height);
332         if (!selfNeedsLayout() && m_caption->checkForRepaintDuringLayout())
333             m_caption->repaintDuringLayoutIfMoved(captionRect);
334
335         m_height += m_caption->height() + m_caption->marginTop() + m_caption->marginBottom();
336         m_overflowLeft = min(m_overflowLeft, m_caption->xPos() + m_caption->overflowLeft(false));
337         m_overflowWidth = max(m_overflowWidth, m_caption->xPos() + m_caption->overflowWidth(false));
338         m_overflowTop = min(m_overflowTop, m_caption->yPos() + m_caption->overflowTop(false));
339         m_overflowHeight = max(m_overflowHeight, m_caption->yPos() + m_caption->overflowHeight(false));
340
341         if (m_height != oldTableTop) {
342             sectionMoved = true;
343             movedSectionTop = min(m_height, oldTableTop);
344         }
345     }
346
347     int bpTop = borderTop() + (collapseBorders() ? 0 : paddingTop());
348     int bpBottom = borderBottom() + (collapseBorders() ? 0 : paddingBottom());
349     
350     m_height += bpTop;
351
352     int oldHeight = m_height;
353     if (!isPositioned())
354         calcHeight();
355     m_height = oldHeight;
356
357     Length h = style()->height();
358     int th = 0;
359     if (h.isFixed())
360         // Tables size as though CSS height includes border/padding.
361         th = h.value() - (bpTop + bpBottom);
362     else if (h.isPercent())
363         th = calcPercentageHeight(h);
364     th = max(0, th);
365
366     // layout rows
367     if (th > calculatedHeight) {
368         // we have to redistribute that height to get the constraint correctly
369         // just force the first body to the height needed
370         // FIXME: This should take height constraints on all table sections into account and distribute
371         // accordingly. For now this should be good enough.
372         if (m_firstBody) {
373             m_firstBody->calcRowHeight();
374             m_firstBody->layoutRows(th - calculatedHeight);
375         } else if (!style()->htmlHacks())
376             // Completely empty tables (with no sections or anything) should at least honor specified height
377             // in strict mode.
378             m_height += th;
379     }
380     
381     int bl = borderLeft();
382     if (!collapseBorders())
383         bl += paddingLeft();
384
385     // position the table sections
386     RenderTableSection* section = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot);
387     while (section) {
388         if (!sectionMoved && section->yPos() != m_height) {
389             sectionMoved = true;
390             movedSectionTop = min(m_height, section->yPos()) + section->overflowTop(false);
391         }
392         section->setPos(bl, m_height);
393
394         m_height += section->height();
395         m_overflowLeft = min(m_overflowLeft, section->xPos() + section->overflowLeft(false));
396         m_overflowWidth = max(m_overflowWidth, section->xPos() + section->overflowWidth(false));
397         m_overflowTop = min(m_overflowTop, section->yPos() + section->overflowTop(false));
398         m_overflowHeight = max(m_overflowHeight, section->yPos() + section->overflowHeight(false));
399         section = sectionBelow(section);
400     }
401
402     m_height += bpBottom;
403
404     if (m_caption && m_caption->style()->captionSide() == CAPBOTTOM) {
405         IntRect captionRect(m_caption->xPos(), m_caption->yPos(), m_caption->width(), m_caption->height());
406
407         m_caption->setPos(m_caption->marginLeft(), m_height);
408         if (!selfNeedsLayout() && m_caption->checkForRepaintDuringLayout())
409             m_caption->repaintDuringLayoutIfMoved(captionRect);
410
411         m_height += m_caption->height() + m_caption->marginTop() + m_caption->marginBottom();
412         m_overflowLeft = min(m_overflowLeft, m_caption->xPos() + m_caption->overflowLeft(false));
413         m_overflowWidth = max(m_overflowWidth, m_caption->xPos() + m_caption->overflowWidth(false));
414     }
415
416     if (isPositioned())
417         calcHeight();
418
419     m_overflowHeight = max(m_overflowHeight, m_height);
420
421     // table can be containing block of positioned elements.
422     // FIXME: Only pass true if width or height changed.
423     layoutPositionedObjects(true);
424
425     bool didFullRepaint = true;
426     // Repaint with our new bounds if they are different from our old bounds.
427     if (checkForRepaint)
428         didFullRepaint = repaintAfterLayoutIfNeeded(oldBounds);
429     if (!didFullRepaint && sectionMoved) {
430         IntRect repaintRect(m_overflowLeft, movedSectionTop, m_overflowWidth - m_overflowLeft, m_overflowHeight - movedSectionTop);
431         if (FrameView* frameView = view()->frameView())
432             frameView->addRepaintInfo(this, repaintRect);
433     }
434     
435     setNeedsLayout(false);
436 }
437
438 void RenderTable::setCellWidths()
439 {
440     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
441         if (child->isTableSection())
442             static_cast<RenderTableSection*>(child)->setCellWidths();
443     }
444 }
445
446 void RenderTable::paint(PaintInfo& paintInfo, int tx, int ty)
447 {
448     tx += xPos();
449     ty += yPos();
450
451     PaintPhase paintPhase = paintInfo.phase;
452
453     int os = 2 * maximalOutlineSize(paintPhase);
454     if (ty + overflowTop(false) >= paintInfo.rect.bottom() + os || ty + overflowHeight(false) <= paintInfo.rect.y() - os)
455         return;
456     if (tx + overflowLeft(false) >= paintInfo.rect.right() + os || tx + overflowWidth(false) <= paintInfo.rect.x() - os)
457         return;
458
459     if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && hasBoxDecorations() && style()->visibility() == VISIBLE)
460         paintBoxDecorations(paintInfo, tx, ty);
461
462     // We're done.  We don't bother painting any children.
463     if (paintPhase == PaintPhaseBlockBackground)
464         return;
465
466     // We don't paint our own background, but we do let the kids paint their backgrounds.
467     if (paintPhase == PaintPhaseChildBlockBackgrounds)
468         paintPhase = PaintPhaseChildBlockBackground;
469     PaintInfo info(paintInfo);
470     info.phase = paintPhase;
471     info.paintingRoot = paintingRootForChildren(paintInfo);
472
473     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
474         if (!child->layer() && (child->isTableSection() || child == m_caption))
475             child->paint(info, tx, ty);
476     }
477
478     if (collapseBorders() && paintPhase == PaintPhaseChildBlockBackground && style()->visibility() == VISIBLE) {
479         // Collect all the unique border styles that we want to paint in a sorted list.  Once we
480         // have all the styles sorted, we then do individual passes, painting each style of border
481         // from lowest precedence to highest precedence.
482         info.phase = PaintPhaseCollapsedTableBorders;
483         RenderTableCell::CollapsedBorderStyles borderStyles;
484         RenderObject* stop = nextInPreOrderAfterChildren();
485         for (RenderObject* o = firstChild(); o && o != stop; o = o->nextInPreOrder())
486             if (o->isTableCell())
487                 static_cast<RenderTableCell*>(o)->collectBorderStyles(borderStyles);
488         RenderTableCell::sortBorderStyles(borderStyles);
489         size_t count = borderStyles.size();
490         for (size_t i = 0; i < count; ++i) {
491             m_currentBorder = &borderStyles[i];
492             for (RenderObject* child = firstChild(); child; child = child->nextSibling())
493                 if (child->isTableSection())
494                     child->paint(info, tx, ty);
495         }
496         m_currentBorder = 0;
497     }
498 }
499
500 void RenderTable::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
501 {
502     int w = width();
503     int h = height();
504
505     // Account for the caption.
506     if (m_caption) {
507         int captionHeight = (m_caption->height() + m_caption->marginBottom() +  m_caption->marginTop());
508         h -= captionHeight;
509         if (m_caption->style()->captionSide() != CAPBOTTOM)
510             ty += captionHeight;
511     }
512
513     int my = max(ty, paintInfo.rect.y());
514     int mh;
515     if (ty < paintInfo.rect.y())
516         mh = max(0, h - (paintInfo.rect.y() - ty));
517     else
518         mh = min(paintInfo.rect.height(), h);
519
520     paintBoxShadow(paintInfo.context, tx, ty, w, h, style());
521     
522     paintBackground(paintInfo.context, style()->backgroundColor(), style()->backgroundLayers(), my, mh, tx, ty, w, h);
523
524     if (style()->hasBorder() && !collapseBorders())
525         paintBorder(paintInfo.context, tx, ty, w, h, style());
526 }
527
528 void RenderTable::calcMinMaxWidth()
529 {
530     ASSERT(!minMaxKnown());
531
532     recalcSectionsIfNeeded();
533     recalcHorizontalBorders();
534
535     m_tableLayout->calcMinMaxWidth(m_minWidth, m_maxWidth);
536
537     if (m_caption)
538         m_minWidth = max(m_minWidth, m_caption->minWidth());
539
540     setMinMaxKnown();
541 }
542
543 void RenderTable::splitColumn(int pos, int firstSpan)
544 {
545     // we need to add a new columnStruct
546     int oldSize = m_columns.size();
547     m_columns.resize(oldSize + 1);
548     int oldSpan = m_columns[pos].span;
549     ASSERT(oldSpan > firstSpan);
550     m_columns[pos].span = firstSpan;
551     memmove(m_columns.data() + pos + 1, m_columns.data() + pos, (oldSize - pos) * sizeof(ColumnStruct));
552     m_columns[pos + 1].span = oldSpan - firstSpan;
553
554     // change width of all rows.
555     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
556         if (child->isTableSection())
557             static_cast<RenderTableSection*>(child)->splitColumn(pos, oldSize + 1);
558     }
559
560     m_columnPos.resize(numEffCols() + 1);
561     setNeedsLayoutAndMinMaxRecalc();
562 }
563
564 void RenderTable::appendColumn(int span)
565 {
566     // easy case.
567     int pos = m_columns.size();
568     int newSize = pos + 1;
569     m_columns.resize(newSize);
570     m_columns[pos].span = span;
571
572     // change width of all rows.
573     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
574         if (child->isTableSection())
575             static_cast<RenderTableSection*>(child)->appendColumn(pos);
576     }
577
578     m_columnPos.resize(numEffCols() + 1);
579     setNeedsLayoutAndMinMaxRecalc();
580 }
581
582 RenderTableCol* RenderTable::colElement(int col) const
583 {
584     if (!m_hasColElements)
585         return 0;
586     RenderObject* child = firstChild();
587     int cCol = 0;
588
589     while (child) {
590         if (child->isTableCol()) {
591             RenderTableCol* colElem = static_cast<RenderTableCol*>(child);
592             int span = colElem->span();
593             if (!colElem->firstChild()) {
594                 cCol += span;
595                 if (cCol > col)
596                     return colElem;
597             }
598
599             RenderObject* next = child->firstChild();
600             if (!next)
601                 next = child->nextSibling();
602             if (!next && child->parent()->isTableCol())
603                 next = child->parent()->nextSibling();
604             child = next;
605         } else if (child == m_caption)
606             child = child->nextSibling();
607         else
608             break;
609     }
610
611     return 0;
612 }
613
614 void RenderTable::recalcSections()
615 {
616     m_caption = 0;
617     m_head = 0;
618     m_foot = 0;
619     m_firstBody = 0;
620     m_hasColElements = false;
621
622     // We need to get valid pointers to caption, head, foot and first body again
623     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
624         switch (child->style()->display()) {
625             case TABLE_CAPTION:
626                 if (!m_caption && child->isRenderBlock()) {
627                     m_caption = static_cast<RenderBlock*>(child);
628                     m_caption->setNeedsLayout(true);
629                 }
630                 break;
631             case TABLE_COLUMN:
632             case TABLE_COLUMN_GROUP:
633                 m_hasColElements = true;
634                 break;
635             case TABLE_HEADER_GROUP:
636                 if (child->isTableSection()) {
637                     RenderTableSection* section = static_cast<RenderTableSection*>(child);
638                     if (!m_head)
639                         m_head = section;
640                     else if (!m_firstBody)
641                         m_firstBody = section;
642                     section->recalcCellsIfNeeded();
643                 }
644                 break;
645             case TABLE_FOOTER_GROUP:
646                 if (child->isTableSection()) {
647                     RenderTableSection* section = static_cast<RenderTableSection*>(child);
648                     if (!m_foot)
649                         m_foot = section;
650                     else if (!m_firstBody)
651                         m_firstBody = section;
652                     section->recalcCellsIfNeeded();
653                 }
654                 break;
655             case TABLE_ROW_GROUP:
656                 if (child->isTableSection()) {
657                     RenderTableSection* section = static_cast<RenderTableSection*>(child);
658                     if (!m_firstBody)
659                         m_firstBody = section;
660                     section->recalcCellsIfNeeded();
661                 }
662                 break;
663             default:
664                 break;
665         }
666     }
667
668     // repair column count (addChild can grow it too much, because it always adds elements to the last row of a section)
669     int maxCols = 0;
670     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
671         if (child->isTableSection()) {
672             RenderTableSection* section = static_cast<RenderTableSection*>(child);
673             int sectionCols = section->numColumns();
674             if (sectionCols > maxCols)
675                 maxCols = sectionCols;
676         }
677     }
678     
679     m_columns.resize(maxCols);
680     m_columnPos.resize(maxCols + 1);
681     
682     m_needsSectionRecalc = false;
683     setNeedsLayout(true);
684 }
685
686 RenderObject* RenderTable::removeChildNode(RenderObject* child)
687 {
688     setNeedsSectionRecalc();
689     return RenderContainer::removeChildNode(child);
690 }
691
692 int RenderTable::calcBorderLeft() const
693 {
694     if (collapseBorders()) {
695         // Determined by the first cell of the first row. See the CSS 2.1 spec, section 17.6.2.
696         if (!numEffCols())
697             return 0;
698
699         unsigned borderWidth = 0;
700
701         const BorderValue& tb = style()->borderLeft();
702         if (tb.style() == BHIDDEN)
703             return 0;
704         if (tb.style() > BHIDDEN)
705             borderWidth = tb.width;
706
707         int leftmostColumn = style()->direction() == RTL ? numEffCols() - 1 : 0;
708         RenderTableCol* colGroup = colElement(leftmostColumn);
709         if (colGroup) {
710             const BorderValue& gb = style()->borderLeft();
711             if (gb.style() == BHIDDEN)
712                 return 0;
713             if (gb.style() > BHIDDEN)
714                 borderWidth = max(borderWidth, gb.width);
715         }
716         
717         RenderTableSection* firstNonEmptySection = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot);
718         if (firstNonEmptySection && !firstNonEmptySection->numRows())
719             firstNonEmptySection = sectionBelow(firstNonEmptySection, true);
720         
721         if (firstNonEmptySection) {
722             const BorderValue& sb = firstNonEmptySection->style()->borderLeft();
723             if (sb.style() == BHIDDEN)
724                 return 0;
725
726             if (sb.style() > BHIDDEN)
727                 borderWidth = max(borderWidth, sb.width);
728
729             const RenderTableSection::CellStruct& cs = firstNonEmptySection->cellAt(0, leftmostColumn);
730             
731             if (cs.cell) {
732                 const BorderValue& cb = cs.cell->style()->borderLeft();
733                 if (cb.style() == BHIDDEN)
734                     return 0;
735
736                 const BorderValue& rb = cs.cell->parent()->style()->borderLeft();
737                 if (rb.style() == BHIDDEN)
738                     return 0;
739
740                 if (cb.style() > BHIDDEN)
741                     borderWidth = max(borderWidth, cb.width);
742                 if (rb.style() > BHIDDEN)
743                     borderWidth = max(borderWidth, rb.width);
744             }
745         }
746         return borderWidth / 2;
747     }
748     return RenderBlock::borderLeft();
749 }
750     
751 int RenderTable::calcBorderRight() const
752 {
753     if (collapseBorders()) {
754         // Determined by the last cell of the first row. See the CSS 2.1 spec, section 17.6.2.
755         if (!numEffCols())
756             return 0;
757
758         unsigned borderWidth = 0;
759
760         const BorderValue& tb = style()->borderRight();
761         if (tb.style() == BHIDDEN)
762             return 0;
763         if (tb.style() > BHIDDEN)
764             borderWidth = tb.width;
765
766         int rightmostColumn = style()->direction() == RTL ? 0 : numEffCols() - 1;
767         RenderTableCol* colGroup = colElement(rightmostColumn);
768         if (colGroup) {
769             const BorderValue& gb = style()->borderRight();
770             if (gb.style() == BHIDDEN)
771                 return 0;
772             if (gb.style() > BHIDDEN)
773                 borderWidth = max(borderWidth, gb.width);
774         }
775         
776         RenderTableSection* firstNonEmptySection = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot);
777         if (firstNonEmptySection && !firstNonEmptySection->numRows())
778             firstNonEmptySection = sectionBelow(firstNonEmptySection, true);
779         
780         if (firstNonEmptySection) {
781             const BorderValue& sb = firstNonEmptySection->style()->borderRight();
782             if (sb.style() == BHIDDEN)
783                 return 0;
784
785             if (sb.style() > BHIDDEN)
786                 borderWidth = max(borderWidth, sb.width);
787
788             const RenderTableSection::CellStruct& cs = firstNonEmptySection->cellAt(0, rightmostColumn);
789             
790             if (cs.cell) {
791                 const BorderValue& cb = cs.cell->style()->borderRight();
792                 if (cb.style() == BHIDDEN)
793                     return 0;
794
795                 const BorderValue& rb = cs.cell->parent()->style()->borderRight();
796                 if (rb.style() == BHIDDEN)
797                     return 0;
798
799                 if (cb.style() > BHIDDEN)
800                     borderWidth = max(borderWidth, cb.width);
801                 if (rb.style() > BHIDDEN)
802                     borderWidth = max(borderWidth, rb.width);
803             }
804         }
805         return (borderWidth + 1) / 2;
806     }
807     return RenderBlock::borderRight();
808 }
809
810 void RenderTable::recalcHorizontalBorders()
811 {
812     m_borderLeft = calcBorderLeft();
813     m_borderRight = calcBorderRight();
814 }
815
816 int RenderTable::borderTop() const
817 {
818     if (collapseBorders())
819         return outerBorderTop();
820     return RenderBlock::borderTop();
821 }
822
823 int RenderTable::borderBottom() const
824 {
825     if (collapseBorders())
826         return outerBorderBottom();
827     return RenderBlock::borderBottom();
828 }
829
830 int RenderTable::outerBorderTop() const
831 {
832     if (!collapseBorders())
833         return 0;
834     int borderWidth = 0;
835     RenderTableSection* topSection;
836     if (m_head)
837         topSection = m_head;
838     else if (m_firstBody)
839         topSection = m_firstBody;
840     else if (m_foot)
841         topSection = m_foot;
842     else
843         topSection = 0;
844     if (topSection) {
845         borderWidth = topSection->outerBorderTop();
846         if (borderWidth == -1)
847             return 0;   // Overridden by hidden
848     }
849     const BorderValue& tb = style()->borderTop();
850     if (tb.style() == BHIDDEN)
851         return 0;
852     if (tb.style() > BHIDDEN)
853         borderWidth = max(borderWidth, static_cast<int>(tb.width / 2));
854     return borderWidth;
855 }
856
857 int RenderTable::outerBorderBottom() const
858 {
859     if (!collapseBorders())
860         return 0;
861     int borderWidth = 0;
862     RenderTableSection* bottomSection;
863     if (m_foot)
864         bottomSection = m_foot;
865     else {
866         RenderObject* child;
867         for (child = lastChild(); child && !child->isTableSection(); child = child->previousSibling())
868             ;
869         bottomSection = child ? static_cast<RenderTableSection*>(child) : 0;
870     }
871     if (bottomSection) {
872         borderWidth = bottomSection->outerBorderBottom();
873         if (borderWidth == -1)
874             return 0;   // Overridden by hidden
875     }
876     const BorderValue& tb = style()->borderBottom();
877     if (tb.style() == BHIDDEN)
878         return 0;
879     if (tb.style() > BHIDDEN)
880         borderWidth = max(borderWidth, static_cast<int>((tb.width + 1) / 2));
881     return borderWidth;
882 }
883
884 int RenderTable::outerBorderLeft() const
885 {
886     if (!collapseBorders())
887         return 0;
888
889     int borderWidth = 0;
890
891     const BorderValue& tb = style()->borderLeft();
892     if (tb.style() == BHIDDEN)
893         return 0;
894     if (tb.style() > BHIDDEN)
895         borderWidth = tb.width / 2;
896
897     bool allHidden = true;
898     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
899         if (!child->isTableSection())
900             continue;
901         int sw = static_cast<RenderTableSection*>(child)->outerBorderLeft();
902         if (sw == -1)
903             continue;
904         else
905             allHidden = false;
906         borderWidth = max(borderWidth, sw);
907     }
908     if (allHidden)
909         return 0;
910
911     return borderWidth;
912 }
913
914 int RenderTable::outerBorderRight() const
915 {
916     if (!collapseBorders())
917         return 0;
918
919     int borderWidth = 0;
920
921     const BorderValue& tb = style()->borderRight();
922     if (tb.style() == BHIDDEN)
923         return 0;
924     if (tb.style() > BHIDDEN)
925         borderWidth = (tb.width + 1) / 2;
926
927     bool allHidden = true;
928     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
929         if (!child->isTableSection())
930             continue;
931         int sw = static_cast<RenderTableSection*>(child)->outerBorderRight();
932         if (sw == -1)
933             continue;
934         else
935             allHidden = false;
936         borderWidth = max(borderWidth, sw);
937     }
938     if (allHidden)
939         return 0;
940
941     return borderWidth;
942 }
943
944 RenderTableSection* RenderTable::sectionAbove(const RenderTableSection* section, bool skipEmptySections) const
945 {
946     if (section == m_head)
947         return 0;
948     RenderObject* prevSection = section == m_foot ? lastChild() : section->previousSibling();
949     while (prevSection) {
950         if (prevSection->isTableSection() && prevSection != m_head && prevSection != m_foot && (!skipEmptySections || static_cast<RenderTableSection*>(prevSection)->numRows()))
951             break;
952         prevSection = prevSection->previousSibling();
953     }
954     if (!prevSection && m_head && (!skipEmptySections || m_head->numRows()))
955         prevSection = m_head;
956     return static_cast<RenderTableSection*>(prevSection);
957 }
958
959 RenderTableSection* RenderTable::sectionBelow(const RenderTableSection* section, bool skipEmptySections) const
960 {
961     if (section == m_foot)
962         return 0;
963     RenderObject* nextSection = section == m_head ? firstChild() : section->nextSibling();
964     while (nextSection) {
965         if (nextSection->isTableSection() && nextSection != m_head && nextSection != m_foot && (!skipEmptySections || static_cast<RenderTableSection*>(nextSection)->numRows()))
966             break;
967         nextSection = nextSection->nextSibling();
968     }
969     if (!nextSection && m_foot && (!skipEmptySections || m_foot->numRows()))
970         nextSection = m_foot;
971     return static_cast<RenderTableSection*>(nextSection);
972 }
973
974 RenderTableCell* RenderTable::cellAbove(const RenderTableCell* cell) const
975 {
976     // Find the section and row to look in
977     int r = cell->row();
978     RenderTableSection* section = 0;
979     int rAbove = 0;
980     if (r > 0) {
981         // cell is not in the first row, so use the above row in its own section
982         section = cell->section();
983         rAbove = r - 1;
984     } else {
985         section = sectionAbove(cell->section(), true);
986         if (section)
987             rAbove = section->numRows() - 1;
988     }
989
990     // Look up the cell in the section's grid, which requires effective col index
991     if (section) {
992         int effCol = colToEffCol(cell->col());
993         RenderTableSection::CellStruct aboveCell;
994         // If we hit a span back up to a real cell.
995         do {
996             aboveCell = section->cellAt(rAbove, effCol);
997             effCol--;
998         } while (!aboveCell.cell && aboveCell.inColSpan && effCol >= 0);
999         return aboveCell.cell;
1000     } else
1001         return 0;
1002 }
1003
1004 RenderTableCell* RenderTable::cellBelow(const RenderTableCell* cell) const
1005 {
1006     // Find the section and row to look in
1007     int r = cell->row() + cell->rowSpan() - 1;
1008     RenderTableSection* section = 0;
1009     int rBelow = 0;
1010     if (r < cell->section()->numRows() - 1) {
1011         // The cell is not in the last row, so use the next row in the section.
1012         section = cell->section();
1013         rBelow = r + 1;
1014     } else {
1015         section = sectionBelow(cell->section(), true);
1016         if (section)
1017             rBelow = 0;
1018     }
1019
1020     // Look up the cell in the section's grid, which requires effective col index
1021     if (section) {
1022         int effCol = colToEffCol(cell->col());
1023         RenderTableSection::CellStruct belowCell;
1024         // If we hit a colspan back up to a real cell.
1025         do {
1026             belowCell = section->cellAt(rBelow, effCol);
1027             effCol--;
1028         } while (!belowCell.cell && belowCell.inColSpan && effCol >= 0);
1029         return belowCell.cell;
1030     } else
1031         return 0;
1032 }
1033
1034 RenderTableCell* RenderTable::cellBefore(const RenderTableCell* cell) const
1035 {
1036     RenderTableSection* section = cell->section();
1037     int effCol = colToEffCol(cell->col());
1038     if (!effCol)
1039         return 0;
1040     
1041     // If we hit a colspan back up to a real cell.
1042     RenderTableSection::CellStruct prevCell;
1043     do {
1044         prevCell = section->cellAt(cell->row(), effCol - 1);
1045         effCol--;
1046     } while (!prevCell.cell && prevCell.inColSpan && effCol >= 0);
1047     return prevCell.cell;
1048 }
1049
1050 RenderTableCell* RenderTable::cellAfter(const RenderTableCell* cell) const
1051 {
1052     int effCol = colToEffCol(cell->col() + cell->colSpan());
1053     if (effCol >= numEffCols())
1054         return 0;
1055     return cell->section()->cellAt(cell->row(), effCol).cell;
1056 }
1057
1058 RenderBlock* RenderTable::firstLineBlock() const
1059 {
1060     return 0;
1061 }
1062
1063 void RenderTable::updateFirstLetter()
1064 {
1065 }
1066
1067 IntRect RenderTable::getOverflowClipRect(int tx, int ty)
1068 {
1069     IntRect rect = RenderBlock::getOverflowClipRect(tx, ty);
1070     
1071     // If we have a caption, expand the clip to include the caption.
1072     // FIXME: Technically this is wrong, but it's virtually impossible to fix this
1073     // for real until captions have been re-written.
1074     // FIXME: This code assumes (like all our other caption code) that only top/bottom are
1075     // supported.  When we actually support left/right and stop mapping them to top/bottom,
1076     // we might have to hack this code first (depending on what order we do these bug fixes in).
1077     if (m_caption) {
1078         rect.setHeight(height());
1079         rect.setY(ty);
1080     }
1081
1082     return rect;
1083 }
1084
1085 #ifndef NDEBUG
1086 void RenderTable::dump(TextStream* stream, DeprecatedString ind) const
1087 {
1088     if (m_caption)
1089         *stream << " tCaption";
1090     if (m_head)
1091         *stream << " head";
1092     if (m_foot)
1093         *stream << " foot";
1094
1095     *stream << endl << ind << "cspans:";
1096     for (unsigned i = 0; i < m_columns.size(); i++)
1097         *stream << " " << m_columns[i].span;
1098     *stream << endl << ind;
1099
1100     RenderBlock::dump(stream, ind);
1101 }
1102 #endif
1103
1104 }