10ba1a0fb1e0a454c3460e37c87285d60fb3a07b
[WebKit-https.git] / Source / 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, 2010 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 "CollapsedBorderValue.h"
31 #include "DeleteButtonController.h"
32 #include "Document.h"
33 #include "FixedTableLayout.h"
34 #include "FrameView.h"
35 #include "HitTestResult.h"
36 #include "HTMLNames.h"
37 #include "LayoutRepainter.h"
38 #include "RenderLayer.h"
39 #include "RenderTableCell.h"
40 #include "RenderTableCol.h"
41 #include "RenderTableSection.h"
42 #include "RenderView.h"
43
44 using namespace std;
45
46 namespace WebCore {
47
48 using namespace HTMLNames;
49
50 RenderTable::RenderTable(Node* node)
51     : RenderBlock(node)
52     , m_caption(0)
53     , m_head(0)
54     , m_foot(0)
55     , m_firstBody(0)
56     , m_currentBorder(0)
57     , m_collapsedBordersValid(false)
58     , m_hasColElements(false)
59     , m_needsSectionRecalc(false)
60     , m_hSpacing(0)
61     , m_vSpacing(0)
62     , m_borderStart(0)
63     , m_borderEnd(0)
64 {
65     setChildrenInline(false);
66     m_columnPos.fill(0, 1);
67     
68 }
69
70 RenderTable::~RenderTable()
71 {
72 }
73
74 void RenderTable::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
75 {
76     RenderBlock::styleDidChange(diff, oldStyle);
77     propagateStyleToAnonymousChildren();
78
79     ETableLayout oldTableLayout = oldStyle ? oldStyle->tableLayout() : TAUTO;
80
81     // In the collapsed border model, there is no cell spacing.
82     m_hSpacing = collapseBorders() ? 0 : style()->horizontalBorderSpacing();
83     m_vSpacing = collapseBorders() ? 0 : style()->verticalBorderSpacing();
84     m_columnPos[0] = m_hSpacing;
85
86     if (!m_tableLayout || style()->tableLayout() != oldTableLayout) {
87         // According to the CSS2 spec, you only use fixed table layout if an
88         // explicit width is specified on the table.  Auto width implies auto table layout.
89         if (style()->tableLayout() == TFIXED && !style()->logicalWidth().isAuto())
90             m_tableLayout = adoptPtr(new FixedTableLayout(this));
91         else
92             m_tableLayout = adoptPtr(new AutoTableLayout(this));
93     }
94
95     // If border was changed, invalidate collapsed borders cache.
96     if (!needsLayout() && oldStyle && oldStyle->border() != style()->border())
97         invalidateCollapsedBorders();
98 }
99
100 static inline void resetSectionPointerIfNotBefore(RenderTableSection*& ptr, RenderObject* before)
101 {
102     if (!before || !ptr)
103         return;
104     RenderObject* o = before->previousSibling();
105     while (o && o != ptr)
106         o = o->previousSibling();
107     if (!o)
108         ptr = 0;
109 }
110
111 void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild)
112 {
113     // Make sure we don't append things after :after-generated content if we have it.
114     if (!beforeChild)
115         beforeChild = findAfterContentRenderer();
116
117     bool wrapInAnonymousSection = !child->isPositioned();
118
119     if (child->isRenderBlock() && child->style()->display() == TABLE_CAPTION) {
120         // First caption wins.
121         if (beforeChild && m_caption) {
122             RenderObject* o = beforeChild->previousSibling();
123             while (o && o != m_caption)
124                 o = o->previousSibling();
125             if (!o) {
126                 m_caption = 0;
127                 setNeedsSectionRecalc();
128             }
129         }
130         if (!m_caption)
131             m_caption = toRenderBlock(child);
132         else
133             setNeedsSectionRecalc();
134         wrapInAnonymousSection = false;
135     } else if (child->isTableCol()) {
136         m_hasColElements = true;
137         wrapInAnonymousSection = false;
138     } else if (child->isTableSection()) {
139         switch (child->style()->display()) {
140             case TABLE_HEADER_GROUP:
141                 resetSectionPointerIfNotBefore(m_head, beforeChild);
142                 if (!m_head) {
143                     m_head = toRenderTableSection(child);
144                 } else {
145                     resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
146                     if (!m_firstBody) 
147                         m_firstBody = toRenderTableSection(child);
148                 }
149                 wrapInAnonymousSection = false;
150                 break;
151             case TABLE_FOOTER_GROUP:
152                 resetSectionPointerIfNotBefore(m_foot, beforeChild);
153                 if (!m_foot) {
154                     m_foot = toRenderTableSection(child);
155                     wrapInAnonymousSection = false;
156                     break;
157                 }
158                 // Fall through.
159             case TABLE_ROW_GROUP:
160                 resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
161                 if (!m_firstBody)
162                     m_firstBody = toRenderTableSection(child);
163                 wrapInAnonymousSection = false;
164                 break;
165             default:
166                 ASSERT_NOT_REACHED();
167         }
168     } else if (child->isTableCell() || child->isTableRow())
169         wrapInAnonymousSection = true;
170     else
171         wrapInAnonymousSection = true;
172
173     if (!wrapInAnonymousSection) {
174         // If the next renderer is actually wrapped in an anonymous table section, we need to go up and find that.
175         while (beforeChild && beforeChild->parent() != this)
176             beforeChild = beforeChild->parent();
177
178         RenderBox::addChild(child, beforeChild);
179         return;
180     }
181
182     if (!beforeChild && lastChild() && lastChild()->isTableSection() && lastChild()->isAnonymous() && !lastChild()->isBeforeContent()) {
183         lastChild()->addChild(child);
184         return;
185     }
186
187     if (beforeChild && !beforeChild->isAnonymous() && beforeChild->parent() == this) {
188         RenderObject* section = beforeChild->previousSibling();
189         if (section && section->isTableSection()) {
190             ASSERT(section->isAnonymous());
191             section->addChild(child);
192             return;
193         }
194     }
195
196     RenderObject* lastBox = beforeChild;
197     while (lastBox && lastBox->parent()->isAnonymous() && !lastBox->isTableSection() && lastBox->style()->display() != TABLE_CAPTION && lastBox->style()->display() != TABLE_COLUMN_GROUP)
198         lastBox = lastBox->parent();
199     if (lastBox && lastBox->isAnonymous() && !isAfterContent(lastBox)) {
200         if (beforeChild == lastBox)
201             beforeChild = lastBox->firstChild();
202         lastBox->addChild(child, beforeChild);
203         return;
204     }
205
206     if (beforeChild && !beforeChild->isTableSection() && beforeChild->style()->display() != TABLE_CAPTION && beforeChild->style()->display() != TABLE_COLUMN_GROUP)
207         beforeChild = 0;
208     RenderTableSection* section = new (renderArena()) RenderTableSection(document() /* anonymous */);
209     RefPtr<RenderStyle> newStyle = RenderStyle::create();
210     newStyle->inheritFrom(style());
211     newStyle->setDisplay(TABLE_ROW_GROUP);
212     section->setStyle(newStyle.release());
213     addChild(section, beforeChild);
214     section->addChild(child);
215 }
216
217 void RenderTable::removeChild(RenderObject* oldChild)
218 {
219     RenderBox::removeChild(oldChild);
220     
221     if (m_caption && oldChild == m_caption && node())
222         node()->setNeedsStyleRecalc();
223     setNeedsSectionRecalc();
224 }
225
226 void RenderTable::computeLogicalWidth()
227 {
228     if (isPositioned())
229         computePositionedLogicalWidth();
230
231     RenderBlock* cb = containingBlock();
232
233     LayoutUnit availableLogicalWidth = containingBlockLogicalWidthForContent();
234     bool hasPerpendicularContainingBlock = cb->style()->isHorizontalWritingMode() != style()->isHorizontalWritingMode();
235     LayoutUnit containerWidthInInlineDirection = hasPerpendicularContainingBlock ? perpendicularContainingBlockLogicalHeight() : availableLogicalWidth;
236
237     LengthType logicalWidthType = style()->logicalWidth().type();
238     if (logicalWidthType > Relative && style()->logicalWidth().isPositive()) {
239         // Percent or fixed table
240         setLogicalWidth(style()->logicalWidth().calcMinValue(containerWidthInInlineDirection));
241         setLogicalWidth(max(minPreferredLogicalWidth(), logicalWidth()));
242     } else {
243         // Subtract out any fixed margins from our available width for auto width tables.
244         LayoutUnit marginTotal = 0;
245         if (!style()->marginStart().isAuto())
246             marginTotal += style()->marginStart().calcValue(availableLogicalWidth);
247         if (!style()->marginEnd().isAuto())
248             marginTotal += style()->marginEnd().calcValue(availableLogicalWidth);
249             
250         // Subtract out our margins to get the available content width.
251         LayoutUnit availableContentLogicalWidth = max<LayoutUnit>(0, containerWidthInInlineDirection - marginTotal);
252         
253         // Ensure we aren't bigger than our max width or smaller than our min width.
254         setLogicalWidth(min(availableContentLogicalWidth, maxPreferredLogicalWidth()));
255     }
256
257     setLogicalWidth(max(logicalWidth(), minPreferredLogicalWidth()));
258
259     // Finally, with our true width determined, compute our margins for real.
260     setMarginStart(0);
261     setMarginEnd(0);
262     if (!hasPerpendicularContainingBlock)
263         computeInlineDirectionMargins(cb, availableLogicalWidth, logicalWidth());
264     else {
265         setMarginStart(style()->marginStart().calcMinValue(availableLogicalWidth));
266         setMarginEnd(style()->marginEnd().calcMinValue(availableLogicalWidth));
267     }
268 }
269
270 void RenderTable::adjustLogicalHeightForCaption()
271 {
272     ASSERT(m_caption);
273     IntRect captionRect(m_caption->x(), m_caption->y(), m_caption->width(), m_caption->height());
274
275     m_caption->setLogicalLocation(IntPoint(m_caption->marginStart(), m_caption->marginBefore() + logicalHeight()));
276     if (!selfNeedsLayout() && m_caption->checkForRepaintDuringLayout())
277         m_caption->repaintDuringLayoutIfMoved(captionRect);
278
279     setLogicalHeight(logicalHeight() + m_caption->logicalHeight() + m_caption->marginBefore() + m_caption->marginAfter());
280 }
281
282 void RenderTable::layout()
283 {
284     ASSERT(needsLayout());
285
286     if (simplifiedLayout())
287         return;
288
289     recalcSectionsIfNeeded();
290         
291     LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
292     LayoutStateMaintainer statePusher(view(), this, locationOffset(), style()->isFlippedBlocksWritingMode());
293
294     setLogicalHeight(0);
295     m_overflow.clear();
296
297     initMaxMarginValues();
298     
299     LayoutUnit oldLogicalWidth = logicalWidth();
300     computeLogicalWidth();
301
302     if (m_caption && logicalWidth() != oldLogicalWidth)
303         m_caption->setNeedsLayout(true, false);
304
305     // FIXME: The optimisation below doesn't work since the internal table
306     // layout could have changed.  we need to add a flag to the table
307     // layout that tells us if something has changed in the min max
308     // calculations to do it correctly.
309 //     if ( oldWidth != width() || columns.size() + 1 != columnPos.size() )
310     m_tableLayout->layout();
311
312     setCellLogicalWidths();
313
314     LayoutUnit totalSectionLogicalHeight = 0;
315     LayoutUnit oldTableLogicalTop = m_caption ? m_caption->logicalHeight() + m_caption->marginBefore() + m_caption->marginAfter() : 0;
316
317     bool collapsing = collapseBorders();
318
319     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
320         if (child->isTableSection()) {
321             child->layoutIfNeeded();
322             RenderTableSection* section = toRenderTableSection(child);
323             totalSectionLogicalHeight += section->calcRowLogicalHeight();
324             if (collapsing)
325                 section->recalcOuterBorder();
326             ASSERT(!section->needsLayout());
327         } else if (child->isTableCol()) {
328             child->layoutIfNeeded();
329             ASSERT(!child->needsLayout());
330         }
331     }
332
333     // Only lay out one caption, since it's the only one we're going to end up painting.
334     if (m_caption)
335         m_caption->layoutIfNeeded();
336
337     // If any table section moved vertically, we will just repaint everything from that
338     // section down (it is quite unlikely that any of the following sections
339     // did not shift).
340     bool sectionMoved = false;
341     LayoutUnit movedSectionLogicalTop = 0;
342
343     // FIXME: Collapse caption margin.
344     if (m_caption && m_caption->style()->captionSide() != CAPBOTTOM) {
345         adjustLogicalHeightForCaption();
346         if (logicalHeight() != oldTableLogicalTop) {
347             sectionMoved = true;
348             movedSectionLogicalTop = min(logicalHeight(), oldTableLogicalTop);
349         }
350     }
351
352     LayoutUnit borderAndPaddingBefore = borderBefore() + (collapsing ? 0 : paddingBefore());
353     LayoutUnit borderAndPaddingAfter = borderAfter() + (collapsing ? 0 : paddingAfter());
354
355     setLogicalHeight(logicalHeight() + borderAndPaddingBefore);
356
357     if (!isPositioned())
358         computeLogicalHeight();
359
360     Length logicalHeightLength = style()->logicalHeight();
361     LayoutUnit computedLogicalHeight = 0;
362     if (logicalHeightLength.isFixed()) {
363         // Tables size as though CSS height includes border/padding.
364         computedLogicalHeight = logicalHeightLength.value() - (borderAndPaddingBefore + borderAndPaddingAfter);
365     } else if (logicalHeightLength.isPercent())
366         computedLogicalHeight = computePercentageLogicalHeight(logicalHeightLength);
367     computedLogicalHeight = max<LayoutUnit>(0, computedLogicalHeight);
368
369     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
370         if (child->isTableSection())
371             // FIXME: Distribute extra height between all table body sections instead of giving it all to the first one.
372             toRenderTableSection(child)->layoutRows(child == m_firstBody ? max<LayoutUnit>(0, computedLogicalHeight - totalSectionLogicalHeight) : 0);
373     }
374
375     if (!m_firstBody && computedLogicalHeight > totalSectionLogicalHeight && !document()->inQuirksMode()) {
376         // Completely empty tables (with no sections or anything) should at least honor specified height
377         // in strict mode.
378         setLogicalHeight(logicalHeight() + computedLogicalHeight);
379     }
380
381     LayoutUnit sectionLogicalLeft = style()->isLeftToRightDirection() ? borderStart() : borderEnd();
382     if (!collapsing)
383         sectionLogicalLeft += style()->isLeftToRightDirection() ? paddingStart() : paddingEnd();
384
385     // position the table sections
386     RenderTableSection* section = topSection();
387     while (section) {
388         if (!sectionMoved && section->logicalTop() != logicalHeight()) {
389             sectionMoved = true;
390             movedSectionLogicalTop = min(logicalHeight(), section->logicalTop()) + (style()->isHorizontalWritingMode() ? section->minYVisualOverflow() : section->minXVisualOverflow());
391         }
392         section->setLogicalLocation(LayoutPoint(sectionLogicalLeft, logicalHeight()));
393
394         setLogicalHeight(logicalHeight() + section->logicalHeight());
395         section = sectionBelow(section);
396     }
397
398     setLogicalHeight(logicalHeight() + borderAndPaddingAfter);
399
400     if (m_caption && m_caption->style()->captionSide() == CAPBOTTOM)
401         adjustLogicalHeightForCaption();
402
403     if (isPositioned())
404         computeLogicalHeight();
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     updateLayerTransform();
411
412     // Layout was changed, so probably borders too.
413     invalidateCollapsedBorders();
414
415     computeOverflow(clientLogicalBottom());
416
417     statePusher.pop();
418
419     if (view()->layoutState()->pageLogicalHeight())
420         setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(logicalTop()));
421
422     bool didFullRepaint = repainter.repaintAfterLayout();
423     // Repaint with our new bounds if they are different from our old bounds.
424     if (!didFullRepaint && sectionMoved) {
425         if (style()->isHorizontalWritingMode())
426             repaintRectangle(LayoutRect(minXVisualOverflow(), movedSectionLogicalTop, maxXVisualOverflow() - minXVisualOverflow(), maxYVisualOverflow() - movedSectionLogicalTop));
427         else
428             repaintRectangle(LayoutRect(movedSectionLogicalTop, minYVisualOverflow(), maxXVisualOverflow() - movedSectionLogicalTop, maxYVisualOverflow() - minYVisualOverflow()));
429     }
430
431     setNeedsLayout(false);
432 }
433
434 // Collect all the unique border values that we want to paint in a sorted list.
435 void RenderTable::recalcCollapsedBorders()
436 {
437     if (m_collapsedBordersValid)
438         return;
439     m_collapsedBordersValid = true;
440     m_collapsedBorders.clear();
441     RenderObject* stop = nextInPreOrderAfterChildren();
442     for (RenderObject* o = firstChild(); o && o != stop; o = o->nextInPreOrder()) {
443         if (o->isTableCell())
444             toRenderTableCell(o)->collectBorderValues(m_collapsedBorders);
445     }
446     RenderTableCell::sortBorderValues(m_collapsedBorders);
447 }
448
449
450 void RenderTable::addOverflowFromChildren()
451 {
452     // Add overflow from borders.
453     // Technically it's odd that we are incorporating the borders into layout overflow, which is only supposed to be about overflow from our
454     // descendant objects, but since tables don't support overflow:auto, this works out fine.
455     if (collapseBorders()) {
456         int rightBorderOverflow = width() + outerBorderRight() - borderRight();
457         int leftBorderOverflow = borderLeft() - outerBorderLeft();
458         int bottomBorderOverflow = height() + outerBorderBottom() - borderBottom();
459         int topBorderOverflow = borderTop() - outerBorderTop();
460         IntRect borderOverflowRect(leftBorderOverflow, topBorderOverflow, rightBorderOverflow - leftBorderOverflow, bottomBorderOverflow - topBorderOverflow);
461         if (borderOverflowRect != borderBoxRect()) {
462             addLayoutOverflow(borderOverflowRect);
463             addVisualOverflow(borderOverflowRect);
464         }
465     }
466
467     // Add overflow from our caption.
468     if (m_caption)
469         addOverflowFromChild(m_caption);
470
471     // Add overflow from our sections.
472     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
473         if (child->isTableSection()) {
474             RenderTableSection* section = toRenderTableSection(child);
475             addOverflowFromChild(section);
476         }
477     }
478 }
479
480 void RenderTable::setCellLogicalWidths()
481 {
482     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
483         if (child->isTableSection())
484             toRenderTableSection(child)->setCellLogicalWidths();
485     }
486 }
487
488 void RenderTable::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
489 {
490     LayoutPoint adjustedPaintOffset = paintOffset + location();
491
492     PaintPhase paintPhase = paintInfo.phase;
493
494     if (!isRoot()) {
495         LayoutRect overflowBox = visualOverflowRect();
496         flipForWritingMode(overflowBox);
497         overflowBox.inflate(maximalOutlineSize(paintInfo.phase));
498         overflowBox.moveBy(adjustedPaintOffset);
499         if (!overflowBox.intersects(paintInfo.rect))
500             return;
501     }
502
503     bool pushedClip = pushContentsClip(paintInfo, adjustedPaintOffset);
504     paintObject(paintInfo, adjustedPaintOffset);
505     if (pushedClip)
506         popContentsClip(paintInfo, paintPhase, adjustedPaintOffset);
507 }
508
509 void RenderTable::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
510 {
511     PaintPhase paintPhase = paintInfo.phase;
512     if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && hasBoxDecorations() && style()->visibility() == VISIBLE)
513         paintBoxDecorations(paintInfo, paintOffset);
514
515     if (paintPhase == PaintPhaseMask) {
516         paintMask(paintInfo, paintOffset);
517         return;
518     }
519
520     // We're done.  We don't bother painting any children.
521     if (paintPhase == PaintPhaseBlockBackground)
522         return;
523     
524     // We don't paint our own background, but we do let the kids paint their backgrounds.
525     if (paintPhase == PaintPhaseChildBlockBackgrounds)
526         paintPhase = PaintPhaseChildBlockBackground;
527
528     PaintInfo info(paintInfo);
529     info.phase = paintPhase;
530     info.updatePaintingRootForChildren(this);
531
532     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
533         if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child == m_caption)) {
534             LayoutPoint childPoint = flipForWritingModeForChild(toRenderBox(child), paintOffset);
535             child->paint(info, childPoint);
536         }
537     }
538     
539     if (collapseBorders() && paintPhase == PaintPhaseChildBlockBackground && style()->visibility() == VISIBLE) {
540         recalcCollapsedBorders();
541         // Using our cached sorted styles, we then do individual passes,
542         // painting each style of border from lowest precedence to highest precedence.
543         info.phase = PaintPhaseCollapsedTableBorders;
544         size_t count = m_collapsedBorders.size();
545         for (size_t i = 0; i < count; ++i) {
546             m_currentBorder = &m_collapsedBorders[i];
547             for (RenderObject* child = firstChild(); child; child = child->nextSibling())
548                 if (child->isTableSection()) {
549                     LayoutPoint childPoint = flipForWritingModeForChild(toRenderTableSection(child), paintOffset);
550                     child->paint(info, childPoint);
551                 }
552         }
553         m_currentBorder = 0;
554     }
555
556     // Paint outline.
557     if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE)
558         paintOutline(paintInfo.context, LayoutRect(paintOffset, size()));
559 }
560
561 void RenderTable::subtractCaptionRect(LayoutRect& rect) const
562 {
563     if (!m_caption)
564         return;
565
566     LayoutUnit captionLogicalHeight = m_caption->logicalHeight() + m_caption->marginBefore() + m_caption->marginAfter();
567     bool captionIsBefore = (m_caption->style()->captionSide() != CAPBOTTOM) ^ style()->isFlippedBlocksWritingMode();
568     if (style()->isHorizontalWritingMode()) {
569         rect.setHeight(rect.height() - captionLogicalHeight);
570         if (captionIsBefore)
571             rect.move(0, captionLogicalHeight);
572     } else {
573         rect.setWidth(rect.width() - captionLogicalHeight);
574         if (captionIsBefore)
575             rect.move(captionLogicalHeight, 0);
576     }
577 }
578
579 void RenderTable::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
580 {
581     if (!paintInfo.shouldPaintWithinRoot(this))
582         return;
583
584     LayoutRect rect(paintOffset, size());
585     subtractCaptionRect(rect);
586
587     paintBoxShadow(paintInfo, rect, style(), Normal);
588     paintBackground(paintInfo, rect);
589     paintBoxShadow(paintInfo, rect, style(), Inset);
590
591     if (style()->hasBorder() && !collapseBorders())
592         paintBorder(paintInfo, rect, style());
593 }
594
595 void RenderTable::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
596 {
597     if (style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
598         return;
599
600     LayoutRect rect(paintOffset, size());
601     subtractCaptionRect(rect);
602
603     paintMaskImages(paintInfo, rect);
604 }
605
606 void RenderTable::computePreferredLogicalWidths()
607 {
608     ASSERT(preferredLogicalWidthsDirty());
609
610     recalcSectionsIfNeeded();
611     recalcBordersInRowDirection();
612
613     m_tableLayout->computePreferredLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
614
615     if (m_caption)
616         m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, m_caption->minPreferredLogicalWidth());
617
618     setPreferredLogicalWidthsDirty(false);
619 }
620
621 RenderTableSection* RenderTable::topNonEmptySection() const
622 {
623     RenderTableSection* section = topSection();
624     if (section && !section->numRows())
625         section = sectionBelow(section, SkipEmptySections);
626     return section;
627 }
628
629 void RenderTable::splitColumn(int pos, int firstSpan)
630 {
631     // we need to add a new columnStruct
632     int oldSize = m_columns.size();
633     m_columns.grow(oldSize + 1);
634     int oldSpan = m_columns[pos].span;
635     ASSERT(oldSpan > firstSpan);
636     m_columns[pos].span = firstSpan;
637     memmove(m_columns.data() + pos + 1, m_columns.data() + pos, (oldSize - pos) * sizeof(ColumnStruct));
638     m_columns[pos + 1].span = oldSpan - firstSpan;
639
640     // change width of all rows.
641     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
642         if (child->isTableSection())
643             toRenderTableSection(child)->splitColumn(pos, firstSpan);
644     }
645
646     m_columnPos.grow(numEffCols() + 1);
647     setNeedsLayoutAndPrefWidthsRecalc();
648 }
649
650 void RenderTable::appendColumn(int span)
651 {
652     // easy case.
653     int pos = m_columns.size();
654     int newSize = pos + 1;
655     m_columns.grow(newSize);
656     m_columns[pos].span = span;
657
658     // change width of all rows.
659     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
660         if (child->isTableSection())
661             toRenderTableSection(child)->appendColumn(pos);
662     }
663
664     m_columnPos.grow(numEffCols() + 1);
665     setNeedsLayoutAndPrefWidthsRecalc();
666 }
667
668 RenderTableCol* RenderTable::nextColElement(RenderTableCol* current) const
669 {
670     RenderObject* next = current->firstChild();
671     if (!next)
672         next = current->nextSibling();
673     if (!next && current->parent()->isTableCol())
674         next = current->parent()->nextSibling();
675
676     while (next) {
677         if (next->isTableCol())
678             return toRenderTableCol(next);
679         if (next != m_caption)
680             return 0;
681         next = next->nextSibling();
682     }
683     
684     return 0;
685 }
686
687 RenderTableCol* RenderTable::colElement(int col, bool* startEdge, bool* endEdge) const
688 {
689     if (!m_hasColElements)
690         return 0;
691     RenderObject* child = firstChild();
692     int cCol = 0;
693
694     while (child) {
695         if (child->isTableCol())
696             break;
697         if (child != m_caption)
698             return 0;
699         child = child->nextSibling();
700     }
701     if (!child)
702         return 0;
703
704     RenderTableCol* colElem = toRenderTableCol(child);
705     while (colElem) {
706         int span = colElem->span();
707         if (!colElem->firstChild()) {
708             int startCol = cCol;
709             int endCol = cCol + span - 1;
710             cCol += span;
711             if (cCol > col) {
712                 if (startEdge)
713                     *startEdge = startCol == col;
714                 if (endEdge)
715                     *endEdge = endCol == col;
716                 return colElem;
717             }
718         }
719         colElem = nextColElement(colElem);
720     }
721
722     return 0;
723 }
724
725 void RenderTable::recalcCaption(RenderBlock* caption) const
726 {
727     if (!m_caption) {
728         m_caption = caption;
729         m_caption->setNeedsLayout(true);
730     } else {
731         // Make sure to null out the child's renderer.
732         if (Node* node = caption->node())
733             node->setRenderer(0);
734
735         // Destroy the child now.
736         caption->destroy();
737     }
738 }
739
740 void RenderTable::recalcSections() const
741 {
742     m_caption = 0;
743     m_head = 0;
744     m_foot = 0;
745     m_firstBody = 0;
746     m_hasColElements = false;
747
748     // We need to get valid pointers to caption, head, foot and first body again
749     RenderObject* nextSibling;
750     for (RenderObject* child = firstChild(); child; child = nextSibling) {
751         nextSibling = child->nextSibling();
752         switch (child->style()->display()) {
753             case TABLE_CAPTION:
754                 if (child->isRenderBlock())
755                     recalcCaption(toRenderBlock(child));
756                 break;
757             case TABLE_COLUMN:
758             case TABLE_COLUMN_GROUP:
759                 m_hasColElements = true;
760                 break;
761             case TABLE_HEADER_GROUP:
762                 if (child->isTableSection()) {
763                     RenderTableSection* section = toRenderTableSection(child);
764                     if (!m_head)
765                         m_head = section;
766                     else if (!m_firstBody)
767                         m_firstBody = section;
768                     section->recalcCellsIfNeeded();
769                 }
770                 break;
771             case TABLE_FOOTER_GROUP:
772                 if (child->isTableSection()) {
773                     RenderTableSection* section = toRenderTableSection(child);
774                     if (!m_foot)
775                         m_foot = section;
776                     else if (!m_firstBody)
777                         m_firstBody = section;
778                     section->recalcCellsIfNeeded();
779                 }
780                 break;
781             case TABLE_ROW_GROUP:
782                 if (child->isTableSection()) {
783                     RenderTableSection* section = toRenderTableSection(child);
784                     if (!m_firstBody)
785                         m_firstBody = section;
786                     section->recalcCellsIfNeeded();
787                 }
788                 break;
789             default:
790                 break;
791         }
792     }
793
794     // repair column count (addChild can grow it too much, because it always adds elements to the last row of a section)
795     int maxCols = 0;
796     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
797         if (child->isTableSection()) {
798             RenderTableSection* section = toRenderTableSection(child);
799             int sectionCols = section->numColumns();
800             if (sectionCols > maxCols)
801                 maxCols = sectionCols;
802         }
803     }
804     
805     m_columns.resize(maxCols);
806     m_columnPos.resize(maxCols + 1);
807
808     ASSERT(selfNeedsLayout());
809
810     m_needsSectionRecalc = false;
811 }
812
813 LayoutUnit RenderTable::calcBorderStart() const
814 {
815     if (collapseBorders()) {
816         // Determined by the first cell of the first row. See the CSS 2.1 spec, section 17.6.2.
817         if (!numEffCols())
818             return 0;
819
820         LayoutUnit borderWidth = 0;
821
822         const BorderValue& tb = style()->borderStart();
823         if (tb.style() == BHIDDEN)
824             return 0;
825         if (tb.style() > BHIDDEN)
826             borderWidth = tb.width();
827
828         if (RenderTableCol* colGroup = colElement(0)) {
829             const BorderValue& gb = colGroup->style()->borderStart();
830             if (gb.style() == BHIDDEN)
831                 return 0;
832             if (gb.style() > BHIDDEN)
833                 borderWidth = max<LayoutUnit>(borderWidth, gb.width());
834         }
835         
836         if (const RenderTableSection* topNonEmptySection = this->topNonEmptySection()) {
837             const BorderValue& sb = topNonEmptySection->style()->borderStart();
838             if (sb.style() == BHIDDEN)
839                 return 0;
840
841             if (sb.style() > BHIDDEN)
842                 borderWidth = max<LayoutUnit>(borderWidth, sb.width());
843
844             const RenderTableSection::CellStruct& cs = topNonEmptySection->cellAt(0, 0);
845             
846             if (cs.hasCells()) {
847                 const BorderValue& cb = cs.primaryCell()->style()->borderStart(); // FIXME: Make this work with perpendicualr and flipped cells.
848                 if (cb.style() == BHIDDEN)
849                     return 0;
850
851                 const BorderValue& rb = cs.primaryCell()->parent()->style()->borderStart();
852                 if (rb.style() == BHIDDEN)
853                     return 0;
854
855                 if (cb.style() > BHIDDEN)
856                     borderWidth = max<LayoutUnit>(borderWidth, cb.width());
857                 if (rb.style() > BHIDDEN)
858                     borderWidth = max<LayoutUnit>(borderWidth, rb.width());
859             }
860         }
861         return (borderWidth + (style()->isLeftToRightDirection() ? 0 : 1)) / 2;
862     }
863     return RenderBlock::borderStart();
864 }
865
866 LayoutUnit RenderTable::calcBorderEnd() const
867 {
868     if (collapseBorders()) {
869         // Determined by the last cell of the first row. See the CSS 2.1 spec, section 17.6.2.
870         if (!numEffCols())
871             return 0;
872
873         LayoutUnit borderWidth = 0;
874
875         const BorderValue& tb = style()->borderEnd();
876         if (tb.style() == BHIDDEN)
877             return 0;
878         if (tb.style() > BHIDDEN)
879             borderWidth = tb.width();
880
881         int endColumn = numEffCols() - 1;
882         if (RenderTableCol* colGroup = colElement(endColumn)) {
883             const BorderValue& gb = colGroup->style()->borderEnd();
884             if (gb.style() == BHIDDEN)
885                 return 0;
886             if (gb.style() > BHIDDEN)
887                 borderWidth = max<LayoutUnit>(borderWidth, gb.width());
888         }
889
890         if (const RenderTableSection* topNonEmptySection = this->topNonEmptySection()) {
891             const BorderValue& sb = topNonEmptySection->style()->borderEnd();
892             if (sb.style() == BHIDDEN)
893                 return 0;
894
895             if (sb.style() > BHIDDEN)
896                 borderWidth = max<LayoutUnit>(borderWidth, sb.width());
897
898             const RenderTableSection::CellStruct& cs = topNonEmptySection->cellAt(0, endColumn);
899             
900             if (cs.hasCells()) {
901                 const BorderValue& cb = cs.primaryCell()->style()->borderEnd(); // FIXME: Make this work with perpendicular and flipped cells.
902                 if (cb.style() == BHIDDEN)
903                     return 0;
904
905                 const BorderValue& rb = cs.primaryCell()->parent()->style()->borderEnd();
906                 if (rb.style() == BHIDDEN)
907                     return 0;
908
909                 if (cb.style() > BHIDDEN)
910                     borderWidth = max<LayoutUnit>(borderWidth, cb.width());
911                 if (rb.style() > BHIDDEN)
912                     borderWidth = max<LayoutUnit>(borderWidth, rb.width());
913             }
914         }
915         return (borderWidth + (style()->isLeftToRightDirection() ? 1 : 0)) / 2;
916     }
917     return RenderBlock::borderEnd();
918 }
919
920 void RenderTable::recalcBordersInRowDirection()
921 {
922     m_borderStart = calcBorderStart();
923     m_borderEnd = calcBorderEnd();
924 }
925
926 LayoutUnit RenderTable::borderBefore() const
927 {
928     if (collapseBorders())
929         return outerBorderBefore();
930     return RenderBlock::borderBefore();
931 }
932
933 LayoutUnit RenderTable::borderAfter() const
934 {
935     if (collapseBorders())
936         return outerBorderAfter();
937     return RenderBlock::borderAfter();
938 }
939
940 LayoutUnit RenderTable::outerBorderBefore() const
941 {
942     if (!collapseBorders())
943         return 0;
944     LayoutUnit borderWidth = 0;
945     if (RenderTableSection* topSection = this->topSection()) {
946         borderWidth = topSection->outerBorderBefore();
947         if (borderWidth < 0)
948             return 0;   // Overridden by hidden
949     }
950     const BorderValue& tb = style()->borderBefore();
951     if (tb.style() == BHIDDEN)
952         return 0;
953     if (tb.style() > BHIDDEN)
954         borderWidth = max<LayoutUnit>(borderWidth, tb.width() / 2);
955     return borderWidth;
956 }
957
958 LayoutUnit RenderTable::outerBorderAfter() const
959 {
960     if (!collapseBorders())
961         return 0;
962     LayoutUnit borderWidth = 0;
963     RenderTableSection* bottomSection;
964     if (m_foot)
965         bottomSection = m_foot;
966     else {
967         RenderObject* child;
968         for (child = lastChild(); child && !child->isTableSection(); child = child->previousSibling()) { }
969         bottomSection = child ? toRenderTableSection(child) : 0;
970     }
971     if (bottomSection) {
972         borderWidth = bottomSection->outerBorderAfter();
973         if (borderWidth < 0)
974             return 0;   // Overridden by hidden
975     }
976     const BorderValue& tb = style()->borderAfter();
977     if (tb.style() == BHIDDEN)
978         return 0;
979     if (tb.style() > BHIDDEN)
980         borderWidth = max<LayoutUnit>(borderWidth, (tb.width() + 1) / 2);
981     return borderWidth;
982 }
983
984 LayoutUnit RenderTable::outerBorderStart() const
985 {
986     if (!collapseBorders())
987         return 0;
988
989     LayoutUnit borderWidth = 0;
990
991     const BorderValue& tb = style()->borderStart();
992     if (tb.style() == BHIDDEN)
993         return 0;
994     if (tb.style() > BHIDDEN)
995         borderWidth = (tb.width() + (style()->isLeftToRightDirection() ? 0 : 1)) / 2;
996
997     bool allHidden = true;
998     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
999         if (!child->isTableSection())
1000             continue;
1001         LayoutUnit sw = toRenderTableSection(child)->outerBorderStart();
1002         if (sw < 0)
1003             continue;
1004         allHidden = false;
1005         borderWidth = max(borderWidth, sw);
1006     }
1007     if (allHidden)
1008         return 0;
1009
1010     return borderWidth;
1011 }
1012
1013 LayoutUnit RenderTable::outerBorderEnd() const
1014 {
1015     if (!collapseBorders())
1016         return 0;
1017
1018     LayoutUnit borderWidth = 0;
1019
1020     const BorderValue& tb = style()->borderEnd();
1021     if (tb.style() == BHIDDEN)
1022         return 0;
1023     if (tb.style() > BHIDDEN)
1024         borderWidth = (tb.width() + (style()->isLeftToRightDirection() ? 1 : 0)) / 2;
1025
1026     bool allHidden = true;
1027     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
1028         if (!child->isTableSection())
1029             continue;
1030         LayoutUnit sw = toRenderTableSection(child)->outerBorderEnd();
1031         if (sw < 0)
1032             continue;
1033         allHidden = false;
1034         borderWidth = max(borderWidth, sw);
1035     }
1036     if (allHidden)
1037         return 0;
1038
1039     return borderWidth;
1040 }
1041
1042 RenderTableSection* RenderTable::sectionAbove(const RenderTableSection* section, SkipEmptySectionsValue skipEmptySections) const
1043 {
1044     recalcSectionsIfNeeded();
1045
1046     if (section == m_head)
1047         return 0;
1048
1049     RenderObject* prevSection = section == m_foot ? lastChild() : section->previousSibling();
1050     while (prevSection) {
1051         if (prevSection->isTableSection() && prevSection != m_head && prevSection != m_foot && (skipEmptySections == DoNotSkipEmptySections || toRenderTableSection(prevSection)->numRows()))
1052             break;
1053         prevSection = prevSection->previousSibling();
1054     }
1055     if (!prevSection && m_head && (skipEmptySections == DoNotSkipEmptySections || m_head->numRows()))
1056         prevSection = m_head;
1057     return toRenderTableSection(prevSection);
1058 }
1059
1060 RenderTableSection* RenderTable::sectionBelow(const RenderTableSection* section, SkipEmptySectionsValue skipEmptySections) const
1061 {
1062     recalcSectionsIfNeeded();
1063
1064     if (section == m_foot)
1065         return 0;
1066
1067     RenderObject* nextSection = section == m_head ? firstChild() : section->nextSibling();
1068     while (nextSection) {
1069         if (nextSection->isTableSection() && nextSection != m_head && nextSection != m_foot && (skipEmptySections  == DoNotSkipEmptySections || toRenderTableSection(nextSection)->numRows()))
1070             break;
1071         nextSection = nextSection->nextSibling();
1072     }
1073     if (!nextSection && m_foot && (skipEmptySections == DoNotSkipEmptySections || m_foot->numRows()))
1074         nextSection = m_foot;
1075     return toRenderTableSection(nextSection);
1076 }
1077
1078 RenderTableCell* RenderTable::cellAbove(const RenderTableCell* cell) const
1079 {
1080     recalcSectionsIfNeeded();
1081
1082     // Find the section and row to look in
1083     int r = cell->row();
1084     RenderTableSection* section = 0;
1085     int rAbove = 0;
1086     if (r > 0) {
1087         // cell is not in the first row, so use the above row in its own section
1088         section = cell->section();
1089         rAbove = r - 1;
1090     } else {
1091         section = sectionAbove(cell->section(), SkipEmptySections);
1092         if (section)
1093             rAbove = section->numRows() - 1;
1094     }
1095
1096     // Look up the cell in the section's grid, which requires effective col index
1097     if (section) {
1098         int effCol = colToEffCol(cell->col());
1099         RenderTableSection::CellStruct& aboveCell = section->cellAt(rAbove, effCol);
1100         return aboveCell.primaryCell();
1101     } else
1102         return 0;
1103 }
1104
1105 RenderTableCell* RenderTable::cellBelow(const RenderTableCell* cell) const
1106 {
1107     recalcSectionsIfNeeded();
1108
1109     // Find the section and row to look in
1110     int r = cell->row() + cell->rowSpan() - 1;
1111     RenderTableSection* section = 0;
1112     int rBelow = 0;
1113     if (r < cell->section()->numRows() - 1) {
1114         // The cell is not in the last row, so use the next row in the section.
1115         section = cell->section();
1116         rBelow = r + 1;
1117     } else {
1118         section = sectionBelow(cell->section(), SkipEmptySections);
1119         if (section)
1120             rBelow = 0;
1121     }
1122
1123     // Look up the cell in the section's grid, which requires effective col index
1124     if (section) {
1125         int effCol = colToEffCol(cell->col());
1126         RenderTableSection::CellStruct& belowCell = section->cellAt(rBelow, effCol);
1127         return belowCell.primaryCell();
1128     } else
1129         return 0;
1130 }
1131
1132 RenderTableCell* RenderTable::cellBefore(const RenderTableCell* cell) const
1133 {
1134     recalcSectionsIfNeeded();
1135
1136     RenderTableSection* section = cell->section();
1137     int effCol = colToEffCol(cell->col());
1138     if (!effCol)
1139         return 0;
1140     
1141     // If we hit a colspan back up to a real cell.
1142     RenderTableSection::CellStruct& prevCell = section->cellAt(cell->row(), effCol - 1);
1143     return prevCell.primaryCell();
1144 }
1145
1146 RenderTableCell* RenderTable::cellAfter(const RenderTableCell* cell) const
1147 {
1148     recalcSectionsIfNeeded();
1149
1150     int effCol = colToEffCol(cell->col() + cell->colSpan());
1151     if (effCol >= numEffCols())
1152         return 0;
1153     return cell->section()->primaryCellAt(cell->row(), effCol);
1154 }
1155
1156 RenderBlock* RenderTable::firstLineBlock() const
1157 {
1158     return 0;
1159 }
1160
1161 void RenderTable::updateFirstLetter()
1162 {
1163 }
1164
1165 LayoutUnit RenderTable::firstLineBoxBaseline() const
1166 {
1167     if (isWritingModeRoot())
1168         return -1;
1169
1170     recalcSectionsIfNeeded();
1171
1172     const RenderTableSection* topNonEmptySection = this->topNonEmptySection();
1173     if (!topNonEmptySection)
1174         return -1;
1175
1176     return topNonEmptySection->logicalTop() + topNonEmptySection->firstLineBoxBaseline();
1177 }
1178
1179 LayoutRect RenderTable::overflowClipRect(const LayoutPoint& location, RenderRegion* region, OverlayScrollbarSizeRelevancy relevancy)
1180 {
1181     LayoutRect rect = RenderBlock::overflowClipRect(location, region, relevancy);
1182     
1183     // If we have a caption, expand the clip to include the caption.
1184     // FIXME: Technically this is wrong, but it's virtually impossible to fix this
1185     // for real until captions have been re-written.
1186     // FIXME: This code assumes (like all our other caption code) that only top/bottom are
1187     // supported.  When we actually support left/right and stop mapping them to top/bottom,
1188     // we might have to hack this code first (depending on what order we do these bug fixes in).
1189     if (m_caption) {
1190         if (style()->isHorizontalWritingMode()) {
1191             rect.setHeight(height());
1192             rect.setY(location.y());
1193         } else {
1194             rect.setWidth(width());
1195             rect.setX(location.x());
1196         }
1197     }
1198
1199     return rect;
1200 }
1201
1202 bool RenderTable::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
1203 {
1204     LayoutPoint adjustedLocation = accumulatedOffset + location();
1205
1206     // Check kids first.
1207     if (!hasOverflowClip() || overflowClipRect(adjustedLocation, result.region()).intersects(result.rectForPoint(pointInContainer))) {
1208         for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
1209             if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child == m_caption)) {
1210                 LayoutPoint childPoint = flipForWritingModeForChild(toRenderBox(child), adjustedLocation);
1211                 if (child->nodeAtPoint(request, result, pointInContainer, childPoint, action)) {
1212                     updateHitTestResult(result, toLayoutPoint(pointInContainer - childPoint));
1213                     return true;
1214                 }
1215             }
1216         }
1217     }
1218
1219     // Check our bounds next.
1220     LayoutRect boundsRect(adjustedLocation, size());
1221     if (visibleToHitTesting() && (action == HitTestBlockBackground || action == HitTestChildBlockBackground) && boundsRect.intersects(result.rectForPoint(pointInContainer))) {
1222         updateHitTestResult(result, flipForWritingMode(pointInContainer - toLayoutSize(adjustedLocation)));
1223         if (!result.addNodeToRectBasedTestResult(node(), pointInContainer, boundsRect))
1224             return true;
1225     }
1226
1227     return false;
1228 }
1229
1230 }