webengine/osswebengine/WebCore/rendering/RenderTableCell.cpp
changeset 0 dd21522fd290
equal deleted inserted replaced
-1:000000000000 0:dd21522fd290
       
     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 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 "GraphicsContext.h"
       
    29 #include "HTMLNames.h"
       
    30 #include "HTMLTableCellElement.h"
       
    31 #include "RenderTableCol.h"
       
    32 #include "RenderView.h"
       
    33 #include "TextStream.h"
       
    34 
       
    35 using namespace std;
       
    36 
       
    37 namespace WebCore {
       
    38 
       
    39 using namespace HTMLNames;
       
    40 
       
    41 RenderTableCell::RenderTableCell(Node* node)
       
    42     : RenderBlock(node)
       
    43     , m_row(-1)
       
    44     , m_column(-1)
       
    45     , m_rowSpan(1)
       
    46     , m_columnSpan(1)
       
    47     , m_topExtra(0)
       
    48     , m_bottomExtra(0)
       
    49     , m_widthChanged(false)
       
    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* node = element();
       
    68     if (node && (node->hasTagName(tdTag) || node->hasTagName(thTag))) {
       
    69         HTMLTableCellElement* tc = static_cast<HTMLTableCellElement*>(node);
       
    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 (colSpan() > 1 || !w.isAuto())
       
    87         return w;
       
    88     RenderTableCol* tableCol = table()->colElement(col());
       
    89     if (tableCol) {
       
    90         w = tableCol->style()->width();
       
    91         
       
    92         // Column widths specified on <col> apply to the border box of the cell.
       
    93         // Percentages don't need to be handled since they're always treated this way (even when specified on the cells).
       
    94         // See Bugzilla bug 8126 for details.
       
    95         if (w.isFixed() && w.value() > 0)
       
    96             w = Length(max(0, w.value() - borderLeft() - borderRight() - paddingLeft() - paddingRight()), Fixed);
       
    97     }
       
    98     return w;
       
    99 }
       
   100 
       
   101 void RenderTableCell::calcPrefWidths()
       
   102 {
       
   103     // 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
       
   104     // cells are added, but relayout can cause the cells to be freed, leaving stale pointers in the sections'
       
   105     // grids.  We must refresh those grids before the child cells try to use them.
       
   106     table()->recalcSectionsIfNeeded();
       
   107 
       
   108     RenderBlock::calcPrefWidths();
       
   109     if (element() && style()->autoWrap()) {
       
   110         // See if nowrap was set.
       
   111         Length w = styleOrColWidth();
       
   112         String nowrap = static_cast<Element*>(element())->getAttribute(nowrapAttr);
       
   113         if (!nowrap.isNull() && w.isFixed())
       
   114             // Nowrap is set, but we didn't actually use it because of the
       
   115             // fixed width set on the cell.  Even so, it is a WinIE/Moz trait
       
   116             // to make the minwidth of the cell into the fixed width.  They do this
       
   117             // even in strict mode, so do not make this a quirk.  Affected the top
       
   118             // of hiptop.com.
       
   119             m_minPrefWidth = max(w.value(), m_minPrefWidth);
       
   120     }
       
   121 }
       
   122 
       
   123 void RenderTableCell::calcWidth()
       
   124 {
       
   125 }
       
   126 
       
   127 void RenderTableCell::setWidth(int width)
       
   128 {
       
   129     if (width != m_width) {
       
   130         m_width = width;
       
   131         m_widthChanged = true;
       
   132     }
       
   133 }
       
   134 
       
   135 void RenderTableCell::layout()
       
   136 {
       
   137     layoutBlock(m_widthChanged);
       
   138     m_widthChanged = false;
       
   139 }
       
   140 
       
   141 IntRect RenderTableCell::absoluteClippedOverflowRect()
       
   142 {
       
   143     // If the table grid is dirty, we cannot get reliable information about adjoining cells,
       
   144     // so we ignore outside borders. This should not be a problem because it means that
       
   145     // the table is going to recalculate the grid, relayout and repaint its current rect, which
       
   146     // includes any outside borders of this cell.
       
   147     if (table()->collapseBorders() && !table()->needsSectionRecalc()) {
       
   148         bool rtl = table()->style()->direction() == RTL;
       
   149         int outlineSize = style()->outlineSize();
       
   150         int left = max(borderHalfLeft(true), outlineSize);
       
   151         int right = max(borderHalfRight(true), outlineSize);
       
   152         int top = max(borderHalfTop(true), outlineSize);
       
   153         int bottom = max(borderHalfBottom(true), outlineSize);
       
   154         if (left && !rtl || right && rtl) {
       
   155             if (RenderTableCell* before = table()->cellBefore(this)) {
       
   156                 top = max(top, before->borderHalfTop(true));
       
   157                 bottom = max(bottom, before->borderHalfBottom(true));
       
   158             }
       
   159         }
       
   160         if (left && rtl || right && !rtl) {
       
   161             if (RenderTableCell* after = table()->cellAfter(this)) {
       
   162                 top = max(top, after->borderHalfTop(true));
       
   163                 bottom = max(bottom, after->borderHalfBottom(true));
       
   164             }
       
   165         }
       
   166         if (top) {
       
   167             if (RenderTableCell* above = table()->cellAbove(this)) {
       
   168                 left = max(left, above->borderHalfLeft(true));
       
   169                 right = max(right, above->borderHalfRight(true));
       
   170             }
       
   171         }
       
   172         if (bottom) {
       
   173             if (RenderTableCell* below = table()->cellBelow(this)) {
       
   174                 left = max(left, below->borderHalfLeft(true));
       
   175                 right = max(right, below->borderHalfRight(true));
       
   176             }
       
   177         }
       
   178         left = max(left, -overflowLeft(false));
       
   179         top = max(top, -overflowTop(false) - borderTopExtra());
       
   180         IntRect r(-left, -borderTopExtra() - top, left + max(width() + right, overflowWidth(false)), borderTopExtra() + top + max(height() + bottom + borderBottomExtra(), overflowHeight(false)));
       
   181 
       
   182         if (RenderView* v = view())
       
   183             r.move(v->layoutDelta());
       
   184 
       
   185         computeAbsoluteRepaintRect(r);
       
   186         return r;
       
   187     }
       
   188     return RenderBlock::absoluteClippedOverflowRect();
       
   189 }
       
   190 
       
   191 void RenderTableCell::computeAbsoluteRepaintRect(IntRect& r, bool fixed)
       
   192 {
       
   193     r.setY(r.y() + m_topExtra);
       
   194     RenderView* v = view();
       
   195     if (!v || !v->layoutState())
       
   196         r.move(-parent()->xPos(), -parent()->yPos()); // Rows are in the same coordinate space, so don't add their offset in.
       
   197     RenderBlock::computeAbsoluteRepaintRect(r, fixed);
       
   198 }
       
   199 
       
   200 bool RenderTableCell::absolutePosition(int& xPos, int& yPos, bool fixed) const
       
   201 {
       
   202     bool result = RenderBlock::absolutePosition(xPos, yPos, fixed);
       
   203     RenderView* v = view();
       
   204     if (!v || !v->layoutState()) {
       
   205         xPos -= parent()->xPos(); // Rows are in the same coordinate space, so don't add their offset in.
       
   206         yPos -= parent()->yPos();
       
   207     }
       
   208     return result;
       
   209 }
       
   210 
       
   211 short RenderTableCell::baselinePosition(bool /*firstLine*/, bool /*isRootLineBox*/) const
       
   212 {
       
   213     RenderObject* o = firstChild();
       
   214     int offset = paddingTop() + borderTop();
       
   215     
       
   216     if (!o)
       
   217         return offset + contentHeight();
       
   218     while (o->firstChild() && !o->isReplaced()) {
       
   219         if (!o->isInline())
       
   220             offset += o->paddingTop() + o->borderTop();
       
   221         o = o->firstChild();
       
   222     }
       
   223     
       
   224     if (!o->isInline())
       
   225         return paddingTop() + borderTop() + contentHeight();
       
   226 
       
   227     offset += o->baselinePosition(true);
       
   228     return offset;
       
   229 }
       
   230 
       
   231 void RenderTableCell::setStyle(RenderStyle* newStyle)
       
   232 {
       
   233     if (parent() && section() && style() && style()->height() != newStyle->height())
       
   234         section()->setNeedsCellRecalc();
       
   235 
       
   236     newStyle->setDisplay(TABLE_CELL);
       
   237 
       
   238     if (newStyle->whiteSpace() == KHTML_NOWRAP) {
       
   239         // Figure out if we are really nowrapping or if we should just
       
   240         // use normal instead.  If the width of the cell is fixed, then
       
   241         // we don't actually use NOWRAP.
       
   242         if (newStyle->width().isFixed())
       
   243             newStyle->setWhiteSpace(NORMAL);
       
   244         else
       
   245             newStyle->setWhiteSpace(NOWRAP);
       
   246     }
       
   247 
       
   248     RenderBlock::setStyle(newStyle);
       
   249     setHasBoxDecorations(true);
       
   250 }
       
   251 
       
   252 bool RenderTableCell::requiresLayer()
       
   253 {
       
   254     return isPositioned() || isTransparent() || hasOverflowClip();
       
   255 }
       
   256 
       
   257 // The following rules apply for resolving conflicts and figuring out which border
       
   258 // to use.
       
   259 // (1) Borders with the 'border-style' of 'hidden' take precedence over all other conflicting 
       
   260 // borders. Any border with this value suppresses all borders at this location.
       
   261 // (2) Borders with a style of 'none' have the lowest priority. Only if the border properties of all 
       
   262 // the elements meeting at this edge are 'none' will the border be omitted (but note that 'none' is 
       
   263 // the default value for the border style.)
       
   264 // (3) If none of the styles are 'hidden' and at least one of them is not 'none', then narrow borders 
       
   265 // are discarded in favor of wider ones. If several have the same 'border-width' then styles are preferred 
       
   266 // in this order: 'double', 'solid', 'dashed', 'dotted', 'ridge', 'outset', 'groove', and the lowest: 'inset'.
       
   267 // (4) If border styles differ only in color, then a style set on a cell wins over one on a row, 
       
   268 // which wins over a row group, column, column group and, lastly, table. It is undefined which color 
       
   269 // is used when two elements of the same type disagree.
       
   270 static CollapsedBorderValue compareBorders(const CollapsedBorderValue& border1, const CollapsedBorderValue& border2)
       
   271 {
       
   272     // Sanity check the values passed in.  If either is null, return the other.
       
   273     if (!border2.exists())
       
   274         return border1;
       
   275     if (!border1.exists())
       
   276         return border2;
       
   277 
       
   278     // Rule #1 above.
       
   279     if (border1.style() == BHIDDEN || border2.style() == BHIDDEN)
       
   280         return CollapsedBorderValue(); // No border should exist at this location.
       
   281     
       
   282     // Rule #2 above.  A style of 'none' has lowest priority and always loses to any other border.
       
   283     if (border2.style() == BNONE)
       
   284         return border1;
       
   285     if (border1.style() == BNONE)
       
   286         return border2;
       
   287 
       
   288     // The first part of rule #3 above. Wider borders win.
       
   289     if (border1.width() != border2.width())
       
   290         return border1.width() > border2.width() ? border1 : border2;
       
   291     
       
   292     // The borders have equal width.  Sort by border style.
       
   293     if (border1.style() != border2.style())
       
   294         return border1.style() > border2.style() ? border1 : border2;
       
   295     
       
   296     // The border have the same width and style.  Rely on precedence (cell over row over row group, etc.)
       
   297     return border1.precedence >= border2.precedence ? border1 : border2;
       
   298 }
       
   299 
       
   300 CollapsedBorderValue RenderTableCell::collapsedLeftBorder(bool rtl) const
       
   301 {
       
   302     RenderTable* tableElt = table();
       
   303     bool leftmostColumn;
       
   304     if (!rtl)
       
   305         leftmostColumn = col() == 0;
       
   306     else {
       
   307         int effCol = tableElt->colToEffCol(col() + colSpan() - 1);
       
   308         leftmostColumn = effCol == tableElt->numEffCols() - 1;
       
   309     }
       
   310     
       
   311     // For border left, we need to check, in order of precedence:
       
   312     // (1) Our left border.
       
   313     CollapsedBorderValue result(&style()->borderLeft(), BCELL);
       
   314     
       
   315     // (2) The right border of the cell to the left.
       
   316     RenderTableCell* prevCell = rtl ? tableElt->cellAfter(this) : tableElt->cellBefore(this);
       
   317     if (prevCell) {
       
   318         result = compareBorders(result, CollapsedBorderValue(&prevCell->style()->borderRight(), BCELL));
       
   319         if (!result.exists())
       
   320             return result;
       
   321     } else if (leftmostColumn) {
       
   322         // (3) Our row's left border.
       
   323         result = compareBorders(result, CollapsedBorderValue(&parent()->style()->borderLeft(), BROW));
       
   324         if (!result.exists())
       
   325             return result;
       
   326         
       
   327         // (4) Our row group's left border.
       
   328         result = compareBorders(result, CollapsedBorderValue(&section()->style()->borderLeft(), BROWGROUP));
       
   329         if (!result.exists())
       
   330             return result;
       
   331     }
       
   332     
       
   333     // (5) Our column and column group's left borders.
       
   334     bool startColEdge;
       
   335     bool endColEdge;
       
   336     RenderTableCol* colElt = tableElt->colElement(col() + (rtl ? colSpan() - 1 : 0), &startColEdge, &endColEdge);
       
   337     if (colElt && (!rtl ? startColEdge : endColEdge)) {
       
   338         result = compareBorders(result, CollapsedBorderValue(&colElt->style()->borderLeft(), BCOL));
       
   339         if (!result.exists())
       
   340             return result;
       
   341         if (colElt->parent()->isTableCol() && (!rtl ? !colElt->previousSibling() : !colElt->nextSibling())) {
       
   342             result = compareBorders(result, CollapsedBorderValue(&colElt->parent()->style()->borderLeft(), BCOLGROUP));
       
   343             if (!result.exists())
       
   344                 return result;
       
   345         }
       
   346     }
       
   347     
       
   348     // (6) The right border of the column to the left.
       
   349     if (!leftmostColumn) {
       
   350         colElt = tableElt->colElement(col() + (rtl ? colSpan() : -1), &startColEdge, &endColEdge);
       
   351         if (colElt && (!rtl ? endColEdge : startColEdge)) {
       
   352             result = compareBorders(result, CollapsedBorderValue(&colElt->style()->borderRight(), BCOL));
       
   353             if (!result.exists())
       
   354                 return result;
       
   355         }
       
   356     } else {
       
   357         // (7) The table's left border.
       
   358         result = compareBorders(result, CollapsedBorderValue(&tableElt->style()->borderLeft(), BTABLE));
       
   359         if (!result.exists())
       
   360             return result;
       
   361     }
       
   362     
       
   363     return result;
       
   364 }
       
   365 
       
   366 CollapsedBorderValue RenderTableCell::collapsedRightBorder(bool rtl) const
       
   367 {
       
   368     RenderTable* tableElt = table();
       
   369     bool rightmostColumn;
       
   370     if (rtl)
       
   371         rightmostColumn = col() == 0;
       
   372     else {
       
   373         int effCol = tableElt->colToEffCol(col() + colSpan() - 1);
       
   374         rightmostColumn = effCol == tableElt->numEffCols() - 1;
       
   375     }
       
   376     
       
   377     // For border right, we need to check, in order of precedence:
       
   378     // (1) Our right border.
       
   379     CollapsedBorderValue result = CollapsedBorderValue(&style()->borderRight(), BCELL);
       
   380     
       
   381     // (2) The left border of the cell to the right.
       
   382     if (!rightmostColumn) {
       
   383         RenderTableCell* nextCell = rtl ? tableElt->cellBefore(this) : tableElt->cellAfter(this);
       
   384         if (nextCell && nextCell->style()) {
       
   385             result = compareBorders(result, CollapsedBorderValue(&nextCell->style()->borderLeft(), BCELL));
       
   386             if (!result.exists())
       
   387                 return result;
       
   388         }
       
   389     } else {
       
   390         // (3) Our row's right border.
       
   391         result = compareBorders(result, CollapsedBorderValue(&parent()->style()->borderRight(), BROW));
       
   392         if (!result.exists())
       
   393             return result;
       
   394         
       
   395         // (4) Our row group's right border.
       
   396         result = compareBorders(result, CollapsedBorderValue(&section()->style()->borderRight(), BROWGROUP));
       
   397         if (!result.exists())
       
   398             return result;
       
   399     }
       
   400     
       
   401     // (5) Our column and column group's right borders.
       
   402     bool startColEdge;
       
   403     bool endColEdge;
       
   404     RenderTableCol* colElt = tableElt->colElement(col() + (rtl ? 0 : colSpan() - 1), &startColEdge, &endColEdge);
       
   405     if (colElt && (!rtl ? endColEdge : startColEdge)) {
       
   406         result = compareBorders(result, CollapsedBorderValue(&colElt->style()->borderRight(), BCOL));
       
   407         if (!result.exists())
       
   408             return result;
       
   409         if (colElt->parent()->isTableCol() && (!rtl ? !colElt->nextSibling() : !colElt->previousSibling())) {
       
   410             result = compareBorders(result, CollapsedBorderValue(&colElt->parent()->style()->borderRight(), BCOLGROUP));
       
   411             if (!result.exists())
       
   412                 return result;
       
   413         }
       
   414     }
       
   415     
       
   416     // (6) The left border of the column to the right.
       
   417     if (!rightmostColumn) {
       
   418         colElt = tableElt->colElement(col() + (rtl ? -1 : colSpan()), &startColEdge, &endColEdge);
       
   419         if (colElt && (!rtl ? startColEdge : endColEdge)) {
       
   420             result = compareBorders(result, CollapsedBorderValue(&colElt->style()->borderLeft(), BCOL));
       
   421             if (!result.exists())
       
   422                 return result;
       
   423         }
       
   424     } else {
       
   425         // (7) The table's right border.
       
   426         result = compareBorders(result, CollapsedBorderValue(&tableElt->style()->borderRight(), BTABLE));
       
   427         if (!result.exists())
       
   428             return result;
       
   429     }
       
   430     
       
   431     return result;
       
   432 }
       
   433 
       
   434 CollapsedBorderValue RenderTableCell::collapsedTopBorder() const
       
   435 {
       
   436     // For border top, we need to check, in order of precedence:
       
   437     // (1) Our top border.
       
   438     CollapsedBorderValue result = CollapsedBorderValue(&style()->borderTop(), BCELL);
       
   439     
       
   440     RenderTableCell* prevCell = table()->cellAbove(this);
       
   441     if (prevCell) {
       
   442         // (2) A previous cell's bottom border.
       
   443         result = compareBorders(result, CollapsedBorderValue(&prevCell->style()->borderBottom(), BCELL));
       
   444         if (!result.exists()) 
       
   445             return result;
       
   446     }
       
   447     
       
   448     // (3) Our row's top border.
       
   449     result = compareBorders(result, CollapsedBorderValue(&parent()->style()->borderTop(), BROW));
       
   450     if (!result.exists())
       
   451         return result;
       
   452     
       
   453     // (4) The previous row's bottom border.
       
   454     if (prevCell) {
       
   455         RenderObject* prevRow = 0;
       
   456         if (prevCell->section() == section())
       
   457             prevRow = parent()->previousSibling();
       
   458         else
       
   459             prevRow = prevCell->section()->lastChild();
       
   460     
       
   461         if (prevRow) {
       
   462             result = compareBorders(result, CollapsedBorderValue(&prevRow->style()->borderBottom(), BROW));
       
   463             if (!result.exists())
       
   464                 return result;
       
   465         }
       
   466     }
       
   467     
       
   468     // Now check row groups.
       
   469     RenderTableSection* currSection = section();
       
   470     if (!row()) {
       
   471         // (5) Our row group's top border.
       
   472         result = compareBorders(result, CollapsedBorderValue(&currSection->style()->borderTop(), BROWGROUP));
       
   473         if (!result.exists())
       
   474             return result;
       
   475         
       
   476         // (6) Previous row group's bottom border.
       
   477         currSection = table()->sectionAbove(currSection);
       
   478         if (currSection) {
       
   479             result = compareBorders(result, CollapsedBorderValue(&currSection->style()->borderBottom(), BROWGROUP));
       
   480             if (!result.exists())
       
   481                 return result;
       
   482         }
       
   483     }
       
   484     
       
   485     if (!currSection) {
       
   486         // (8) Our column and column group's top borders.
       
   487         RenderTableCol* colElt = table()->colElement(col());
       
   488         if (colElt) {
       
   489             result = compareBorders(result, CollapsedBorderValue(&colElt->style()->borderTop(), BCOL));
       
   490             if (!result.exists())
       
   491                 return result;
       
   492             if (colElt->parent()->isTableCol()) {
       
   493                 result = compareBorders(result, CollapsedBorderValue(&colElt->parent()->style()->borderTop(), BCOLGROUP));
       
   494                 if (!result.exists())
       
   495                     return result;
       
   496             }
       
   497         }
       
   498         
       
   499         // (9) The table's top border.
       
   500         result = compareBorders(result, CollapsedBorderValue(&table()->style()->borderTop(), BTABLE));
       
   501         if (!result.exists())
       
   502             return result;
       
   503     }
       
   504     
       
   505     return result;
       
   506 }
       
   507 
       
   508 CollapsedBorderValue RenderTableCell::collapsedBottomBorder() const
       
   509 {
       
   510     // For border top, we need to check, in order of precedence:
       
   511     // (1) Our bottom border.
       
   512     CollapsedBorderValue result = CollapsedBorderValue(&style()->borderBottom(), BCELL);
       
   513     
       
   514     RenderTableCell* nextCell = table()->cellBelow(this);
       
   515     if (nextCell) {
       
   516         // (2) A following cell's top border.
       
   517         result = compareBorders(result, CollapsedBorderValue(&nextCell->style()->borderTop(), BCELL));
       
   518         if (!result.exists())
       
   519             return result;
       
   520     }
       
   521     
       
   522     // (3) Our row's bottom border. (FIXME: Deal with rowspan!)
       
   523     result = compareBorders(result, CollapsedBorderValue(&parent()->style()->borderBottom(), BROW));
       
   524     if (!result.exists())
       
   525         return result;
       
   526     
       
   527     // (4) The next row's top border.
       
   528     if (nextCell) {
       
   529         result = compareBorders(result, CollapsedBorderValue(&nextCell->parent()->style()->borderTop(), BROW));
       
   530         if (!result.exists())
       
   531             return result;
       
   532     }
       
   533     
       
   534     // Now check row groups.
       
   535     RenderTableSection* currSection = section();
       
   536     if (row() + rowSpan() >= static_cast<RenderTableSection*>(currSection)->numRows()) {
       
   537         // (5) Our row group's bottom border.
       
   538         result = compareBorders(result, CollapsedBorderValue(&currSection->style()->borderBottom(), BROWGROUP));
       
   539         if (!result.exists())
       
   540             return result;
       
   541         
       
   542         // (6) Following row group's top border.
       
   543         currSection = table()->sectionBelow(currSection);
       
   544         if (currSection) {
       
   545             result = compareBorders(result, CollapsedBorderValue(&currSection->style()->borderTop(), BROWGROUP));
       
   546             if (!result.exists())
       
   547                 return result;
       
   548         }
       
   549     }
       
   550     
       
   551     if (!currSection) {
       
   552         // (8) Our column and column group's bottom borders.
       
   553         RenderTableCol* colElt = table()->colElement(col());
       
   554         if (colElt) {
       
   555             result = compareBorders(result, CollapsedBorderValue(&colElt->style()->borderBottom(), BCOL));
       
   556             if (!result.exists()) return result;
       
   557             if (colElt->parent()->isTableCol()) {
       
   558                 result = compareBorders(result, CollapsedBorderValue(&colElt->parent()->style()->borderBottom(), BCOLGROUP));
       
   559                 if (!result.exists())
       
   560                     return result;
       
   561             }
       
   562         }
       
   563         
       
   564         // (9) The table's bottom border.
       
   565         result = compareBorders(result, CollapsedBorderValue(&table()->style()->borderBottom(), BTABLE));
       
   566         if (!result.exists())
       
   567             return result;
       
   568     }
       
   569     
       
   570     return result;    
       
   571 }
       
   572 
       
   573 int RenderTableCell::borderLeft() const
       
   574 {
       
   575     return table()->collapseBorders() ? borderHalfLeft(false) : RenderBlock::borderLeft();
       
   576 }
       
   577 
       
   578 int RenderTableCell::borderRight() const
       
   579 {
       
   580     return table()->collapseBorders() ? borderHalfRight(false) : RenderBlock::borderRight();
       
   581 }
       
   582 
       
   583 int RenderTableCell::borderTop() const
       
   584 {
       
   585     return table()->collapseBorders() ? borderHalfTop(false) : RenderBlock::borderTop();
       
   586 }
       
   587 
       
   588 int RenderTableCell::borderBottom() const
       
   589 {
       
   590     return table()->collapseBorders() ? borderHalfBottom(false) : RenderBlock::borderBottom();
       
   591 }
       
   592 
       
   593 int RenderTableCell::borderHalfLeft(bool outer) const
       
   594 {
       
   595     CollapsedBorderValue border = collapsedLeftBorder(table()->style()->direction() == RTL);
       
   596     if (border.exists())
       
   597         return (border.width() + (outer ? 0 : 1)) / 2; // Give the extra pixel to top and left.
       
   598     return 0;
       
   599 }
       
   600     
       
   601 int RenderTableCell::borderHalfRight(bool outer) const
       
   602 {
       
   603     CollapsedBorderValue border = collapsedRightBorder(table()->style()->direction() == RTL);
       
   604     if (border.exists())
       
   605         return (border.width() + (outer ? 1 : 0)) / 2;
       
   606     return 0;
       
   607 }
       
   608 
       
   609 int RenderTableCell::borderHalfTop(bool outer) const
       
   610 {
       
   611     CollapsedBorderValue border = collapsedTopBorder();
       
   612     if (border.exists())
       
   613         return (border.width() + (outer ? 0 : 1)) / 2; // Give the extra pixel to top and left.
       
   614     return 0;
       
   615 }
       
   616 
       
   617 int RenderTableCell::borderHalfBottom(bool outer) const
       
   618 {
       
   619     CollapsedBorderValue border = collapsedBottomBorder();
       
   620     if (border.exists())
       
   621         return (border.width() + (outer ? 1 : 0)) / 2;
       
   622     return 0;
       
   623 }
       
   624 
       
   625 void RenderTableCell::paint(PaintInfo& paintInfo, int tx, int ty)
       
   626 {
       
   627     tx += m_x;
       
   628     ty += m_y;
       
   629 
       
   630     // check if we need to do anything at all...
       
   631     int os = 2 * maximalOutlineSize(paintInfo.phase);
       
   632 
       
   633     if (paintInfo.phase == PaintPhaseCollapsedTableBorders && style()->visibility() == VISIBLE) {
       
   634         if (ty - table()->outerBorderTop() >= paintInfo.rect.bottom() + os ||
       
   635                 ty + m_topExtra + m_height + m_bottomExtra + table()->outerBorderBottom() <= paintInfo.rect.y() - os)
       
   636             return;
       
   637         int w = width();
       
   638         int h = height() + borderTopExtra() + borderBottomExtra();
       
   639         paintCollapsedBorder(paintInfo.context, tx, ty, w, h);
       
   640     } else {
       
   641         if (ty + overflowTop(false) >= paintInfo.rect.bottom() + os || ty + m_topExtra + overflowHeight(false) + m_bottomExtra <= paintInfo.rect.y() - os)
       
   642             return;
       
   643         RenderBlock::paintObject(paintInfo, tx, ty + m_topExtra);
       
   644     }
       
   645 }
       
   646 
       
   647 static EBorderStyle collapsedBorderStyle(EBorderStyle style)
       
   648 {
       
   649     if (style == OUTSET)
       
   650         return GROOVE;
       
   651     if (style == INSET)
       
   652         return RIDGE;
       
   653     return style;
       
   654 }
       
   655 
       
   656 struct CollapsedBorder {
       
   657     CollapsedBorderValue borderValue;
       
   658     RenderObject::BorderSide side;
       
   659     bool shouldPaint;
       
   660     int x1;
       
   661     int y1;
       
   662     int x2;
       
   663     int y2;
       
   664     EBorderStyle style;
       
   665 };
       
   666 
       
   667 class CollapsedBorders {
       
   668 public:
       
   669     CollapsedBorders()
       
   670         : m_count(0)
       
   671     {
       
   672     }
       
   673     
       
   674     void addBorder(const CollapsedBorderValue& borderValue, RenderObject::BorderSide borderSide, bool shouldPaint,
       
   675                    int x1, int y1, int x2, int y2, EBorderStyle borderStyle)
       
   676     {
       
   677         if (borderValue.exists() && shouldPaint) {
       
   678             m_borders[m_count].borderValue = borderValue;
       
   679             m_borders[m_count].side = borderSide;
       
   680             m_borders[m_count].shouldPaint = shouldPaint;
       
   681             m_borders[m_count].x1 = x1;
       
   682             m_borders[m_count].x2 = x2;
       
   683             m_borders[m_count].y1 = y1;
       
   684             m_borders[m_count].y2 = y2;
       
   685             m_borders[m_count].style = borderStyle;
       
   686             m_count++;
       
   687         }
       
   688     }
       
   689 
       
   690     CollapsedBorder* nextBorder()
       
   691     {
       
   692         for (int i = 0; i < m_count; i++) {
       
   693             if (m_borders[i].borderValue.exists() && m_borders[i].shouldPaint) {
       
   694                 m_borders[i].shouldPaint = false;
       
   695                 return &m_borders[i];
       
   696             }
       
   697         }
       
   698         
       
   699         return 0;
       
   700     }
       
   701     
       
   702     CollapsedBorder m_borders[4];
       
   703     int m_count;
       
   704 };
       
   705 
       
   706 static void addBorderStyle(RenderTableCell::CollapsedBorderStyles& borderStyles, CollapsedBorderValue borderValue)
       
   707 {
       
   708     if (!borderValue.exists())
       
   709         return;
       
   710     size_t count = borderStyles.size();
       
   711     for (size_t i = 0; i < count; ++i)
       
   712         if (borderStyles[i] == borderValue)
       
   713             return;
       
   714     borderStyles.append(borderValue);
       
   715 }
       
   716 
       
   717 void RenderTableCell::collectBorderStyles(CollapsedBorderStyles& borderStyles) const
       
   718 {
       
   719     bool rtl = table()->style()->direction() == RTL;
       
   720     addBorderStyle(borderStyles, collapsedLeftBorder(rtl));
       
   721     addBorderStyle(borderStyles, collapsedRightBorder(rtl));
       
   722     addBorderStyle(borderStyles, collapsedTopBorder());
       
   723     addBorderStyle(borderStyles, collapsedBottomBorder());
       
   724 }
       
   725 
       
   726 static int compareBorderStylesForQSort(const void* pa, const void* pb)
       
   727 {
       
   728     const CollapsedBorderValue* a = static_cast<const CollapsedBorderValue*>(pa);
       
   729     const CollapsedBorderValue* b = static_cast<const CollapsedBorderValue*>(pb);
       
   730     if (*a == *b)
       
   731         return 0;
       
   732     CollapsedBorderValue borderWithHigherPrecedence = compareBorders(*a, *b);
       
   733     if (*a == borderWithHigherPrecedence)
       
   734         return 1;
       
   735     return -1;
       
   736 }
       
   737 
       
   738 void RenderTableCell::sortBorderStyles(CollapsedBorderStyles& borderStyles)
       
   739 {
       
   740     qsort(borderStyles.data(), borderStyles.size(), sizeof(CollapsedBorderValue),
       
   741         compareBorderStylesForQSort);
       
   742 }
       
   743 
       
   744 void RenderTableCell::paintCollapsedBorder(GraphicsContext* graphicsContext, int tx, int ty, int w, int h)
       
   745 {
       
   746     if (!table()->currentBorderStyle())
       
   747         return;
       
   748     
       
   749     bool rtl = table()->style()->direction() == RTL;
       
   750     CollapsedBorderValue leftVal = collapsedLeftBorder(rtl);
       
   751     CollapsedBorderValue rightVal = collapsedRightBorder(rtl);
       
   752     CollapsedBorderValue topVal = collapsedTopBorder();
       
   753     CollapsedBorderValue bottomVal = collapsedBottomBorder();
       
   754      
       
   755     // Adjust our x/y/width/height so that we paint the collapsed borders at the correct location.
       
   756     int topWidth = topVal.width();
       
   757     int bottomWidth = bottomVal.width();
       
   758     int leftWidth = leftVal.width();
       
   759     int rightWidth = rightVal.width();
       
   760     
       
   761     tx -= leftWidth / 2;
       
   762     ty -= topWidth / 2;
       
   763     w += leftWidth / 2 + (rightWidth + 1) / 2;
       
   764     h += topWidth / 2 + (bottomWidth + 1) / 2;
       
   765     
       
   766     EBorderStyle topStyle = collapsedBorderStyle(topVal.style());
       
   767     EBorderStyle bottomStyle = collapsedBorderStyle(bottomVal.style());
       
   768     EBorderStyle leftStyle = collapsedBorderStyle(leftVal.style());
       
   769     EBorderStyle rightStyle = collapsedBorderStyle(rightVal.style());
       
   770     
       
   771     bool renderTop = topStyle > BHIDDEN && !topVal.isTransparent();
       
   772     bool renderBottom = bottomStyle > BHIDDEN && !bottomVal.isTransparent();
       
   773     bool renderLeft = leftStyle > BHIDDEN && !leftVal.isTransparent();
       
   774     bool renderRight = rightStyle > BHIDDEN && !rightVal.isTransparent();
       
   775 
       
   776     // We never paint diagonals at the joins.  We simply let the border with the highest
       
   777     // precedence paint on top of borders with lower precedence.  
       
   778     CollapsedBorders borders;
       
   779     borders.addBorder(topVal, BSTop, renderTop, tx, ty, tx + w, ty + topWidth, topStyle);
       
   780     borders.addBorder(bottomVal, BSBottom, renderBottom, tx, ty + h - bottomWidth, tx + w, ty + h, bottomStyle);
       
   781     borders.addBorder(leftVal, BSLeft, renderLeft, tx, ty, tx + leftWidth, ty + h, leftStyle);
       
   782     borders.addBorder(rightVal, BSRight, renderRight, tx + w - rightWidth, ty, tx + w, ty + h, rightStyle);
       
   783     
       
   784     for (CollapsedBorder* border = borders.nextBorder(); border; border = borders.nextBorder()) {
       
   785         if (border->borderValue == *table()->currentBorderStyle())
       
   786             drawBorder(graphicsContext, border->x1, border->y1, border->x2, border->y2, border->side, 
       
   787                        border->borderValue.color(), style()->color(), border->style, 0, 0);
       
   788     }
       
   789 }
       
   790 
       
   791 void RenderTableCell::paintBackgroundsBehindCell(PaintInfo& paintInfo, int tx, int ty, RenderObject* backgroundObject)
       
   792 {
       
   793     if (!backgroundObject)
       
   794         return;
       
   795 
       
   796     if (style()->visibility() != VISIBLE)
       
   797         return;
       
   798 
       
   799     RenderTable* tableElt = table();
       
   800     if (!tableElt->collapseBorders() && style()->emptyCells() == HIDE && !firstChild())
       
   801         return;
       
   802 
       
   803     if (backgroundObject != this) {
       
   804         tx += m_x;
       
   805         ty += m_y + m_topExtra;
       
   806     }
       
   807 
       
   808     int w = width();
       
   809     int h = height() + borderTopExtra() + borderBottomExtra();
       
   810     ty -= borderTopExtra();
       
   811 
       
   812     int my = max(ty, paintInfo.rect.y());
       
   813     int end = min(paintInfo.rect.bottom(), ty + h);
       
   814     int mh = end - my;
       
   815 
       
   816     Color c = backgroundObject->style()->backgroundColor();
       
   817     const BackgroundLayer* bgLayer = backgroundObject->style()->backgroundLayers();
       
   818 
       
   819     if (bgLayer->hasImage() || c.isValid()) {
       
   820         // We have to clip here because the background would paint
       
   821         // on top of the borders otherwise.  This only matters for cells and rows.
       
   822         bool shouldClip = backgroundObject->hasLayer() && (backgroundObject == this || backgroundObject == parent()) && tableElt->collapseBorders();
       
   823         if (shouldClip) {
       
   824             IntRect clipRect(tx + borderLeft(), ty + borderTop(),
       
   825                 w - borderLeft() - borderRight(), h - borderTop() - borderBottom());
       
   826 #if PLATFORM(SYMBIAN)
       
   827             // make sure we don't draw outside the current rendering area.
       
   828             clipRect.intersect(paintInfo.rect);
       
   829 #endif
       
   830             paintInfo.context->save();
       
   831             paintInfo.context->clip(clipRect);
       
   832         }
       
   833         paintBackground(paintInfo.context, c, bgLayer, my, mh, tx, ty, w, h);
       
   834         if (shouldClip)
       
   835             paintInfo.context->restore();
       
   836     }
       
   837 }
       
   838 
       
   839 void RenderTableCell::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
       
   840 {
       
   841     RenderTable* tableElt = table();
       
   842     if (!tableElt->collapseBorders() && style()->emptyCells() == HIDE && !firstChild())
       
   843         return;
       
   844 
       
   845     int w = width();
       
   846     int h = height() + borderTopExtra() + borderBottomExtra();
       
   847    
       
   848     if (style()->boxShadow())
       
   849         paintBoxShadow(paintInfo.context, tx, ty - borderTopExtra(), w, h, style());
       
   850     
       
   851     // Paint our cell background.
       
   852     paintBackgroundsBehindCell(paintInfo, tx, ty, this);
       
   853 
       
   854     if (!style()->hasBorder() || tableElt->collapseBorders())
       
   855         return;
       
   856 
       
   857     ty -= borderTopExtra();
       
   858     paintBorder(paintInfo.context, tx, ty, w, h, style());
       
   859 }
       
   860 
       
   861 #ifndef NDEBUG
       
   862 void RenderTableCell::dump(TextStream* stream, DeprecatedString ind) const
       
   863 {
       
   864     *stream << " row=" << row();
       
   865     *stream << " col=" << col();
       
   866     *stream << " rSpan=" << rowSpan();
       
   867     *stream << " cSpan=" << colSpan();
       
   868 
       
   869     RenderBlock::dump(stream,ind);
       
   870 }
       
   871 #endif
       
   872 
       
   873 } // namespace WebCore