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