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 "Document.h"
32#include "FixedTableLayout.h"
33#include "FrameView.h"
34#include "HitTestResult.h"
35#include "HTMLNames.h"
36#include "LayoutRepainter.h"
37#include "RenderLayer.h"
38#include "RenderTableCaption.h"
39#include "RenderTableCell.h"
40#include "RenderTableCol.h"
41#include "RenderTableSection.h"
42#include "RenderView.h"
43#include "StyleInheritedData.h"
44#include <wtf/StackStats.h>
45
46using namespace std;
47
48namespace WebCore {
49
50using namespace HTMLNames;
51
52RenderTable::RenderTable(Element* element)
53    : RenderBlock(element)
54    , m_head(0)
55    , m_foot(0)
56    , m_firstBody(0)
57    , m_currentBorder(0)
58    , m_collapsedBordersValid(false)
59    , m_hasColElements(false)
60    , m_needsSectionRecalc(false)
61    , m_columnLogicalWidthChanged(false)
62    , m_columnRenderersValid(false)
63    , m_hSpacing(0)
64    , m_vSpacing(0)
65    , m_borderStart(0)
66    , m_borderEnd(0)
67{
68    setChildrenInline(false);
69    m_columnPos.fill(0, 1);
70
71}
72
73RenderTable::~RenderTable()
74{
75}
76
77void RenderTable::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
78{
79    RenderBlock::styleDidChange(diff, oldStyle);
80    propagateStyleToAnonymousChildren();
81
82    ETableLayout oldTableLayout = oldStyle ? oldStyle->tableLayout() : TAUTO;
83
84    // In the collapsed border model, there is no cell spacing.
85    m_hSpacing = collapseBorders() ? 0 : style()->horizontalBorderSpacing();
86    m_vSpacing = collapseBorders() ? 0 : style()->verticalBorderSpacing();
87    m_columnPos[0] = m_hSpacing;
88
89    if (!m_tableLayout || style()->tableLayout() != oldTableLayout) {
90        // According to the CSS2 spec, you only use fixed table layout if an
91        // explicit width is specified on the table.  Auto width implies auto table layout.
92        if (style()->tableLayout() == TFIXED && !style()->logicalWidth().isAuto())
93            m_tableLayout = adoptPtr(new FixedTableLayout(this));
94        else
95            m_tableLayout = adoptPtr(new AutoTableLayout(this));
96    }
97
98    // If border was changed, invalidate collapsed borders cache.
99    if (!needsLayout() && oldStyle && oldStyle->border() != style()->border())
100        invalidateCollapsedBorders();
101}
102
103static inline void resetSectionPointerIfNotBefore(RenderTableSection*& ptr, RenderObject* before)
104{
105    if (!before || !ptr)
106        return;
107    RenderObject* o = before->previousSibling();
108    while (o && o != ptr)
109        o = o->previousSibling();
110    if (!o)
111        ptr = 0;
112}
113
114void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild)
115{
116    bool wrapInAnonymousSection = !child->isOutOfFlowPositioned();
117
118    if (child->isTableCaption())
119        wrapInAnonymousSection = false;
120    else if (child->isRenderTableCol()) {
121        m_hasColElements = true;
122        wrapInAnonymousSection = false;
123    } else if (child->isTableSection()) {
124        switch (child->style()->display()) {
125            case TABLE_HEADER_GROUP:
126                resetSectionPointerIfNotBefore(m_head, beforeChild);
127                if (!m_head) {
128                    m_head = toRenderTableSection(child);
129                } else {
130                    resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
131                    if (!m_firstBody)
132                        m_firstBody = toRenderTableSection(child);
133                }
134                wrapInAnonymousSection = false;
135                break;
136            case TABLE_FOOTER_GROUP:
137                resetSectionPointerIfNotBefore(m_foot, beforeChild);
138                if (!m_foot) {
139                    m_foot = toRenderTableSection(child);
140                    wrapInAnonymousSection = false;
141                    break;
142                }
143                // Fall through.
144            case TABLE_ROW_GROUP:
145                resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
146                if (!m_firstBody)
147                    m_firstBody = toRenderTableSection(child);
148                wrapInAnonymousSection = false;
149                break;
150            default:
151                ASSERT_NOT_REACHED();
152        }
153    } else if (child->isTableCell() || child->isTableRow())
154        wrapInAnonymousSection = true;
155    else
156        wrapInAnonymousSection = true;
157
158    if (child->isTableSection())
159        setNeedsSectionRecalc();
160
161    if (!wrapInAnonymousSection) {
162        if (beforeChild && beforeChild->parent() != this)
163            beforeChild = splitAnonymousBoxesAroundChild(beforeChild);
164
165        RenderBox::addChild(child, beforeChild);
166        return;
167    }
168
169    if (!beforeChild && lastChild() && lastChild()->isTableSection() && lastChild()->isAnonymous() && !lastChild()->isBeforeContent()) {
170        lastChild()->addChild(child);
171        return;
172    }
173
174    if (beforeChild && !beforeChild->isAnonymous() && beforeChild->parent() == this) {
175        RenderObject* section = beforeChild->previousSibling();
176        if (section && section->isTableSection() && section->isAnonymous()) {
177            section->addChild(child);
178            return;
179        }
180    }
181
182    RenderObject* lastBox = beforeChild;
183    while (lastBox && lastBox->parent()->isAnonymous() && !lastBox->isTableSection() && lastBox->style()->display() != TABLE_CAPTION && lastBox->style()->display() != TABLE_COLUMN_GROUP)
184        lastBox = lastBox->parent();
185    if (lastBox && lastBox->isAnonymous() && !isAfterContent(lastBox) && lastBox->isTableSection()) {
186        if (beforeChild == lastBox)
187            beforeChild = lastBox->firstChild();
188        lastBox->addChild(child, beforeChild);
189        return;
190    }
191
192    if (beforeChild && !beforeChild->isTableSection() && beforeChild->style()->display() != TABLE_CAPTION && beforeChild->style()->display() != TABLE_COLUMN_GROUP)
193        beforeChild = 0;
194
195    RenderTableSection* section = RenderTableSection::createAnonymousWithParentRenderer(this);
196    addChild(section, beforeChild);
197    section->addChild(child);
198}
199
200void RenderTable::addCaption(const RenderTableCaption* caption)
201{
202    ASSERT(m_captions.find(caption) == notFound);
203    m_captions.append(const_cast<RenderTableCaption*>(caption));
204}
205
206void RenderTable::removeCaption(const RenderTableCaption* oldCaption)
207{
208    size_t index = m_captions.find(oldCaption);
209    ASSERT(index != notFound);
210    if (index == notFound)
211        return;
212
213    m_captions.remove(index);
214}
215
216void RenderTable::invalidateCachedColumns()
217{
218    m_columnRenderersValid = false;
219    m_columnRenderers.resize(0);
220}
221
222void RenderTable::addColumn(const RenderTableCol*)
223{
224    invalidateCachedColumns();
225}
226
227void RenderTable::removeColumn(const RenderTableCol*)
228{
229    invalidateCachedColumns();
230    // We don't really need to recompute our sections, but we need to update our
231    // column count and whether we have a column. Currently, we only have one
232    // size-fit-all flag but we may have to consider splitting it.
233    setNeedsSectionRecalc();
234}
235
236void RenderTable::updateLogicalWidth()
237{
238    recalcSectionsIfNeeded();
239
240    if (isOutOfFlowPositioned()) {
241        LogicalExtentComputedValues computedValues;
242        computePositionedLogicalWidth(computedValues);
243        setLogicalWidth(computedValues.m_extent);
244        setLogicalLeft(computedValues.m_position);
245        setMarginStart(computedValues.m_margins.m_start);
246        setMarginEnd(computedValues.m_margins.m_end);
247    }
248
249    RenderBlock* cb = containingBlock();
250    RenderView* renderView = view();
251
252    LayoutUnit availableLogicalWidth = containingBlockLogicalWidthForContent();
253    bool hasPerpendicularContainingBlock = cb->style()->isHorizontalWritingMode() != style()->isHorizontalWritingMode();
254    LayoutUnit containerWidthInInlineDirection = hasPerpendicularContainingBlock ? perpendicularContainingBlockLogicalHeight() : availableLogicalWidth;
255
256    Length styleLogicalWidth = style()->logicalWidth();
257    if ((styleLogicalWidth.isSpecified() && styleLogicalWidth.isPositive()) || styleLogicalWidth.isIntrinsic())
258        setLogicalWidth(convertStyleLogicalWidthToComputedWidth(styleLogicalWidth, containerWidthInInlineDirection));
259    else {
260        // Subtract out any fixed margins from our available width for auto width tables.
261        LayoutUnit marginStart = minimumValueForLength(style()->marginStart(), availableLogicalWidth, renderView);
262        LayoutUnit marginEnd = minimumValueForLength(style()->marginEnd(), availableLogicalWidth, renderView);
263        LayoutUnit marginTotal = marginStart + marginEnd;
264
265        // Subtract out our margins to get the available content width.
266        LayoutUnit availableContentLogicalWidth = max<LayoutUnit>(0, containerWidthInInlineDirection - marginTotal);
267        if (shrinkToAvoidFloats() && cb->containsFloats() && !hasPerpendicularContainingBlock) {
268            // FIXME: Work with regions someday.
269            availableContentLogicalWidth = shrinkLogicalWidthToAvoidFloats(marginStart, marginEnd, cb, 0);
270        }
271
272        // Ensure we aren't bigger than our available width.
273        setLogicalWidth(min<int>(availableContentLogicalWidth, maxPreferredLogicalWidth()));
274    }
275
276    // Ensure we aren't smaller than our min preferred width.
277    setLogicalWidth(max<int>(logicalWidth(), minPreferredLogicalWidth()));
278
279
280    // Ensure we aren't bigger than our max-width style.
281    Length styleMaxLogicalWidth = style()->logicalMaxWidth();
282    if ((styleMaxLogicalWidth.isSpecified() && !styleMaxLogicalWidth.isNegative()) || styleMaxLogicalWidth.isIntrinsic()) {
283        LayoutUnit computedMaxLogicalWidth = convertStyleLogicalWidthToComputedWidth(styleMaxLogicalWidth, availableLogicalWidth);
284        setLogicalWidth(min<int>(logicalWidth(), computedMaxLogicalWidth));
285    }
286
287    // Ensure we aren't smaller than our min-width style.
288    Length styleMinLogicalWidth = style()->logicalMinWidth();
289    if ((styleMinLogicalWidth.isSpecified() && !styleMinLogicalWidth.isNegative()) || styleMinLogicalWidth.isIntrinsic()) {
290        LayoutUnit computedMinLogicalWidth = convertStyleLogicalWidthToComputedWidth(styleMinLogicalWidth, availableLogicalWidth);
291        setLogicalWidth(max<int>(logicalWidth(), computedMinLogicalWidth));
292    }
293
294    // Finally, with our true width determined, compute our margins for real.
295    setMarginStart(0);
296    setMarginEnd(0);
297    if (!hasPerpendicularContainingBlock) {
298        LayoutUnit containerLogicalWidthForAutoMargins = availableLogicalWidth;
299        if (avoidsFloats() && cb->containsFloats())
300            containerLogicalWidthForAutoMargins = containingBlockAvailableLineWidthInRegion(0); // FIXME: Work with regions someday.
301        ComputedMarginValues marginValues;
302        bool hasInvertedDirection =  cb->style()->isLeftToRightDirection() == style()->isLeftToRightDirection();
303        computeInlineDirectionMargins(cb, containerLogicalWidthForAutoMargins, logicalWidth(),
304            hasInvertedDirection ? marginValues.m_start : marginValues.m_end,
305            hasInvertedDirection ? marginValues.m_end : marginValues.m_start);
306        setMarginStart(marginValues.m_start);
307        setMarginEnd(marginValues.m_end);
308    } else {
309        setMarginStart(minimumValueForLength(style()->marginStart(), availableLogicalWidth, renderView));
310        setMarginEnd(minimumValueForLength(style()->marginEnd(), availableLogicalWidth, renderView));
311    }
312}
313
314// This method takes a RenderStyle's logical width, min-width, or max-width length and computes its actual value.
315LayoutUnit RenderTable::convertStyleLogicalWidthToComputedWidth(const Length& styleLogicalWidth, LayoutUnit availableWidth)
316{
317    if (styleLogicalWidth.isIntrinsic())
318        return computeIntrinsicLogicalWidthUsing(styleLogicalWidth, availableWidth, bordersPaddingAndSpacingInRowDirection());
319
320    // HTML tables' width styles already include borders and paddings, but CSS tables' width styles do not.
321    LayoutUnit borders = 0;
322    bool isCSSTable = !node() || !node()->hasTagName(tableTag);
323    if (isCSSTable && styleLogicalWidth.isSpecified() && styleLogicalWidth.isPositive() && style()->boxSizing() == CONTENT_BOX)
324        borders = borderStart() + borderEnd() + (collapseBorders() ? LayoutUnit() : paddingStart() + paddingEnd());
325
326    return minimumValueForLength(styleLogicalWidth, availableWidth, view()) + borders;
327}
328
329LayoutUnit RenderTable::convertStyleLogicalHeightToComputedHeight(const Length& styleLogicalHeight)
330{
331    LayoutUnit computedLogicalHeight = 0;
332    if (styleLogicalHeight.isFixed()) {
333        // HTML tables size as though CSS height includes border/padding, CSS tables do not.
334        LayoutUnit borders = LayoutUnit();
335        // FIXME: We cannot apply box-sizing: content-box on <table> which other browsers allow.
336        if ((node() && node()->hasTagName(tableTag)) || style()->boxSizing() == BORDER_BOX) {
337            LayoutUnit borderAndPaddingBefore = borderBefore() + (collapseBorders() ? LayoutUnit() : paddingBefore());
338            LayoutUnit borderAndPaddingAfter = borderAfter() + (collapseBorders() ? LayoutUnit() : paddingAfter());
339            borders = borderAndPaddingBefore + borderAndPaddingAfter;
340        }
341        computedLogicalHeight = styleLogicalHeight.value() - borders;
342    } else if (styleLogicalHeight.isPercent())
343        computedLogicalHeight = computePercentageLogicalHeight(styleLogicalHeight);
344    else if (styleLogicalHeight.isViewportPercentage())
345        computedLogicalHeight = minimumValueForLength(styleLogicalHeight, 0, view());
346    else
347        ASSERT_NOT_REACHED();
348    return max<LayoutUnit>(0, computedLogicalHeight);
349}
350
351void RenderTable::layoutCaption(RenderTableCaption* caption)
352{
353    LayoutRect captionRect(caption->frameRect());
354
355    if (caption->needsLayout()) {
356        // The margins may not be available but ensure the caption is at least located beneath any previous sibling caption
357        // so that it does not mistakenly think any floats in the previous caption intrude into it.
358        caption->setLogicalLocation(LayoutPoint(caption->marginStart(), caption->marginBefore() + logicalHeight()));
359        // If RenderTableCaption ever gets a layout() function, use it here.
360        caption->layoutIfNeeded();
361    }
362    // Apply the margins to the location now that they are definitely available from layout
363    caption->setLogicalLocation(LayoutPoint(caption->marginStart(), caption->marginBefore() + logicalHeight()));
364
365    if (!selfNeedsLayout() && caption->checkForRepaintDuringLayout())
366        caption->repaintDuringLayoutIfMoved(captionRect);
367
368    setLogicalHeight(logicalHeight() + caption->logicalHeight() + caption->marginBefore() + caption->marginAfter());
369}
370
371void RenderTable::distributeExtraLogicalHeight(int extraLogicalHeight)
372{
373    if (extraLogicalHeight <= 0)
374        return;
375
376    // FIXME: Distribute the extra logical height between all table sections instead of giving it all to the first one.
377    if (RenderTableSection* section = firstBody())
378        extraLogicalHeight -= section->distributeExtraLogicalHeightToRows(extraLogicalHeight);
379
380    // FIXME: We really would like to enable this ASSERT to ensure that all the extra space has been distributed.
381    // However our current distribution algorithm does not round properly and thus we can have some remaining height.
382    // ASSERT(!topSection() || !extraLogicalHeight);
383}
384
385void RenderTable::simplifiedNormalFlowLayout()
386{
387    for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) {
388        section->layoutIfNeeded();
389        section->computeOverflowFromCells();
390    }
391}
392
393void RenderTable::layout()
394{
395    StackStats::LayoutCheckPoint layoutCheckPoint;
396    ASSERT(needsLayout());
397
398    if (simplifiedLayout())
399        return;
400
401    recalcSectionsIfNeeded();
402    // FIXME: We should do this recalc lazily in borderStart/borderEnd so that we don't have to make sure
403    // to call this before we call borderStart/borderEnd to avoid getting a stale value.
404    recalcBordersInRowDirection();
405
406    LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
407    LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
408
409    setLogicalHeight(0);
410
411    initMaxMarginValues();
412
413    LayoutUnit oldLogicalWidth = logicalWidth();
414    updateLogicalWidth();
415
416    if (logicalWidth() != oldLogicalWidth) {
417        for (unsigned i = 0; i < m_captions.size(); i++)
418            m_captions[i]->setNeedsLayout(true, MarkOnlyThis);
419    }
420    // FIXME: The optimisation below doesn't work since the internal table
421    // layout could have changed.  we need to add a flag to the table
422    // layout that tells us if something has changed in the min max
423    // calculations to do it correctly.
424//     if ( oldWidth != width() || columns.size() + 1 != columnPos.size() )
425    m_tableLayout->layout();
426
427    LayoutUnit totalSectionLogicalHeight = 0;
428    LayoutUnit oldTableLogicalTop = 0;
429    for (unsigned i = 0; i < m_captions.size(); i++)
430        oldTableLogicalTop += m_captions[i]->logicalHeight() + m_captions[i]->marginBefore() + m_captions[i]->marginAfter();
431
432    bool collapsing = collapseBorders();
433
434    for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
435        if (child->isTableSection()) {
436            RenderTableSection* section = toRenderTableSection(child);
437            if (m_columnLogicalWidthChanged)
438                section->setChildNeedsLayout(true, MarkOnlyThis);
439            section->layoutIfNeeded();
440            totalSectionLogicalHeight += section->calcRowLogicalHeight();
441            if (collapsing)
442                section->recalcOuterBorder();
443            ASSERT(!section->needsLayout());
444        } else if (child->isRenderTableCol()) {
445            child->layoutIfNeeded();
446            ASSERT(!child->needsLayout());
447        }
448    }
449
450    // If any table section moved vertically, we will just repaint everything from that
451    // section down (it is quite unlikely that any of the following sections
452    // did not shift).
453    bool sectionMoved = false;
454    LayoutUnit movedSectionLogicalTop = 0;
455
456    // FIXME: Collapse caption margin.
457    if (!m_captions.isEmpty()) {
458        for (unsigned i = 0; i < m_captions.size(); i++) {
459            if (m_captions[i]->style()->captionSide() == CAPBOTTOM)
460                continue;
461            layoutCaption(m_captions[i]);
462        }
463        if (logicalHeight() != oldTableLogicalTop) {
464            sectionMoved = true;
465            movedSectionLogicalTop = min(logicalHeight(), oldTableLogicalTop);
466        }
467    }
468
469    LayoutUnit borderAndPaddingBefore = borderBefore() + (collapsing ? LayoutUnit() : paddingBefore());
470    LayoutUnit borderAndPaddingAfter = borderAfter() + (collapsing ? LayoutUnit() : paddingAfter());
471
472    setLogicalHeight(logicalHeight() + borderAndPaddingBefore);
473
474    if (!isOutOfFlowPositioned())
475        updateLogicalHeight();
476
477    LayoutUnit computedLogicalHeight = 0;
478
479    Length logicalHeightLength = style()->logicalHeight();
480    if (logicalHeightLength.isSpecified() && logicalHeightLength.isPositive())
481        computedLogicalHeight = convertStyleLogicalHeightToComputedHeight(logicalHeightLength);
482
483    Length logicalMaxHeightLength = style()->logicalMaxHeight();
484    if (logicalMaxHeightLength.isSpecified() && !logicalMaxHeightLength.isNegative()) {
485        LayoutUnit computedMaxLogicalHeight = convertStyleLogicalHeightToComputedHeight(logicalMaxHeightLength);
486        computedLogicalHeight = min(computedLogicalHeight, computedMaxLogicalHeight);
487    }
488
489    Length logicalMinHeightLength = style()->logicalMinHeight();
490    if (logicalMinHeightLength.isSpecified() && !logicalMinHeightLength.isNegative()) {
491        LayoutUnit computedMinLogicalHeight = convertStyleLogicalHeightToComputedHeight(logicalMinHeightLength);
492        computedLogicalHeight = max(computedLogicalHeight, computedMinLogicalHeight);
493    }
494
495    distributeExtraLogicalHeight(floorToInt(computedLogicalHeight - totalSectionLogicalHeight));
496
497    for (RenderTableSection* section = topSection(); section; section = sectionBelow(section))
498        section->layoutRows();
499
500    if (!topSection() && computedLogicalHeight > totalSectionLogicalHeight && !document()->inQuirksMode()) {
501        // Completely empty tables (with no sections or anything) should at least honor specified height
502        // in strict mode.
503        setLogicalHeight(logicalHeight() + computedLogicalHeight);
504    }
505
506    LayoutUnit sectionLogicalLeft = style()->isLeftToRightDirection() ? borderStart() : borderEnd();
507    if (!collapsing)
508        sectionLogicalLeft += style()->isLeftToRightDirection() ? paddingStart() : paddingEnd();
509
510    // position the table sections
511    RenderTableSection* section = topSection();
512    while (section) {
513        if (!sectionMoved && section->logicalTop() != logicalHeight()) {
514            sectionMoved = true;
515            movedSectionLogicalTop = min(logicalHeight(), section->logicalTop()) + (style()->isHorizontalWritingMode() ? section->visualOverflowRect().y() : section->visualOverflowRect().x());
516        }
517        section->setLogicalLocation(LayoutPoint(sectionLogicalLeft, logicalHeight()));
518
519        setLogicalHeight(logicalHeight() + section->logicalHeight());
520        section = sectionBelow(section);
521    }
522
523    setLogicalHeight(logicalHeight() + borderAndPaddingAfter);
524
525    for (unsigned i = 0; i < m_captions.size(); i++) {
526        if (m_captions[i]->style()->captionSide() != CAPBOTTOM)
527            continue;
528        layoutCaption(m_captions[i]);
529    }
530
531    if (isOutOfFlowPositioned())
532        updateLogicalHeight();
533
534    // table can be containing block of positioned elements.
535    // FIXME: Only pass true if width or height changed.
536    layoutPositionedObjects(true);
537
538    updateLayerTransform();
539
540    // Layout was changed, so probably borders too.
541    invalidateCollapsedBorders();
542
543    computeOverflow(clientLogicalBottom());
544
545    statePusher.pop();
546
547    if (view()->layoutState()->pageLogicalHeight())
548        setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(this, logicalTop()));
549
550    bool didFullRepaint = repainter.repaintAfterLayout();
551    // Repaint with our new bounds if they are different from our old bounds.
552    if (!didFullRepaint && sectionMoved) {
553        if (style()->isHorizontalWritingMode())
554            repaintRectangle(LayoutRect(visualOverflowRect().x(), movedSectionLogicalTop, visualOverflowRect().width(), visualOverflowRect().maxY() - movedSectionLogicalTop));
555        else
556            repaintRectangle(LayoutRect(movedSectionLogicalTop, visualOverflowRect().y(), visualOverflowRect().maxX() - movedSectionLogicalTop, visualOverflowRect().height()));
557    }
558
559    m_columnLogicalWidthChanged = false;
560    setNeedsLayout(false);
561}
562
563// Collect all the unique border values that we want to paint in a sorted list.
564void RenderTable::recalcCollapsedBorders()
565{
566    if (m_collapsedBordersValid)
567        return;
568    m_collapsedBordersValid = true;
569    m_collapsedBorders.clear();
570    for (RenderObject* section = firstChild(); section; section = section->nextSibling()) {
571        if (!section->isTableSection())
572            continue;
573        for (RenderObject* row = section->firstChild(); row; row = row->nextSibling()) {
574            if (!row->isTableRow())
575                continue;
576            for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) {
577                if (!cell->isTableCell())
578                    continue;
579                ASSERT(toRenderTableCell(cell)->table() == this);
580                toRenderTableCell(cell)->collectBorderValues(m_collapsedBorders);
581            }
582        }
583    }
584    RenderTableCell::sortBorderValues(m_collapsedBorders);
585}
586
587
588void RenderTable::addOverflowFromChildren()
589{
590    // Add overflow from borders.
591    // Technically it's odd that we are incorporating the borders into layout overflow, which is only supposed to be about overflow from our
592    // descendant objects, but since tables don't support overflow:auto, this works out fine.
593    if (collapseBorders()) {
594        int rightBorderOverflow = width() + outerBorderRight() - borderRight();
595        int leftBorderOverflow = borderLeft() - outerBorderLeft();
596        int bottomBorderOverflow = height() + outerBorderBottom() - borderBottom();
597        int topBorderOverflow = borderTop() - outerBorderTop();
598        IntRect borderOverflowRect(leftBorderOverflow, topBorderOverflow, rightBorderOverflow - leftBorderOverflow, bottomBorderOverflow - topBorderOverflow);
599        if (borderOverflowRect != pixelSnappedBorderBoxRect()) {
600            addLayoutOverflow(borderOverflowRect);
601            addVisualOverflow(borderOverflowRect);
602        }
603    }
604
605    // Add overflow from our caption.
606    for (unsigned i = 0; i < m_captions.size(); i++)
607        addOverflowFromChild(m_captions[i]);
608
609    // Add overflow from our sections.
610    for (RenderTableSection* section = topSection(); section; section = sectionBelow(section))
611        addOverflowFromChild(section);
612}
613
614void RenderTable::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
615{
616    LayoutPoint adjustedPaintOffset = paintOffset + location();
617
618    PaintPhase paintPhase = paintInfo.phase;
619
620    if (!isRoot()) {
621        LayoutRect overflowBox = visualOverflowRect();
622        flipForWritingMode(overflowBox);
623        overflowBox.inflate(maximalOutlineSize(paintInfo.phase));
624        overflowBox.moveBy(adjustedPaintOffset);
625        if (!overflowBox.intersects(paintInfo.rect))
626            return;
627    }
628
629    bool pushedClip = pushContentsClip(paintInfo, adjustedPaintOffset);
630    paintObject(paintInfo, adjustedPaintOffset);
631    if (pushedClip)
632        popContentsClip(paintInfo, paintPhase, adjustedPaintOffset);
633}
634
635void RenderTable::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
636{
637    PaintPhase paintPhase = paintInfo.phase;
638    if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && hasBoxDecorations() && style()->visibility() == VISIBLE)
639        paintBoxDecorations(paintInfo, paintOffset);
640
641    if (paintPhase == PaintPhaseMask) {
642        paintMask(paintInfo, paintOffset);
643        return;
644    }
645
646    // We're done.  We don't bother painting any children.
647    if (paintPhase == PaintPhaseBlockBackground)
648        return;
649
650    // We don't paint our own background, but we do let the kids paint their backgrounds.
651    if (paintPhase == PaintPhaseChildBlockBackgrounds)
652        paintPhase = PaintPhaseChildBlockBackground;
653
654    PaintInfo info(paintInfo);
655    info.phase = paintPhase;
656    info.updateSubtreePaintRootForChildren(this);
657
658    for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
659        if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child->isTableCaption())) {
660            LayoutPoint childPoint = flipForWritingModeForChild(toRenderBox(child), paintOffset);
661            child->paint(info, childPoint);
662        }
663    }
664
665    if (collapseBorders() && paintPhase == PaintPhaseChildBlockBackground && style()->visibility() == VISIBLE) {
666        recalcCollapsedBorders();
667        // Using our cached sorted styles, we then do individual passes,
668        // painting each style of border from lowest precedence to highest precedence.
669        info.phase = PaintPhaseCollapsedTableBorders;
670        size_t count = m_collapsedBorders.size();
671        for (size_t i = 0; i < count; ++i) {
672            m_currentBorder = &m_collapsedBorders[i];
673            for (RenderTableSection* section = bottomSection(); section; section = sectionAbove(section)) {
674                LayoutPoint childPoint = flipForWritingModeForChild(section, paintOffset);
675                section->paint(info, childPoint);
676            }
677        }
678        m_currentBorder = 0;
679    }
680
681    // Paint outline.
682    if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE)
683        paintOutline(paintInfo.context, LayoutRect(paintOffset, size()));
684}
685
686void RenderTable::subtractCaptionRect(LayoutRect& rect) const
687{
688    for (unsigned i = 0; i < m_captions.size(); i++) {
689        LayoutUnit captionLogicalHeight = m_captions[i]->logicalHeight() + m_captions[i]->marginBefore() + m_captions[i]->marginAfter();
690        bool captionIsBefore = (m_captions[i]->style()->captionSide() != CAPBOTTOM) ^ style()->isFlippedBlocksWritingMode();
691        if (style()->isHorizontalWritingMode()) {
692            rect.setHeight(rect.height() - captionLogicalHeight);
693            if (captionIsBefore)
694                rect.move(0, captionLogicalHeight);
695        } else {
696            rect.setWidth(rect.width() - captionLogicalHeight);
697            if (captionIsBefore)
698                rect.move(captionLogicalHeight, 0);
699        }
700    }
701}
702
703void RenderTable::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
704{
705    if (!paintInfo.shouldPaintWithinRoot(this))
706        return;
707
708    LayoutRect rect(paintOffset, size());
709    subtractCaptionRect(rect);
710
711    BackgroundBleedAvoidance bleedAvoidance = determineBackgroundBleedAvoidance(paintInfo.context);
712    if (!boxShadowShouldBeAppliedToBackground(bleedAvoidance))
713        paintBoxShadow(paintInfo, rect, style(), Normal);
714    paintBackground(paintInfo, rect, bleedAvoidance);
715    paintBoxShadow(paintInfo, rect, style(), Inset);
716
717    if (style()->hasBorder() && !collapseBorders())
718        paintBorder(paintInfo, rect, style());
719}
720
721void RenderTable::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
722{
723    if (style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
724        return;
725
726    LayoutRect rect(paintOffset, size());
727    subtractCaptionRect(rect);
728
729    paintMaskImages(paintInfo, rect);
730}
731
732void RenderTable::computeIntrinsicLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth) const
733{
734    recalcSectionsIfNeeded();
735    // FIXME: Do the recalc in borderStart/borderEnd and make those const_cast this call.
736    // Then m_borderStart/m_borderEnd will be transparent a cache and it removes the possibility
737    // of reading out stale values.
738    const_cast<RenderTable*>(this)->recalcBordersInRowDirection();
739    // FIXME: Restructure the table layout code so that we can make this method const.
740    const_cast<RenderTable*>(this)->m_tableLayout->computeIntrinsicLogicalWidths(minWidth, maxWidth);
741
742    // FIXME: We should include captions widths here like we do in computePreferredLogicalWidths.
743}
744
745void RenderTable::computePreferredLogicalWidths()
746{
747    ASSERT(preferredLogicalWidthsDirty());
748
749    computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
750
751    int bordersPaddingAndSpacing = bordersPaddingAndSpacingInRowDirection();
752    m_minPreferredLogicalWidth += bordersPaddingAndSpacing;
753    m_maxPreferredLogicalWidth += bordersPaddingAndSpacing;
754
755    m_tableLayout->applyPreferredLogicalWidthQuirks(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
756
757    for (unsigned i = 0; i < m_captions.size(); i++)
758        m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, m_captions[i]->minPreferredLogicalWidth());
759
760    RenderStyle* styleToUse = style();
761    // FIXME: This should probably be checking for isSpecified since you should be able to use percentage, calc or viewport relative values for min-width.
762    if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0) {
763        m_maxPreferredLogicalWidth = std::max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
764        m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
765    }
766
767    // FIXME: This should probably be checking for isSpecified since you should be able to use percentage, calc or viewport relative values for maxWidth.
768    if (styleToUse->logicalMaxWidth().isFixed()) {
769        m_maxPreferredLogicalWidth = std::min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value()));
770        m_minPreferredLogicalWidth = std::min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value()));
771    }
772
773    // FIXME: We should be adding borderAndPaddingLogicalWidth here, but m_tableLayout->computePreferredLogicalWidths already does,
774    // so a bunch of tests break doing this naively.
775    setPreferredLogicalWidthsDirty(false);
776}
777
778RenderTableSection* RenderTable::topNonEmptySection() const
779{
780    RenderTableSection* section = topSection();
781    if (section && !section->numRows())
782        section = sectionBelow(section, SkipEmptySections);
783    return section;
784}
785
786void RenderTable::splitColumn(unsigned position, unsigned firstSpan)
787{
788    // We split the column at "position", taking "firstSpan" cells from the span.
789    ASSERT(m_columns[position].span > firstSpan);
790    m_columns.insert(position, ColumnStruct(firstSpan));
791    m_columns[position + 1].span -= firstSpan;
792
793    // Propagate the change in our columns representation to the sections that don't need
794    // cell recalc. If they do, they will be synced up directly with m_columns later.
795    for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
796        if (!child->isTableSection())
797            continue;
798
799        RenderTableSection* section = toRenderTableSection(child);
800        if (section->needsCellRecalc())
801            continue;
802
803        section->splitColumn(position, firstSpan);
804    }
805
806    m_columnPos.grow(numEffCols() + 1);
807}
808
809void RenderTable::appendColumn(unsigned span)
810{
811    unsigned newColumnIndex = m_columns.size();
812    m_columns.append(ColumnStruct(span));
813
814    // Propagate the change in our columns representation to the sections that don't need
815    // cell recalc. If they do, they will be synced up directly with m_columns later.
816    for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
817        if (!child->isTableSection())
818            continue;
819
820        RenderTableSection* section = toRenderTableSection(child);
821        if (section->needsCellRecalc())
822            continue;
823
824        section->appendColumn(newColumnIndex);
825    }
826
827    m_columnPos.grow(numEffCols() + 1);
828}
829
830RenderTableCol* RenderTable::firstColumn() const
831{
832    for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
833        if (child->isRenderTableCol())
834            return toRenderTableCol(child);
835
836        // We allow only table-captions before columns or column-groups.
837        if (!child->isTableCaption())
838            return 0;
839    }
840
841    return 0;
842}
843
844void RenderTable::updateColumnCache() const
845{
846    ASSERT(m_hasColElements);
847    ASSERT(m_columnRenderers.isEmpty());
848    ASSERT(!m_columnRenderersValid);
849
850    for (RenderTableCol* columnRenderer = firstColumn(); columnRenderer; columnRenderer = columnRenderer->nextColumn()) {
851        if (columnRenderer->isTableColumnGroupWithColumnChildren())
852            continue;
853        m_columnRenderers.append(columnRenderer);
854    }
855    m_columnRenderersValid = true;
856}
857
858RenderTableCol* RenderTable::slowColElement(unsigned col, bool* startEdge, bool* endEdge) const
859{
860    ASSERT(m_hasColElements);
861
862    if (!m_columnRenderersValid)
863        updateColumnCache();
864
865    unsigned columnCount = 0;
866    for (unsigned i = 0; i < m_columnRenderers.size(); i++) {
867        RenderTableCol* columnRenderer = m_columnRenderers[i];
868        unsigned span = columnRenderer->span();
869        unsigned startCol = columnCount;
870        ASSERT(span >= 1);
871        unsigned endCol = columnCount + span - 1;
872        columnCount += span;
873        if (columnCount > col) {
874            if (startEdge)
875                *startEdge = startCol == col;
876            if (endEdge)
877                *endEdge = endCol == col;
878            return columnRenderer;
879        }
880    }
881    return 0;
882}
883
884void RenderTable::recalcSections() const
885{
886    ASSERT(m_needsSectionRecalc);
887
888    m_head = 0;
889    m_foot = 0;
890    m_firstBody = 0;
891    m_hasColElements = false;
892
893    // We need to get valid pointers to caption, head, foot and first body again
894    RenderObject* nextSibling;
895    for (RenderObject* child = firstChild(); child; child = nextSibling) {
896        nextSibling = child->nextSibling();
897        switch (child->style()->display()) {
898        case TABLE_COLUMN:
899        case TABLE_COLUMN_GROUP:
900            m_hasColElements = true;
901            break;
902        case TABLE_HEADER_GROUP:
903            if (child->isTableSection()) {
904                RenderTableSection* section = toRenderTableSection(child);
905                if (!m_head)
906                    m_head = section;
907                else if (!m_firstBody)
908                    m_firstBody = section;
909                section->recalcCellsIfNeeded();
910            }
911            break;
912        case TABLE_FOOTER_GROUP:
913            if (child->isTableSection()) {
914                RenderTableSection* section = toRenderTableSection(child);
915                if (!m_foot)
916                    m_foot = section;
917                else if (!m_firstBody)
918                    m_firstBody = section;
919                section->recalcCellsIfNeeded();
920            }
921            break;
922        case TABLE_ROW_GROUP:
923            if (child->isTableSection()) {
924                RenderTableSection* section = toRenderTableSection(child);
925                if (!m_firstBody)
926                    m_firstBody = section;
927                section->recalcCellsIfNeeded();
928            }
929            break;
930        default:
931            break;
932        }
933    }
934
935    // repair column count (addChild can grow it too much, because it always adds elements to the last row of a section)
936    unsigned maxCols = 0;
937    for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
938        if (child->isTableSection()) {
939            RenderTableSection* section = toRenderTableSection(child);
940            unsigned sectionCols = section->numColumns();
941            if (sectionCols > maxCols)
942                maxCols = sectionCols;
943        }
944    }
945
946    m_columns.resize(maxCols);
947    m_columnPos.resize(maxCols + 1);
948
949    ASSERT(selfNeedsLayout());
950
951    m_needsSectionRecalc = false;
952}
953
954int RenderTable::calcBorderStart() const
955{
956    if (!collapseBorders())
957        return RenderBlock::borderStart();
958
959    // Determined by the first cell of the first row. See the CSS 2.1 spec, section 17.6.2.
960    if (!numEffCols())
961        return 0;
962
963    unsigned borderWidth = 0;
964
965    const BorderValue& tableStartBorder = style()->borderStart();
966    if (tableStartBorder.style() == BHIDDEN)
967        return 0;
968    if (tableStartBorder.style() > BHIDDEN)
969        borderWidth = tableStartBorder.width();
970
971    if (RenderTableCol* column = colElement(0)) {
972        // FIXME: We don't account for direction on columns and column groups.
973        const BorderValue& columnAdjoiningBorder = column->style()->borderStart();
974        if (columnAdjoiningBorder.style() == BHIDDEN)
975            return 0;
976        if (columnAdjoiningBorder.style() > BHIDDEN)
977            borderWidth = max(borderWidth, columnAdjoiningBorder.width());
978        // FIXME: This logic doesn't properly account for the first column in the first column-group case.
979    }
980
981    if (const RenderTableSection* topNonEmptySection = this->topNonEmptySection()) {
982        const BorderValue& sectionAdjoiningBorder = topNonEmptySection->borderAdjoiningTableStart();
983        if (sectionAdjoiningBorder.style() == BHIDDEN)
984            return 0;
985
986        if (sectionAdjoiningBorder.style() > BHIDDEN)
987            borderWidth = max(borderWidth, sectionAdjoiningBorder.width());
988
989        if (const RenderTableCell* adjoiningStartCell = topNonEmptySection->firstRowCellAdjoiningTableStart()) {
990            // FIXME: Make this work with perpendicular and flipped cells.
991            const BorderValue& startCellAdjoiningBorder = adjoiningStartCell->borderAdjoiningTableStart();
992            if (startCellAdjoiningBorder.style() == BHIDDEN)
993                return 0;
994
995            const BorderValue& firstRowAdjoiningBorder = adjoiningStartCell->row()->borderAdjoiningTableStart();
996            if (firstRowAdjoiningBorder.style() == BHIDDEN)
997                return 0;
998
999            if (startCellAdjoiningBorder.style() > BHIDDEN)
1000                borderWidth = max(borderWidth, startCellAdjoiningBorder.width());
1001            if (firstRowAdjoiningBorder.style() > BHIDDEN)
1002                borderWidth = max(borderWidth, firstRowAdjoiningBorder.width());
1003        }
1004    }
1005    return (borderWidth + (style()->isLeftToRightDirection() ? 0 : 1)) / 2;
1006}
1007
1008int RenderTable::calcBorderEnd() const
1009{
1010    if (!collapseBorders())
1011        return RenderBlock::borderEnd();
1012
1013    // Determined by the last cell of the first row. See the CSS 2.1 spec, section 17.6.2.
1014    if (!numEffCols())
1015        return 0;
1016
1017    unsigned borderWidth = 0;
1018
1019    const BorderValue& tableEndBorder = style()->borderEnd();
1020    if (tableEndBorder.style() == BHIDDEN)
1021        return 0;
1022    if (tableEndBorder.style() > BHIDDEN)
1023        borderWidth = tableEndBorder.width();
1024
1025    unsigned endColumn = numEffCols() - 1;
1026    if (RenderTableCol* column = colElement(endColumn)) {
1027        // FIXME: We don't account for direction on columns and column groups.
1028        const BorderValue& columnAdjoiningBorder = column->style()->borderEnd();
1029        if (columnAdjoiningBorder.style() == BHIDDEN)
1030            return 0;
1031        if (columnAdjoiningBorder.style() > BHIDDEN)
1032            borderWidth = max(borderWidth, columnAdjoiningBorder.width());
1033        // FIXME: This logic doesn't properly account for the last column in the last column-group case.
1034    }
1035
1036    if (const RenderTableSection* topNonEmptySection = this->topNonEmptySection()) {
1037        const BorderValue& sectionAdjoiningBorder = topNonEmptySection->borderAdjoiningTableEnd();
1038        if (sectionAdjoiningBorder.style() == BHIDDEN)
1039            return 0;
1040
1041        if (sectionAdjoiningBorder.style() > BHIDDEN)
1042            borderWidth = max(borderWidth, sectionAdjoiningBorder.width());
1043
1044        if (const RenderTableCell* adjoiningEndCell = topNonEmptySection->firstRowCellAdjoiningTableEnd()) {
1045            // FIXME: Make this work with perpendicular and flipped cells.
1046            const BorderValue& endCellAdjoiningBorder = adjoiningEndCell->borderAdjoiningTableEnd();
1047            if (endCellAdjoiningBorder.style() == BHIDDEN)
1048                return 0;
1049
1050            const BorderValue& firstRowAdjoiningBorder = adjoiningEndCell->row()->borderAdjoiningTableEnd();
1051            if (firstRowAdjoiningBorder.style() == BHIDDEN)
1052                return 0;
1053
1054            if (endCellAdjoiningBorder.style() > BHIDDEN)
1055                borderWidth = max(borderWidth, endCellAdjoiningBorder.width());
1056            if (firstRowAdjoiningBorder.style() > BHIDDEN)
1057                borderWidth = max(borderWidth, firstRowAdjoiningBorder.width());
1058        }
1059    }
1060    return (borderWidth + (style()->isLeftToRightDirection() ? 1 : 0)) / 2;
1061}
1062
1063void RenderTable::recalcBordersInRowDirection()
1064{
1065    // FIXME: We need to compute the collapsed before / after borders in the same fashion.
1066    m_borderStart = calcBorderStart();
1067    m_borderEnd = calcBorderEnd();
1068}
1069
1070int RenderTable::borderBefore() const
1071{
1072    if (collapseBorders()) {
1073        recalcSectionsIfNeeded();
1074        return outerBorderBefore();
1075    }
1076    return RenderBlock::borderBefore();
1077}
1078
1079int RenderTable::borderAfter() const
1080{
1081    if (collapseBorders()) {
1082        recalcSectionsIfNeeded();
1083        return outerBorderAfter();
1084    }
1085    return RenderBlock::borderAfter();
1086}
1087
1088int RenderTable::outerBorderBefore() const
1089{
1090    if (!collapseBorders())
1091        return 0;
1092    int borderWidth = 0;
1093    if (RenderTableSection* topSection = this->topSection()) {
1094        borderWidth = topSection->outerBorderBefore();
1095        if (borderWidth < 0)
1096            return 0;   // Overridden by hidden
1097    }
1098    const BorderValue& tb = style()->borderBefore();
1099    if (tb.style() == BHIDDEN)
1100        return 0;
1101    if (tb.style() > BHIDDEN)
1102        borderWidth = max<int>(borderWidth, tb.width() / 2);
1103    return borderWidth;
1104}
1105
1106int RenderTable::outerBorderAfter() const
1107{
1108    if (!collapseBorders())
1109        return 0;
1110    int borderWidth = 0;
1111
1112    if (RenderTableSection* section = bottomSection()) {
1113        borderWidth = section->outerBorderAfter();
1114        if (borderWidth < 0)
1115            return 0; // Overridden by hidden
1116    }
1117    const BorderValue& tb = style()->borderAfter();
1118    if (tb.style() == BHIDDEN)
1119        return 0;
1120    if (tb.style() > BHIDDEN)
1121        borderWidth = max<int>(borderWidth, (tb.width() + 1) / 2);
1122    return borderWidth;
1123}
1124
1125int RenderTable::outerBorderStart() const
1126{
1127    if (!collapseBorders())
1128        return 0;
1129
1130    int borderWidth = 0;
1131
1132    const BorderValue& tb = style()->borderStart();
1133    if (tb.style() == BHIDDEN)
1134        return 0;
1135    if (tb.style() > BHIDDEN)
1136        borderWidth = (tb.width() + (style()->isLeftToRightDirection() ? 0 : 1)) / 2;
1137
1138    bool allHidden = true;
1139    for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) {
1140        int sw = section->outerBorderStart();
1141        if (sw < 0)
1142            continue;
1143        allHidden = false;
1144        borderWidth = max(borderWidth, sw);
1145    }
1146    if (allHidden)
1147        return 0;
1148
1149    return borderWidth;
1150}
1151
1152int RenderTable::outerBorderEnd() const
1153{
1154    if (!collapseBorders())
1155        return 0;
1156
1157    int borderWidth = 0;
1158
1159    const BorderValue& tb = style()->borderEnd();
1160    if (tb.style() == BHIDDEN)
1161        return 0;
1162    if (tb.style() > BHIDDEN)
1163        borderWidth = (tb.width() + (style()->isLeftToRightDirection() ? 1 : 0)) / 2;
1164
1165    bool allHidden = true;
1166    for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) {
1167        int sw = section->outerBorderEnd();
1168        if (sw < 0)
1169            continue;
1170        allHidden = false;
1171        borderWidth = max(borderWidth, sw);
1172    }
1173    if (allHidden)
1174        return 0;
1175
1176    return borderWidth;
1177}
1178
1179RenderTableSection* RenderTable::sectionAbove(const RenderTableSection* section, SkipEmptySectionsValue skipEmptySections) const
1180{
1181    recalcSectionsIfNeeded();
1182
1183    if (section == m_head)
1184        return 0;
1185
1186    RenderObject* prevSection = section == m_foot ? lastChild() : section->previousSibling();
1187    while (prevSection) {
1188        if (prevSection->isTableSection() && prevSection != m_head && prevSection != m_foot && (skipEmptySections == DoNotSkipEmptySections || toRenderTableSection(prevSection)->numRows()))
1189            break;
1190        prevSection = prevSection->previousSibling();
1191    }
1192    if (!prevSection && m_head && (skipEmptySections == DoNotSkipEmptySections || m_head->numRows()))
1193        prevSection = m_head;
1194    return toRenderTableSection(prevSection);
1195}
1196
1197RenderTableSection* RenderTable::sectionBelow(const RenderTableSection* section, SkipEmptySectionsValue skipEmptySections) const
1198{
1199    recalcSectionsIfNeeded();
1200
1201    if (section == m_foot)
1202        return 0;
1203
1204    RenderObject* nextSection = section == m_head ? firstChild() : section->nextSibling();
1205    while (nextSection) {
1206        if (nextSection->isTableSection() && nextSection != m_head && nextSection != m_foot && (skipEmptySections  == DoNotSkipEmptySections || toRenderTableSection(nextSection)->numRows()))
1207            break;
1208        nextSection = nextSection->nextSibling();
1209    }
1210    if (!nextSection && m_foot && (skipEmptySections == DoNotSkipEmptySections || m_foot->numRows()))
1211        nextSection = m_foot;
1212    return toRenderTableSection(nextSection);
1213}
1214
1215RenderTableSection* RenderTable::bottomSection() const
1216{
1217    recalcSectionsIfNeeded();
1218
1219    if (m_foot)
1220        return m_foot;
1221
1222    for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
1223        if (child->isTableSection())
1224            return toRenderTableSection(child);
1225    }
1226
1227    return 0;
1228}
1229
1230RenderTableCell* RenderTable::cellAbove(const RenderTableCell* cell) const
1231{
1232    recalcSectionsIfNeeded();
1233
1234    // Find the section and row to look in
1235    unsigned r = cell->rowIndex();
1236    RenderTableSection* section = 0;
1237    unsigned rAbove = 0;
1238    if (r > 0) {
1239        // cell is not in the first row, so use the above row in its own section
1240        section = cell->section();
1241        rAbove = r - 1;
1242    } else {
1243        section = sectionAbove(cell->section(), SkipEmptySections);
1244        if (section) {
1245            ASSERT(section->numRows());
1246            rAbove = section->numRows() - 1;
1247        }
1248    }
1249
1250    // Look up the cell in the section's grid, which requires effective col index
1251    if (section) {
1252        unsigned effCol = colToEffCol(cell->col());
1253        RenderTableSection::CellStruct& aboveCell = section->cellAt(rAbove, effCol);
1254        return aboveCell.primaryCell();
1255    } else
1256        return 0;
1257}
1258
1259RenderTableCell* RenderTable::cellBelow(const RenderTableCell* cell) const
1260{
1261    recalcSectionsIfNeeded();
1262
1263    // Find the section and row to look in
1264    unsigned r = cell->rowIndex() + cell->rowSpan() - 1;
1265    RenderTableSection* section = 0;
1266    unsigned rBelow = 0;
1267    if (r < cell->section()->numRows() - 1) {
1268        // The cell is not in the last row, so use the next row in the section.
1269        section = cell->section();
1270        rBelow = r + 1;
1271    } else {
1272        section = sectionBelow(cell->section(), SkipEmptySections);
1273        if (section)
1274            rBelow = 0;
1275    }
1276
1277    // Look up the cell in the section's grid, which requires effective col index
1278    if (section) {
1279        unsigned effCol = colToEffCol(cell->col());
1280        RenderTableSection::CellStruct& belowCell = section->cellAt(rBelow, effCol);
1281        return belowCell.primaryCell();
1282    } else
1283        return 0;
1284}
1285
1286RenderTableCell* RenderTable::cellBefore(const RenderTableCell* cell) const
1287{
1288    recalcSectionsIfNeeded();
1289
1290    RenderTableSection* section = cell->section();
1291    unsigned effCol = colToEffCol(cell->col());
1292    if (!effCol)
1293        return 0;
1294
1295    // If we hit a colspan back up to a real cell.
1296    RenderTableSection::CellStruct& prevCell = section->cellAt(cell->rowIndex(), effCol - 1);
1297    return prevCell.primaryCell();
1298}
1299
1300RenderTableCell* RenderTable::cellAfter(const RenderTableCell* cell) const
1301{
1302    recalcSectionsIfNeeded();
1303
1304    unsigned effCol = colToEffCol(cell->col() + cell->colSpan());
1305    if (effCol >= numEffCols())
1306        return 0;
1307    return cell->section()->primaryCellAt(cell->rowIndex(), effCol);
1308}
1309
1310RenderBlock* RenderTable::firstLineBlock() const
1311{
1312    return 0;
1313}
1314
1315void RenderTable::updateFirstLetter()
1316{
1317}
1318
1319int RenderTable::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
1320{
1321    LayoutUnit baseline = firstLineBoxBaseline();
1322    if (baseline != -1)
1323        return baseline;
1324
1325    return RenderBox::baselinePosition(baselineType, firstLine, direction, linePositionMode);
1326}
1327
1328int RenderTable::inlineBlockBaseline(LineDirectionMode) const
1329{
1330    // Tables are skipped when computing an inline-block's baseline.
1331    return -1;
1332}
1333
1334int RenderTable::firstLineBoxBaseline() const
1335{
1336    // The baseline of a 'table' is the same as the 'inline-table' baseline per CSS 3 Flexbox (CSS 2.1
1337    // doesn't define the baseline of a 'table' only an 'inline-table').
1338    // This is also needed to properly determine the baseline of a cell if it has a table child.
1339
1340    if (isWritingModeRoot())
1341        return -1;
1342
1343    recalcSectionsIfNeeded();
1344
1345    const RenderTableSection* topNonEmptySection = this->topNonEmptySection();
1346    if (!topNonEmptySection)
1347        return -1;
1348
1349    int baseline = topNonEmptySection->firstLineBoxBaseline();
1350    if (baseline > 0)
1351        return topNonEmptySection->logicalTop() + baseline;
1352
1353    // FIXME: A table row always has a baseline per CSS 2.1. Will this return the right value?
1354    return -1;
1355}
1356
1357LayoutRect RenderTable::overflowClipRect(const LayoutPoint& location, RenderRegion* region, OverlayScrollbarSizeRelevancy relevancy)
1358{
1359    LayoutRect rect = RenderBlock::overflowClipRect(location, region, relevancy);
1360
1361    // If we have a caption, expand the clip to include the caption.
1362    // FIXME: Technically this is wrong, but it's virtually impossible to fix this
1363    // for real until captions have been re-written.
1364    // FIXME: This code assumes (like all our other caption code) that only top/bottom are
1365    // supported.  When we actually support left/right and stop mapping them to top/bottom,
1366    // we might have to hack this code first (depending on what order we do these bug fixes in).
1367    if (!m_captions.isEmpty()) {
1368        if (style()->isHorizontalWritingMode()) {
1369            rect.setHeight(height());
1370            rect.setY(location.y());
1371        } else {
1372            rect.setWidth(width());
1373            rect.setX(location.x());
1374        }
1375    }
1376
1377    return rect;
1378}
1379
1380bool RenderTable::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
1381{
1382    LayoutPoint adjustedLocation = accumulatedOffset + location();
1383
1384    // Check kids first.
1385    if (!hasOverflowClip() || locationInContainer.intersects(overflowClipRect(adjustedLocation, locationInContainer.region()))) {
1386        for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
1387            if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child->isTableCaption())) {
1388                LayoutPoint childPoint = flipForWritingModeForChild(toRenderBox(child), adjustedLocation);
1389                if (child->nodeAtPoint(request, result, locationInContainer, childPoint, action)) {
1390                    updateHitTestResult(result, toLayoutPoint(locationInContainer.point() - childPoint));
1391                    return true;
1392                }
1393            }
1394        }
1395    }
1396
1397    // Check our bounds next.
1398    LayoutRect boundsRect(adjustedLocation, size());
1399    if (visibleToHitTesting() && (action == HitTestBlockBackground || action == HitTestChildBlockBackground) && locationInContainer.intersects(boundsRect)) {
1400        updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - toLayoutSize(adjustedLocation)));
1401        if (!result.addNodeToRectBasedTestResult(node(), request, locationInContainer, boundsRect))
1402            return true;
1403    }
1404
1405    return false;
1406}
1407
1408RenderTable* RenderTable::createAnonymousWithParentRenderer(const RenderObject* parent)
1409{
1410    RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), TABLE);
1411    RenderTable* newTable = new (parent->renderArena()) RenderTable(0);
1412    newTable->setDocumentForAnonymous(parent->document());
1413    newTable->setStyle(newStyle.release());
1414    return newTable;
1415}
1416
1417const BorderValue& RenderTable::tableStartBorderAdjoiningCell(const RenderTableCell* cell) const
1418{
1419    ASSERT(cell->isFirstOrLastCellInRow());
1420    if (hasSameDirectionAs(cell->row()))
1421        return style()->borderStart();
1422
1423    return style()->borderEnd();
1424}
1425
1426const BorderValue& RenderTable::tableEndBorderAdjoiningCell(const RenderTableCell* cell) const
1427{
1428    ASSERT(cell->isFirstOrLastCellInRow());
1429    if (hasSameDirectionAs(cell->row()))
1430        return style()->borderEnd();
1431
1432    return style()->borderStart();
1433}
1434
1435}
1436