WebCore/rendering/RenderTableCell.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     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 "FloatQuad.h"
       
    29 #include "GraphicsContext.h"
       
    30 #include "HTMLNames.h"
       
    31 #include "HTMLTableCellElement.h"
       
    32 #include "RenderTableCol.h"
       
    33 #include "RenderView.h"
       
    34 #include "TransformState.h"
       
    35 
       
    36 using namespace std;
       
    37 
       
    38 namespace WebCore {
       
    39 
       
    40 using namespace HTMLNames;
       
    41 
       
    42 RenderTableCell::RenderTableCell(Node* node)
       
    43     : RenderBlock(node)
       
    44     , m_row(-1)
       
    45     , m_column(-1)
       
    46     , m_rowSpan(1)
       
    47     , m_columnSpan(1)
       
    48     , m_intrinsicPaddingTop(0)
       
    49     , m_intrinsicPaddingBottom(0)
       
    50     , m_percentageHeight(0)
       
    51 {
       
    52     updateFromElement();
       
    53 }
       
    54 
       
    55 void RenderTableCell::destroy()
       
    56 {
       
    57     RenderTableSection* recalcSection = parent() ? section() : 0;
       
    58 
       
    59     RenderBlock::destroy();
       
    60 
       
    61     if (recalcSection)
       
    62         recalcSection->setNeedsCellRecalc();
       
    63 }
       
    64 
       
    65 void RenderTableCell::updateFromElement()
       
    66 {
       
    67     Node* n = node();
       
    68     if (n && (n->hasTagName(tdTag) || n->hasTagName(thTag))) {
       
    69         HTMLTableCellElement* tc = static_cast<HTMLTableCellElement*>(n);
       
    70         int oldRSpan = m_rowSpan;
       
    71         int oldCSpan = m_columnSpan;
       
    72 
       
    73         m_columnSpan = tc->colSpan();
       
    74         m_rowSpan = tc->rowSpan();
       
    75         if ((oldRSpan != m_rowSpan || oldCSpan != m_columnSpan) && style() && parent()) {
       
    76             setNeedsLayoutAndPrefWidthsRecalc();
       
    77             if (section())
       
    78                 section()->setNeedsCellRecalc();
       
    79         }
       
    80     }
       
    81 }
       
    82 
       
    83 Length RenderTableCell::styleOrColWidth() const
       
    84 {
       
    85     Length w = style()->width();
       
    86     if (!w.isAuto())
       
    87         return w;
       
    88 
       
    89     RenderTableCol* tableCol = table()->colElement(col());
       
    90 
       
    91     if (tableCol) {
       
    92         int colSpanCount = colSpan();
       
    93 
       
    94         Length colWidthSum = Length(0, Fixed);
       
    95         for (int i = 1; i <= colSpanCount; i++) {
       
    96             Length colWidth = tableCol->style()->width();
       
    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() - borderAndPaddingWidth()), Fixed);
       
   119         return colWidthSum;
       
   120     }
       
   121 
       
   122     return w;
       
   123 }
       
   124 
       
   125 void RenderTableCell::calcPrefWidths()
       
   126 {
       
   127     // The child cells rely on the grids up in the sections to do their calcPrefWidths 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::calcPrefWidths();
       
   133     if (node() && style()->autoWrap()) {
       
   134         // See if nowrap was set.
       
   135         Length w = styleOrColWidth();
       
   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_minPrefWidth = max(w.value(), m_minPrefWidth);
       
   144     }
       
   145 }
       
   146 
       
   147 void RenderTableCell::calcWidth()
       
   148 {
       
   149 }
       
   150 
       
   151 void RenderTableCell::updateWidth(int w)
       
   152 {
       
   153     if (w != width()) {
       
   154         setWidth(w);
       
   155         setCellWidthChanged(true);
       
   156     }
       
   157 }
       
   158 
       
   159 void RenderTableCell::layout()
       
   160 {
       
   161     layoutBlock(cellWidthChanged());
       
   162     setCellWidthChanged(false);
       
   163 }
       
   164 
       
   165 int RenderTableCell::paddingTop(bool includeIntrinsicPadding) const
       
   166 {
       
   167     return RenderBlock::paddingTop() + (includeIntrinsicPadding ? intrinsicPaddingTop() : 0);
       
   168 }
       
   169 
       
   170 int RenderTableCell::paddingBottom(bool includeIntrinsicPadding) const
       
   171 {
       
   172     return RenderBlock::paddingBottom() + (includeIntrinsicPadding ? intrinsicPaddingBottom() : 0);
       
   173 }
       
   174 
       
   175 void RenderTableCell::setOverrideSize(int size)
       
   176 {
       
   177     clearIntrinsicPadding();
       
   178     RenderBlock::setOverrideSize(size);
       
   179 }
       
   180 
       
   181 IntSize RenderTableCell::offsetFromContainer(RenderObject* o, const IntPoint& point) const
       
   182 {
       
   183     ASSERT(o == container());
       
   184 
       
   185     IntSize offset = RenderBlock::offsetFromContainer(o, point);
       
   186     if (parent())
       
   187         offset.expand(-parentBox()->x(), -parentBox()->y());
       
   188 
       
   189     return offset;
       
   190 }
       
   191 
       
   192 IntRect RenderTableCell::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
       
   193 {
       
   194     // If the table grid is dirty, we cannot get reliable information about adjoining cells,
       
   195     // so we ignore outside borders. This should not be a problem because it means that
       
   196     // the table is going to recalculate the grid, relayout and repaint its current rect, which
       
   197     // includes any outside borders of this cell.
       
   198     if (!table()->collapseBorders() || table()->needsSectionRecalc())
       
   199         return RenderBlock::clippedOverflowRectForRepaint(repaintContainer);
       
   200 
       
   201     bool rtl = table()->style()->direction() == RTL;
       
   202     int outlineSize = style()->outlineSize();
       
   203     int left = max(borderHalfLeft(true), outlineSize);
       
   204     int right = max(borderHalfRight(true), outlineSize);
       
   205     int top = max(borderHalfTop(true), outlineSize);
       
   206     int bottom = max(borderHalfBottom(true), outlineSize);
       
   207     if ((left && !rtl) || (right && rtl)) {
       
   208         if (RenderTableCell* before = table()->cellBefore(this)) {
       
   209             top = max(top, before->borderHalfTop(true));
       
   210             bottom = max(bottom, before->borderHalfBottom(true));
       
   211         }
       
   212     }
       
   213     if ((left && rtl) || (right && !rtl)) {
       
   214         if (RenderTableCell* after = table()->cellAfter(this)) {
       
   215             top = max(top, after->borderHalfTop(true));
       
   216             bottom = max(bottom, after->borderHalfBottom(true));
       
   217         }
       
   218     }
       
   219     if (top) {
       
   220         if (RenderTableCell* above = table()->cellAbove(this)) {
       
   221             left = max(left, above->borderHalfLeft(true));
       
   222             right = max(right, above->borderHalfRight(true));
       
   223         }
       
   224     }
       
   225     if (bottom) {
       
   226         if (RenderTableCell* below = table()->cellBelow(this)) {
       
   227             left = max(left, below->borderHalfLeft(true));
       
   228             right = max(right, below->borderHalfRight(true));
       
   229         }
       
   230     }
       
   231     left = max(left, -leftVisibleOverflow());
       
   232     top = max(top, -topVisibleOverflow());
       
   233     IntRect r(-left, - top, left + max(width() + right, rightVisibleOverflow()), top + max(height() + bottom, bottomVisibleOverflow()));
       
   234 
       
   235     if (RenderView* v = view()) {
       
   236         // FIXME: layoutDelta needs to be applied in parts before/after transforms and
       
   237         // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
       
   238         r.move(v->layoutDelta());
       
   239     }
       
   240     computeRectForRepaint(repaintContainer, r);
       
   241     return r;
       
   242 }
       
   243 
       
   244 void RenderTableCell::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& r, bool fixed)
       
   245 {
       
   246     if (repaintContainer == this)
       
   247         return;
       
   248     r.setY(r.y());
       
   249     RenderView* v = view();
       
   250     if ((!v || !v->layoutStateEnabled() || repaintContainer) && parent())
       
   251         r.move(-parentBox()->x(), -parentBox()->y()); // Rows are in the same coordinate space, so don't add their offset in.
       
   252     RenderBlock::computeRectForRepaint(repaintContainer, r, fixed);
       
   253 }
       
   254 
       
   255 int RenderTableCell::baselinePosition(bool firstLine, bool isRootLineBox) const
       
   256 {
       
   257     if (isRootLineBox)
       
   258         return RenderBox::baselinePosition(firstLine, isRootLineBox);
       
   259 
       
   260     // <http://www.w3.org/TR/2007/CR-CSS21-20070719/tables.html#height-layout>: The baseline of a cell is the baseline of
       
   261     // the first in-flow line box in the cell, or the first in-flow table-row in the cell, whichever comes first. If there
       
   262     // is no such line box or table-row, the baseline is the bottom of content edge of the cell box.
       
   263     int firstLineBaseline = firstLineBoxBaseline();
       
   264     if (firstLineBaseline != -1)
       
   265         return firstLineBaseline;
       
   266     return paddingTop() + borderTop() + contentHeight();
       
   267 }
       
   268 
       
   269 void RenderTableCell::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
       
   270 {
       
   271     if (parent() && section() && style() && style()->height() != newStyle->height())
       
   272         section()->setNeedsCellRecalc();
       
   273 
       
   274     ASSERT(newStyle->display() == TABLE_CELL);
       
   275 
       
   276     RenderBlock::styleWillChange(diff, newStyle);
       
   277 }
       
   278 
       
   279 void RenderTableCell::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
       
   280 {
       
   281     RenderBlock::styleDidChange(diff, oldStyle);
       
   282     setHasBoxDecorations(true);
       
   283 }
       
   284 
       
   285 // The following rules apply for resolving conflicts and figuring out which border
       
   286 // to use.
       
   287 // (1) Borders with the 'border-style' of 'hidden' take precedence over all other conflicting 
       
   288 // borders. Any border with this value suppresses all borders at this location.
       
   289 // (2) Borders with a style of 'none' have the lowest priority. Only if the border properties of all 
       
   290 // the elements meeting at this edge are 'none' will the border be omitted (but note that 'none' is 
       
   291 // the default value for the border style.)
       
   292 // (3) If none of the styles are 'hidden' and at least one of them is not 'none', then narrow borders 
       
   293 // are discarded in favor of wider ones. If several have the same 'border-width' then styles are preferred 
       
   294 // in this order: 'double', 'solid', 'dashed', 'dotted', 'ridge', 'outset', 'groove', and the lowest: 'inset'.
       
   295 // (4) If border styles differ only in color, then a style set on a cell wins over one on a row, 
       
   296 // which wins over a row group, column, column group and, lastly, table. It is undefined which color 
       
   297 // is used when two elements of the same type disagree.
       
   298 static CollapsedBorderValue compareBorders(const CollapsedBorderValue& border1, const CollapsedBorderValue& border2)
       
   299 {
       
   300     // Sanity check the values passed in.  If either is null, return the other.
       
   301     if (!border2.exists())
       
   302         return border1;
       
   303     if (!border1.exists())
       
   304         return border2;
       
   305 
       
   306     // Rule #1 above.
       
   307     if (border1.style() == BHIDDEN || border2.style() == BHIDDEN)
       
   308         return CollapsedBorderValue(); // No border should exist at this location.
       
   309     
       
   310     // Rule #2 above.  A style of 'none' has lowest priority and always loses to any other border.
       
   311     if (border2.style() == BNONE)
       
   312         return border1;
       
   313     if (border1.style() == BNONE)
       
   314         return border2;
       
   315 
       
   316     // The first part of rule #3 above. Wider borders win.
       
   317     if (border1.width() != border2.width())
       
   318         return border1.width() > border2.width() ? border1 : border2;
       
   319     
       
   320     // The borders have equal width.  Sort by border style.
       
   321     if (border1.style() != border2.style())
       
   322         return border1.style() > border2.style() ? border1 : border2;
       
   323     
       
   324     // The border have the same width and style.  Rely on precedence (cell over row over row group, etc.)
       
   325     return border1.precedence() >= border2.precedence() ? border1 : border2;
       
   326 }
       
   327 
       
   328 CollapsedBorderValue RenderTableCell::collapsedLeftBorder(bool rtl) const
       
   329 {
       
   330     RenderTable* tableElt = table();
       
   331     bool leftmostColumn;
       
   332     if (!rtl)
       
   333         leftmostColumn = col() == 0;
       
   334     else {
       
   335         int effCol = tableElt->colToEffCol(col() + colSpan() - 1);
       
   336         leftmostColumn = effCol == tableElt->numEffCols() - 1;
       
   337     }
       
   338     
       
   339     // For border left, we need to check, in order of precedence:
       
   340     // (1) Our left border.
       
   341     int left = CSSPropertyBorderLeftColor;
       
   342     int right = CSSPropertyBorderRightColor;
       
   343     CollapsedBorderValue result(&style()->borderLeft(), style()->visitedDependentColor(left), BCELL);
       
   344     
       
   345     // (2) The right border of the cell to the left.
       
   346     RenderTableCell* prevCell = rtl ? tableElt->cellAfter(this) : tableElt->cellBefore(this);
       
   347     if (prevCell) {
       
   348         CollapsedBorderValue prevCellBorder = CollapsedBorderValue(&prevCell->style()->borderRight(), prevCell->style()->visitedDependentColor(right), BCELL);
       
   349         result = rtl ? compareBorders(result, prevCellBorder) : compareBorders(prevCellBorder, result);
       
   350         if (!result.exists())
       
   351             return result;
       
   352     } else if (leftmostColumn) {
       
   353         // (3) Our row's left border.
       
   354         result = compareBorders(result, CollapsedBorderValue(&parent()->style()->borderLeft(), parent()->style()->visitedDependentColor(left), BROW));
       
   355         if (!result.exists())
       
   356             return result;
       
   357         
       
   358         // (4) Our row group's left border.
       
   359         result = compareBorders(result, CollapsedBorderValue(&section()->style()->borderLeft(), section()->style()->visitedDependentColor(left), BROWGROUP));
       
   360         if (!result.exists())
       
   361             return result;
       
   362     }
       
   363     
       
   364     // (5) Our column and column group's left borders.
       
   365     bool startColEdge;
       
   366     bool endColEdge;
       
   367     RenderTableCol* colElt = tableElt->colElement(col() + (rtl ? colSpan() - 1 : 0), &startColEdge, &endColEdge);
       
   368     if (colElt && (!rtl ? startColEdge : endColEdge)) {
       
   369         result = compareBorders(result, CollapsedBorderValue(&colElt->style()->borderLeft(), colElt->style()->visitedDependentColor(left), BCOL));
       
   370         if (!result.exists())
       
   371             return result;
       
   372         if (colElt->parent()->isTableCol() && (!rtl ? !colElt->previousSibling() : !colElt->nextSibling())) {
       
   373             result = compareBorders(result, CollapsedBorderValue(&colElt->parent()->style()->borderLeft(), colElt->parent()->style()->visitedDependentColor(left), BCOLGROUP));
       
   374             if (!result.exists())
       
   375                 return result;
       
   376         }
       
   377     }
       
   378     
       
   379     // (6) The right border of the column to the left.
       
   380     if (!leftmostColumn) {
       
   381         colElt = tableElt->colElement(col() + (rtl ? colSpan() : -1), &startColEdge, &endColEdge);
       
   382         if (colElt && (!rtl ? endColEdge : startColEdge)) {
       
   383             CollapsedBorderValue rightBorder = CollapsedBorderValue(&colElt->style()->borderRight(), colElt->style()->visitedDependentColor(right), BCOL);
       
   384             result = rtl ? compareBorders(result, rightBorder) : compareBorders(rightBorder, result);
       
   385             if (!result.exists())
       
   386                 return result;
       
   387         }
       
   388     } else {
       
   389         // (7) The table's left border.
       
   390         result = compareBorders(result, CollapsedBorderValue(&tableElt->style()->borderLeft(), tableElt->style()->visitedDependentColor(left), BTABLE));
       
   391         if (!result.exists())
       
   392             return result;
       
   393     }
       
   394     
       
   395     return result;
       
   396 }
       
   397 
       
   398 CollapsedBorderValue RenderTableCell::collapsedRightBorder(bool rtl) const
       
   399 {
       
   400     RenderTable* tableElt = table();
       
   401     bool rightmostColumn;
       
   402     if (rtl)
       
   403         rightmostColumn = col() == 0;
       
   404     else {
       
   405         int effCol = tableElt->colToEffCol(col() + colSpan() - 1);
       
   406         rightmostColumn = effCol == tableElt->numEffCols() - 1;
       
   407     }
       
   408     
       
   409     // For border right, we need to check, in order of precedence:
       
   410     // (1) Our right border.
       
   411     int left = CSSPropertyBorderLeftColor;
       
   412     int right = CSSPropertyBorderRightColor;
       
   413     CollapsedBorderValue result = CollapsedBorderValue(&style()->borderRight(), style()->visitedDependentColor(right), BCELL);
       
   414     
       
   415     // (2) The left border of the cell to the right.
       
   416     if (!rightmostColumn) {
       
   417         RenderTableCell* nextCell = rtl ? tableElt->cellBefore(this) : tableElt->cellAfter(this);
       
   418         if (nextCell && nextCell->style()) {
       
   419             CollapsedBorderValue leftBorder = CollapsedBorderValue(&nextCell->style()->borderLeft(), nextCell->style()->visitedDependentColor(left), BCELL);
       
   420             result = rtl ? compareBorders(leftBorder, result) : compareBorders(result, leftBorder);
       
   421             if (!result.exists())
       
   422                 return result;
       
   423         }
       
   424     } else {
       
   425         // (3) Our row's right border.
       
   426         result = compareBorders(result, CollapsedBorderValue(&parent()->style()->borderRight(), parent()->style()->visitedDependentColor(right), BROW));
       
   427         if (!result.exists())
       
   428             return result;
       
   429         
       
   430         // (4) Our row group's right border.
       
   431         result = compareBorders(result, CollapsedBorderValue(&section()->style()->borderRight(), section()->style()->visitedDependentColor(right), BROWGROUP));
       
   432         if (!result.exists())
       
   433             return result;
       
   434     }
       
   435     
       
   436     // (5) Our column and column group's right borders.
       
   437     bool startColEdge;
       
   438     bool endColEdge;
       
   439     RenderTableCol* colElt = tableElt->colElement(col() + (rtl ? 0 : colSpan() - 1), &startColEdge, &endColEdge);
       
   440     if (colElt && (!rtl ? endColEdge : startColEdge)) {
       
   441         result = compareBorders(result, CollapsedBorderValue(&colElt->style()->borderRight(), colElt->style()->visitedDependentColor(right), BCOL));
       
   442         if (!result.exists())
       
   443             return result;
       
   444         if (colElt->parent()->isTableCol() && (!rtl ? !colElt->nextSibling() : !colElt->previousSibling())) {
       
   445             result = compareBorders(result, CollapsedBorderValue(&colElt->parent()->style()->borderRight(), colElt->parent()->style()->visitedDependentColor(right), BCOLGROUP));
       
   446             if (!result.exists())
       
   447                 return result;
       
   448         }
       
   449     }
       
   450     
       
   451     // (6) The left border of the column to the right.
       
   452     if (!rightmostColumn) {
       
   453         colElt = tableElt->colElement(col() + (rtl ? -1 : colSpan()), &startColEdge, &endColEdge);
       
   454         if (colElt && (!rtl ? startColEdge : endColEdge)) {
       
   455             CollapsedBorderValue leftBorder = CollapsedBorderValue(&colElt->style()->borderLeft(), colElt->style()->visitedDependentColor(left), BCOL);
       
   456             result = rtl ? compareBorders(leftBorder, result) : compareBorders(result, leftBorder);
       
   457             if (!result.exists())
       
   458                 return result;
       
   459         }
       
   460     } else {
       
   461         // (7) The table's right border.
       
   462         result = compareBorders(result, CollapsedBorderValue(&tableElt->style()->borderRight(), tableElt->style()->visitedDependentColor(right), BTABLE));
       
   463         if (!result.exists())
       
   464             return result;
       
   465     }
       
   466     
       
   467     return result;
       
   468 }
       
   469 
       
   470 CollapsedBorderValue RenderTableCell::collapsedTopBorder() const
       
   471 {
       
   472     // For border top, we need to check, in order of precedence:
       
   473     // (1) Our top border.
       
   474     int top = CSSPropertyBorderTopColor;
       
   475     int bottom = CSSPropertyBorderBottomColor;
       
   476     CollapsedBorderValue result = CollapsedBorderValue(&style()->borderTop(), style()->visitedDependentColor(top), BCELL);
       
   477     
       
   478     RenderTableCell* prevCell = table()->cellAbove(this);
       
   479     if (prevCell) {
       
   480         // (2) A previous cell's bottom border.
       
   481         result = compareBorders(CollapsedBorderValue(&prevCell->style()->borderBottom(), prevCell->style()->visitedDependentColor(bottom), BCELL), result);
       
   482         if (!result.exists()) 
       
   483             return result;
       
   484     }
       
   485     
       
   486     // (3) Our row's top border.
       
   487     result = compareBorders(result, CollapsedBorderValue(&parent()->style()->borderTop(), parent()->style()->visitedDependentColor(top), BROW));
       
   488     if (!result.exists())
       
   489         return result;
       
   490     
       
   491     // (4) The previous row's bottom border.
       
   492     if (prevCell) {
       
   493         RenderObject* prevRow = 0;
       
   494         if (prevCell->section() == section())
       
   495             prevRow = parent()->previousSibling();
       
   496         else
       
   497             prevRow = prevCell->section()->lastChild();
       
   498     
       
   499         if (prevRow) {
       
   500             result = compareBorders(CollapsedBorderValue(&prevRow->style()->borderBottom(), prevRow->style()->visitedDependentColor(bottom), BROW), result);
       
   501             if (!result.exists())
       
   502                 return result;
       
   503         }
       
   504     }
       
   505     
       
   506     // Now check row groups.
       
   507     RenderTableSection* currSection = section();
       
   508     if (!row()) {
       
   509         // (5) Our row group's top border.
       
   510         result = compareBorders(result, CollapsedBorderValue(&currSection->style()->borderTop(), currSection->style()->visitedDependentColor(top), BROWGROUP));
       
   511         if (!result.exists())
       
   512             return result;
       
   513         
       
   514         // (6) Previous row group's bottom border.
       
   515         currSection = table()->sectionAbove(currSection);
       
   516         if (currSection) {
       
   517             result = compareBorders(CollapsedBorderValue(&currSection->style()->borderBottom(), currSection->style()->visitedDependentColor(bottom), BROWGROUP), result);
       
   518             if (!result.exists())
       
   519                 return result;
       
   520         }
       
   521     }
       
   522     
       
   523     if (!currSection) {
       
   524         // (8) Our column and column group's top borders.
       
   525         RenderTableCol* colElt = table()->colElement(col());
       
   526         if (colElt) {
       
   527             result = compareBorders(result, CollapsedBorderValue(&colElt->style()->borderTop(), colElt->style()->visitedDependentColor(top), BCOL));
       
   528             if (!result.exists())
       
   529                 return result;
       
   530             if (colElt->parent()->isTableCol()) {
       
   531                 result = compareBorders(result, CollapsedBorderValue(&colElt->parent()->style()->borderTop(), colElt->parent()->style()->visitedDependentColor(top), BCOLGROUP));
       
   532                 if (!result.exists())
       
   533                     return result;
       
   534             }
       
   535         }
       
   536         
       
   537         // (9) The table's top border.
       
   538         RenderTable* enclosingTable = table();
       
   539         result = compareBorders(result, CollapsedBorderValue(&enclosingTable->style()->borderTop(), enclosingTable->style()->visitedDependentColor(top), BTABLE));
       
   540         if (!result.exists())
       
   541             return result;
       
   542     }
       
   543     
       
   544     return result;
       
   545 }
       
   546 
       
   547 CollapsedBorderValue RenderTableCell::collapsedBottomBorder() const
       
   548 {
       
   549     // For border top, we need to check, in order of precedence:
       
   550     // (1) Our bottom border.
       
   551     int top = CSSPropertyBorderTopColor;
       
   552     int bottom = CSSPropertyBorderBottomColor;
       
   553     CollapsedBorderValue result = CollapsedBorderValue(&style()->borderBottom(), style()->visitedDependentColor(bottom), BCELL);
       
   554     
       
   555     RenderTableCell* nextCell = table()->cellBelow(this);
       
   556     if (nextCell) {
       
   557         // (2) A following cell's top border.
       
   558         result = compareBorders(result, CollapsedBorderValue(&nextCell->style()->borderTop(), nextCell->style()->visitedDependentColor(top), BCELL));
       
   559         if (!result.exists())
       
   560             return result;
       
   561     }
       
   562     
       
   563     // (3) Our row's bottom border. (FIXME: Deal with rowspan!)
       
   564     result = compareBorders(result, CollapsedBorderValue(&parent()->style()->borderBottom(), parent()->style()->visitedDependentColor(bottom), BROW));
       
   565     if (!result.exists())
       
   566         return result;
       
   567     
       
   568     // (4) The next row's top border.
       
   569     if (nextCell) {
       
   570         result = compareBorders(result, CollapsedBorderValue(&nextCell->parent()->style()->borderTop(), nextCell->parent()->style()->visitedDependentColor(top), BROW));
       
   571         if (!result.exists())
       
   572             return result;
       
   573     }
       
   574     
       
   575     // Now check row groups.
       
   576     RenderTableSection* currSection = section();
       
   577     if (row() + rowSpan() >= currSection->numRows()) {
       
   578         // (5) Our row group's bottom border.
       
   579         result = compareBorders(result, CollapsedBorderValue(&currSection->style()->borderBottom(), currSection->style()->visitedDependentColor(bottom), BROWGROUP));
       
   580         if (!result.exists())
       
   581             return result;
       
   582         
       
   583         // (6) Following row group's top border.
       
   584         currSection = table()->sectionBelow(currSection);
       
   585         if (currSection) {
       
   586             result = compareBorders(result, CollapsedBorderValue(&currSection->style()->borderTop(), currSection->style()->visitedDependentColor(top), BROWGROUP));
       
   587             if (!result.exists())
       
   588                 return result;
       
   589         }
       
   590     }
       
   591     
       
   592     if (!currSection) {
       
   593         // (8) Our column and column group's bottom borders.
       
   594         RenderTableCol* colElt = table()->colElement(col());
       
   595         if (colElt) {
       
   596             result = compareBorders(result, CollapsedBorderValue(&colElt->style()->borderBottom(), colElt->style()->visitedDependentColor(bottom), BCOL));
       
   597             if (!result.exists()) return result;
       
   598             if (colElt->parent()->isTableCol()) {
       
   599                 result = compareBorders(result, CollapsedBorderValue(&colElt->parent()->style()->borderBottom(), colElt->parent()->style()->visitedDependentColor(bottom), BCOLGROUP));
       
   600                 if (!result.exists())
       
   601                     return result;
       
   602             }
       
   603         }
       
   604         
       
   605         // (9) The table's bottom border.
       
   606         RenderTable* enclosingTable = table();
       
   607         result = compareBorders(result, CollapsedBorderValue(&enclosingTable->style()->borderBottom(), enclosingTable->style()->visitedDependentColor(bottom), BTABLE));
       
   608         if (!result.exists())
       
   609             return result;
       
   610     }
       
   611     
       
   612     return result;    
       
   613 }
       
   614 
       
   615 int RenderTableCell::borderLeft() const
       
   616 {
       
   617     return table()->collapseBorders() ? borderHalfLeft(false) : RenderBlock::borderLeft();
       
   618 }
       
   619 
       
   620 int RenderTableCell::borderRight() const
       
   621 {
       
   622     return table()->collapseBorders() ? borderHalfRight(false) : RenderBlock::borderRight();
       
   623 }
       
   624 
       
   625 int RenderTableCell::borderTop() const
       
   626 {
       
   627     return table()->collapseBorders() ? borderHalfTop(false) : RenderBlock::borderTop();
       
   628 }
       
   629 
       
   630 int RenderTableCell::borderBottom() const
       
   631 {
       
   632     return table()->collapseBorders() ? borderHalfBottom(false) : RenderBlock::borderBottom();
       
   633 }
       
   634 
       
   635 int RenderTableCell::borderHalfLeft(bool outer) const
       
   636 {
       
   637     CollapsedBorderValue border = collapsedLeftBorder(table()->style()->direction() == RTL);
       
   638     if (border.exists())
       
   639         return (border.width() + (outer ? 0 : 1)) / 2; // Give the extra pixel to top and left.
       
   640     return 0;
       
   641 }
       
   642     
       
   643 int RenderTableCell::borderHalfRight(bool outer) const
       
   644 {
       
   645     CollapsedBorderValue border = collapsedRightBorder(table()->style()->direction() == RTL);
       
   646     if (border.exists())
       
   647         return (border.width() + (outer ? 1 : 0)) / 2;
       
   648     return 0;
       
   649 }
       
   650 
       
   651 int RenderTableCell::borderHalfTop(bool outer) const
       
   652 {
       
   653     CollapsedBorderValue border = collapsedTopBorder();
       
   654     if (border.exists())
       
   655         return (border.width() + (outer ? 0 : 1)) / 2; // Give the extra pixel to top and left.
       
   656     return 0;
       
   657 }
       
   658 
       
   659 int RenderTableCell::borderHalfBottom(bool outer) const
       
   660 {
       
   661     CollapsedBorderValue border = collapsedBottomBorder();
       
   662     if (border.exists())
       
   663         return (border.width() + (outer ? 1 : 0)) / 2;
       
   664     return 0;
       
   665 }
       
   666 
       
   667 void RenderTableCell::paint(PaintInfo& paintInfo, int tx, int ty)
       
   668 {
       
   669     if (paintInfo.phase == PaintPhaseCollapsedTableBorders && style()->visibility() == VISIBLE) {
       
   670         if (!paintInfo.shouldPaintWithinRoot(this))
       
   671             return;
       
   672 
       
   673         tx += x();
       
   674         ty += y();
       
   675         int os = 2 * maximalOutlineSize(paintInfo.phase);
       
   676         if (ty - table()->outerBorderTop() < paintInfo.rect.bottom() + os &&
       
   677             ty + height() + table()->outerBorderBottom() > paintInfo.rect.y() - os)
       
   678             paintCollapsedBorder(paintInfo.context, tx, ty, width(), height());
       
   679         return;
       
   680     } 
       
   681     
       
   682     RenderBlock::paint(paintInfo, tx, ty);
       
   683 }
       
   684 
       
   685 static EBorderStyle collapsedBorderStyle(EBorderStyle style)
       
   686 {
       
   687     if (style == OUTSET)
       
   688         return GROOVE;
       
   689     if (style == INSET)
       
   690         return RIDGE;
       
   691     return style;
       
   692 }
       
   693 
       
   694 struct CollapsedBorder {
       
   695     CollapsedBorderValue borderValue;
       
   696     BoxSide side;
       
   697     bool shouldPaint;
       
   698     int x1;
       
   699     int y1;
       
   700     int x2;
       
   701     int y2;
       
   702     EBorderStyle style;
       
   703 };
       
   704 
       
   705 class CollapsedBorders {
       
   706 public:
       
   707     CollapsedBorders()
       
   708         : m_count(0)
       
   709     {
       
   710     }
       
   711     
       
   712     void addBorder(const CollapsedBorderValue& borderValue, BoxSide borderSide, bool shouldPaint,
       
   713                    int x1, int y1, int x2, int y2, EBorderStyle borderStyle)
       
   714     {
       
   715         if (borderValue.exists() && shouldPaint) {
       
   716             m_borders[m_count].borderValue = borderValue;
       
   717             m_borders[m_count].side = borderSide;
       
   718             m_borders[m_count].shouldPaint = shouldPaint;
       
   719             m_borders[m_count].x1 = x1;
       
   720             m_borders[m_count].x2 = x2;
       
   721             m_borders[m_count].y1 = y1;
       
   722             m_borders[m_count].y2 = y2;
       
   723             m_borders[m_count].style = borderStyle;
       
   724             m_count++;
       
   725         }
       
   726     }
       
   727 
       
   728     CollapsedBorder* nextBorder()
       
   729     {
       
   730         for (int i = 0; i < m_count; i++) {
       
   731             if (m_borders[i].borderValue.exists() && m_borders[i].shouldPaint) {
       
   732                 m_borders[i].shouldPaint = false;
       
   733                 return &m_borders[i];
       
   734             }
       
   735         }
       
   736         
       
   737         return 0;
       
   738     }
       
   739     
       
   740     CollapsedBorder m_borders[4];
       
   741     int m_count;
       
   742 };
       
   743 
       
   744 static void addBorderStyle(RenderTableCell::CollapsedBorderStyles& borderStyles, CollapsedBorderValue borderValue)
       
   745 {
       
   746     if (!borderValue.exists())
       
   747         return;
       
   748     size_t count = borderStyles.size();
       
   749     for (size_t i = 0; i < count; ++i)
       
   750         if (borderStyles[i] == borderValue)
       
   751             return;
       
   752     borderStyles.append(borderValue);
       
   753 }
       
   754 
       
   755 void RenderTableCell::collectBorderStyles(CollapsedBorderStyles& borderStyles) const
       
   756 {
       
   757     bool rtl = table()->style()->direction() == RTL;
       
   758     addBorderStyle(borderStyles, collapsedLeftBorder(rtl));
       
   759     addBorderStyle(borderStyles, collapsedRightBorder(rtl));
       
   760     addBorderStyle(borderStyles, collapsedTopBorder());
       
   761     addBorderStyle(borderStyles, collapsedBottomBorder());
       
   762 }
       
   763 
       
   764 static int compareBorderStylesForQSort(const void* pa, const void* pb)
       
   765 {
       
   766     const CollapsedBorderValue* a = static_cast<const CollapsedBorderValue*>(pa);
       
   767     const CollapsedBorderValue* b = static_cast<const CollapsedBorderValue*>(pb);
       
   768     if (*a == *b)
       
   769         return 0;
       
   770     CollapsedBorderValue borderWithHigherPrecedence = compareBorders(*a, *b);
       
   771     if (*a == borderWithHigherPrecedence)
       
   772         return 1;
       
   773     return -1;
       
   774 }
       
   775 
       
   776 void RenderTableCell::sortBorderStyles(CollapsedBorderStyles& borderStyles)
       
   777 {
       
   778     qsort(borderStyles.data(), borderStyles.size(), sizeof(CollapsedBorderValue),
       
   779         compareBorderStylesForQSort);
       
   780 }
       
   781 
       
   782 void RenderTableCell::paintCollapsedBorder(GraphicsContext* graphicsContext, int tx, int ty, int w, int h)
       
   783 {
       
   784     if (!table()->currentBorderStyle())
       
   785         return;
       
   786     
       
   787     bool rtl = table()->style()->direction() == RTL;
       
   788     CollapsedBorderValue leftVal = collapsedLeftBorder(rtl);
       
   789     CollapsedBorderValue rightVal = collapsedRightBorder(rtl);
       
   790     CollapsedBorderValue topVal = collapsedTopBorder();
       
   791     CollapsedBorderValue bottomVal = collapsedBottomBorder();
       
   792      
       
   793     // Adjust our x/y/width/height so that we paint the collapsed borders at the correct location.
       
   794     int topWidth = topVal.width();
       
   795     int bottomWidth = bottomVal.width();
       
   796     int leftWidth = leftVal.width();
       
   797     int rightWidth = rightVal.width();
       
   798     
       
   799     tx -= leftWidth / 2;
       
   800     ty -= topWidth / 2;
       
   801     w += leftWidth / 2 + (rightWidth + 1) / 2;
       
   802     h += topWidth / 2 + (bottomWidth + 1) / 2;
       
   803     
       
   804     EBorderStyle topStyle = collapsedBorderStyle(topVal.style());
       
   805     EBorderStyle bottomStyle = collapsedBorderStyle(bottomVal.style());
       
   806     EBorderStyle leftStyle = collapsedBorderStyle(leftVal.style());
       
   807     EBorderStyle rightStyle = collapsedBorderStyle(rightVal.style());
       
   808     
       
   809     bool renderTop = topStyle > BHIDDEN && !topVal.isTransparent();
       
   810     bool renderBottom = bottomStyle > BHIDDEN && !bottomVal.isTransparent();
       
   811     bool renderLeft = leftStyle > BHIDDEN && !leftVal.isTransparent();
       
   812     bool renderRight = rightStyle > BHIDDEN && !rightVal.isTransparent();
       
   813 
       
   814     // We never paint diagonals at the joins.  We simply let the border with the highest
       
   815     // precedence paint on top of borders with lower precedence.  
       
   816     CollapsedBorders borders;
       
   817     borders.addBorder(topVal, BSTop, renderTop, tx, ty, tx + w, ty + topWidth, topStyle);
       
   818     borders.addBorder(bottomVal, BSBottom, renderBottom, tx, ty + h - bottomWidth, tx + w, ty + h, bottomStyle);
       
   819     borders.addBorder(leftVal, BSLeft, renderLeft, tx, ty, tx + leftWidth, ty + h, leftStyle);
       
   820     borders.addBorder(rightVal, BSRight, renderRight, tx + w - rightWidth, ty, tx + w, ty + h, rightStyle);
       
   821     
       
   822     for (CollapsedBorder* border = borders.nextBorder(); border; border = borders.nextBorder()) {
       
   823         if (border->borderValue == *table()->currentBorderStyle())
       
   824             drawLineForBoxSide(graphicsContext, border->x1, border->y1, border->x2, border->y2, border->side, 
       
   825                                border->borderValue.color(), border->style, 0, 0);
       
   826     }
       
   827 }
       
   828 
       
   829 void RenderTableCell::paintBackgroundsBehindCell(PaintInfo& paintInfo, int tx, int ty, RenderObject* backgroundObject)
       
   830 {
       
   831     if (!paintInfo.shouldPaintWithinRoot(this))
       
   832         return;
       
   833 
       
   834     if (!backgroundObject)
       
   835         return;
       
   836 
       
   837     if (style()->visibility() != VISIBLE)
       
   838         return;
       
   839 
       
   840     RenderTable* tableElt = table();
       
   841     if (!tableElt->collapseBorders() && style()->emptyCells() == HIDE && !firstChild())
       
   842         return;
       
   843 
       
   844     if (backgroundObject != this) {
       
   845         tx += x();
       
   846         ty += y();
       
   847     }
       
   848 
       
   849     int w = width();
       
   850     int h = height();
       
   851 
       
   852     Color c = backgroundObject->style()->visitedDependentColor(CSSPropertyBackgroundColor);
       
   853     const FillLayer* bgLayer = backgroundObject->style()->backgroundLayers();
       
   854 
       
   855     if (bgLayer->hasImage() || c.isValid()) {
       
   856         // We have to clip here because the background would paint
       
   857         // on top of the borders otherwise.  This only matters for cells and rows.
       
   858         bool shouldClip = backgroundObject->hasLayer() && (backgroundObject == this || backgroundObject == parent()) && tableElt->collapseBorders();
       
   859         if (shouldClip) {
       
   860             IntRect clipRect(tx + borderLeft(), ty + borderTop(),
       
   861                 w - borderLeft() - borderRight(), h - borderTop() - borderBottom());
       
   862             paintInfo.context->save();
       
   863             paintInfo.context->clip(clipRect);
       
   864         }
       
   865         paintFillLayers(paintInfo, c, bgLayer, tx, ty, w, h, CompositeSourceOver, backgroundObject);
       
   866         if (shouldClip)
       
   867             paintInfo.context->restore();
       
   868     }
       
   869 }
       
   870 
       
   871 void RenderTableCell::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
       
   872 {
       
   873     if (!paintInfo.shouldPaintWithinRoot(this))
       
   874         return;
       
   875 
       
   876     RenderTable* tableElt = table();
       
   877     if (!tableElt->collapseBorders() && style()->emptyCells() == HIDE && !firstChild())
       
   878         return;
       
   879 
       
   880     int w = width();
       
   881     int h = height();
       
   882    
       
   883     if (style()->boxShadow())
       
   884         paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Normal);
       
   885     
       
   886     // Paint our cell background.
       
   887     paintBackgroundsBehindCell(paintInfo, tx, ty, this);
       
   888     if (style()->boxShadow())
       
   889         paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Inset);
       
   890 
       
   891     if (!style()->hasBorder() || tableElt->collapseBorders())
       
   892         return;
       
   893 
       
   894     paintBorder(paintInfo.context, tx, ty, w, h, style());
       
   895 }
       
   896 
       
   897 void RenderTableCell::paintMask(PaintInfo& paintInfo, int tx, int ty)
       
   898 {
       
   899     if (style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
       
   900         return;
       
   901 
       
   902     RenderTable* tableElt = table();
       
   903     if (!tableElt->collapseBorders() && style()->emptyCells() == HIDE && !firstChild())
       
   904         return;
       
   905 
       
   906     int w = width();
       
   907     int h = height();
       
   908    
       
   909     paintMaskImages(paintInfo, tx, ty, w, h);
       
   910 }
       
   911 
       
   912 } // namespace WebCore