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