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