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  *
      9  * This library is free software; you can redistribute it and/or
     10  * modify it under the terms of the GNU Library General Public
     11  * License as published by the Free Software Foundation; either
     12  * version 2 of the License, or (at your option) any later version.
     13  *
     14  * This library is distributed in the hope that it will be useful,
     15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     17  * Library General Public License for more details.
     18  *
     19  * You should have received a copy of the GNU Library General Public License
     20  * along with this library; see the file COPYING.LIB.  If not, write to
     21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     22  * Boston, MA 02110-1301, USA.
     23  */
     24 
     25 #include "config.h"
     26 #include "core/rendering/RenderTableCell.h"
     27 
     28 #include "HTMLNames.h"
     29 #include "core/css/StylePropertySet.h"
     30 #include "core/html/HTMLTableCellElement.h"
     31 #include "core/platform/graphics/FloatQuad.h"
     32 #include "core/platform/graphics/GraphicsContextStateSaver.h"
     33 #include "core/platform/graphics/transforms/TransformState.h"
     34 #include "core/rendering/PaintInfo.h"
     35 #include "core/rendering/RenderTableCol.h"
     36 #include "core/rendering/RenderView.h"
     37 #include "core/rendering/style/CollapsedBorderValue.h"
     38 
     39 using namespace std;
     40 
     41 namespace WebCore {
     42 
     43 using namespace HTMLNames;
     44 
     45 struct SameSizeAsRenderTableCell : public RenderBlock {
     46     unsigned bitfields;
     47     int paddings[2];
     48 };
     49 
     50 COMPILE_ASSERT(sizeof(RenderTableCell) == sizeof(SameSizeAsRenderTableCell), RenderTableCell_should_stay_small);
     51 COMPILE_ASSERT(sizeof(CollapsedBorderValue) == 8, CollapsedBorderValue_should_stay_small);
     52 
     53 RenderTableCell::RenderTableCell(Element* element)
     54     : RenderBlock(element)
     55     , m_column(unsetColumnIndex)
     56     , m_cellWidthChanged(false)
     57     , m_intrinsicPaddingBefore(0)
     58     , m_intrinsicPaddingAfter(0)
     59 {
     60     // We only update the flags when notified of DOM changes in colSpanOrRowSpanChanged()
     61     // so we need to set their initial values here in case something asks for colSpan()/rowSpan() before then.
     62     updateColAndRowSpanFlags();
     63 }
     64 
     65 void RenderTableCell::willBeRemovedFromTree()
     66 {
     67     RenderBlock::willBeRemovedFromTree();
     68 
     69     section()->setNeedsCellRecalc();
     70     section()->removeCachedCollapsedBorders(this);
     71 }
     72 
     73 unsigned RenderTableCell::parseColSpanFromDOM() const
     74 {
     75     ASSERT(node());
     76     if (node()->hasTagName(tdTag) || node()->hasTagName(thTag))
     77         return min<unsigned>(toHTMLTableCellElement(node())->colSpan(), maxColumnIndex);
     78     return 1;
     79 }
     80 
     81 unsigned RenderTableCell::parseRowSpanFromDOM() const
     82 {
     83     ASSERT(node());
     84     if (node()->hasTagName(tdTag) || node()->hasTagName(thTag))
     85         return min<unsigned>(toHTMLTableCellElement(node())->rowSpan(), maxRowIndex);
     86     return 1;
     87 }
     88 
     89 void RenderTableCell::updateColAndRowSpanFlags()
     90 {
     91     // The vast majority of table cells do not have a colspan or rowspan,
     92     // so we keep a bool to know if we need to bother reading from the DOM.
     93     m_hasColSpan = node() && parseColSpanFromDOM() != 1;
     94     m_hasRowSpan = node() && parseRowSpanFromDOM() != 1;
     95 }
     96 
     97 void RenderTableCell::colSpanOrRowSpanChanged()
     98 {
     99     ASSERT(node());
    100     ASSERT(node()->hasTagName(tdTag) || node()->hasTagName(thTag));
    101 
    102     updateColAndRowSpanFlags();
    103 
    104     // FIXME: I suspect that we could return early here if !m_hasColSpan && !m_hasRowSpan.
    105 
    106     setNeedsLayoutAndPrefWidthsRecalc();
    107     if (parent() && section())
    108         section()->setNeedsCellRecalc();
    109 }
    110 
    111 Length RenderTableCell::logicalWidthFromColumns(RenderTableCol* firstColForThisCell, Length widthFromStyle) const
    112 {
    113     ASSERT(firstColForThisCell && firstColForThisCell == table()->colElement(col()));
    114     RenderTableCol* tableCol = firstColForThisCell;
    115 
    116     unsigned colSpanCount = colSpan();
    117     int colWidthSum = 0;
    118     for (unsigned i = 1; i <= colSpanCount; i++) {
    119         Length colWidth = tableCol->style()->logicalWidth();
    120 
    121         // Percentage value should be returned only for colSpan == 1.
    122         // Otherwise we return original width for the cell.
    123         if (!colWidth.isFixed()) {
    124             if (colSpanCount > 1)
    125                 return widthFromStyle;
    126             return colWidth;
    127         }
    128 
    129         colWidthSum += colWidth.value();
    130         tableCol = tableCol->nextColumn();
    131         // If no next <col> tag found for the span we just return what we have for now.
    132         if (!tableCol)
    133             break;
    134     }
    135 
    136     // Column widths specified on <col> apply to the border box of the cell, see bug 8126.
    137     // FIXME: Why is border/padding ignored in the negative width case?
    138     if (colWidthSum > 0)
    139         return Length(max(0, colWidthSum - borderAndPaddingLogicalWidth().ceil()), Fixed);
    140     return Length(colWidthSum, Fixed);
    141 }
    142 
    143 void RenderTableCell::computePreferredLogicalWidths()
    144 {
    145     // The child cells rely on the grids up in the sections to do their computePreferredLogicalWidths work.  Normally the sections are set up early, as table
    146     // cells are added, but relayout can cause the cells to be freed, leaving stale pointers in the sections'
    147     // grids.  We must refresh those grids before the child cells try to use them.
    148     table()->recalcSectionsIfNeeded();
    149 
    150     RenderBlock::computePreferredLogicalWidths();
    151     if (node() && style()->autoWrap()) {
    152         // See if nowrap was set.
    153         Length w = styleOrColLogicalWidth();
    154         String nowrap = toElement(node())->getAttribute(nowrapAttr);
    155         if (!nowrap.isNull() && w.isFixed())
    156             // Nowrap is set, but we didn't actually use it because of the
    157             // fixed width set on the cell.  Even so, it is a WinIE/Moz trait
    158             // to make the minwidth of the cell into the fixed width.  They do this
    159             // even in strict mode, so do not make this a quirk.  Affected the top
    160             // of hiptop.com.
    161             m_minPreferredLogicalWidth = max<LayoutUnit>(w.value(), m_minPreferredLogicalWidth);
    162     }
    163 }
    164 
    165 void RenderTableCell::computeIntrinsicPadding(int rowHeight)
    166 {
    167     int oldIntrinsicPaddingBefore = intrinsicPaddingBefore();
    168     int oldIntrinsicPaddingAfter = intrinsicPaddingAfter();
    169     int logicalHeightWithoutIntrinsicPadding = pixelSnappedLogicalHeight() - oldIntrinsicPaddingBefore - oldIntrinsicPaddingAfter;
    170 
    171     int intrinsicPaddingBefore = 0;
    172     switch (style()->verticalAlign()) {
    173     case SUB:
    174     case SUPER:
    175     case TEXT_TOP:
    176     case TEXT_BOTTOM:
    177     case LENGTH:
    178     case BASELINE: {
    179         LayoutUnit baseline = cellBaselinePosition();
    180         if (baseline > borderBefore() + paddingBefore())
    181             intrinsicPaddingBefore = section()->rowBaseline(rowIndex()) - (baseline - oldIntrinsicPaddingBefore);
    182         break;
    183     }
    184     case TOP:
    185         break;
    186     case MIDDLE:
    187         intrinsicPaddingBefore = (rowHeight - logicalHeightWithoutIntrinsicPadding) / 2;
    188         break;
    189     case BOTTOM:
    190         intrinsicPaddingBefore = rowHeight - logicalHeightWithoutIntrinsicPadding;
    191         break;
    192     case BASELINE_MIDDLE:
    193         break;
    194     }
    195 
    196     int intrinsicPaddingAfter = rowHeight - logicalHeightWithoutIntrinsicPadding - intrinsicPaddingBefore;
    197     setIntrinsicPaddingBefore(intrinsicPaddingBefore);
    198     setIntrinsicPaddingAfter(intrinsicPaddingAfter);
    199 
    200     // FIXME: Changing an intrinsic padding shouldn't trigger a relayout as it only shifts the cell inside the row but
    201     // doesn't change the logical height.
    202     if (intrinsicPaddingBefore != oldIntrinsicPaddingBefore || intrinsicPaddingAfter != oldIntrinsicPaddingAfter)
    203         setNeedsLayout(MarkOnlyThis);
    204 }
    205 
    206 void RenderTableCell::updateLogicalWidth()
    207 {
    208 }
    209 
    210 void RenderTableCell::setCellLogicalWidth(int tableLayoutLogicalWidth)
    211 {
    212     if (tableLayoutLogicalWidth == logicalWidth())
    213         return;
    214 
    215     setNeedsLayout(MarkOnlyThis);
    216     row()->setChildNeedsLayout(MarkOnlyThis);
    217 
    218     if (!table()->selfNeedsLayout() && checkForRepaintDuringLayout())
    219         repaint();
    220 
    221     setLogicalWidth(tableLayoutLogicalWidth);
    222     setCellWidthChanged(true);
    223 }
    224 
    225 void RenderTableCell::layout()
    226 {
    227     StackStats::LayoutCheckPoint layoutCheckPoint;
    228     updateFirstLetter();
    229 
    230     int oldCellBaseline = cellBaselinePosition();
    231     layoutBlock(cellWidthChanged());
    232 
    233     // If we have replaced content, the intrinsic height of our content may have changed since the last time we laid out. If that's the case the intrinsic padding we used
    234     // for layout (the padding required to push the contents of the cell down to the row's baseline) is included in our new height and baseline and makes both
    235     // of them wrong. So if our content's intrinsic height has changed push the new content up into the intrinsic padding and relayout so that the rest of
    236     // table and row layout can use the correct baseline and height for this cell.
    237     if (isBaselineAligned() && section()->rowBaseline(rowIndex()) && cellBaselinePosition() > section()->rowBaseline(rowIndex())) {
    238         int newIntrinsicPaddingBefore = max<LayoutUnit>(0, intrinsicPaddingBefore() - max<LayoutUnit>(0, cellBaselinePosition() - oldCellBaseline));
    239         setIntrinsicPaddingBefore(newIntrinsicPaddingBefore);
    240         setNeedsLayout(MarkOnlyThis);
    241         layoutBlock(cellWidthChanged());
    242     }
    243 
    244     setCellWidthChanged(false);
    245 }
    246 
    247 LayoutUnit RenderTableCell::paddingTop() const
    248 {
    249     int result = computedCSSPaddingTop();
    250     if (!isHorizontalWritingMode())
    251         return result;
    252     return result + (style()->writingMode() == TopToBottomWritingMode ? intrinsicPaddingBefore() : intrinsicPaddingAfter());
    253 }
    254 
    255 LayoutUnit RenderTableCell::paddingBottom() const
    256 {
    257     int result = computedCSSPaddingBottom();
    258     if (!isHorizontalWritingMode())
    259         return result;
    260     return result + (style()->writingMode() == TopToBottomWritingMode ? intrinsicPaddingAfter() : intrinsicPaddingBefore());
    261 }
    262 
    263 LayoutUnit RenderTableCell::paddingLeft() const
    264 {
    265     int result = computedCSSPaddingLeft();
    266     if (isHorizontalWritingMode())
    267         return result;
    268     return result + (style()->writingMode() == LeftToRightWritingMode ? intrinsicPaddingBefore() : intrinsicPaddingAfter());
    269 }
    270 
    271 LayoutUnit RenderTableCell::paddingRight() const
    272 {
    273     int result = computedCSSPaddingRight();
    274     if (isHorizontalWritingMode())
    275         return result;
    276     return result + (style()->writingMode() == LeftToRightWritingMode ? intrinsicPaddingAfter() : intrinsicPaddingBefore());
    277 }
    278 
    279 LayoutUnit RenderTableCell::paddingBefore() const
    280 {
    281     return static_cast<int>(computedCSSPaddingBefore()) + intrinsicPaddingBefore();
    282 }
    283 
    284 LayoutUnit RenderTableCell::paddingAfter() const
    285 {
    286     return static_cast<int>(computedCSSPaddingAfter()) + intrinsicPaddingAfter();
    287 }
    288 
    289 void RenderTableCell::setOverrideLogicalContentHeightFromRowHeight(LayoutUnit rowHeight)
    290 {
    291     clearIntrinsicPadding();
    292     setOverrideLogicalContentHeight(max<LayoutUnit>(0, rowHeight - borderAndPaddingLogicalHeight()));
    293 }
    294 
    295 LayoutSize RenderTableCell::offsetFromContainer(RenderObject* o, const LayoutPoint& point, bool* offsetDependsOnPoint) const
    296 {
    297     ASSERT(o == container());
    298 
    299     LayoutSize offset = RenderBlock::offsetFromContainer(o, point, offsetDependsOnPoint);
    300     if (parent())
    301         offset -= parentBox()->locationOffset();
    302 
    303     return offset;
    304 }
    305 
    306 LayoutRect RenderTableCell::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const
    307 {
    308     // If the table grid is dirty, we cannot get reliable information about adjoining cells,
    309     // so we ignore outside borders. This should not be a problem because it means that
    310     // the table is going to recalculate the grid, relayout and repaint its current rect, which
    311     // includes any outside borders of this cell.
    312     if (!table()->collapseBorders() || table()->needsSectionRecalc())
    313         return RenderBlock::clippedOverflowRectForRepaint(repaintContainer);
    314 
    315     bool rtl = !styleForCellFlow()->isLeftToRightDirection();
    316     int outlineSize = style()->outlineSize();
    317     int left = max(borderHalfLeft(true), outlineSize);
    318     int right = max(borderHalfRight(true), outlineSize);
    319     int top = max(borderHalfTop(true), outlineSize);
    320     int bottom = max(borderHalfBottom(true), outlineSize);
    321     if ((left && !rtl) || (right && rtl)) {
    322         if (RenderTableCell* before = table()->cellBefore(this)) {
    323             top = max(top, before->borderHalfTop(true));
    324             bottom = max(bottom, before->borderHalfBottom(true));
    325         }
    326     }
    327     if ((left && rtl) || (right && !rtl)) {
    328         if (RenderTableCell* after = table()->cellAfter(this)) {
    329             top = max(top, after->borderHalfTop(true));
    330             bottom = max(bottom, after->borderHalfBottom(true));
    331         }
    332     }
    333     if (top) {
    334         if (RenderTableCell* above = table()->cellAbove(this)) {
    335             left = max(left, above->borderHalfLeft(true));
    336             right = max(right, above->borderHalfRight(true));
    337         }
    338     }
    339     if (bottom) {
    340         if (RenderTableCell* below = table()->cellBelow(this)) {
    341             left = max(left, below->borderHalfLeft(true));
    342             right = max(right, below->borderHalfRight(true));
    343         }
    344     }
    345     LayoutPoint location(max<LayoutUnit>(left, -visualOverflowRect().x()), max<LayoutUnit>(top, -visualOverflowRect().y()));
    346     LayoutRect r(-location.x(), -location.y(), location.x() + max(width() + right, visualOverflowRect().maxX()), location.y() + max(height() + bottom, visualOverflowRect().maxY()));
    347 
    348     if (RenderView* v = view()) {
    349         // FIXME: layoutDelta needs to be applied in parts before/after transforms and
    350         // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
    351         r.move(v->layoutDelta());
    352     }
    353     computeRectForRepaint(repaintContainer, r);
    354     return r;
    355 }
    356 
    357 void RenderTableCell::computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect& r, bool fixed) const
    358 {
    359     if (repaintContainer == this)
    360         return;
    361     r.setY(r.y());
    362     RenderView* v = view();
    363     if ((!v || !v->layoutStateEnabled() || repaintContainer) && parent())
    364         r.moveBy(-parentBox()->location()); // Rows are in the same coordinate space, so don't add their offset in.
    365     RenderBlock::computeRectForRepaint(repaintContainer, r, fixed);
    366 }
    367 
    368 LayoutUnit RenderTableCell::cellBaselinePosition() const
    369 {
    370     // <http://www.w3.org/TR/2007/CR-CSS21-20070719/tables.html#height-layout>: The baseline of a cell is the baseline of
    371     // the first in-flow line box in the cell, or the first in-flow table-row in the cell, whichever comes first. If there
    372     // is no such line box or table-row, the baseline is the bottom of content edge of the cell box.
    373     LayoutUnit firstLineBaseline = firstLineBoxBaseline();
    374     if (firstLineBaseline != -1)
    375         return firstLineBaseline;
    376     return paddingBefore() + borderBefore() + contentLogicalHeight();
    377 }
    378 
    379 void RenderTableCell::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
    380 {
    381     ASSERT(style()->display() == TABLE_CELL);
    382     ASSERT(!row() || row()->rowIndexWasSet());
    383 
    384     RenderBlock::styleDidChange(diff, oldStyle);
    385     setHasBoxDecorations(true);
    386 
    387     if (parent() && section() && oldStyle && style()->height() != oldStyle->height())
    388         section()->rowLogicalHeightChanged(rowIndex());
    389 
    390     // Our intrinsic padding pushes us down to align with the baseline of other cells on the row. If our vertical-align
    391     // has changed then so will the padding needed to align with other cells - clear it so we can recalculate it from scratch.
    392     if (oldStyle && style()->verticalAlign() != oldStyle->verticalAlign())
    393         clearIntrinsicPadding();
    394 
    395     // If border was changed, notify table.
    396     if (parent()) {
    397         RenderTable* table = this->table();
    398         if (table && !table->selfNeedsLayout() && !table->normalChildNeedsLayout()&& oldStyle && oldStyle->border() != style()->border())
    399             table->invalidateCollapsedBorders();
    400     }
    401 }
    402 
    403 // The following rules apply for resolving conflicts and figuring out which border
    404 // to use.
    405 // (1) Borders with the 'border-style' of 'hidden' take precedence over all other conflicting
    406 // borders. Any border with this value suppresses all borders at this location.
    407 // (2) Borders with a style of 'none' have the lowest priority. Only if the border properties of all
    408 // the elements meeting at this edge are 'none' will the border be omitted (but note that 'none' is
    409 // the default value for the border style.)
    410 // (3) If none of the styles are 'hidden' and at least one of them is not 'none', then narrow borders
    411 // are discarded in favor of wider ones. If several have the same 'border-width' then styles are preferred
    412 // in this order: 'double', 'solid', 'dashed', 'dotted', 'ridge', 'outset', 'groove', and the lowest: 'inset'.
    413 // (4) If border styles differ only in color, then a style set on a cell wins over one on a row,
    414 // which wins over a row group, column, column group and, lastly, table. It is undefined which color
    415 // is used when two elements of the same type disagree.
    416 static int compareBorders(const CollapsedBorderValue& border1, const CollapsedBorderValue& border2)
    417 {
    418     // Sanity check the values passed in. The null border have lowest priority.
    419     if (!border2.exists()) {
    420         if (!border1.exists())
    421             return 0;
    422         return 1;
    423     }
    424     if (!border1.exists())
    425         return -1;
    426 
    427     // Rule #1 above.
    428     if (border2.style() == BHIDDEN) {
    429         if (border1.style() == BHIDDEN)
    430             return 0;
    431         return -1;
    432     }
    433     if (border1.style() == BHIDDEN)
    434         return 1;
    435 
    436     // Rule #2 above.  A style of 'none' has lowest priority and always loses to any other border.
    437     if (border2.style() == BNONE) {
    438         if (border1.style() == BNONE)
    439             return 0;
    440         return 1;
    441     }
    442     if (border1.style() == BNONE)
    443         return -1;
    444 
    445     // The first part of rule #3 above. Wider borders win.
    446     if (border1.width() != border2.width())
    447         return border1.width() < border2.width() ? -1 : 1;
    448 
    449     // The borders have equal width.  Sort by border style.
    450     if (border1.style() != border2.style())
    451         return border1.style() < border2.style() ? -1 : 1;
    452 
    453     // The border have the same width and style.  Rely on precedence (cell over row over row group, etc.)
    454     if (border1.precedence() == border2.precedence())
    455         return 0;
    456     return border1.precedence() < border2.precedence() ? -1 : 1;
    457 }
    458 
    459 static CollapsedBorderValue chooseBorder(const CollapsedBorderValue& border1, const CollapsedBorderValue& border2)
    460 {
    461     const CollapsedBorderValue& border = compareBorders(border1, border2) < 0 ? border2 : border1;
    462     return border.style() == BHIDDEN ? CollapsedBorderValue() : border;
    463 }
    464 
    465 bool RenderTableCell::hasStartBorderAdjoiningTable() const
    466 {
    467     bool isStartColumn = !col();
    468     bool isEndColumn = table()->colToEffCol(col() + colSpan() - 1) == table()->numEffCols() - 1;
    469     bool hasSameDirectionAsTable = hasSameDirectionAs(table());
    470 
    471     // The table direction determines the row direction. In mixed directionality, we cannot guarantee that
    472     // we have a common border with the table (think a ltr table with rtl start cell).
    473     return (isStartColumn && hasSameDirectionAsTable) || (isEndColumn && !hasSameDirectionAsTable);
    474 }
    475 
    476 bool RenderTableCell::hasEndBorderAdjoiningTable() const
    477 {
    478     bool isStartColumn = !col();
    479     bool isEndColumn = table()->colToEffCol(col() + colSpan() - 1) == table()->numEffCols() - 1;
    480     bool hasSameDirectionAsTable = hasSameDirectionAs(table());
    481 
    482     // The table direction determines the row direction. In mixed directionality, we cannot guarantee that
    483     // we have a common border with the table (think a ltr table with ltr end cell).
    484     return (isStartColumn && !hasSameDirectionAsTable) || (isEndColumn && hasSameDirectionAsTable);
    485 }
    486 
    487 CollapsedBorderValue RenderTableCell::collapsedStartBorder(IncludeBorderColorOrNot includeColor) const
    488 {
    489     CollapsedBorderValue result = computeCollapsedStartBorder(includeColor);
    490     if (includeColor)
    491         section()->setCachedCollapsedBorder(this, CBSStart, result);
    492     return result;
    493 }
    494 
    495 CollapsedBorderValue RenderTableCell::computeCollapsedStartBorder(IncludeBorderColorOrNot includeColor) const
    496 {
    497     RenderTable* table = this->table();
    498 
    499     // For the start border, we need to check, in order of precedence:
    500     // (1) Our start border.
    501     int startColorProperty = includeColor ? CSSProperty::resolveDirectionAwareProperty(CSSPropertyWebkitBorderStartColor, styleForCellFlow()->direction(), styleForCellFlow()->writingMode()) : 0;
    502     int endColorProperty = includeColor ? CSSProperty::resolveDirectionAwareProperty(CSSPropertyWebkitBorderEndColor, styleForCellFlow()->direction(), styleForCellFlow()->writingMode()) : 0;
    503     CollapsedBorderValue result(style()->borderStart(), includeColor ? resolveColor(startColorProperty) : Color(), BCELL);
    504 
    505     // (2) The end border of the preceding cell.
    506     RenderTableCell* cellBefore = table->cellBefore(this);
    507     if (cellBefore) {
    508         CollapsedBorderValue cellBeforeAdjoiningBorder = CollapsedBorderValue(cellBefore->borderAdjoiningCellAfter(this), includeColor ? cellBefore->resolveColor(endColorProperty) : Color(), BCELL);
    509         // |result| should be the 2nd argument as |cellBefore| should win in case of equality per CSS 2.1 (Border conflict resolution, point 4).
    510         result = chooseBorder(cellBeforeAdjoiningBorder, result);
    511         if (!result.exists())
    512             return result;
    513     }
    514 
    515     bool startBorderAdjoinsTable = hasStartBorderAdjoiningTable();
    516     if (startBorderAdjoinsTable) {
    517         // (3) Our row's start border.
    518         result = chooseBorder(result, CollapsedBorderValue(row()->borderAdjoiningStartCell(this), includeColor ? parent()->resolveColor(startColorProperty) : Color(), BROW));
    519         if (!result.exists())
    520             return result;
    521 
    522         // (4) Our row group's start border.
    523         result = chooseBorder(result, CollapsedBorderValue(section()->borderAdjoiningStartCell(this), includeColor ? section()->resolveColor(startColorProperty) : Color(), BROWGROUP));
    524         if (!result.exists())
    525             return result;
    526     }
    527 
    528     // (5) Our column and column group's start borders.
    529     bool startColEdge;
    530     bool endColEdge;
    531     if (RenderTableCol* colElt = table->colElement(col(), &startColEdge, &endColEdge)) {
    532         if (colElt->isTableColumnGroup() && startColEdge) {
    533             // The |colElt| is a column group and is also the first colgroup (in case of spanned colgroups).
    534             result = chooseBorder(result, CollapsedBorderValue(colElt->borderAdjoiningCellStartBorder(this), includeColor ? colElt->resolveColor(startColorProperty) : Color(), BCOLGROUP));
    535             if (!result.exists())
    536                 return result;
    537         } else if (!colElt->isTableColumnGroup()) {
    538             // We first consider the |colElt| and irrespective of whether it is a spanned col or not, we apply
    539             // its start border. This is as per HTML5 which states that: "For the purposes of the CSS table model,
    540             // the col element is expected to be treated as if it was present as many times as its span attribute specifies".
    541             result = chooseBorder(result, CollapsedBorderValue(colElt->borderAdjoiningCellStartBorder(this), includeColor ? colElt->resolveColor(startColorProperty) : Color(), BCOL));
    542             if (!result.exists())
    543                 return result;
    544             // Next, apply the start border of the enclosing colgroup but only if it is adjacent to the cell's edge.
    545             if (RenderTableCol* enclosingColumnGroup = colElt->enclosingColumnGroupIfAdjacentBefore()) {
    546                 result = chooseBorder(result, CollapsedBorderValue(enclosingColumnGroup->borderAdjoiningCellStartBorder(this), includeColor ? enclosingColumnGroup->resolveColor(startColorProperty) : Color(), BCOLGROUP));
    547                 if (!result.exists())
    548                     return result;
    549             }
    550         }
    551     }
    552 
    553     // (6) The end border of the preceding column.
    554     if (cellBefore) {
    555         if (RenderTableCol* colElt = table->colElement(col() - 1, &startColEdge, &endColEdge)) {
    556             if (colElt->isTableColumnGroup() && endColEdge) {
    557                 // The element is a colgroup and is also the last colgroup (in case of spanned colgroups).
    558                 result = chooseBorder(CollapsedBorderValue(colElt->borderAdjoiningCellAfter(this), includeColor ? colElt->resolveColor(endColorProperty) : Color(), BCOLGROUP), result);
    559                 if (!result.exists())
    560                     return result;
    561             } else if (colElt->isTableColumn()) {
    562                 // Resolve the collapsing border against the col's border ignoring any 'span' as per HTML5.
    563                 result = chooseBorder(CollapsedBorderValue(colElt->borderAdjoiningCellAfter(this), includeColor ? colElt->resolveColor(endColorProperty) : Color(), BCOL), result);
    564                 if (!result.exists())
    565                     return result;
    566                 // Next, if the previous col has a parent colgroup then its end border should be applied
    567                 // but only if it is adjacent to the cell's edge.
    568                 if (RenderTableCol* enclosingColumnGroup = colElt->enclosingColumnGroupIfAdjacentAfter()) {
    569                     result = chooseBorder(CollapsedBorderValue(enclosingColumnGroup->borderAdjoiningCellEndBorder(this), includeColor ? enclosingColumnGroup->resolveColor(endColorProperty) : Color(), BCOLGROUP), result);
    570                     if (!result.exists())
    571                         return result;
    572                 }
    573             }
    574         }
    575     }
    576 
    577     if (startBorderAdjoinsTable) {
    578         // (7) The table's start border.
    579         result = chooseBorder(result, CollapsedBorderValue(table->tableStartBorderAdjoiningCell(this), includeColor ? table->resolveColor(startColorProperty) : Color(), BTABLE));
    580         if (!result.exists())
    581             return result;
    582     }
    583 
    584     return result;
    585 }
    586 
    587 CollapsedBorderValue RenderTableCell::collapsedEndBorder(IncludeBorderColorOrNot includeColor) const
    588 {
    589     CollapsedBorderValue result = computeCollapsedEndBorder(includeColor);
    590     if (includeColor)
    591         section()->setCachedCollapsedBorder(this, CBSEnd, result);
    592     return result;
    593 }
    594 
    595 CollapsedBorderValue RenderTableCell::computeCollapsedEndBorder(IncludeBorderColorOrNot includeColor) const
    596 {
    597     RenderTable* table = this->table();
    598     // Note: We have to use the effective column information instead of whether we have a cell after as a table doesn't
    599     // have to be regular (any row can have less cells than the total cell count).
    600     bool isEndColumn = table->colToEffCol(col() + colSpan() - 1) == table->numEffCols() - 1;
    601 
    602     // For end border, we need to check, in order of precedence:
    603     // (1) Our end border.
    604     int startColorProperty = includeColor ? CSSProperty::resolveDirectionAwareProperty(CSSPropertyWebkitBorderStartColor, styleForCellFlow()->direction(), styleForCellFlow()->writingMode()) : 0;
    605     int endColorProperty = includeColor ? CSSProperty::resolveDirectionAwareProperty(CSSPropertyWebkitBorderEndColor, styleForCellFlow()->direction(), styleForCellFlow()->writingMode()) : 0;
    606     CollapsedBorderValue result = CollapsedBorderValue(style()->borderEnd(), includeColor ? resolveColor(endColorProperty) : Color(), BCELL);
    607 
    608     // (2) The start border of the following cell.
    609     if (!isEndColumn) {
    610         if (RenderTableCell* cellAfter = table->cellAfter(this)) {
    611             CollapsedBorderValue cellAfterAdjoiningBorder = CollapsedBorderValue(cellAfter->borderAdjoiningCellBefore(this), includeColor ? cellAfter->resolveColor(startColorProperty) : Color(), BCELL);
    612             result = chooseBorder(result, cellAfterAdjoiningBorder);
    613             if (!result.exists())
    614                 return result;
    615         }
    616     }
    617 
    618     bool endBorderAdjoinsTable = hasEndBorderAdjoiningTable();
    619     if (endBorderAdjoinsTable) {
    620         // (3) Our row's end border.
    621         result = chooseBorder(result, CollapsedBorderValue(row()->borderAdjoiningEndCell(this), includeColor ? parent()->resolveColor(endColorProperty) : Color(), BROW));
    622         if (!result.exists())
    623             return result;
    624 
    625         // (4) Our row group's end border.
    626         result = chooseBorder(result, CollapsedBorderValue(section()->borderAdjoiningEndCell(this), includeColor ? section()->resolveColor(endColorProperty) : Color(), BROWGROUP));
    627         if (!result.exists())
    628             return result;
    629     }
    630 
    631     // (5) Our column and column group's end borders.
    632     bool startColEdge;
    633     bool endColEdge;
    634     if (RenderTableCol* colElt = table->colElement(col() + colSpan() - 1, &startColEdge, &endColEdge)) {
    635         if (colElt->isTableColumnGroup() && endColEdge) {
    636             // The element is a colgroup and is also the last colgroup (in case of spanned colgroups).
    637             result = chooseBorder(result, CollapsedBorderValue(colElt->borderAdjoiningCellEndBorder(this), includeColor ? colElt->resolveColor(endColorProperty) : Color(), BCOLGROUP));
    638             if (!result.exists())
    639                 return result;
    640         } else if (!colElt->isTableColumnGroup()) {
    641             // First apply the end border of the column irrespective of whether it is spanned or not. This is as per
    642             // HTML5 which states that: "For the purposes of the CSS table model, the col element is expected to be
    643             // treated as if it was present as many times as its span attribute specifies".
    644             result = chooseBorder(result, CollapsedBorderValue(colElt->borderAdjoiningCellEndBorder(this), includeColor ? colElt->resolveColor(endColorProperty) : Color(), BCOL));
    645             if (!result.exists())
    646                 return result;
    647             // Next, if it has a parent colgroup then we apply its end border but only if it is adjacent to the cell.
    648             if (RenderTableCol* enclosingColumnGroup = colElt->enclosingColumnGroupIfAdjacentAfter()) {
    649                 result = chooseBorder(result, CollapsedBorderValue(enclosingColumnGroup->borderAdjoiningCellEndBorder(this), includeColor ? enclosingColumnGroup->resolveColor(endColorProperty) : Color(), BCOLGROUP));
    650                 if (!result.exists())
    651                     return result;
    652             }
    653         }
    654     }
    655 
    656     // (6) The start border of the next column.
    657     if (!isEndColumn) {
    658         if (RenderTableCol* colElt = table->colElement(col() + colSpan(), &startColEdge, &endColEdge)) {
    659             if (colElt->isTableColumnGroup() && startColEdge) {
    660                 // This case is a colgroup without any col, we only compute it if it is adjacent to the cell's edge.
    661                 result = chooseBorder(result, CollapsedBorderValue(colElt->borderAdjoiningCellBefore(this), includeColor ? colElt->resolveColor(startColorProperty) : Color(), BCOLGROUP));
    662                 if (!result.exists())
    663                     return result;
    664             } else if (colElt->isTableColumn()) {
    665                 // Resolve the collapsing border against the col's border ignoring any 'span' as per HTML5.
    666                 result = chooseBorder(result, CollapsedBorderValue(colElt->borderAdjoiningCellBefore(this), includeColor ? colElt->resolveColor(startColorProperty) : Color(), BCOL));
    667                 if (!result.exists())
    668                     return result;
    669                 // If we have a parent colgroup, resolve the border only if it is adjacent to the cell.
    670                 if (RenderTableCol* enclosingColumnGroup = colElt->enclosingColumnGroupIfAdjacentBefore()) {
    671                     result = chooseBorder(result, CollapsedBorderValue(enclosingColumnGroup->borderAdjoiningCellStartBorder(this), includeColor ? enclosingColumnGroup->resolveColor(startColorProperty) : Color(), BCOLGROUP));
    672                     if (!result.exists())
    673                         return result;
    674                 }
    675             }
    676         }
    677     }
    678 
    679     if (endBorderAdjoinsTable) {
    680         // (7) The table's end border.
    681         result = chooseBorder(result, CollapsedBorderValue(table->tableEndBorderAdjoiningCell(this), includeColor ? table->resolveColor(endColorProperty) : Color(), BTABLE));
    682         if (!result.exists())
    683             return result;
    684     }
    685 
    686     return result;
    687 }
    688 
    689 CollapsedBorderValue RenderTableCell::collapsedBeforeBorder(IncludeBorderColorOrNot includeColor) const
    690 {
    691     CollapsedBorderValue result = computeCollapsedBeforeBorder(includeColor);
    692     if (includeColor)
    693         section()->setCachedCollapsedBorder(this, CBSBefore, result);
    694     return result;
    695 }
    696 
    697 CollapsedBorderValue RenderTableCell::computeCollapsedBeforeBorder(IncludeBorderColorOrNot includeColor) const
    698 {
    699     RenderTable* table = this->table();
    700 
    701     // For before border, we need to check, in order of precedence:
    702     // (1) Our before border.
    703     int beforeColorProperty = includeColor ? CSSProperty::resolveDirectionAwareProperty(CSSPropertyWebkitBorderBeforeColor, styleForCellFlow()->direction(), styleForCellFlow()->writingMode()) : 0;
    704     int afterColorProperty = includeColor ? CSSProperty::resolveDirectionAwareProperty(CSSPropertyWebkitBorderAfterColor, styleForCellFlow()->direction(), styleForCellFlow()->writingMode()) : 0;
    705     CollapsedBorderValue result = CollapsedBorderValue(style()->borderBefore(), includeColor ? resolveColor(beforeColorProperty) : Color(), BCELL);
    706 
    707     RenderTableCell* prevCell = table->cellAbove(this);
    708     if (prevCell) {
    709         // (2) A before cell's after border.
    710         result = chooseBorder(CollapsedBorderValue(prevCell->style()->borderAfter(), includeColor ? prevCell->resolveColor(afterColorProperty) : Color(), BCELL), result);
    711         if (!result.exists())
    712             return result;
    713     }
    714 
    715     // (3) Our row's before border.
    716     result = chooseBorder(result, CollapsedBorderValue(parent()->style()->borderBefore(), includeColor ? parent()->resolveColor(beforeColorProperty) : Color(), BROW));
    717     if (!result.exists())
    718         return result;
    719 
    720     // (4) The previous row's after border.
    721     if (prevCell) {
    722         RenderObject* prevRow = 0;
    723         if (prevCell->section() == section())
    724             prevRow = parent()->previousSibling();
    725         else
    726             prevRow = prevCell->section()->lastChild();
    727 
    728         if (prevRow) {
    729             result = chooseBorder(CollapsedBorderValue(prevRow->style()->borderAfter(), includeColor ? prevRow->resolveColor(afterColorProperty) : Color(), BROW), result);
    730             if (!result.exists())
    731                 return result;
    732         }
    733     }
    734 
    735     // Now check row groups.
    736     RenderTableSection* currSection = section();
    737     if (!rowIndex()) {
    738         // (5) Our row group's before border.
    739         result = chooseBorder(result, CollapsedBorderValue(currSection->style()->borderBefore(), includeColor ? currSection->resolveColor(beforeColorProperty) : Color(), BROWGROUP));
    740         if (!result.exists())
    741             return result;
    742 
    743         // (6) Previous row group's after border.
    744         currSection = table->sectionAbove(currSection, SkipEmptySections);
    745         if (currSection) {
    746             result = chooseBorder(CollapsedBorderValue(currSection->style()->borderAfter(), includeColor ? currSection->resolveColor(afterColorProperty) : Color(), BROWGROUP), result);
    747             if (!result.exists())
    748                 return result;
    749         }
    750     }
    751 
    752     if (!currSection) {
    753         // (8) Our column and column group's before borders.
    754         RenderTableCol* colElt = table->colElement(col());
    755         if (colElt) {
    756             result = chooseBorder(result, CollapsedBorderValue(colElt->style()->borderBefore(), includeColor ? colElt->resolveColor(beforeColorProperty) : Color(), BCOL));
    757             if (!result.exists())
    758                 return result;
    759             if (RenderTableCol* enclosingColumnGroup = colElt->enclosingColumnGroup()) {
    760                 result = chooseBorder(result, CollapsedBorderValue(enclosingColumnGroup->style()->borderBefore(), includeColor ? enclosingColumnGroup->resolveColor(beforeColorProperty) : Color(), BCOLGROUP));
    761                 if (!result.exists())
    762                     return result;
    763             }
    764         }
    765 
    766         // (9) The table's before border.
    767         result = chooseBorder(result, CollapsedBorderValue(table->style()->borderBefore(), includeColor ? table->resolveColor(beforeColorProperty) : Color(), BTABLE));
    768         if (!result.exists())
    769             return result;
    770     }
    771 
    772     return result;
    773 }
    774 
    775 CollapsedBorderValue RenderTableCell::collapsedAfterBorder(IncludeBorderColorOrNot includeColor) const
    776 {
    777     CollapsedBorderValue result = computeCollapsedAfterBorder(includeColor);
    778     if (includeColor)
    779         section()->setCachedCollapsedBorder(this, CBSAfter, result);
    780     return result;
    781 }
    782 
    783 CollapsedBorderValue RenderTableCell::computeCollapsedAfterBorder(IncludeBorderColorOrNot includeColor) const
    784 {
    785     RenderTable* table = this->table();
    786 
    787     // For after border, we need to check, in order of precedence:
    788     // (1) Our after border.
    789     int beforeColorProperty = includeColor ? CSSProperty::resolveDirectionAwareProperty(CSSPropertyWebkitBorderBeforeColor, styleForCellFlow()->direction(), styleForCellFlow()->writingMode()) : 0;
    790     int afterColorProperty = includeColor ? CSSProperty::resolveDirectionAwareProperty(CSSPropertyWebkitBorderAfterColor, styleForCellFlow()->direction(), styleForCellFlow()->writingMode()) : 0;
    791     CollapsedBorderValue result = CollapsedBorderValue(style()->borderAfter(), includeColor ? resolveColor(afterColorProperty) : Color(), BCELL);
    792 
    793     RenderTableCell* nextCell = table->cellBelow(this);
    794     if (nextCell) {
    795         // (2) An after cell's before border.
    796         result = chooseBorder(result, CollapsedBorderValue(nextCell->style()->borderBefore(), includeColor ? nextCell->resolveColor(beforeColorProperty) : Color(), BCELL));
    797         if (!result.exists())
    798             return result;
    799     }
    800 
    801     // (3) Our row's after border. (FIXME: Deal with rowspan!)
    802     result = chooseBorder(result, CollapsedBorderValue(parent()->style()->borderAfter(), includeColor ? parent()->resolveColor(afterColorProperty) : Color(), BROW));
    803     if (!result.exists())
    804         return result;
    805 
    806     // (4) The next row's before border.
    807     if (nextCell) {
    808         result = chooseBorder(result, CollapsedBorderValue(nextCell->parent()->style()->borderBefore(), includeColor ? nextCell->parent()->resolveColor(beforeColorProperty) : Color(), BROW));
    809         if (!result.exists())
    810             return result;
    811     }
    812 
    813     // Now check row groups.
    814     RenderTableSection* currSection = section();
    815     if (rowIndex() + rowSpan() >= currSection->numRows()) {
    816         // (5) Our row group's after border.
    817         result = chooseBorder(result, CollapsedBorderValue(currSection->style()->borderAfter(), includeColor ? currSection->resolveColor(afterColorProperty) : Color(), BROWGROUP));
    818         if (!result.exists())
    819             return result;
    820 
    821         // (6) Following row group's before border.
    822         currSection = table->sectionBelow(currSection, SkipEmptySections);
    823         if (currSection) {
    824             result = chooseBorder(result, CollapsedBorderValue(currSection->style()->borderBefore(), includeColor ? currSection->resolveColor(beforeColorProperty) : Color(), BROWGROUP));
    825             if (!result.exists())
    826                 return result;
    827         }
    828     }
    829 
    830     if (!currSection) {
    831         // (8) Our column and column group's after borders.
    832         RenderTableCol* colElt = table->colElement(col());
    833         if (colElt) {
    834             result = chooseBorder(result, CollapsedBorderValue(colElt->style()->borderAfter(), includeColor ? colElt->resolveColor(afterColorProperty) : Color(), BCOL));
    835             if (!result.exists()) return result;
    836             if (RenderTableCol* enclosingColumnGroup = colElt->enclosingColumnGroup()) {
    837                 result = chooseBorder(result, CollapsedBorderValue(enclosingColumnGroup->style()->borderAfter(), includeColor ? enclosingColumnGroup->resolveColor(afterColorProperty) : Color(), BCOLGROUP));
    838                 if (!result.exists())
    839                     return result;
    840             }
    841         }
    842 
    843         // (9) The table's after border.
    844         result = chooseBorder(result, CollapsedBorderValue(table->style()->borderAfter(), includeColor ? table->resolveColor(afterColorProperty) : Color(), BTABLE));
    845         if (!result.exists())
    846             return result;
    847     }
    848 
    849     return result;
    850 }
    851 
    852 inline CollapsedBorderValue RenderTableCell::cachedCollapsedLeftBorder(const RenderStyle* styleForCellFlow) const
    853 {
    854     if (styleForCellFlow->isHorizontalWritingMode())
    855         return styleForCellFlow->isLeftToRightDirection() ? section()->cachedCollapsedBorder(this, CBSStart) : section()->cachedCollapsedBorder(this, CBSEnd);
    856     return styleForCellFlow->isFlippedBlocksWritingMode() ? section()->cachedCollapsedBorder(this, CBSAfter) : section()->cachedCollapsedBorder(this, CBSBefore);
    857 }
    858 
    859 inline CollapsedBorderValue RenderTableCell::cachedCollapsedRightBorder(const RenderStyle* styleForCellFlow) const
    860 {
    861     if (styleForCellFlow->isHorizontalWritingMode())
    862         return styleForCellFlow->isLeftToRightDirection() ? section()->cachedCollapsedBorder(this, CBSEnd) : section()->cachedCollapsedBorder(this, CBSStart);
    863     return styleForCellFlow->isFlippedBlocksWritingMode() ? section()->cachedCollapsedBorder(this, CBSBefore) : section()->cachedCollapsedBorder(this, CBSAfter);
    864 }
    865 
    866 inline CollapsedBorderValue RenderTableCell::cachedCollapsedTopBorder(const RenderStyle* styleForCellFlow) const
    867 {
    868     if (styleForCellFlow->isHorizontalWritingMode())
    869         return styleForCellFlow->isFlippedBlocksWritingMode() ? section()->cachedCollapsedBorder(this, CBSAfter) : section()->cachedCollapsedBorder(this, CBSBefore);
    870     return styleForCellFlow->isLeftToRightDirection() ? section()->cachedCollapsedBorder(this, CBSStart) : section()->cachedCollapsedBorder(this, CBSEnd);
    871 }
    872 
    873 inline CollapsedBorderValue RenderTableCell::cachedCollapsedBottomBorder(const RenderStyle* styleForCellFlow) const
    874 {
    875     if (styleForCellFlow->isHorizontalWritingMode())
    876         return styleForCellFlow->isFlippedBlocksWritingMode() ? section()->cachedCollapsedBorder(this, CBSBefore) : section()->cachedCollapsedBorder(this, CBSAfter);
    877     return styleForCellFlow->isLeftToRightDirection() ? section()->cachedCollapsedBorder(this, CBSEnd) : section()->cachedCollapsedBorder(this, CBSStart);
    878 }
    879 
    880 int RenderTableCell::borderLeft() const
    881 {
    882     return table()->collapseBorders() ? borderHalfLeft(false) : RenderBlock::borderLeft();
    883 }
    884 
    885 int RenderTableCell::borderRight() const
    886 {
    887     return table()->collapseBorders() ? borderHalfRight(false) : RenderBlock::borderRight();
    888 }
    889 
    890 int RenderTableCell::borderTop() const
    891 {
    892     return table()->collapseBorders() ? borderHalfTop(false) : RenderBlock::borderTop();
    893 }
    894 
    895 int RenderTableCell::borderBottom() const
    896 {
    897     return table()->collapseBorders() ? borderHalfBottom(false) : RenderBlock::borderBottom();
    898 }
    899 
    900 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=46191, make the collapsed border drawing
    901 // work with different block flow values instead of being hard-coded to top-to-bottom.
    902 int RenderTableCell::borderStart() const
    903 {
    904     return table()->collapseBorders() ? borderHalfStart(false) : RenderBlock::borderStart();
    905 }
    906 
    907 int RenderTableCell::borderEnd() const
    908 {
    909     return table()->collapseBorders() ? borderHalfEnd(false) : RenderBlock::borderEnd();
    910 }
    911 
    912 int RenderTableCell::borderBefore() const
    913 {
    914     return table()->collapseBorders() ? borderHalfBefore(false) : RenderBlock::borderBefore();
    915 }
    916 
    917 int RenderTableCell::borderAfter() const
    918 {
    919     return table()->collapseBorders() ? borderHalfAfter(false) : RenderBlock::borderAfter();
    920 }
    921 
    922 int RenderTableCell::borderHalfLeft(bool outer) const
    923 {
    924     const RenderStyle* styleForCellFlow = this->styleForCellFlow();
    925     if (styleForCellFlow->isHorizontalWritingMode())
    926         return styleForCellFlow->isLeftToRightDirection() ? borderHalfStart(outer) : borderHalfEnd(outer);
    927     return styleForCellFlow->isFlippedBlocksWritingMode() ? borderHalfAfter(outer) : borderHalfBefore(outer);
    928 }
    929 
    930 int RenderTableCell::borderHalfRight(bool outer) const
    931 {
    932     const RenderStyle* styleForCellFlow = this->styleForCellFlow();
    933     if (styleForCellFlow->isHorizontalWritingMode())
    934         return styleForCellFlow->isLeftToRightDirection() ? borderHalfEnd(outer) : borderHalfStart(outer);
    935     return styleForCellFlow->isFlippedBlocksWritingMode() ? borderHalfBefore(outer) : borderHalfAfter(outer);
    936 }
    937 
    938 int RenderTableCell::borderHalfTop(bool outer) const
    939 {
    940     const RenderStyle* styleForCellFlow = this->styleForCellFlow();
    941     if (styleForCellFlow->isHorizontalWritingMode())
    942         return styleForCellFlow->isFlippedBlocksWritingMode() ? borderHalfAfter(outer) : borderHalfBefore(outer);
    943     return styleForCellFlow->isLeftToRightDirection() ? borderHalfStart(outer) : borderHalfEnd(outer);
    944 }
    945 
    946 int RenderTableCell::borderHalfBottom(bool outer) const
    947 {
    948     const RenderStyle* styleForCellFlow = this->styleForCellFlow();
    949     if (styleForCellFlow->isHorizontalWritingMode())
    950         return styleForCellFlow->isFlippedBlocksWritingMode() ? borderHalfBefore(outer) : borderHalfAfter(outer);
    951     return styleForCellFlow->isLeftToRightDirection() ? borderHalfEnd(outer) : borderHalfStart(outer);
    952 }
    953 
    954 int RenderTableCell::borderHalfStart(bool outer) const
    955 {
    956     CollapsedBorderValue border = collapsedStartBorder(DoNotIncludeBorderColor);
    957     if (border.exists())
    958         return (border.width() + ((styleForCellFlow()->isLeftToRightDirection() ^ outer) ? 1 : 0)) / 2; // Give the extra pixel to top and left.
    959     return 0;
    960 }
    961 
    962 int RenderTableCell::borderHalfEnd(bool outer) const
    963 {
    964     CollapsedBorderValue border = collapsedEndBorder(DoNotIncludeBorderColor);
    965     if (border.exists())
    966         return (border.width() + ((styleForCellFlow()->isLeftToRightDirection() ^ outer) ? 0 : 1)) / 2;
    967     return 0;
    968 }
    969 
    970 int RenderTableCell::borderHalfBefore(bool outer) const
    971 {
    972     CollapsedBorderValue border = collapsedBeforeBorder(DoNotIncludeBorderColor);
    973     if (border.exists())
    974         return (border.width() + ((styleForCellFlow()->isFlippedBlocksWritingMode() ^ outer) ? 0 : 1)) / 2; // Give the extra pixel to top and left.
    975     return 0;
    976 }
    977 
    978 int RenderTableCell::borderHalfAfter(bool outer) const
    979 {
    980     CollapsedBorderValue border = collapsedAfterBorder(DoNotIncludeBorderColor);
    981     if (border.exists())
    982         return (border.width() + ((styleForCellFlow()->isFlippedBlocksWritingMode() ^ outer) ? 1 : 0)) / 2;
    983     return 0;
    984 }
    985 
    986 void RenderTableCell::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
    987 {
    988     ASSERT(paintInfo.phase != PaintPhaseCollapsedTableBorders);
    989     RenderBlock::paint(paintInfo, paintOffset);
    990 }
    991 
    992 static EBorderStyle collapsedBorderStyle(EBorderStyle style)
    993 {
    994     if (style == OUTSET)
    995         return GROOVE;
    996     if (style == INSET)
    997         return RIDGE;
    998     return style;
    999 }
   1000 
   1001 struct CollapsedBorder {
   1002     CollapsedBorderValue borderValue;
   1003     BoxSide side;
   1004     bool shouldPaint;
   1005     int x1;
   1006     int y1;
   1007     int x2;
   1008     int y2;
   1009     EBorderStyle style;
   1010 };
   1011 
   1012 class CollapsedBorders {
   1013 public:
   1014     CollapsedBorders()
   1015         : m_count(0)
   1016     {
   1017     }
   1018 
   1019     void addBorder(const CollapsedBorderValue& borderValue, BoxSide borderSide, bool shouldPaint,
   1020                    int x1, int y1, int x2, int y2, EBorderStyle borderStyle)
   1021     {
   1022         if (borderValue.exists() && shouldPaint) {
   1023             m_borders[m_count].borderValue = borderValue;
   1024             m_borders[m_count].side = borderSide;
   1025             m_borders[m_count].shouldPaint = shouldPaint;
   1026             m_borders[m_count].x1 = x1;
   1027             m_borders[m_count].x2 = x2;
   1028             m_borders[m_count].y1 = y1;
   1029             m_borders[m_count].y2 = y2;
   1030             m_borders[m_count].style = borderStyle;
   1031             m_count++;
   1032         }
   1033     }
   1034 
   1035     CollapsedBorder* nextBorder()
   1036     {
   1037         for (unsigned i = 0; i < m_count; i++) {
   1038             if (m_borders[i].borderValue.exists() && m_borders[i].shouldPaint) {
   1039                 m_borders[i].shouldPaint = false;
   1040                 return &m_borders[i];
   1041             }
   1042         }
   1043 
   1044         return 0;
   1045     }
   1046 
   1047     CollapsedBorder m_borders[4];
   1048     unsigned m_count;
   1049 };
   1050 
   1051 static void addBorderStyle(RenderTable::CollapsedBorderValues& borderValues,
   1052                            CollapsedBorderValue borderValue)
   1053 {
   1054     if (!borderValue.exists())
   1055         return;
   1056     size_t count = borderValues.size();
   1057     for (size_t i = 0; i < count; ++i)
   1058         if (borderValues[i].isSameIgnoringColor(borderValue))
   1059             return;
   1060     borderValues.append(borderValue);
   1061 }
   1062 
   1063 void RenderTableCell::collectBorderValues(RenderTable::CollapsedBorderValues& borderValues) const
   1064 {
   1065     addBorderStyle(borderValues, collapsedStartBorder());
   1066     addBorderStyle(borderValues, collapsedEndBorder());
   1067     addBorderStyle(borderValues, collapsedBeforeBorder());
   1068     addBorderStyle(borderValues, collapsedAfterBorder());
   1069 }
   1070 
   1071 static int compareBorderValuesForQSort(const void* pa, const void* pb)
   1072 {
   1073     const CollapsedBorderValue* a = static_cast<const CollapsedBorderValue*>(pa);
   1074     const CollapsedBorderValue* b = static_cast<const CollapsedBorderValue*>(pb);
   1075     if (a->isSameIgnoringColor(*b))
   1076         return 0;
   1077     return compareBorders(*a, *b);
   1078 }
   1079 
   1080 void RenderTableCell::sortBorderValues(RenderTable::CollapsedBorderValues& borderValues)
   1081 {
   1082     qsort(borderValues.data(), borderValues.size(), sizeof(CollapsedBorderValue),
   1083         compareBorderValuesForQSort);
   1084 }
   1085 
   1086 void RenderTableCell::paintCollapsedBorders(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
   1087 {
   1088     ASSERT(paintInfo.phase == PaintPhaseCollapsedTableBorders);
   1089 
   1090     if (!paintInfo.shouldPaintWithinRoot(this) || style()->visibility() != VISIBLE)
   1091         return;
   1092 
   1093     LayoutRect localRepaintRect = paintInfo.rect;
   1094     localRepaintRect.inflate(maximalOutlineSize(paintInfo.phase));
   1095 
   1096     LayoutRect paintRect = LayoutRect(paintOffset + location(), pixelSnappedSize());
   1097     if (paintRect.y() - table()->outerBorderTop() >= localRepaintRect.maxY())
   1098         return;
   1099 
   1100     if (paintRect.maxY() + table()->outerBorderBottom() <= localRepaintRect.y())
   1101         return;
   1102 
   1103     GraphicsContext* graphicsContext = paintInfo.context;
   1104     if (!table()->currentBorderValue() || graphicsContext->paintingDisabled())
   1105         return;
   1106 
   1107     const RenderStyle* styleForCellFlow = this->styleForCellFlow();
   1108     CollapsedBorderValue leftVal = cachedCollapsedLeftBorder(styleForCellFlow);
   1109     CollapsedBorderValue rightVal = cachedCollapsedRightBorder(styleForCellFlow);
   1110     CollapsedBorderValue topVal = cachedCollapsedTopBorder(styleForCellFlow);
   1111     CollapsedBorderValue bottomVal = cachedCollapsedBottomBorder(styleForCellFlow);
   1112 
   1113     // Adjust our x/y/width/height so that we paint the collapsed borders at the correct location.
   1114     int topWidth = topVal.width();
   1115     int bottomWidth = bottomVal.width();
   1116     int leftWidth = leftVal.width();
   1117     int rightWidth = rightVal.width();
   1118 
   1119     IntRect borderRect = pixelSnappedIntRect(paintRect.x() - leftWidth / 2,
   1120             paintRect.y() - topWidth / 2,
   1121             paintRect.width() + leftWidth / 2 + (rightWidth + 1) / 2,
   1122             paintRect.height() + topWidth / 2 + (bottomWidth + 1) / 2);
   1123 
   1124     EBorderStyle topStyle = collapsedBorderStyle(topVal.style());
   1125     EBorderStyle bottomStyle = collapsedBorderStyle(bottomVal.style());
   1126     EBorderStyle leftStyle = collapsedBorderStyle(leftVal.style());
   1127     EBorderStyle rightStyle = collapsedBorderStyle(rightVal.style());
   1128 
   1129     bool renderTop = topStyle > BHIDDEN && !topVal.isTransparent();
   1130     bool renderBottom = bottomStyle > BHIDDEN && !bottomVal.isTransparent();
   1131     bool renderLeft = leftStyle > BHIDDEN && !leftVal.isTransparent();
   1132     bool renderRight = rightStyle > BHIDDEN && !rightVal.isTransparent();
   1133 
   1134     // We never paint diagonals at the joins.  We simply let the border with the highest
   1135     // precedence paint on top of borders with lower precedence.
   1136     CollapsedBorders borders;
   1137     borders.addBorder(topVal, BSTop, renderTop, borderRect.x(), borderRect.y(), borderRect.maxX(), borderRect.y() + topWidth, topStyle);
   1138     borders.addBorder(bottomVal, BSBottom, renderBottom, borderRect.x(), borderRect.maxY() - bottomWidth, borderRect.maxX(), borderRect.maxY(), bottomStyle);
   1139     borders.addBorder(leftVal, BSLeft, renderLeft, borderRect.x(), borderRect.y(), borderRect.x() + leftWidth, borderRect.maxY(), leftStyle);
   1140     borders.addBorder(rightVal, BSRight, renderRight, borderRect.maxX() - rightWidth, borderRect.y(), borderRect.maxX(), borderRect.maxY(), rightStyle);
   1141 
   1142     bool antialias = shouldAntialiasLines(graphicsContext);
   1143 
   1144     for (CollapsedBorder* border = borders.nextBorder(); border; border = borders.nextBorder()) {
   1145         if (border->borderValue.isSameIgnoringColor(*table()->currentBorderValue())) {
   1146             drawLineForBoxSide(graphicsContext, border->x1, border->y1, border->x2, border->y2, border->side,
   1147                 resolveColor(border->borderValue.color()), border->style, 0, 0, antialias);
   1148         }
   1149     }
   1150 }
   1151 
   1152 void RenderTableCell::paintBackgroundsBehindCell(PaintInfo& paintInfo, const LayoutPoint& paintOffset, RenderObject* backgroundObject)
   1153 {
   1154     if (!paintInfo.shouldPaintWithinRoot(this))
   1155         return;
   1156 
   1157     if (!backgroundObject)
   1158         return;
   1159 
   1160     if (style()->visibility() != VISIBLE)
   1161         return;
   1162 
   1163     RenderTable* tableElt = table();
   1164     if (!tableElt->collapseBorders() && style()->emptyCells() == HIDE && !firstChild())
   1165         return;
   1166 
   1167     LayoutPoint adjustedPaintOffset = paintOffset;
   1168     if (backgroundObject != this)
   1169         adjustedPaintOffset.moveBy(location());
   1170 
   1171     StyleColor c = backgroundObject->resolveStyleColor(CSSPropertyBackgroundColor);
   1172     const FillLayer* bgLayer = backgroundObject->style()->backgroundLayers();
   1173 
   1174     if (bgLayer->hasImage() || c.isValid()) {
   1175         // We have to clip here because the background would paint
   1176         // on top of the borders otherwise.  This only matters for cells and rows.
   1177         bool shouldClip = backgroundObject->hasLayer() && (backgroundObject == this || backgroundObject == parent()) && tableElt->collapseBorders();
   1178         GraphicsContextStateSaver stateSaver(*paintInfo.context, shouldClip);
   1179         if (shouldClip) {
   1180             LayoutRect clipRect(adjustedPaintOffset.x() + borderLeft(), adjustedPaintOffset.y() + borderTop(),
   1181                 width() - borderLeft() - borderRight(), height() - borderTop() - borderBottom());
   1182             paintInfo.context->clip(clipRect);
   1183         }
   1184         paintFillLayers(paintInfo, c.color(), bgLayer, LayoutRect(adjustedPaintOffset, pixelSnappedSize()), BackgroundBleedNone, CompositeSourceOver, backgroundObject);
   1185     }
   1186 }
   1187 
   1188 void RenderTableCell::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
   1189 {
   1190     if (!paintInfo.shouldPaintWithinRoot(this))
   1191         return;
   1192 
   1193     RenderTable* tableElt = table();
   1194     if (!tableElt->collapseBorders() && style()->emptyCells() == HIDE && !firstChild())
   1195         return;
   1196 
   1197     LayoutRect paintRect = LayoutRect(paintOffset, pixelSnappedSize());
   1198     paintBoxShadow(paintInfo, paintRect, style(), Normal);
   1199 
   1200     // Paint our cell background.
   1201     paintBackgroundsBehindCell(paintInfo, paintOffset, this);
   1202 
   1203     paintBoxShadow(paintInfo, paintRect, style(), Inset);
   1204 
   1205     if (!style()->hasBorder() || tableElt->collapseBorders())
   1206         return;
   1207 
   1208     paintBorder(paintInfo, paintRect, style());
   1209 }
   1210 
   1211 void RenderTableCell::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
   1212 {
   1213     if (style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
   1214         return;
   1215 
   1216     RenderTable* tableElt = table();
   1217     if (!tableElt->collapseBorders() && style()->emptyCells() == HIDE && !firstChild())
   1218         return;
   1219 
   1220     paintMaskImages(paintInfo, LayoutRect(paintOffset, pixelSnappedSize()));
   1221 }
   1222 
   1223 bool RenderTableCell::boxShadowShouldBeAppliedToBackground(BackgroundBleedAvoidance, InlineFlowBox*) const
   1224 {
   1225     return false;
   1226 }
   1227 
   1228 void RenderTableCell::scrollbarsChanged(bool horizontalScrollbarChanged, bool verticalScrollbarChanged)
   1229 {
   1230     LayoutUnit scrollbarHeight = scrollbarLogicalHeight();
   1231     if (!scrollbarHeight)
   1232         return; // Not sure if we should be doing something when a scrollbar goes away or not.
   1233 
   1234     // We only care if the scrollbar that affects our intrinsic padding has been added.
   1235     if ((isHorizontalWritingMode() && !horizontalScrollbarChanged) ||
   1236         (!isHorizontalWritingMode() && !verticalScrollbarChanged))
   1237         return;
   1238 
   1239     // Shrink our intrinsic padding as much as possible to accommodate the scrollbar.
   1240     if (style()->verticalAlign() == MIDDLE) {
   1241         LayoutUnit totalHeight = logicalHeight();
   1242         LayoutUnit heightWithoutIntrinsicPadding = totalHeight - intrinsicPaddingBefore() - intrinsicPaddingAfter();
   1243         totalHeight -= scrollbarHeight;
   1244         LayoutUnit newBeforePadding = (totalHeight - heightWithoutIntrinsicPadding) / 2;
   1245         LayoutUnit newAfterPadding = totalHeight - heightWithoutIntrinsicPadding - newBeforePadding;
   1246         setIntrinsicPaddingBefore(newBeforePadding);
   1247         setIntrinsicPaddingAfter(newAfterPadding);
   1248     } else
   1249         setIntrinsicPaddingAfter(intrinsicPaddingAfter() - scrollbarHeight);
   1250 }
   1251 
   1252 RenderTableCell* RenderTableCell::createAnonymous(Document* document)
   1253 {
   1254     RenderTableCell* renderer = new RenderTableCell(0);
   1255     renderer->setDocumentForAnonymous(document);
   1256     return renderer;
   1257 }
   1258 
   1259 RenderTableCell* RenderTableCell::createAnonymousWithParentRenderer(const RenderObject* parent)
   1260 {
   1261     RenderTableCell* newCell = RenderTableCell::createAnonymous(parent->document());
   1262     RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), TABLE_CELL);
   1263     newCell->setStyle(newStyle.release());
   1264     return newCell;
   1265 }
   1266 
   1267 } // namespace WebCore
   1268