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