void TableCellPainter::paintBoxDecorationBackground(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { LayoutTable* table = m_layoutTableCell.table(); if (!table->collapseBorders() && m_layoutTableCell.style()->emptyCells() == EmptyCellsHide && !m_layoutTableCell.firstChild()) return; bool needsToPaintBorder = m_layoutTableCell.styleRef().hasBorderDecoration() && !table->collapseBorders(); if (!m_layoutTableCell.hasBackground() && !m_layoutTableCell.styleRef().boxShadow() && !needsToPaintBorder) return; if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(paintInfo.context, m_layoutTableCell, DisplayItem::BoxDecorationBackground)) return; LayoutRect visualOverflowRect = m_layoutTableCell.visualOverflowRect(); visualOverflowRect.moveBy(paintOffset); // TODO(chrishtr): the pixel-snapping here is likely incorrect. LayoutObjectDrawingRecorder recorder(paintInfo.context, m_layoutTableCell, DisplayItem::BoxDecorationBackground, pixelSnappedIntRect(visualOverflowRect)); LayoutRect paintRect = paintBounds(paintOffset, DoNotAddOffsetFromParent); BoxPainter::paintBoxShadow(paintInfo, paintRect, m_layoutTableCell.styleRef(), Normal); // Paint our cell background. paintBackgroundsBehindCell(paintInfo, paintOffset, &m_layoutTableCell, DisplayItem::BoxDecorationBackground); BoxPainter::paintBoxShadow(paintInfo, paintRect, m_layoutTableCell.styleRef(), Inset); if (!needsToPaintBorder) return; BoxPainter::paintBorder(m_layoutTableCell, paintInfo, paintRect, m_layoutTableCell.styleRef()); }
void TableCellPainter::paintBoxDecorationBackground(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (!paintInfo.shouldPaintWithinRoot(&m_layoutTableCell)) return; LayoutTable* table = m_layoutTableCell.table(); if (!table->collapseBorders() && m_layoutTableCell.style()->emptyCells() == HIDE && !m_layoutTableCell.firstChild()) return; bool needsToPaintBorder = m_layoutTableCell.styleRef().hasBorder() && !table->collapseBorders(); if (!m_layoutTableCell.hasBackground() && !m_layoutTableCell.styleRef().boxShadow() && !needsToPaintBorder) return; LayoutRect paintRect = paintBounds(paintOffset, DoNotAddOffsetFromParent); LayoutObjectDrawingRecorder recorder(*paintInfo.context, m_layoutTableCell, DisplayItem::BoxDecorationBackground, pixelSnappedIntRect(paintRect)); if (recorder.canUseCachedDrawing()) return; BoxPainter::paintBoxShadow(paintInfo, paintRect, m_layoutTableCell.styleRef(), Normal); // Paint our cell background. paintBackgroundsBehindCell(paintInfo, paintOffset, &m_layoutTableCell); BoxPainter::paintBoxShadow(paintInfo, paintRect, m_layoutTableCell.styleRef(), Inset); if (!needsToPaintBorder) return; BoxPainter::paintBorder(m_layoutTableCell, paintInfo, paintRect, m_layoutTableCell.styleRef()); }
void TableCellPainter::paintBackgroundsBehindCell(const PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutObject* backgroundObject) { if (!paintInfo.shouldPaintWithinRoot(&m_layoutTableCell)) return; if (!backgroundObject) return; if (m_layoutTableCell.style()->visibility() != VISIBLE) return; LayoutTable* tableElt = m_layoutTableCell.table(); if (!tableElt->collapseBorders() && m_layoutTableCell.style()->emptyCells() == HIDE && !m_layoutTableCell.firstChild()) return; Color c = backgroundObject->resolveColor(CSSPropertyBackgroundColor); const FillLayer& bgLayer = backgroundObject->style()->backgroundLayers(); LayoutRect paintRect = paintBounds(paintOffset, backgroundObject != &m_layoutTableCell ? AddOffsetFromParent : DoNotAddOffsetFromParent); if (bgLayer.hasImage() || c.alpha()) { // We have to clip here because the background would paint // on top of the borders otherwise. This only matters for cells and rows. bool shouldClip = backgroundObject->hasLayer() && (backgroundObject == &m_layoutTableCell || backgroundObject == m_layoutTableCell.parent()) && tableElt->collapseBorders(); GraphicsContextStateSaver stateSaver(*paintInfo.context, shouldClip); if (shouldClip) { LayoutRect clipRect(paintRect.location(), m_layoutTableCell.size()); clipRect.expand(m_layoutTableCell.borderInsets()); paintInfo.context->clip(clipRect); } BoxPainter(m_layoutTableCell).paintFillLayers(paintInfo, c, bgLayer, paintRect, BackgroundBleedNone, SkXfermode::kSrcOver_Mode, backgroundObject); } }
void TableCellPainter::paintBoxDecorationBackground(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (!paintInfo.shouldPaintWithinRoot(&m_renderTableCell)) return; RenderTable* tableElt = m_renderTableCell.table(); if (!tableElt->collapseBorders() && m_renderTableCell.style()->emptyCells() == HIDE && !m_renderTableCell.firstChild()) return; LayoutRect paintRect = paintBounds(paintOffset, DoNotAddOffsetFromParent); RenderDrawingRecorder recorder(paintInfo.context, m_renderTableCell, paintInfo.phase, pixelSnappedIntRect(paintRect)); if (recorder.canUseCachedDrawing()) return; BoxPainter::paintBoxShadow(paintInfo, paintRect, m_renderTableCell.style(), Normal); // Paint our cell background. paintBackgroundsBehindCell(paintInfo, paintOffset, &m_renderTableCell); BoxPainter::paintBoxShadow(paintInfo, paintRect, m_renderTableCell.style(), Inset); if (!m_renderTableCell.style()->hasBorder() || tableElt->collapseBorders()) return; BoxPainter::paintBorder(m_renderTableCell, paintInfo, paintRect, m_renderTableCell.style()); }
void TableCellPainter::paintMask(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (m_layoutTableCell.style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask) return; LayoutTable* tableElt = m_layoutTableCell.table(); if (!tableElt->collapseBorders() && m_layoutTableCell.style()->emptyCells() == HIDE && !m_layoutTableCell.firstChild()) return; BoxPainter(m_layoutTableCell).paintMaskImages(paintInfo, paintBounds(paintOffset, DoNotAddOffsetFromParent)); }
void TableCellPainter::paintMask(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (m_layoutTableCell.style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask) return; LayoutTable* tableElt = m_layoutTableCell.table(); if (!tableElt->collapseBorders() && m_layoutTableCell.style()->emptyCells() == EmptyCellsHide && !m_layoutTableCell.firstChild()) return; if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(paintInfo.context, m_layoutTableCell, paintInfo.phase)) return; LayoutRect paintRect = paintBounds(paintOffset, DoNotAddOffsetFromParent); LayoutObjectDrawingRecorder recorder(paintInfo.context, m_layoutTableCell, paintInfo.phase, paintRect); BoxPainter(m_layoutTableCell).paintMaskImages(paintInfo, paintRect); }
void TableCellPainter::paintBackgroundsBehindCell(const PaintInfo& paintInfo, const LayoutPoint& paintOffset, const LayoutObject* backgroundObject, DisplayItem::Type type) { if (!paintInfo.shouldPaintWithinRoot(&m_layoutTableCell)) return; if (!backgroundObject) return; if (m_layoutTableCell.style()->visibility() != VISIBLE) return; LayoutTable* tableElt = m_layoutTableCell.table(); if (!tableElt->collapseBorders() && m_layoutTableCell.style()->emptyCells() == HIDE && !m_layoutTableCell.firstChild()) return; LayoutRect paintRect = paintBounds(paintOffset, backgroundObject != &m_layoutTableCell ? AddOffsetFromParent : DoNotAddOffsetFromParent); // Record drawing only if the cell is painting background from containers. Optional<LayoutObjectDrawingRecorder> recorder; if (backgroundObject != &m_layoutTableCell) { LayoutPoint adjustedPaintOffset = paintRect.location(); if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*paintInfo.context, m_layoutTableCell, type, adjustedPaintOffset)) return; recorder.emplace(*paintInfo.context, m_layoutTableCell, type, paintRect, adjustedPaintOffset); } else { ASSERT(paintRect.location() == paintOffset); } Color c = backgroundObject->resolveColor(CSSPropertyBackgroundColor); const FillLayer& bgLayer = backgroundObject->style()->backgroundLayers(); if (bgLayer.hasImage() || c.alpha()) { // We have to clip here because the background would paint // on top of the borders otherwise. This only matters for cells and rows. bool shouldClip = backgroundObject->hasLayer() && (backgroundObject == &m_layoutTableCell || backgroundObject == m_layoutTableCell.parent()) && tableElt->collapseBorders(); GraphicsContextStateSaver stateSaver(*paintInfo.context, shouldClip); if (shouldClip) { LayoutRect clipRect(paintRect.location(), m_layoutTableCell.size()); clipRect.expand(m_layoutTableCell.borderInsets()); paintInfo.context->clip(pixelSnappedIntRect(clipRect)); } BoxPainter(m_layoutTableCell).paintFillLayers(paintInfo, c, bgLayer, paintRect, BackgroundBleedNone, SkXfermode::kSrcOver_Mode, backgroundObject); } }
void TableCellPainter::paintCollapsedBorders(const PaintInfo& paintInfo, const LayoutPoint& paintOffset, const CollapsedBorderValue& currentBorderValue) { if (m_layoutTableCell.style()->visibility() != VISIBLE) return; const ComputedStyle& styleForCellFlow = m_layoutTableCell.styleForCellFlow(); const CollapsedBorderValue* leftBorderValue = cachedCollapsedLeftBorder(styleForCellFlow); const CollapsedBorderValue* rightBorderValue = cachedCollapsedRightBorder(styleForCellFlow); const CollapsedBorderValue* topBorderValue = cachedCollapsedTopBorder(styleForCellFlow); const CollapsedBorderValue* bottomBorderValue = cachedCollapsedBottomBorder(styleForCellFlow); int displayItemType = DisplayItem::TableCollapsedBorderBase; int topWidth = 0; int bottomWidth = 0; int leftWidth = 0; int rightWidth = 0; if (topBorderValue) { if (topBorderValue->shouldPaint(currentBorderValue)) displayItemType |= DisplayItem::TableCollapsedBorderTop; topWidth = topBorderValue->width(); } if (bottomBorderValue) { if (bottomBorderValue->shouldPaint(currentBorderValue)) displayItemType |= DisplayItem::TableCollapsedBorderBottom; bottomWidth = bottomBorderValue->width(); } if (leftBorderValue) { if (leftBorderValue->shouldPaint(currentBorderValue)) displayItemType |= DisplayItem::TableCollapsedBorderLeft; leftWidth = leftBorderValue->width(); } if (rightBorderValue) { if (rightBorderValue->shouldPaint(currentBorderValue)) displayItemType |= DisplayItem::TableCollapsedBorderRight; rightWidth = rightBorderValue->width(); } if (displayItemType == DisplayItem::TableCollapsedBorderBase) return; // Adjust our x/y/width/height so that we paint the collapsed borders at the correct location. LayoutRect paintRect = paintBounds(paintOffset, AddOffsetFromParent); 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); if (!paintInfo.cullRect().intersectsCullRect(borderRect)) return; GraphicsContext& graphicsContext = paintInfo.context; if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(graphicsContext, m_layoutTableCell, static_cast<DisplayItem::Type>(displayItemType))) return; LayoutObjectDrawingRecorder recorder(graphicsContext, m_layoutTableCell, static_cast<DisplayItem::Type>(displayItemType), borderRect); Color cellColor = m_layoutTableCell.resolveColor(CSSPropertyColor); // We never paint diagonals at the joins. We simply let the border with the highest // precedence paint on top of borders with lower precedence. if (displayItemType & DisplayItem::TableCollapsedBorderTop) { ObjectPainter::drawLineForBoxSide(graphicsContext, borderRect.x(), borderRect.y(), borderRect.maxX(), borderRect.y() + topWidth, BSTop, topBorderValue->color().resolve(cellColor), collapsedBorderStyle(topBorderValue->style()), 0, 0, true); } if (displayItemType & DisplayItem::TableCollapsedBorderBottom) { ObjectPainter::drawLineForBoxSide(graphicsContext, borderRect.x(), borderRect.maxY() - bottomWidth, borderRect.maxX(), borderRect.maxY(), BSBottom, bottomBorderValue->color().resolve(cellColor), collapsedBorderStyle(bottomBorderValue->style()), 0, 0, true); } if (displayItemType & DisplayItem::TableCollapsedBorderLeft) { ObjectPainter::drawLineForBoxSide(graphicsContext, borderRect.x(), borderRect.y(), borderRect.x() + leftWidth, borderRect.maxY(), BSLeft, leftBorderValue->color().resolve(cellColor), collapsedBorderStyle(leftBorderValue->style()), 0, 0, true); } if (displayItemType & DisplayItem::TableCollapsedBorderRight) { ObjectPainter::drawLineForBoxSide(graphicsContext, borderRect.maxX() - rightWidth, borderRect.y(), borderRect.maxX(), borderRect.maxY(), BSRight, rightBorderValue->color().resolve(cellColor), collapsedBorderStyle(rightBorderValue->style()), 0, 0, true); } }
void TableCellPainter::paintCollapsedBorders(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { ASSERT(paintInfo.phase == PaintPhaseCollapsedTableBorders); if (!paintInfo.shouldPaintWithinRoot(&m_layoutTableCell) || m_layoutTableCell.style()->visibility() != VISIBLE) return; LayoutRect paintRect = paintBounds(paintOffset, AddOffsetFromParent); LayoutRect drawingCullRect(paintRect); drawingCullRect.expandEdges(m_layoutTableCell.table()->outerBorderTop(), m_layoutTableCell.table()->outerBorderRight(), m_layoutTableCell.table()->outerBorderBottom(), m_layoutTableCell.table()->outerBorderLeft()); if (drawingCullRect.y() >= paintInfo.rect.maxY()) return; if (drawingCullRect.maxY() <= paintInfo.rect.y()) return; const CollapsedBorderValue* tableCurrentBorderValue = m_layoutTableCell.table()->currentBorderValue(); if (!tableCurrentBorderValue) return; const ComputedStyle& styleForCellFlow = m_layoutTableCell.styleForCellFlow(); const CollapsedBorderValue& leftBorderValue = cachedCollapsedLeftBorder(styleForCellFlow); const CollapsedBorderValue& rightBorderValue = cachedCollapsedRightBorder(styleForCellFlow); const CollapsedBorderValue& topBorderValue = cachedCollapsedTopBorder(styleForCellFlow); const CollapsedBorderValue& bottomBorderValue = cachedCollapsedBottomBorder(styleForCellFlow); bool shouldPaintTop = topBorderValue.shouldPaint(*tableCurrentBorderValue); bool shouldPaintBottom = bottomBorderValue.shouldPaint(*tableCurrentBorderValue); bool shouldPaintLeft = leftBorderValue.shouldPaint(*tableCurrentBorderValue); bool shouldPaintRight = rightBorderValue.shouldPaint(*tableCurrentBorderValue); if (!shouldPaintTop && !shouldPaintBottom && !shouldPaintLeft && !shouldPaintRight) return; GraphicsContext* graphicsContext = paintInfo.context; LayoutObjectDrawingRecorder recorder(*graphicsContext, m_layoutTableCell, paintInfo.phase, drawingCullRect); if (recorder.canUseCachedDrawing()) return; bool antialias = BoxPainter::shouldAntialiasLines(graphicsContext); // Adjust our x/y/width/height so that we paint the collapsed borders at the correct location. int topWidth = topBorderValue.width(); int bottomWidth = bottomBorderValue.width(); int leftWidth = leftBorderValue.width(); int rightWidth = rightBorderValue.width(); 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); Color cellColor = m_layoutTableCell.resolveColor(CSSPropertyColor); // We never paint diagonals at the joins. We simply let the border with the highest // precedence paint on top of borders with lower precedence. if (shouldPaintTop) { ObjectPainter::drawLineForBoxSide(graphicsContext, borderRect.x(), borderRect.y(), borderRect.maxX(), borderRect.y() + topWidth, BSTop, topBorderValue.color().resolve(cellColor), collapsedBorderStyle(topBorderValue.style()), 0, 0, antialias); } if (shouldPaintBottom) { ObjectPainter::drawLineForBoxSide(graphicsContext, borderRect.x(), borderRect.maxY() - bottomWidth, borderRect.maxX(), borderRect.maxY(), BSBottom, bottomBorderValue.color().resolve(cellColor), collapsedBorderStyle(bottomBorderValue.style()), 0, 0, antialias); } if (shouldPaintLeft) { ObjectPainter::drawLineForBoxSide(graphicsContext, borderRect.x(), borderRect.y(), borderRect.x() + leftWidth, borderRect.maxY(), BSLeft, leftBorderValue.color().resolve(cellColor), collapsedBorderStyle(leftBorderValue.style()), 0, 0, antialias); } if (shouldPaintRight) { ObjectPainter::drawLineForBoxSide(graphicsContext, borderRect.maxX() - rightWidth, borderRect.y(), borderRect.maxX(), borderRect.maxY(), BSRight, rightBorderValue.color().resolve(cellColor), collapsedBorderStyle(rightBorderValue.style()), 0, 0, antialias); } }
void TableCellPainter::paintCollapsedBorders(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { ASSERT(paintInfo.phase == PaintPhaseCollapsedTableBorders); if (!paintInfo.shouldPaintWithinRoot(&m_renderTableCell) || m_renderTableCell.style()->visibility() != VISIBLE) return; LayoutRect paintRect = paintBounds(paintOffset, AddOffsetFromParent); if (paintRect.y() - m_renderTableCell.table()->outerBorderTop() >= paintInfo.rect.maxY()) return; if (paintRect.maxY() + m_renderTableCell.table()->outerBorderBottom() <= paintInfo.rect.y()) return; if (!m_renderTableCell.table()->currentBorderValue()) return; RenderDrawingRecorder recorder(paintInfo.context, m_renderTableCell, paintInfo.phase, paintRect); if (recorder.canUseCachedDrawing()) return; const RenderStyle* styleForCellFlow = m_renderTableCell.styleForCellFlow(); CollapsedBorderValue leftVal = cachedCollapsedLeftBorder(styleForCellFlow); CollapsedBorderValue rightVal = cachedCollapsedRightBorder(styleForCellFlow); CollapsedBorderValue topVal = cachedCollapsedTopBorder(styleForCellFlow); CollapsedBorderValue bottomVal = cachedCollapsedBottomBorder(styleForCellFlow); // Adjust our x/y/width/height so that we paint the collapsed borders at the correct location. int topWidth = topVal.width(); int bottomWidth = bottomVal.width(); int leftWidth = leftVal.width(); int rightWidth = rightVal.width(); 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); 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 renderBottom = bottomStyle > BHIDDEN && !bottomVal.isTransparent(); bool renderLeft = leftStyle > BHIDDEN && !leftVal.isTransparent(); bool renderRight = rightStyle > BHIDDEN && !rightVal.isTransparent(); // 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); GraphicsContext* graphicsContext = paintInfo.context; bool antialias = BoxPainter::shouldAntialiasLines(graphicsContext); for (CollapsedBorder* border = borders.nextBorder(); border; border = borders.nextBorder()) { if (border->borderValue.isSameIgnoringColor(*m_renderTableCell.table()->currentBorderValue())) { ObjectPainter::drawLineForBoxSide(graphicsContext, border->x1, border->y1, border->x2, border->y2, border->side, border->borderValue.color().resolve(m_renderTableCell.resolveColor(CSSPropertyColor)), border->style, 0, 0, antialias); } } }