1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 #include "core/paint/TableCellPainter.h"
8 #include "core/layout/LayoutTableCell.h"
9 #include "core/paint/BlockPainter.h"
10 #include "core/paint/BoxPainter.h"
11 #include "core/paint/LayoutObjectDrawingRecorder.h"
12 #include "core/paint/PaintInfo.h"
13 #include "platform/graphics/GraphicsContextStateSaver.h"
17 inline const CollapsedBorderValue
& TableCellPainter::cachedCollapsedLeftBorder(const ComputedStyle
& styleForCellFlow
) const
19 if (styleForCellFlow
.isHorizontalWritingMode()) {
20 return styleForCellFlow
.isLeftToRightDirection() ? m_layoutTableCell
.section()->cachedCollapsedBorder(&m_layoutTableCell
, CBSStart
)
21 : m_layoutTableCell
.section()->cachedCollapsedBorder(&m_layoutTableCell
, CBSEnd
);
23 return styleForCellFlow
.isFlippedBlocksWritingMode() ? m_layoutTableCell
.section()->cachedCollapsedBorder(&m_layoutTableCell
, CBSAfter
)
24 : m_layoutTableCell
.section()->cachedCollapsedBorder(&m_layoutTableCell
, CBSBefore
);
27 inline const CollapsedBorderValue
& TableCellPainter::cachedCollapsedRightBorder(const ComputedStyle
& styleForCellFlow
) const
29 if (styleForCellFlow
.isHorizontalWritingMode()) {
30 return styleForCellFlow
.isLeftToRightDirection() ? m_layoutTableCell
.section()->cachedCollapsedBorder(&m_layoutTableCell
, CBSEnd
)
31 : m_layoutTableCell
.section()->cachedCollapsedBorder(&m_layoutTableCell
, CBSStart
);
33 return styleForCellFlow
.isFlippedBlocksWritingMode() ? m_layoutTableCell
.section()->cachedCollapsedBorder(&m_layoutTableCell
, CBSBefore
)
34 : m_layoutTableCell
.section()->cachedCollapsedBorder(&m_layoutTableCell
, CBSAfter
);
37 inline const CollapsedBorderValue
& TableCellPainter::cachedCollapsedTopBorder(const ComputedStyle
& styleForCellFlow
) const
39 if (styleForCellFlow
.isHorizontalWritingMode())
40 return styleForCellFlow
.isFlippedBlocksWritingMode() ? m_layoutTableCell
.section()->cachedCollapsedBorder(&m_layoutTableCell
, CBSAfter
) : m_layoutTableCell
.section()->cachedCollapsedBorder(&m_layoutTableCell
, CBSBefore
);
41 return styleForCellFlow
.isLeftToRightDirection() ? m_layoutTableCell
.section()->cachedCollapsedBorder(&m_layoutTableCell
, CBSStart
) : m_layoutTableCell
.section()->cachedCollapsedBorder(&m_layoutTableCell
, CBSEnd
);
44 inline const CollapsedBorderValue
& TableCellPainter::cachedCollapsedBottomBorder(const ComputedStyle
& styleForCellFlow
) const
46 if (styleForCellFlow
.isHorizontalWritingMode()) {
47 return styleForCellFlow
.isFlippedBlocksWritingMode() ? m_layoutTableCell
.section()->cachedCollapsedBorder(&m_layoutTableCell
, CBSBefore
)
48 : m_layoutTableCell
.section()->cachedCollapsedBorder(&m_layoutTableCell
, CBSAfter
);
50 return styleForCellFlow
.isLeftToRightDirection() ? m_layoutTableCell
.section()->cachedCollapsedBorder(&m_layoutTableCell
, CBSEnd
)
51 : m_layoutTableCell
.section()->cachedCollapsedBorder(&m_layoutTableCell
, CBSStart
);
54 void TableCellPainter::paint(const PaintInfo
& paintInfo
, const LayoutPoint
& paintOffset
)
56 ASSERT(paintInfo
.phase
!= PaintPhaseCollapsedTableBorders
);
57 BlockPainter(m_layoutTableCell
).paint(paintInfo
, paintOffset
);
60 static EBorderStyle
collapsedBorderStyle(EBorderStyle style
)
69 void TableCellPainter::paintCollapsedBorders(const PaintInfo
& paintInfo
, const LayoutPoint
& paintOffset
)
71 ASSERT(paintInfo
.phase
== PaintPhaseCollapsedTableBorders
);
73 if (!paintInfo
.shouldPaintWithinRoot(&m_layoutTableCell
) || m_layoutTableCell
.style()->visibility() != VISIBLE
)
76 const CollapsedBorderValue
* tableCurrentBorderValue
= m_layoutTableCell
.table()->currentBorderValue();
77 if (!tableCurrentBorderValue
)
80 const ComputedStyle
& styleForCellFlow
= m_layoutTableCell
.styleForCellFlow();
81 const CollapsedBorderValue
& leftBorderValue
= cachedCollapsedLeftBorder(styleForCellFlow
);
82 const CollapsedBorderValue
& rightBorderValue
= cachedCollapsedRightBorder(styleForCellFlow
);
83 const CollapsedBorderValue
& topBorderValue
= cachedCollapsedTopBorder(styleForCellFlow
);
84 const CollapsedBorderValue
& bottomBorderValue
= cachedCollapsedBottomBorder(styleForCellFlow
);
86 int displayItemType
= DisplayItem::TableCollapsedBorderBase
;
87 if (topBorderValue
.shouldPaint(*tableCurrentBorderValue
))
88 displayItemType
|= DisplayItem::TableCollapsedBorderTop
;
89 if (bottomBorderValue
.shouldPaint(*tableCurrentBorderValue
))
90 displayItemType
|= DisplayItem::TableCollapsedBorderBottom
;
91 if (leftBorderValue
.shouldPaint(*tableCurrentBorderValue
))
92 displayItemType
|= DisplayItem::TableCollapsedBorderLeft
;
93 if (rightBorderValue
.shouldPaint(*tableCurrentBorderValue
))
94 displayItemType
|= DisplayItem::TableCollapsedBorderRight
;
96 if (displayItemType
== DisplayItem::TableCollapsedBorderBase
)
99 // Adjust our x/y/width/height so that we paint the collapsed borders at the correct location.
100 int topWidth
= topBorderValue
.width();
101 int bottomWidth
= bottomBorderValue
.width();
102 int leftWidth
= leftBorderValue
.width();
103 int rightWidth
= rightBorderValue
.width();
105 LayoutRect paintRect
= paintBounds(paintOffset
, AddOffsetFromParent
);
106 IntRect borderRect
= pixelSnappedIntRect(paintRect
.x() - leftWidth
/ 2,
107 paintRect
.y() - topWidth
/ 2,
108 paintRect
.width() + leftWidth
/ 2 + (rightWidth
+ 1) / 2,
109 paintRect
.height() + topWidth
/ 2 + (bottomWidth
+ 1) / 2);
111 if (!borderRect
.intersects(paintInfo
.rect
))
114 GraphicsContext
* graphicsContext
= paintInfo
.context
;
115 if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*graphicsContext
, m_layoutTableCell
, static_cast<DisplayItem::Type
>(displayItemType
), paintOffset
))
118 LayoutObjectDrawingRecorder
recorder(*graphicsContext
, m_layoutTableCell
, static_cast<DisplayItem::Type
>(displayItemType
), borderRect
, paintOffset
);
119 Color cellColor
= m_layoutTableCell
.resolveColor(CSSPropertyColor
);
121 // We never paint diagonals at the joins. We simply let the border with the highest
122 // precedence paint on top of borders with lower precedence.
123 if (displayItemType
& DisplayItem::TableCollapsedBorderTop
) {
124 ObjectPainter::drawLineForBoxSide(graphicsContext
, borderRect
.x(), borderRect
.y(), borderRect
.maxX(), borderRect
.y() + topWidth
, BSTop
,
125 topBorderValue
.color().resolve(cellColor
), collapsedBorderStyle(topBorderValue
.style()), 0, 0, true);
127 if (displayItemType
& DisplayItem::TableCollapsedBorderBottom
) {
128 ObjectPainter::drawLineForBoxSide(graphicsContext
, borderRect
.x(), borderRect
.maxY() - bottomWidth
, borderRect
.maxX(), borderRect
.maxY(), BSBottom
,
129 bottomBorderValue
.color().resolve(cellColor
), collapsedBorderStyle(bottomBorderValue
.style()), 0, 0, true);
131 if (displayItemType
& DisplayItem::TableCollapsedBorderLeft
) {
132 ObjectPainter::drawLineForBoxSide(graphicsContext
, borderRect
.x(), borderRect
.y(), borderRect
.x() + leftWidth
, borderRect
.maxY(), BSLeft
,
133 leftBorderValue
.color().resolve(cellColor
), collapsedBorderStyle(leftBorderValue
.style()), 0, 0, true);
135 if (displayItemType
& DisplayItem::TableCollapsedBorderRight
) {
136 ObjectPainter::drawLineForBoxSide(graphicsContext
, borderRect
.maxX() - rightWidth
, borderRect
.y(), borderRect
.maxX(), borderRect
.maxY(), BSRight
,
137 rightBorderValue
.color().resolve(cellColor
), collapsedBorderStyle(rightBorderValue
.style()), 0, 0, true);
141 void TableCellPainter::paintBackgroundsBehindCell(const PaintInfo
& paintInfo
, const LayoutPoint
& paintOffset
, LayoutObject
* backgroundObject
)
143 if (!paintInfo
.shouldPaintWithinRoot(&m_layoutTableCell
))
146 if (!backgroundObject
)
149 if (m_layoutTableCell
.style()->visibility() != VISIBLE
)
152 LayoutTable
* tableElt
= m_layoutTableCell
.table();
153 if (!tableElt
->collapseBorders() && m_layoutTableCell
.style()->emptyCells() == HIDE
&& !m_layoutTableCell
.firstChild())
156 Color c
= backgroundObject
->resolveColor(CSSPropertyBackgroundColor
);
157 const FillLayer
& bgLayer
= backgroundObject
->style()->backgroundLayers();
159 LayoutRect paintRect
= paintBounds(paintOffset
, backgroundObject
!= &m_layoutTableCell
? AddOffsetFromParent
: DoNotAddOffsetFromParent
);
161 if (bgLayer
.hasImage() || c
.alpha()) {
162 // We have to clip here because the background would paint
163 // on top of the borders otherwise. This only matters for cells and rows.
164 bool shouldClip
= backgroundObject
->hasLayer() && (backgroundObject
== &m_layoutTableCell
|| backgroundObject
== m_layoutTableCell
.parent()) && tableElt
->collapseBorders();
165 GraphicsContextStateSaver
stateSaver(*paintInfo
.context
, shouldClip
);
167 LayoutRect
clipRect(paintRect
.location(), m_layoutTableCell
.size());
168 clipRect
.expand(m_layoutTableCell
.borderInsets());
169 paintInfo
.context
->clip(pixelSnappedIntRect(clipRect
));
171 BoxPainter(m_layoutTableCell
).paintFillLayers(paintInfo
, c
, bgLayer
, paintRect
, BackgroundBleedNone
, SkXfermode::kSrcOver_Mode
, backgroundObject
);
175 void TableCellPainter::paintBoxDecorationBackground(const PaintInfo
& paintInfo
, const LayoutPoint
& paintOffset
)
177 if (!paintInfo
.shouldPaintWithinRoot(&m_layoutTableCell
))
180 LayoutTable
* table
= m_layoutTableCell
.table();
181 if (!table
->collapseBorders() && m_layoutTableCell
.style()->emptyCells() == HIDE
&& !m_layoutTableCell
.firstChild())
184 bool needsToPaintBorder
= m_layoutTableCell
.styleRef().hasBorderDecoration() && !table
->collapseBorders();
185 if (!m_layoutTableCell
.hasBackground() && !m_layoutTableCell
.styleRef().boxShadow() && !needsToPaintBorder
)
188 if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*paintInfo
.context
, m_layoutTableCell
, DisplayItem::BoxDecorationBackground
, paintOffset
))
191 LayoutRect visualOverflowRect
= m_layoutTableCell
.visualOverflowRect();
192 visualOverflowRect
.moveBy(paintOffset
);
193 // TODO(chrishtr): the pixel-snapping here is likely incorrect.
194 LayoutObjectDrawingRecorder
recorder(*paintInfo
.context
, m_layoutTableCell
, DisplayItem::BoxDecorationBackground
, pixelSnappedIntRect(visualOverflowRect
), paintOffset
);
196 LayoutRect paintRect
= paintBounds(paintOffset
, DoNotAddOffsetFromParent
);
198 BoxPainter::paintBoxShadow(paintInfo
, paintRect
, m_layoutTableCell
.styleRef(), Normal
);
200 // Paint our cell background.
201 paintBackgroundsBehindCell(paintInfo
, paintOffset
, &m_layoutTableCell
);
203 BoxPainter::paintBoxShadow(paintInfo
, paintRect
, m_layoutTableCell
.styleRef(), Inset
);
205 if (!needsToPaintBorder
)
208 BoxPainter::paintBorder(m_layoutTableCell
, paintInfo
, paintRect
, m_layoutTableCell
.styleRef());
211 void TableCellPainter::paintMask(const PaintInfo
& paintInfo
, const LayoutPoint
& paintOffset
)
213 if (m_layoutTableCell
.style()->visibility() != VISIBLE
|| paintInfo
.phase
!= PaintPhaseMask
)
216 LayoutTable
* tableElt
= m_layoutTableCell
.table();
217 if (!tableElt
->collapseBorders() && m_layoutTableCell
.style()->emptyCells() == HIDE
&& !m_layoutTableCell
.firstChild())
220 if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*paintInfo
.context
, m_layoutTableCell
, paintInfo
.phase
, paintOffset
))
223 LayoutRect paintRect
= paintBounds(paintOffset
, DoNotAddOffsetFromParent
);
224 LayoutObjectDrawingRecorder
recorder(*paintInfo
.context
, m_layoutTableCell
, paintInfo
.phase
, paintRect
, paintOffset
);
225 BoxPainter(m_layoutTableCell
).paintMaskImages(paintInfo
, paintRect
);
228 LayoutRect
TableCellPainter::paintBounds(const LayoutPoint
& paintOffset
, PaintBoundOffsetBehavior paintBoundOffsetBehavior
)
230 LayoutPoint adjustedPaintOffset
= paintOffset
;
231 if (paintBoundOffsetBehavior
== AddOffsetFromParent
)
232 adjustedPaintOffset
.moveBy(m_layoutTableCell
.location());
233 return LayoutRect(adjustedPaintOffset
, LayoutSize(m_layoutTableCell
.pixelSnappedSize()));