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