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