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