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