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