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