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