summaryrefslogtreecommitdiff
path: root/Source/WebCore/rendering/RenderTableCell.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/rendering/RenderTableCell.cpp')
-rw-r--r--Source/WebCore/rendering/RenderTableCell.cpp149
1 files changed, 123 insertions, 26 deletions
diff --git a/Source/WebCore/rendering/RenderTableCell.cpp b/Source/WebCore/rendering/RenderTableCell.cpp
index aa3ad197f..9b0d57cd3 100644
--- a/Source/WebCore/rendering/RenderTableCell.cpp
+++ b/Source/WebCore/rendering/RenderTableCell.cpp
@@ -33,8 +33,9 @@
#include "PaintInfo.h"
#include "RenderTableCol.h"
#include "RenderView.h"
-#include "StyleInheritedData.h"
+#include "StylePropertySet.h"
#include "TransformState.h"
+#include <wtf/StackStats.h>
#if ENABLE(MATHML)
#include "MathMLElement.h"
@@ -55,8 +56,8 @@ struct SameSizeAsRenderTableCell : public RenderBlock {
COMPILE_ASSERT(sizeof(RenderTableCell) == sizeof(SameSizeAsRenderTableCell), RenderTableCell_should_stay_small);
COMPILE_ASSERT(sizeof(CollapsedBorderValue) == 8, CollapsedBorderValue_should_stay_small);
-RenderTableCell::RenderTableCell(Node* node)
- : RenderBlock(node)
+RenderTableCell::RenderTableCell(Element* element)
+ : RenderBlock(element)
, m_column(unsetColumnIndex)
, m_cellWidthChanged(false)
, m_intrinsicPaddingBefore(0)
@@ -79,10 +80,10 @@ unsigned RenderTableCell::parseColSpanFromDOM() const
{
ASSERT(node());
if (node()->hasTagName(tdTag) || node()->hasTagName(thTag))
- return toHTMLTableCellElement(node())->colSpan();
+ return min<unsigned>(toHTMLTableCellElement(node())->colSpan(), maxColumnIndex);
#if ENABLE(MATHML)
if (node()->hasTagName(MathMLNames::mtdTag))
- return toMathMLElement(node())->colSpan();
+ return min<unsigned>(toMathMLElement(node())->colSpan(), maxColumnIndex);
#endif
return 1;
}
@@ -91,10 +92,10 @@ unsigned RenderTableCell::parseRowSpanFromDOM() const
{
ASSERT(node());
if (node()->hasTagName(tdTag) || node()->hasTagName(thTag))
- return toHTMLTableCellElement(node())->rowSpan();
+ return min<unsigned>(toHTMLTableCellElement(node())->rowSpan(), maxRowIndex);
#if ENABLE(MATHML)
if (node()->hasTagName(MathMLNames::mtdTag))
- return toMathMLElement(node())->rowSpan();
+ return min<unsigned>(toMathMLElement(node())->rowSpan(), maxRowIndex);
#endif
return 1;
}
@@ -168,7 +169,7 @@ void RenderTableCell::computePreferredLogicalWidths()
if (node() && style()->autoWrap()) {
// See if nowrap was set.
Length w = styleOrColLogicalWidth();
- String nowrap = static_cast<Element*>(node())->getAttribute(nowrapAttr);
+ String nowrap = toElement(node())->getAttribute(nowrapAttr);
if (!nowrap.isNull() && w.isFixed())
// Nowrap is set, but we didn't actually use it because of the
// fixed width set on the cell. Even so, it is a WinIE/Moz trait
@@ -194,7 +195,7 @@ void RenderTableCell::computeIntrinsicPadding(int rowHeight)
case LENGTH:
case BASELINE: {
LayoutUnit baseline = cellBaselinePosition();
- if (baseline > borderBefore() + paddingBefore())
+ if (baseline > borderAndPaddingBefore())
intrinsicPaddingBefore = section()->rowBaseline(rowIndex()) - (baseline - oldIntrinsicPaddingBefore);
break;
}
@@ -243,7 +244,21 @@ void RenderTableCell::layout()
{
StackStats::LayoutCheckPoint layoutCheckPoint;
updateFirstLetter();
+
+ int oldCellBaseline = cellBaselinePosition();
layoutBlock(cellWidthChanged());
+
+ // If we have replaced content, the intrinsic height of our content may have changed since the last time we laid out. If that's the case the intrinsic padding we used
+ // for layout (the padding required to push the contents of the cell down to the row's baseline) is included in our new height and baseline and makes both
+ // of them wrong. So if our content's intrinsic height has changed push the new content up into the intrinsic padding and relayout so that the rest of
+ // table and row layout can use the correct baseline and height for this cell.
+ if (isBaselineAligned() && section()->rowBaseline(rowIndex()) && cellBaselinePosition() > section()->rowBaseline(rowIndex())) {
+ int newIntrinsicPaddingBefore = max<LayoutUnit>(0, intrinsicPaddingBefore() - max<LayoutUnit>(0, cellBaselinePosition() - oldCellBaseline));
+ setIntrinsicPaddingBefore(newIntrinsicPaddingBefore);
+ setNeedsLayout(true, MarkOnlyThis);
+ layoutBlock(cellWidthChanged());
+ }
+
setCellWidthChanged(false);
}
@@ -376,7 +391,7 @@ LayoutUnit RenderTableCell::cellBaselinePosition() const
LayoutUnit firstLineBaseline = firstLineBoxBaseline();
if (firstLineBaseline != -1)
return firstLineBaseline;
- return paddingBefore() + borderBefore() + contentLogicalHeight();
+ return borderAndPaddingBefore() + contentLogicalHeight();
}
void RenderTableCell::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
@@ -390,6 +405,11 @@ void RenderTableCell::styleDidChange(StyleDifference diff, const RenderStyle* ol
if (parent() && section() && oldStyle && style()->height() != oldStyle->height())
section()->rowLogicalHeightChanged(rowIndex());
+ // Our intrinsic padding pushes us down to align with the baseline of other cells on the row. If our vertical-align
+ // has changed then so will the padding needed to align with other cells - clear it so we can recalculate it from scratch.
+ if (oldStyle && style()->verticalAlign() != oldStyle->verticalAlign())
+ clearIntrinsicPadding();
+
// If border was changed, notify table.
if (parent()) {
RenderTable* table = this->table();
@@ -1081,6 +1101,31 @@ void RenderTableCell::sortBorderValues(RenderTable::CollapsedBorderValues& borde
compareBorderValuesForQSort);
}
+bool RenderTableCell::alignLeftRightBorderPaintRect(int& leftXOffset, int& rightXOffset)
+{
+ const RenderStyle* styleForTopCell = styleForCellFlow();
+ int left = cachedCollapsedLeftBorder(styleForTopCell).width();
+ int right = cachedCollapsedRightBorder(styleForTopCell).width();
+ leftXOffset = max<int>(leftXOffset, left);
+ rightXOffset = max<int>(rightXOffset, right);
+ if (colSpan() > 1)
+ return false;
+ return true;
+}
+
+bool RenderTableCell::alignTopBottomBorderPaintRect(int& topYOffset, int& bottomYOffset)
+{
+ const RenderStyle* styleForBottomCell = styleForCellFlow();
+ int top = cachedCollapsedTopBorder(styleForBottomCell).width();
+ int bottom = cachedCollapsedBottomBorder(styleForBottomCell).width();
+ topYOffset = max<int>(topYOffset, top);
+ bottomYOffset = max<int>(bottomYOffset, bottom);
+ if (rowSpan() > 1)
+ return false;
+ return true;
+}
+
+
void RenderTableCell::paintCollapsedBorders(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
ASSERT(paintInfo.phase == PaintPhaseCollapsedTableBorders);
@@ -1091,7 +1136,7 @@ void RenderTableCell::paintCollapsedBorders(PaintInfo& paintInfo, const LayoutPo
LayoutRect localRepaintRect = paintInfo.rect;
localRepaintRect.inflate(maximalOutlineSize(paintInfo.phase));
- LayoutRect paintRect = LayoutRect(paintOffset + location(), size());
+ LayoutRect paintRect = LayoutRect(paintOffset + location(), pixelSnappedSize());
if (paintRect.y() - table()->outerBorderTop() >= localRepaintRect.maxY())
return;
@@ -1114,35 +1159,80 @@ void RenderTableCell::paintCollapsedBorders(PaintInfo& paintInfo, const LayoutPo
int leftWidth = leftVal.width();
int rightWidth = rightVal.width();
+ int leftXOffsetTop = leftWidth;
+ int leftXOffsetBottom = leftWidth;
+ int rightXOffsetTop = rightWidth;
+ int rightXOffsetBottom = rightWidth;
+ int topYOffsetLeft = topWidth;
+ int topYOffsetRight = topWidth;
+ int bottomYOffsetLeft = bottomWidth;
+ int bottomYOffsetRight = bottomWidth;
+
+ bool shouldDrawTopBorder = true;
+ bool shouldDrawLeftBorder = true;
+ bool shouldDrawRightBorder = true;
+
+ if (RenderTableCell* top = table()->cellAbove(this)) {
+ shouldDrawTopBorder = top->alignLeftRightBorderPaintRect(leftXOffsetTop, rightXOffsetTop);
+ if (this->colSpan() > 1)
+ shouldDrawTopBorder = false;
+ }
+
+ if (RenderTableCell* bottom = table()->cellBelow(this))
+ bottom->alignLeftRightBorderPaintRect(leftXOffsetBottom, rightXOffsetBottom);
+
+ if (RenderTableCell* left = table()->cellBefore(this))
+ shouldDrawLeftBorder = left->alignTopBottomBorderPaintRect(topYOffsetLeft, bottomYOffsetLeft);
+
+ if (RenderTableCell* right = table()->cellAfter(this))
+ shouldDrawRightBorder = right->alignTopBottomBorderPaintRect(topYOffsetRight, bottomYOffsetRight);
+
+ IntRect cellRect = pixelSnappedIntRect(paintRect.x(), paintRect.y(), paintRect.width(), paintRect.height());
+
IntRect borderRect = pixelSnappedIntRect(paintRect.x() - leftWidth / 2,
- paintRect.y() - topWidth / 2,
- paintRect.width() + leftWidth / 2 + (rightWidth + 1) / 2,
- paintRect.height() + topWidth / 2 + (bottomWidth + 1) / 2);
+ paintRect.y() - topWidth / 2,
+ paintRect.width() + leftWidth / 2 + (rightWidth + 1) / 2,
+ paintRect.height() + topWidth / 2 + (bottomWidth + 1) / 2);
EBorderStyle topStyle = collapsedBorderStyle(topVal.style());
EBorderStyle bottomStyle = collapsedBorderStyle(bottomVal.style());
EBorderStyle leftStyle = collapsedBorderStyle(leftVal.style());
EBorderStyle rightStyle = collapsedBorderStyle(rightVal.style());
- bool renderTop = topStyle > BHIDDEN && !topVal.isTransparent();
+ bool renderTop = topStyle > BHIDDEN && !topVal.isTransparent() && shouldDrawTopBorder;
bool renderBottom = bottomStyle > BHIDDEN && !bottomVal.isTransparent();
- bool renderLeft = leftStyle > BHIDDEN && !leftVal.isTransparent();
- bool renderRight = rightStyle > BHIDDEN && !rightVal.isTransparent();
+ bool renderLeft = leftStyle > BHIDDEN && !leftVal.isTransparent() && shouldDrawLeftBorder;
+ bool renderRight = rightStyle > BHIDDEN && !rightVal.isTransparent() && shouldDrawRightBorder;
// We never paint diagonals at the joins. We simply let the border with the highest
// precedence paint on top of borders with lower precedence.
CollapsedBorders borders;
- borders.addBorder(topVal, BSTop, renderTop, borderRect.x(), borderRect.y(), borderRect.maxX(), borderRect.y() + topWidth, topStyle);
- borders.addBorder(bottomVal, BSBottom, renderBottom, borderRect.x(), borderRect.maxY() - bottomWidth, borderRect.maxX(), borderRect.maxY(), bottomStyle);
- borders.addBorder(leftVal, BSLeft, renderLeft, borderRect.x(), borderRect.y(), borderRect.x() + leftWidth, borderRect.maxY(), leftStyle);
- borders.addBorder(rightVal, BSRight, renderRight, borderRect.maxX() - rightWidth, borderRect.y(), borderRect.maxX(), borderRect.maxY(), rightStyle);
+ if (topVal.style() == DOTTED)
+ borders.addBorder(topVal, BSTop, renderTop, cellRect.x() - leftXOffsetTop / 2, cellRect.y() - topWidth / 2, cellRect.maxX() + rightXOffsetTop / 2, cellRect.y() + topWidth / 2 + topWidth % 2, topStyle);
+ else
+ borders.addBorder(topVal, BSTop, renderTop, borderRect.x(), borderRect.y(), borderRect.maxX(), borderRect.y() + topWidth, topStyle);
+
+ if (bottomVal.style() == DOTTED)
+ borders.addBorder(bottomVal, BSBottom, renderBottom, cellRect.x() - leftXOffsetBottom / 2, cellRect.maxY() - bottomWidth / 2, cellRect.maxX() + rightXOffsetBottom / 2, cellRect.maxY() + bottomWidth / 2 + bottomWidth % 2, bottomStyle);
+ else
+ borders.addBorder(bottomVal, BSBottom, renderBottom, borderRect.x(), borderRect.maxY() - bottomWidth, borderRect.maxX(), borderRect.maxY(), bottomStyle);
+
+ if (leftVal.style() == DOTTED)
+ borders.addBorder(leftVal, BSLeft, renderLeft, cellRect.x() - leftWidth / 2, cellRect.y() - topYOffsetLeft / 2, cellRect.x() + leftWidth / 2 + leftWidth % 2, cellRect.maxY() + bottomYOffsetLeft / 2 + bottomYOffsetLeft % 2, leftStyle);
+ else
+ borders.addBorder(leftVal, BSLeft, renderLeft, borderRect.x(), borderRect.y(), borderRect.x() + leftWidth, borderRect.maxY(), leftStyle);
+
+ if (rightVal.style() == DOTTED)
+ borders.addBorder(rightVal, BSRight, renderRight, cellRect.maxX() - rightWidth / 2, cellRect.y() - topYOffsetRight / 2, cellRect.maxX() + rightWidth / 2 + rightWidth % 2, cellRect.maxY() + bottomYOffsetRight / 2 + bottomYOffsetRight % 2, rightStyle);
+ else
+ borders.addBorder(rightVal, BSRight, renderRight, borderRect.maxX() - rightWidth, borderRect.y(), borderRect.maxX(), borderRect.maxY(), rightStyle);
bool antialias = shouldAntialiasLines(graphicsContext);
for (CollapsedBorder* border = borders.nextBorder(); border; border = borders.nextBorder()) {
if (border->borderValue.isSameIgnoringColor(*table()->currentBorderValue()))
drawLineForBoxSide(graphicsContext, border->x1, border->y1, border->x2, border->y2, border->side,
- border->borderValue.color(), border->style, 0, 0, antialias);
+ border->borderValue.color(), border->style, 0, 0, antialias);
}
}
@@ -1178,7 +1268,7 @@ void RenderTableCell::paintBackgroundsBehindCell(PaintInfo& paintInfo, const Lay
width() - borderLeft() - borderRight(), height() - borderTop() - borderBottom());
paintInfo.context->clip(clipRect);
}
- paintFillLayers(paintInfo, c, bgLayer, LayoutRect(adjustedPaintOffset, size()), BackgroundBleedNone, CompositeSourceOver, backgroundObject);
+ paintFillLayers(paintInfo, c, bgLayer, LayoutRect(adjustedPaintOffset, pixelSnappedSize()), BackgroundBleedNone, CompositeSourceOver, backgroundObject);
}
}
@@ -1191,7 +1281,7 @@ void RenderTableCell::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoin
if (!tableElt->collapseBorders() && style()->emptyCells() == HIDE && !firstChild())
return;
- LayoutRect paintRect = LayoutRect(paintOffset, size());
+ LayoutRect paintRect = LayoutRect(paintOffset, pixelSnappedSize());
paintBoxShadow(paintInfo, paintRect, style(), Normal);
// Paint our cell background.
@@ -1214,7 +1304,7 @@ void RenderTableCell::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOf
if (!tableElt->collapseBorders() && style()->emptyCells() == HIDE && !firstChild())
return;
- paintMaskImages(paintInfo, LayoutRect(paintOffset, size()));
+ paintMaskImages(paintInfo, LayoutRect(paintOffset, pixelSnappedSize()));
}
bool RenderTableCell::boxShadowShouldBeAppliedToBackground(BackgroundBleedAvoidance, InlineFlowBox*) const
@@ -1246,10 +1336,17 @@ void RenderTableCell::scrollbarsChanged(bool horizontalScrollbarChanged, bool ve
setIntrinsicPaddingAfter(intrinsicPaddingAfter() - scrollbarHeight);
}
+RenderTableCell* RenderTableCell::createAnonymous(Document* document)
+{
+ RenderTableCell* renderer = new (document->renderArena()) RenderTableCell(0);
+ renderer->setDocumentForAnonymous(document);
+ return renderer;
+}
+
RenderTableCell* RenderTableCell::createAnonymousWithParentRenderer(const RenderObject* parent)
{
+ RenderTableCell* newCell = RenderTableCell::createAnonymous(parent->document());
RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), TABLE_CELL);
- RenderTableCell* newCell = new (parent->renderArena()) RenderTableCell(parent->document() /* is anonymous */);
newCell->setStyle(newStyle.release());
return newCell;
}