Try to fix the Apple LLVM Compiler build after r88087.
[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 "TransformState.h"
37
38 using namespace std;
39
40 namespace WebCore {
41
42 using namespace HTMLNames;
43
44 RenderTableCell::RenderTableCell(Node* node)
45     : RenderBlock(node)
46     , m_row(-1)
47     , m_column(-1)
48     , m_rowSpan(1)
49     , m_columnSpan(1)
50     , m_cellWidthChanged(false)
51     , m_intrinsicPaddingBefore(0)
52     , m_intrinsicPaddingAfter(0)
53 {
54     updateFromElement();
55 }
56
57 void RenderTableCell::destroy()
58 {
59     RenderTableSection* recalcSection = parent() ? section() : 0;
60
61     RenderBlock::destroy();
62
63     if (recalcSection)
64         recalcSection->setNeedsCellRecalc();
65 }
66
67 void RenderTableCell::updateFromElement()
68 {
69     Node* n = node();
70     if (n && (n->hasTagName(tdTag) || n->hasTagName(thTag))) {
71         HTMLTableCellElement* tc = static_cast<HTMLTableCellElement*>(n);
72         int oldRSpan = m_rowSpan;
73         int oldCSpan = m_columnSpan;
74
75         m_columnSpan = tc->colSpan();
76         m_rowSpan = tc->rowSpan();
77         if ((oldRSpan != m_rowSpan || oldCSpan != m_columnSpan) && style() && parent()) {
78             setNeedsLayoutAndPrefWidthsRecalc();
79             if (section())
80                 section()->setNeedsCellRecalc();
81         }
82     }
83 }
84
85 Length RenderTableCell::styleOrColLogicalWidth() const
86 {
87     Length w = style()->logicalWidth();
88     if (!w.isAuto())
89         return w;
90
91     if (RenderTableCol* tableCol = table()->colElement(col())) {
92         int colSpanCount = colSpan();
93
94         Length colWidthSum = Length(0, Fixed);
95         for (int i = 1; i <= colSpanCount; i++) {
96             Length colWidth = tableCol->style()->logicalWidth();
97
98             // Percentage value should be returned only for colSpan == 1.
99             // Otherwise we return original width for the cell.
100             if (!colWidth.isFixed()) {
101                 if (colSpanCount > 1)
102                     return w;
103                 return colWidth;
104             }
105
106             colWidthSum = Length(colWidthSum.value() + colWidth.value(), Fixed);
107
108             tableCol = table()->nextColElement(tableCol);
109             // If no next <col> tag found for the span we just return what we have for now.
110             if (!tableCol)
111                 break;
112         }
113
114         // Column widths specified on <col> apply to the border box of the cell.
115         // Percentages don't need to be handled since they're always treated this way (even when specified on the cells).
116         // See Bugzilla bug 8126 for details.
117         if (colWidthSum.isFixed() && colWidthSum.value() > 0)
118             colWidthSum = Length(max(0, colWidthSum.value() - borderAndPaddingLogicalWidth()), Fixed);
119         return colWidthSum;
120     }
121
122     return w;
123 }
124
125 void RenderTableCell::computePreferredLogicalWidths()
126 {
127     // 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
128     // cells are added, but relayout can cause the cells to be freed, leaving stale pointers in the sections'
129     // grids.  We must refresh those grids before the child cells try to use them.
130     table()->recalcSectionsIfNeeded();
131
132     RenderBlock::computePreferredLogicalWidths();
133     if (node() && style()->autoWrap()) {
134         // See if nowrap was set.
135         Length w = styleOrColLogicalWidth();
136         String nowrap = static_cast<Element*>(node())->getAttribute(nowrapAttr);
137         if (!nowrap.isNull() && w.isFixed())
138             // Nowrap is set, but we didn't actually use it because of the
139             // fixed width set on the cell.  Even so, it is a WinIE/Moz trait
140             // to make the minwidth of the cell into the fixed width.  They do this
141             // even in strict mode, so do not make this a quirk.  Affected the top
142             // of hiptop.com.
143             m_minPreferredLogicalWidth = max(w.value(), m_minPreferredLogicalWidth);
144     }
145 }
146
147 void RenderTableCell::computeLogicalWidth()
148 {
149 }
150
151 void RenderTableCell::updateLogicalWidth(int w)
152 {
153     if (w == logicalWidth())
154         return;
155
156     setLogicalWidth(w);
157     setCellWidthChanged(true);
158 }
159
160 void RenderTableCell::layout()
161 {
162     layoutBlock(cellWidthChanged());
163     setCellWidthChanged(false);
164 }
165
166 int RenderTableCell::paddingTop(bool includeIntrinsicPadding) const
167 {
168     int result = RenderBlock::paddingTop();
169     if (!includeIntrinsicPadding || !isHorizontalWritingMode())
170         return result;
171     return result + (style()->writingMode() == TopToBottomWritingMode ? intrinsicPaddingBefore() : intrinsicPaddingAfter());
172 }
173
174 int RenderTableCell::paddingBottom(bool includeIntrinsicPadding) const
175 {
176     int result = RenderBlock::paddingBottom();
177     if (!includeIntrinsicPadding || !isHorizontalWritingMode())
178         return result;
179     return result + (style()->writingMode() == TopToBottomWritingMode ? intrinsicPaddingAfter() : intrinsicPaddingBefore());
180 }
181
182 int RenderTableCell::paddingLeft(bool includeIntrinsicPadding) const
183 {
184     int result = RenderBlock::paddingLeft();
185     if (!includeIntrinsicPadding || isHorizontalWritingMode())
186         return result;
187     return result + (style()->writingMode() == LeftToRightWritingMode ? intrinsicPaddingBefore() : intrinsicPaddingAfter());
188     
189 }
190
191 int RenderTableCell::paddingRight(bool includeIntrinsicPadding) const
192 {   
193     int result = RenderBlock::paddingRight();
194     if (!includeIntrinsicPadding || isHorizontalWritingMode())
195         return result;
196     return result + (style()->writingMode() == LeftToRightWritingMode ? intrinsicPaddingAfter() : intrinsicPaddingBefore());
197 }
198
199 int RenderTableCell::paddingBefore(bool includeIntrinsicPadding) const
200 {
201     int result = RenderBlock::paddingBefore();
202     if (!includeIntrinsicPadding)
203         return result;
204     return result + intrinsicPaddingBefore();
205 }
206
207 int RenderTableCell::paddingAfter(bool includeIntrinsicPadding) const
208 {
209     int result = RenderBlock::paddingAfter();
210     if (!includeIntrinsicPadding)
211         return result;
212     return result + intrinsicPaddingAfter();
213 }
214
215 void RenderTableCell::setOverrideSize(int size)
216 {
217     clearIntrinsicPadding();
218     RenderBlock::setOverrideSize(size);
219 }
220     
221 void RenderTableCell::setOverrideSizeFromRowHeight(int rowHeight)
222 {
223     clearIntrinsicPadding();
224     RenderBlock::setOverrideSize(max(0, rowHeight - borderBefore() - paddingBefore() - borderAfter() - paddingAfter()));
225 }
226
227 IntSize RenderTableCell::offsetFromContainer(RenderObject* o, const IntPoint& point) const
228 {
229     ASSERT(o == container());
230
231     IntSize offset = RenderBlock::offsetFromContainer(o, point);
232     if (parent())
233         offset.expand(-parentBox()->x(), -parentBox()->y());
234
235     return offset;
236 }
237
238 IntRect RenderTableCell::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
239 {
240     // If the table grid is dirty, we cannot get reliable information about adjoining cells,
241     // so we ignore outside borders. This should not be a problem because it means that
242     // the table is going to recalculate the grid, relayout and repaint its current rect, which
243     // includes any outside borders of this cell.
244     if (!table()->collapseBorders() || table()->needsSectionRecalc())
245         return RenderBlock::clippedOverflowRectForRepaint(repaintContainer);
246
247     bool rtl = !table()->style()->isLeftToRightDirection();
248     int outlineSize = style()->outlineSize();
249     int left = max(borderHalfLeft(true), outlineSize);
250     int right = max(borderHalfRight(true), outlineSize);
251     int top = max(borderHalfTop(true), outlineSize);
252     int bottom = max(borderHalfBottom(true), outlineSize);
253     if ((left && !rtl) || (right && rtl)) {
254         if (RenderTableCell* before = table()->cellBefore(this)) {
255             top = max(top, before->borderHalfTop(true));
256             bottom = max(bottom, before->borderHalfBottom(true));
257         }
258     }
259     if ((left && rtl) || (right && !rtl)) {
260         if (RenderTableCell* after = table()->cellAfter(this)) {
261             top = max(top, after->borderHalfTop(true));
262             bottom = max(bottom, after->borderHalfBottom(true));
263         }
264     }
265     if (top) {
266         if (RenderTableCell* above = table()->cellAbove(this)) {
267             left = max(left, above->borderHalfLeft(true));
268             right = max(right, above->borderHalfRight(true));
269         }
270     }
271     if (bottom) {
272         if (RenderTableCell* below = table()->cellBelow(this)) {
273             left = max(left, below->borderHalfLeft(true));
274             right = max(right, below->borderHalfRight(true));
275         }
276     }
277     left = max(left, -minXVisualOverflow());
278     top = max(top, -minYVisualOverflow());
279     IntRect r(-left, - top, left + max(width() + right, maxXVisualOverflow()), top + max(height() + bottom, maxYVisualOverflow()));
280
281     if (RenderView* v = view()) {
282         // FIXME: layoutDelta needs to be applied in parts before/after transforms and
283         // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
284         r.move(v->layoutDelta());
285     }
286     computeRectForRepaint(repaintContainer, r);
287     return r;
288 }
289
290 void RenderTableCell::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& r, bool fixed)
291 {
292     if (repaintContainer == this)
293         return;
294     r.setY(r.y());
295     RenderView* v = view();
296     if ((!v || !v->layoutStateEnabled() || repaintContainer) && parent())
297         r.moveBy(-parentBox()->location()); // Rows are in the same coordinate space, so don't add their offset in.
298     RenderBlock::computeRectForRepaint(repaintContainer, r, fixed);
299 }
300
301 int RenderTableCell::cellBaselinePosition() const
302 {
303     // <http://www.w3.org/TR/2007/CR-CSS21-20070719/tables.html#height-layout>: The baseline of a cell is the baseline of
304     // the first in-flow line box in the cell, or the first in-flow table-row in the cell, whichever comes first. If there
305     // is no such line box or table-row, the baseline is the bottom of content edge of the cell box.
306     int firstLineBaseline = firstLineBoxBaseline();
307     if (firstLineBaseline != -1)
308         return firstLineBaseline;
309     return paddingBefore() + borderBefore() + contentLogicalHeight();
310 }
311
312 void RenderTableCell::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
313 {
314     if (parent() && section() && style() && style()->height() != newStyle->height())
315         section()->setNeedsCellRecalc();
316
317     ASSERT(newStyle->display() == TABLE_CELL);
318
319     RenderBlock::styleWillChange(diff, newStyle);
320 }
321
322 void RenderTableCell::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
323 {
324     RenderBlock::styleDidChange(diff, oldStyle);
325     setHasBoxDecorations(true);
326 }
327
328 // The following rules apply for resolving conflicts and figuring out which border
329 // to use.
330 // (1) Borders with the 'border-style' of 'hidden' take precedence over all other conflicting 
331 // borders. Any border with this value suppresses all borders at this location.
332 // (2) Borders with a style of 'none' have the lowest priority. Only if the border properties of all 
333 // the elements meeting at this edge are 'none' will the border be omitted (but note that 'none' is 
334 // the default value for the border style.)
335 // (3) If none of the styles are 'hidden' and at least one of them is not 'none', then narrow borders 
336 // are discarded in favor of wider ones. If several have the same 'border-width' then styles are preferred 
337 // in this order: 'double', 'solid', 'dashed', 'dotted', 'ridge', 'outset', 'groove', and the lowest: 'inset'.
338 // (4) If border styles differ only in color, then a style set on a cell wins over one on a row, 
339 // which wins over a row group, column, column group and, lastly, table. It is undefined which color 
340 // is used when two elements of the same type disagree.
341 static int compareBorders(const CollapsedBorderValue& border1, const CollapsedBorderValue& border2)
342 {
343     // Sanity check the values passed in. The null border have lowest priority.
344     if (!border2.exists()) {
345         if (!border1.exists())
346             return 0;
347         return 1;
348     }
349     if (!border1.exists())
350         return -1;
351
352     // Rule #1 above.
353     if (border2.style() == BHIDDEN) {
354         if (border1.style() == BHIDDEN)
355             return 0;
356         return -1;
357     }
358     if (border1.style() == BHIDDEN)
359         return 1;
360     
361     // Rule #2 above.  A style of 'none' has lowest priority and always loses to any other border.
362     if (border2.style() == BNONE) {
363         if (border1.style() == BNONE)
364             return 0;
365         return 1;
366     }
367     if (border1.style() == BNONE)
368         return -1;
369
370     // The first part of rule #3 above. Wider borders win.
371     if (border1.width() != border2.width())
372         return border1.width() < border2.width() ? -1 : 1;
373     
374     // The borders have equal width.  Sort by border style.
375     if (border1.style() != border2.style())
376         return border1.style() < border2.style() ? -1 : 1;
377     
378     // The border have the same width and style.  Rely on precedence (cell over row over row group, etc.)
379     if (border1.precedence() == border2.precedence())
380         return 0;
381     return border1.precedence() < border2.precedence() ? -1 : 1;
382 }
383
384 static CollapsedBorderValue chooseBorder(const CollapsedBorderValue& border1, const CollapsedBorderValue& border2)
385 {
386     const CollapsedBorderValue& border = compareBorders(border1, border2) < 0 ? border2 : border1;
387     return border.style() == BHIDDEN ? CollapsedBorderValue() : border;
388 }
389
390 CollapsedBorderValue RenderTableCell::collapsedStartBorder() const
391 {
392     RenderTable* table = this->table();
393     bool isStartColumn = col() == 0;
394
395     // For the start border, we need to check, in order of precedence:
396     // (1) Our start border.
397     int start = CSSProperty::resolveDirectionAwareProperty(CSSPropertyWebkitBorderStartColor, table->style()->direction(), table->style()->writingMode());
398     int end = CSSProperty::resolveDirectionAwareProperty(CSSPropertyWebkitBorderEndColor, table->style()->direction(), table->style()->writingMode());
399     CollapsedBorderValue result(&style()->borderStart(), style()->visitedDependentColor(start), BCELL);
400
401     // (2) The end border of the preceding cell.
402     if (RenderTableCell* prevCell = table->cellBefore(this)) {
403         CollapsedBorderValue prevCellBorder = CollapsedBorderValue(&prevCell->style()->borderEnd(), prevCell->style()->visitedDependentColor(end), BCELL);
404         result = chooseBorder(prevCellBorder, result);
405         if (!result.exists())
406             return result;
407     } else if (isStartColumn) {
408         // (3) Our row's start border.
409         result = chooseBorder(result, CollapsedBorderValue(&parent()->style()->borderStart(), parent()->style()->visitedDependentColor(start), BROW));
410         if (!result.exists())
411             return result;
412         
413         // (4) Our row group's start border.
414         result = chooseBorder(result, CollapsedBorderValue(&section()->style()->borderStart(), section()->style()->visitedDependentColor(start), BROWGROUP));
415         if (!result.exists())
416             return result;
417     }
418     
419     // (5) Our column and column group's start borders.
420     bool startColEdge;
421     bool endColEdge;
422     RenderTableCol* colElt = table->colElement(col(), &startColEdge, &endColEdge);
423     if (colElt && startColEdge) {
424         result = chooseBorder(result, CollapsedBorderValue(&colElt->style()->borderStart(), colElt->style()->visitedDependentColor(start), BCOL));
425         if (!result.exists())
426             return result;
427         if (colElt->parent()->isTableCol() && !colElt->previousSibling()) {
428             result = chooseBorder(result, CollapsedBorderValue(&colElt->parent()->style()->borderStart(), colElt->parent()->style()->visitedDependentColor(start), BCOLGROUP));
429             if (!result.exists())
430                 return result;
431         }
432     }
433     
434     // (6) The end border of the preceding column.
435     if (!isStartColumn) {
436         colElt = table->colElement(col() -1, &startColEdge, &endColEdge);
437         if (colElt && endColEdge) {
438             CollapsedBorderValue endBorder = CollapsedBorderValue(&colElt->style()->borderEnd(), colElt->style()->visitedDependentColor(end), BCOL);
439             result = chooseBorder(endBorder, result);
440             if (!result.exists())
441                 return result;
442         }
443     } else {
444         // (7) The table's start border.
445         result = chooseBorder(result, CollapsedBorderValue(&table->style()->borderStart(), table->style()->visitedDependentColor(start), BTABLE));
446         if (!result.exists())
447             return result;
448     }
449     
450     return result;
451 }
452
453 CollapsedBorderValue RenderTableCell::collapsedEndBorder() const
454 {
455     RenderTable* table = this->table();
456     bool isEndColumn = table->colToEffCol(col() + colSpan() - 1) == table->numEffCols() - 1;
457
458     // For end border, we need to check, in order of precedence:
459     // (1) Our end border.
460     int start = CSSProperty::resolveDirectionAwareProperty(CSSPropertyWebkitBorderStartColor, table->style()->direction(), table->style()->writingMode());
461     int end = CSSProperty::resolveDirectionAwareProperty(CSSPropertyWebkitBorderEndColor, table->style()->direction(), table->style()->writingMode());
462     CollapsedBorderValue result = CollapsedBorderValue(&style()->borderEnd(), style()->visitedDependentColor(end), BCELL);
463     
464     // (2) The start border of the following cell.
465     if (!isEndColumn) {
466         RenderTableCell* nextCell = table->cellAfter(this);
467         if (nextCell && nextCell->style()) {
468             CollapsedBorderValue startBorder = CollapsedBorderValue(&nextCell->style()->borderStart(), nextCell->style()->visitedDependentColor(start), BCELL);
469             result = chooseBorder(result, startBorder);
470             if (!result.exists())
471                 return result;
472         }
473     } else {
474         // (3) Our row's end border.
475         result = chooseBorder(result, CollapsedBorderValue(&parent()->style()->borderEnd(), parent()->style()->visitedDependentColor(end), BROW));
476         if (!result.exists())
477             return result;
478         
479         // (4) Our row group's end border.
480         result = chooseBorder(result, CollapsedBorderValue(&section()->style()->borderEnd(), section()->style()->visitedDependentColor(end), BROWGROUP));
481         if (!result.exists())
482             return result;
483     }
484     
485     // (5) Our column and column group's end borders.
486     bool startColEdge;
487     bool endColEdge;
488     RenderTableCol* colElt = table->colElement(col() + colSpan() - 1, &startColEdge, &endColEdge);
489     if (colElt && endColEdge) {
490         result = chooseBorder(result, CollapsedBorderValue(&colElt->style()->borderEnd(), colElt->style()->visitedDependentColor(end), BCOL));
491         if (!result.exists())
492             return result;
493         if (colElt->parent()->isTableCol() && !colElt->nextSibling()) {
494             result = chooseBorder(result, CollapsedBorderValue(&colElt->parent()->style()->borderEnd(), colElt->parent()->style()->visitedDependentColor(end), BCOLGROUP));
495             if (!result.exists())
496                 return result;
497         }
498     }
499     
500     // (6) The start border of the next column.
501     if (!isEndColumn) {
502         colElt = table->colElement(col() + colSpan(), &startColEdge, &endColEdge);
503         if (colElt && startColEdge) {
504             CollapsedBorderValue startBorder = CollapsedBorderValue(&colElt->style()->borderStart(), colElt->style()->visitedDependentColor(start), BCOL);
505             result = chooseBorder(result, startBorder);
506             if (!result.exists())
507                 return result;
508         }
509     } else {
510         // (7) The table's end border.
511         result = chooseBorder(result, CollapsedBorderValue(&table->style()->borderEnd(), table->style()->visitedDependentColor(end), BTABLE));
512         if (!result.exists())
513             return result;
514     }
515     
516     return result;
517 }
518
519 CollapsedBorderValue RenderTableCell::collapsedBeforeBorder() const
520 {
521     RenderTable* table = this->table();
522
523     // For before border, we need to check, in order of precedence:
524     // (1) Our before border.
525     int before = CSSProperty::resolveDirectionAwareProperty(CSSPropertyWebkitBorderBeforeColor, table->style()->direction(), table->style()->writingMode());
526     int after = CSSProperty::resolveDirectionAwareProperty(CSSPropertyWebkitBorderAfterColor, table->style()->direction(), table->style()->writingMode());
527     CollapsedBorderValue result = CollapsedBorderValue(&style()->borderBefore(), style()->visitedDependentColor(before), BCELL);
528     
529     RenderTableCell* prevCell = table->cellAbove(this);
530     if (prevCell) {
531         // (2) A before cell's after border.
532         result = chooseBorder(CollapsedBorderValue(&prevCell->style()->borderAfter(), prevCell->style()->visitedDependentColor(after), BCELL), result);
533         if (!result.exists())
534             return result;
535     }
536     
537     // (3) Our row's before border.
538     result = chooseBorder(result, CollapsedBorderValue(&parent()->style()->borderBefore(), parent()->style()->visitedDependentColor(before), BROW));
539     if (!result.exists())
540         return result;
541     
542     // (4) The previous row's after border.
543     if (prevCell) {
544         RenderObject* prevRow = 0;
545         if (prevCell->section() == section())
546             prevRow = parent()->previousSibling();
547         else
548             prevRow = prevCell->section()->lastChild();
549     
550         if (prevRow) {
551             result = chooseBorder(CollapsedBorderValue(&prevRow->style()->borderAfter(), prevRow->style()->visitedDependentColor(after), BROW), result);
552             if (!result.exists())
553                 return result;
554         }
555     }
556     
557     // Now check row groups.
558     RenderTableSection* currSection = section();
559     if (!row()) {
560         // (5) Our row group's before border.
561         result = chooseBorder(result, CollapsedBorderValue(&currSection->style()->borderBefore(), currSection->style()->visitedDependentColor(before), BROWGROUP));
562         if (!result.exists())
563             return result;
564         
565         // (6) Previous row group's after border.
566         currSection = table->sectionAbove(currSection);
567         if (currSection) {
568             result = chooseBorder(CollapsedBorderValue(&currSection->style()->borderAfter(), currSection->style()->visitedDependentColor(after), BROWGROUP), result);
569             if (!result.exists())
570                 return result;
571         }
572     }
573     
574     if (!currSection) {
575         // (8) Our column and column group's before borders.
576         RenderTableCol* colElt = table->colElement(col());
577         if (colElt) {
578             result = chooseBorder(result, CollapsedBorderValue(&colElt->style()->borderBefore(), colElt->style()->visitedDependentColor(before), BCOL));
579             if (!result.exists())
580                 return result;
581             if (colElt->parent()->isTableCol()) {
582                 result = chooseBorder(result, CollapsedBorderValue(&colElt->parent()->style()->borderBefore(), colElt->parent()->style()->visitedDependentColor(before), BCOLGROUP));
583                 if (!result.exists())
584                     return result;
585             }
586         }
587         
588         // (9) The table's before border.
589         result = chooseBorder(result, CollapsedBorderValue(&table->style()->borderBefore(), table->style()->visitedDependentColor(before), BTABLE));
590         if (!result.exists())
591             return result;
592     }
593     
594     return result;
595 }
596
597 CollapsedBorderValue RenderTableCell::collapsedAfterBorder() const
598 {
599     RenderTable* table = this->table();
600
601     // For after border, we need to check, in order of precedence:
602     // (1) Our after border.
603     int before = CSSProperty::resolveDirectionAwareProperty(CSSPropertyWebkitBorderBeforeColor, table->style()->direction(), table->style()->writingMode());
604     int after = CSSProperty::resolveDirectionAwareProperty(CSSPropertyWebkitBorderAfterColor, table->style()->direction(), table->style()->writingMode());
605     CollapsedBorderValue result = CollapsedBorderValue(&style()->borderAfter(), style()->visitedDependentColor(after), BCELL);
606     
607     RenderTableCell* nextCell = table->cellBelow(this);
608     if (nextCell) {
609         // (2) An after cell's before border.
610         result = chooseBorder(result, CollapsedBorderValue(&nextCell->style()->borderBefore(), nextCell->style()->visitedDependentColor(before), BCELL));
611         if (!result.exists())
612             return result;
613     }
614     
615     // (3) Our row's after border. (FIXME: Deal with rowspan!)
616     result = chooseBorder(result, CollapsedBorderValue(&parent()->style()->borderAfter(), parent()->style()->visitedDependentColor(after), BROW));
617     if (!result.exists())
618         return result;
619     
620     // (4) The next row's before border.
621     if (nextCell) {
622         result = chooseBorder(result, CollapsedBorderValue(&nextCell->parent()->style()->borderBefore(), nextCell->parent()->style()->visitedDependentColor(before), BROW));
623         if (!result.exists())
624             return result;
625     }
626     
627     // Now check row groups.
628     RenderTableSection* currSection = section();
629     if (row() + rowSpan() >= currSection->numRows()) {
630         // (5) Our row group's after border.
631         result = chooseBorder(result, CollapsedBorderValue(&currSection->style()->borderAfter(), currSection->style()->visitedDependentColor(after), BROWGROUP));
632         if (!result.exists())
633             return result;
634         
635         // (6) Following row group's before border.
636         currSection = table->sectionBelow(currSection);
637         if (currSection) {
638             result = chooseBorder(result, CollapsedBorderValue(&currSection->style()->borderBefore(), currSection->style()->visitedDependentColor(before), BROWGROUP));
639             if (!result.exists())
640                 return result;
641         }
642     }
643     
644     if (!currSection) {
645         // (8) Our column and column group's after borders.
646         RenderTableCol* colElt = table->colElement(col());
647         if (colElt) {
648             result = chooseBorder(result, CollapsedBorderValue(&colElt->style()->borderAfter(), colElt->style()->visitedDependentColor(after), BCOL));
649             if (!result.exists()) return result;
650             if (colElt->parent()->isTableCol()) {
651                 result = chooseBorder(result, CollapsedBorderValue(&colElt->parent()->style()->borderAfter(), colElt->parent()->style()->visitedDependentColor(after), BCOLGROUP));
652                 if (!result.exists())
653                     return result;
654             }
655         }
656         
657         // (9) The table's after border.
658         result = chooseBorder(result, CollapsedBorderValue(&table->style()->borderAfter(), table->style()->visitedDependentColor(after), BTABLE));
659         if (!result.exists())
660             return result;
661     }
662     
663     return result;    
664 }
665
666 CollapsedBorderValue RenderTableCell::collapsedLeftBorder() const
667 {
668     RenderStyle* tableStyle = table()->style();
669     if (tableStyle->isHorizontalWritingMode())
670         return tableStyle->isLeftToRightDirection() ? collapsedStartBorder() : collapsedEndBorder();
671     return tableStyle->isFlippedBlocksWritingMode() ? collapsedAfterBorder() : collapsedBeforeBorder();
672 }
673
674 CollapsedBorderValue RenderTableCell::collapsedRightBorder() const
675 {
676     RenderStyle* tableStyle = table()->style();
677     if (tableStyle->isHorizontalWritingMode())
678         return tableStyle->isLeftToRightDirection() ? collapsedEndBorder() : collapsedStartBorder();
679     return tableStyle->isFlippedBlocksWritingMode() ? collapsedBeforeBorder() : collapsedAfterBorder();
680 }
681
682 CollapsedBorderValue RenderTableCell::collapsedTopBorder() const
683 {
684     RenderStyle* tableStyle = table()->style();
685     if (tableStyle->isHorizontalWritingMode())
686         return tableStyle->isFlippedBlocksWritingMode() ? collapsedAfterBorder() : collapsedBeforeBorder();
687     return tableStyle->isLeftToRightDirection() ? collapsedStartBorder() : collapsedEndBorder();
688 }
689
690 CollapsedBorderValue RenderTableCell::collapsedBottomBorder() const
691 {
692     RenderStyle* tableStyle = table()->style();
693     if (tableStyle->isHorizontalWritingMode())
694         return tableStyle->isFlippedBlocksWritingMode() ? collapsedBeforeBorder() : collapsedAfterBorder();
695     return tableStyle->isLeftToRightDirection() ? collapsedEndBorder() : collapsedStartBorder();
696 }
697
698 int RenderTableCell::borderLeft() const
699 {
700     return table()->collapseBorders() ? borderHalfLeft(false) : RenderBlock::borderLeft();
701 }
702
703 int RenderTableCell::borderRight() const
704 {
705     return table()->collapseBorders() ? borderHalfRight(false) : RenderBlock::borderRight();
706 }
707
708 int RenderTableCell::borderTop() const
709 {
710     return table()->collapseBorders() ? borderHalfTop(false) : RenderBlock::borderTop();
711 }
712
713 int RenderTableCell::borderBottom() const
714 {
715     return table()->collapseBorders() ? borderHalfBottom(false) : RenderBlock::borderBottom();
716 }
717
718 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=46191, make the collapsed border drawing
719 // work with different block flow values instead of being hard-coded to top-to-bottom.
720 int RenderTableCell::borderStart() const
721 {
722     return table()->collapseBorders() ? borderHalfStart(false) : RenderBlock::borderStart();
723 }
724
725 int RenderTableCell::borderEnd() const
726 {
727     return table()->collapseBorders() ? borderHalfEnd(false) : RenderBlock::borderEnd();
728 }
729
730 int RenderTableCell::borderBefore() const
731 {
732     return table()->collapseBorders() ? borderHalfBefore(false) : RenderBlock::borderBefore();
733 }
734
735 int RenderTableCell::borderAfter() const
736 {
737     return table()->collapseBorders() ? borderHalfAfter(false) : RenderBlock::borderAfter();
738 }
739
740 int RenderTableCell::borderHalfLeft(bool outer) const
741 {
742     RenderStyle* tableStyle = table()->style();
743     if (tableStyle->isHorizontalWritingMode())
744         return tableStyle->isLeftToRightDirection() ? borderHalfStart(outer) : borderHalfEnd(outer);
745     return tableStyle->isFlippedBlocksWritingMode() ? borderHalfAfter(outer) : borderHalfBefore(outer);
746 }
747
748 int RenderTableCell::borderHalfRight(bool outer) const
749 {
750     RenderStyle* tableStyle = table()->style();
751     if (tableStyle->isHorizontalWritingMode())
752         return tableStyle->isLeftToRightDirection() ? borderHalfEnd(outer) : borderHalfStart(outer);
753     return tableStyle->isFlippedBlocksWritingMode() ? borderHalfBefore(outer) : borderHalfAfter(outer);
754 }
755
756 int RenderTableCell::borderHalfTop(bool outer) const
757 {
758     RenderStyle* tableStyle = table()->style();
759     if (tableStyle->isHorizontalWritingMode())
760         return tableStyle->isFlippedBlocksWritingMode() ? borderHalfAfter(outer) : borderHalfBefore(outer);
761     return tableStyle->isLeftToRightDirection() ? borderHalfStart(outer) : borderHalfEnd(outer);
762 }
763
764 int RenderTableCell::borderHalfBottom(bool outer) const
765 {
766     RenderStyle* tableStyle = table()->style();
767     if (tableStyle->isHorizontalWritingMode())
768         return tableStyle->isFlippedBlocksWritingMode() ? borderHalfBefore(outer) : borderHalfAfter(outer);
769     return tableStyle->isLeftToRightDirection() ? borderHalfEnd(outer) : borderHalfStart(outer);
770 }
771
772 int RenderTableCell::borderHalfStart(bool outer) const
773 {
774     CollapsedBorderValue border = collapsedStartBorder();
775     if (border.exists())
776         return (border.width() + ((table()->style()->isLeftToRightDirection() ^ outer) ? 1 : 0)) / 2; // Give the extra pixel to top and left.
777     return 0;
778 }
779     
780 int RenderTableCell::borderHalfEnd(bool outer) const
781 {
782     CollapsedBorderValue border = collapsedEndBorder();
783     if (border.exists())
784         return (border.width() + ((table()->style()->isLeftToRightDirection() ^ outer) ? 0 : 1)) / 2;
785     return 0;
786 }
787
788 int RenderTableCell::borderHalfBefore(bool outer) const
789 {
790     CollapsedBorderValue border = collapsedBeforeBorder();
791     if (border.exists())
792         return (border.width() + ((table()->style()->isFlippedBlocksWritingMode() ^ outer) ? 0 : 1)) / 2; // Give the extra pixel to top and left.
793     return 0;
794 }
795
796 int RenderTableCell::borderHalfAfter(bool outer) const
797 {
798     CollapsedBorderValue border = collapsedAfterBorder();
799     if (border.exists())
800         return (border.width() + ((table()->style()->isFlippedBlocksWritingMode() ^ outer) ? 1 : 0)) / 2;
801     return 0;
802 }
803
804 void RenderTableCell::paint(PaintInfo& paintInfo, int tx, int ty)
805 {
806     if (paintInfo.phase == PaintPhaseCollapsedTableBorders && style()->visibility() == VISIBLE) {
807         if (!paintInfo.shouldPaintWithinRoot(this))
808             return;
809
810         tx += x();
811         ty += y();
812         int os = 2 * maximalOutlineSize(paintInfo.phase);
813         if (ty - table()->outerBorderTop() < paintInfo.rect.maxY() + os
814             && ty + height() + table()->outerBorderBottom() > paintInfo.rect.y() - os)
815             paintCollapsedBorder(paintInfo.context, IntRect(tx, ty, width(), height()));
816         return;
817     } 
818     
819     RenderBlock::paint(paintInfo, tx, ty);
820 }
821
822 static EBorderStyle collapsedBorderStyle(EBorderStyle style)
823 {
824     if (style == OUTSET)
825         return GROOVE;
826     if (style == INSET)
827         return RIDGE;
828     return style;
829 }
830
831 struct CollapsedBorder {
832     CollapsedBorderValue borderValue;
833     BoxSide side;
834     bool shouldPaint;
835     int x1;
836     int y1;
837     int x2;
838     int y2;
839     EBorderStyle style;
840 };
841
842 class CollapsedBorders {
843 public:
844     CollapsedBorders()
845         : m_count(0)
846     {
847     }
848     
849     void addBorder(const CollapsedBorderValue& borderValue, BoxSide borderSide, bool shouldPaint,
850                    int x1, int y1, int x2, int y2, EBorderStyle borderStyle)
851     {
852         if (borderValue.exists() && shouldPaint) {
853             m_borders[m_count].borderValue = borderValue;
854             m_borders[m_count].side = borderSide;
855             m_borders[m_count].shouldPaint = shouldPaint;
856             m_borders[m_count].x1 = x1;
857             m_borders[m_count].x2 = x2;
858             m_borders[m_count].y1 = y1;
859             m_borders[m_count].y2 = y2;
860             m_borders[m_count].style = borderStyle;
861             m_count++;
862         }
863     }
864
865     CollapsedBorder* nextBorder()
866     {
867         for (int i = 0; i < m_count; i++) {
868             if (m_borders[i].borderValue.exists() && m_borders[i].shouldPaint) {
869                 m_borders[i].shouldPaint = false;
870                 return &m_borders[i];
871             }
872         }
873         
874         return 0;
875     }
876     
877     CollapsedBorder m_borders[4];
878     int m_count;
879 };
880
881 static void addBorderStyle(RenderTableCell::CollapsedBorderStyles& borderStyles, CollapsedBorderValue borderValue)
882 {
883     if (!borderValue.exists())
884         return;
885     size_t count = borderStyles.size();
886     for (size_t i = 0; i < count; ++i)
887         if (borderStyles[i] == borderValue)
888             return;
889     borderStyles.append(borderValue);
890 }
891
892 void RenderTableCell::collectBorderStyles(CollapsedBorderStyles& borderStyles) const
893 {
894     addBorderStyle(borderStyles, collapsedStartBorder());
895     addBorderStyle(borderStyles, collapsedEndBorder());
896     addBorderStyle(borderStyles, collapsedBeforeBorder());
897     addBorderStyle(borderStyles, collapsedAfterBorder());
898 }
899
900 static int compareBorderStylesForQSort(const void* pa, const void* pb)
901 {
902     const CollapsedBorderValue* a = static_cast<const CollapsedBorderValue*>(pa);
903     const CollapsedBorderValue* b = static_cast<const CollapsedBorderValue*>(pb);
904     if (*a == *b)
905         return 0;
906     return compareBorders(*a, *b);
907 }
908
909 void RenderTableCell::sortBorderStyles(CollapsedBorderStyles& borderStyles)
910 {
911     qsort(borderStyles.data(), borderStyles.size(), sizeof(CollapsedBorderValue),
912         compareBorderStylesForQSort);
913 }
914
915 void RenderTableCell::paintCollapsedBorder(GraphicsContext* graphicsContext, const IntRect& paintRect)
916 {
917     if (!table()->currentBorderStyle() || graphicsContext->paintingDisabled())
918         return;
919     
920     CollapsedBorderValue leftVal = collapsedLeftBorder();
921     CollapsedBorderValue rightVal = collapsedRightBorder();
922     CollapsedBorderValue topVal = collapsedTopBorder();
923     CollapsedBorderValue bottomVal = collapsedBottomBorder();
924      
925     // Adjust our x/y/width/height so that we paint the collapsed borders at the correct location.
926     int topWidth = topVal.width();
927     int bottomWidth = bottomVal.width();
928     int leftWidth = leftVal.width();
929     int rightWidth = rightVal.width();
930     
931     int x = paintRect.x() - leftWidth / 2;
932     int y = paintRect.y() - topWidth / 2;
933     int w = paintRect.width() + leftWidth / 2 + (rightWidth + 1) / 2;
934     int h = paintRect.height() + topWidth / 2 + (bottomWidth + 1) / 2;
935     
936     EBorderStyle topStyle = collapsedBorderStyle(topVal.style());
937     EBorderStyle bottomStyle = collapsedBorderStyle(bottomVal.style());
938     EBorderStyle leftStyle = collapsedBorderStyle(leftVal.style());
939     EBorderStyle rightStyle = collapsedBorderStyle(rightVal.style());
940     
941     bool renderTop = topStyle > BHIDDEN && !topVal.isTransparent();
942     bool renderBottom = bottomStyle > BHIDDEN && !bottomVal.isTransparent();
943     bool renderLeft = leftStyle > BHIDDEN && !leftVal.isTransparent();
944     bool renderRight = rightStyle > BHIDDEN && !rightVal.isTransparent();
945
946     // We never paint diagonals at the joins.  We simply let the border with the highest
947     // precedence paint on top of borders with lower precedence.  
948     CollapsedBorders borders;
949     borders.addBorder(topVal, BSTop, renderTop, x, y, x + w, y + topWidth, topStyle);
950     borders.addBorder(bottomVal, BSBottom, renderBottom, x, y + h - bottomWidth, x + w, y + h, bottomStyle);
951     borders.addBorder(leftVal, BSLeft, renderLeft, x, y, x + leftWidth, y + h, leftStyle);
952     borders.addBorder(rightVal, BSRight, renderRight, x + w - rightWidth, y, x + w, y + h, rightStyle);
953
954     const AffineTransform& currentCTM = graphicsContext->getCTM();
955     bool antialias = !currentCTM.isIdentityOrTranslationOrFlipped();
956     
957     for (CollapsedBorder* border = borders.nextBorder(); border; border = borders.nextBorder()) {
958         if (border->borderValue == *table()->currentBorderStyle())
959             drawLineForBoxSide(graphicsContext, border->x1, border->y1, border->x2, border->y2, border->side, 
960                                border->borderValue.color(), border->style, 0, 0, antialias);
961     }
962 }
963
964 void RenderTableCell::paintBackgroundsBehindCell(PaintInfo& paintInfo, const IntPoint& paintOffset, RenderObject* backgroundObject)
965 {
966     if (!paintInfo.shouldPaintWithinRoot(this))
967         return;
968
969     if (!backgroundObject)
970         return;
971
972     if (style()->visibility() != VISIBLE)
973         return;
974
975     RenderTable* tableElt = table();
976     if (!tableElt->collapseBorders() && style()->emptyCells() == HIDE && !firstChild())
977         return;
978
979     IntPoint adjustedPaintOffset = paintOffset;
980     if (backgroundObject != this)
981         adjustedPaintOffset.move(location());
982
983     Color c = backgroundObject->style()->visitedDependentColor(CSSPropertyBackgroundColor);
984     const FillLayer* bgLayer = backgroundObject->style()->backgroundLayers();
985
986     if (bgLayer->hasImage() || c.isValid()) {
987         // We have to clip here because the background would paint
988         // on top of the borders otherwise.  This only matters for cells and rows.
989         bool shouldClip = backgroundObject->hasLayer() && (backgroundObject == this || backgroundObject == parent()) && tableElt->collapseBorders();
990         GraphicsContextStateSaver stateSaver(*paintInfo.context, shouldClip);
991         if (shouldClip) {
992             IntRect clipRect(adjustedPaintOffset.x() + borderLeft(), adjustedPaintOffset.y() + borderTop(),
993                 width() - borderLeft() - borderRight(), height() - borderTop() - borderBottom());
994             paintInfo.context->clip(clipRect);
995         }
996         paintFillLayers(paintInfo, c, bgLayer, IntRect(adjustedPaintOffset, size()), BackgroundBleedNone, CompositeSourceOver, backgroundObject);
997     }
998 }
999
1000 void RenderTableCell::paintBoxDecorations(PaintInfo& paintInfo, const IntPoint& paintOffset)
1001 {
1002     if (!paintInfo.shouldPaintWithinRoot(this))
1003         return;
1004
1005     RenderTable* tableElt = table();
1006     if (!tableElt->collapseBorders() && style()->emptyCells() == HIDE && !firstChild())
1007         return;
1008
1009     IntRect paintRect = IntRect(paintOffset, size());
1010     paintBoxShadow(paintInfo.context, paintRect, style(), Normal);
1011     
1012     // Paint our cell background.
1013     paintBackgroundsBehindCell(paintInfo, paintOffset, this);
1014
1015     paintBoxShadow(paintInfo.context, paintRect, style(), Inset);
1016
1017     if (!style()->hasBorder() || tableElt->collapseBorders())
1018         return;
1019
1020     paintBorder(paintInfo.context, paintRect, style());
1021 }
1022
1023 void RenderTableCell::paintMask(PaintInfo& paintInfo, const IntPoint& paintOffset)
1024 {
1025     if (style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
1026         return;
1027
1028     RenderTable* tableElt = table();
1029     if (!tableElt->collapseBorders() && style()->emptyCells() == HIDE && !firstChild())
1030         return;
1031    
1032     paintMaskImages(paintInfo, IntRect(paintOffset, size()));
1033 }
1034
1035 void RenderTableCell::scrollbarsChanged(bool horizontalScrollbarChanged, bool verticalScrollbarChanged)
1036 {
1037     int scrollbarHeight = scrollbarLogicalHeight();
1038     if (!scrollbarHeight)
1039         return; // Not sure if we should be doing something when a scrollbar goes away or not.
1040     
1041     // We only care if the scrollbar that affects our intrinsic padding has been added.
1042     if ((isHorizontalWritingMode() && !horizontalScrollbarChanged) ||
1043         (!isHorizontalWritingMode() && !verticalScrollbarChanged))
1044         return;
1045
1046     // Shrink our intrinsic padding as much as possible to accommodate the scrollbar.
1047     if (style()->verticalAlign() == MIDDLE) {
1048         int totalHeight = logicalHeight();
1049         int heightWithoutIntrinsicPadding = totalHeight - intrinsicPaddingBefore() - intrinsicPaddingAfter();
1050         totalHeight -= scrollbarHeight;
1051         int newBeforePadding = (totalHeight - heightWithoutIntrinsicPadding) / 2;
1052         int newAfterPadding = totalHeight - heightWithoutIntrinsicPadding - newBeforePadding;
1053         setIntrinsicPaddingBefore(newBeforePadding);
1054         setIntrinsicPaddingAfter(newAfterPadding);
1055     } else
1056         setIntrinsicPaddingAfter(intrinsicPaddingAfter() - scrollbarHeight);
1057 }
1058
1059 } // namespace WebCore