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 InlineFlowBoxPainter::paintBoxDecorationBackground(const PaintInfo& paintInfo, const LayoutPoint& paintOffset, const LayoutRect& cullRect) { ASSERT(paintInfo.phase == PaintPhaseForeground); if (!paintInfo.shouldPaintWithinRoot(&m_inlineFlowBox.layoutObject()) || m_inlineFlowBox.layoutObject().style()->visibility() != VISIBLE) return; // You can use p::first-line to specify a background. If so, the root line boxes for // a line may actually have to paint a background. const ComputedStyle* styleToUse = m_inlineFlowBox.layoutObject().style(m_inlineFlowBox.isFirstLineStyle()); bool shouldPaintBoxDecorationBackground; if (m_inlineFlowBox.parent()) shouldPaintBoxDecorationBackground = m_inlineFlowBox.layoutObject().hasBoxDecorationBackground(); else shouldPaintBoxDecorationBackground = m_inlineFlowBox.isFirstLineStyle() && styleToUse != m_inlineFlowBox.layoutObject().style(); if (!shouldPaintBoxDecorationBackground) return; if (DrawingRecorder::useCachedDrawingIfPossible(*paintInfo.context, m_inlineFlowBox, DisplayItem::BoxDecorationBackground)) return; DrawingRecorder recorder(*paintInfo.context, m_inlineFlowBox, DisplayItem::BoxDecorationBackground, pixelSnappedIntRect(cullRect)); LayoutRect frameRect = roundedFrameRectClampedToLineTopAndBottomIfNeeded(); // Move x/y to our coordinates. LayoutRect localRect(frameRect); m_inlineFlowBox.flipForWritingMode(localRect); LayoutPoint adjustedPaintOffset = paintOffset + localRect.location(); LayoutRect adjustedFrameRect = LayoutRect(adjustedPaintOffset, frameRect.size()); LayoutRect adjustedClipRect; BorderPaintingType borderPaintingType = getBorderPaintType(adjustedFrameRect, adjustedClipRect); // Shadow comes first and is behind the background and border. if (!m_inlineFlowBox.deprecatedBoxModelObject()->boxShadowShouldBeAppliedToBackground(BackgroundBleedNone, &m_inlineFlowBox)) paintBoxShadow(paintInfo, *styleToUse, Normal, adjustedFrameRect); Color backgroundColor = m_inlineFlowBox.layoutObject().resolveColor(*styleToUse, CSSPropertyBackgroundColor); paintFillLayers(paintInfo, backgroundColor, styleToUse->backgroundLayers(), adjustedFrameRect); paintBoxShadow(paintInfo, *styleToUse, Inset, adjustedFrameRect); switch (borderPaintingType) { case DontPaintBorders: break; case PaintBordersWithoutClip: BoxPainter::paintBorder(*m_inlineFlowBox.deprecatedBoxModelObject(), paintInfo, adjustedFrameRect, m_inlineFlowBox.layoutObject().styleRef(m_inlineFlowBox.isFirstLineStyle()), BackgroundBleedNone, m_inlineFlowBox.includeLogicalLeftEdge(), m_inlineFlowBox.includeLogicalRightEdge()); break; case PaintBordersWithClip: // FIXME: What the heck do we do with RTL here? The math we're using is obviously not right, // but it isn't even clear how this should work at all. LayoutRect imageStripPaintRect = paintRectForImageStrip(adjustedPaintOffset, frameRect.size(), LTR); GraphicsContextStateSaver stateSaver(*paintInfo.context); paintInfo.context->clip(adjustedClipRect); BoxPainter::paintBorder(*m_inlineFlowBox.deprecatedBoxModelObject(), paintInfo, imageStripPaintRect, m_inlineFlowBox.layoutObject().styleRef(m_inlineFlowBox.isFirstLineStyle())); break; } }
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::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().hasBorderDecoration() && !table->collapseBorders(); if (!m_layoutTableCell.hasBackground() && !m_layoutTableCell.styleRef().boxShadow() && !needsToPaintBorder) return; if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*paintInfo.context, m_layoutTableCell, DisplayItem::BoxDecorationBackground, paintOffset)) 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), paintOffset); 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 RenderReplaced::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (!shouldPaint(paintInfo, paintOffset)) return; LayoutPoint adjustedPaintOffset = paintOffset + location(); if (hasBoxDecorations() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)) paintBoxDecorations(paintInfo, adjustedPaintOffset); if (paintInfo.phase == PaintPhaseMask) { paintMask(paintInfo, adjustedPaintOffset); return; } LayoutRect paintRect = LayoutRect(adjustedPaintOffset, size()); if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth()) paintOutline(paintInfo.context, paintRect); if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection && !canHaveChildren()) return; if (!paintInfo.shouldPaintWithinRoot(this)) return; bool drawSelectionTint = selectionState() != SelectionNone && !document()->printing(); if (paintInfo.phase == PaintPhaseSelection) { if (selectionState() == SelectionNone) return; drawSelectionTint = false; } bool completelyClippedOut = false; if (style()->hasBorderRadius()) { LayoutRect borderRect = LayoutRect(adjustedPaintOffset, size()); if (borderRect.isEmpty()) completelyClippedOut = true; else { // Push a clip if we have a border radius, since we want to round the foreground content that gets painted. paintInfo.context->save(); paintInfo.context->addRoundedRectClip(style()->getRoundedBorderFor(paintRect, view())); } } if (!completelyClippedOut) { paintReplaced(paintInfo, adjustedPaintOffset); if (style()->hasBorderRadius()) paintInfo.context->restore(); } // The selection tint never gets clipped by border-radius rounding, since we want it to run right up to the edges of // surrounding content. if (drawSelectionTint) { LayoutRect selectionPaintingRect = localSelectionRect(); selectionPaintingRect.moveBy(adjustedPaintOffset); paintInfo.context->fillRect(pixelSnappedIntRect(selectionPaintingRect), selectionBackgroundColor(), style()->colorSpace()); } }
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 SVGInlineTextBox::paintSelectionBackground(PaintInfo& paintInfo) { ASSERT(paintInfo.shouldPaintWithinRoot(renderer())); ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection); ASSERT(truncation() == cNoTruncation); if (renderer()->style()->visibility() != VISIBLE) return; RenderObject* parentRenderer = parent()->renderer(); ASSERT(parentRenderer); ASSERT(!parentRenderer->document().printing()); // Determine whether or not we're selected. bool paintSelectedTextOnly = paintInfo.phase == PaintPhaseSelection; bool hasSelection = selectionState() != RenderObject::SelectionNone; if (!hasSelection || paintSelectedTextOnly) return; Color backgroundColor = renderer()->selectionBackgroundColor(); if (!backgroundColor.alpha()) return; RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); ASSERT(textRenderer); if (!textShouldBePainted(textRenderer)) return; RenderStyle* style = parentRenderer->style(); ASSERT(style); int startPosition, endPosition; selectionStartEnd(startPosition, endPosition); int fragmentStartPosition = 0; int fragmentEndPosition = 0; AffineTransform fragmentTransform; unsigned textFragmentsSize = m_textFragments.size(); for (unsigned i = 0; i < textFragmentsSize; ++i) { SVGTextFragment& fragment = m_textFragments.at(i); ASSERT(!m_paintingResource); fragmentStartPosition = startPosition; fragmentEndPosition = endPosition; if (!mapStartEndPositionsIntoFragmentCoordinates(fragment, fragmentStartPosition, fragmentEndPosition)) continue; GraphicsContextStateSaver stateSaver(*paintInfo.context); fragment.buildFragmentTransform(fragmentTransform); if (!fragmentTransform.isIdentity()) paintInfo.context->concatCTM(fragmentTransform); paintInfo.context->setFillColor(backgroundColor); paintInfo.context->fillRect(selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, style), backgroundColor); m_paintingResourceMode = ApplyToDefaultMode; } ASSERT(!m_paintingResource); }
void RenderReplaced::paint(PaintInfo& paintInfo, int tx, int ty) { if (!shouldPaint(paintInfo, tx, ty)) return; tx += x(); ty += y(); if (hasBoxDecorations() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)) paintBoxDecorations(paintInfo, tx, ty); if (paintInfo.phase == PaintPhaseMask) { paintMask(paintInfo, tx, ty); return; } if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth()) paintOutline(paintInfo.context, tx, ty, width(), height()); if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection) return; if (!paintInfo.shouldPaintWithinRoot(this)) return; bool drawSelectionTint = selectionState() != SelectionNone && !document()->printing(); if (paintInfo.phase == PaintPhaseSelection) { if (selectionState() == SelectionNone) return; drawSelectionTint = false; } bool completelyClippedOut = false; if (style()->hasBorderRadius()) { IntRect borderRect = IntRect(tx, ty, width(), height()); if (borderRect.isEmpty()) completelyClippedOut = true; else { // Push a clip if we have a border radius, since we want to round the foreground content that gets painted. paintInfo.context->save(); paintInfo.context->addRoundedRectClip(style()->getRoundedBorderFor(borderRect)); } } if (!completelyClippedOut) { paintReplaced(paintInfo, tx, ty); if (style()->hasBorderRadius()) paintInfo.context->restore(); } // The selection tint never gets clipped by border-radius rounding, since we want it to run right up to the edges of // surrounding content. if (drawSelectionTint) { IntRect selectionPaintingRect = localSelectionRect(); selectionPaintingRect.move(tx, ty); paintInfo.context->fillRect(selectionPaintingRect, selectionBackgroundColor(), style()->colorSpace()); } }
void SVGInlineTextBoxPainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { ASSERT(paintInfo.shouldPaintWithinRoot(&m_svgInlineTextBox.layoutObject())); ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection); ASSERT(m_svgInlineTextBox.truncation() == cNoTruncation); if (m_svgInlineTextBox.layoutObject().style()->visibility() != VISIBLE) return; // We're explicitly not supporting composition & custom underlines and custom highlighters -- unlike InlineTextBox. // If we ever need that for SVG, it's very easy to refactor and reuse the code. if (paintInfo.phase == PaintPhaseSelection && !shouldPaintSelection()) return; LayoutSVGInlineText& textLayoutObject = toLayoutSVGInlineText(m_svgInlineTextBox.layoutObject()); if (!textShouldBePainted(textLayoutObject)) return; DisplayItem::Type displayItemType = DisplayItem::paintPhaseToDrawingType(paintInfo.phase); if (!DrawingRecorder::useCachedDrawingIfPossible(*paintInfo.context, m_svgInlineTextBox, displayItemType)) { LayoutObject& parentLayoutObject = m_svgInlineTextBox.parent()->layoutObject(); const ComputedStyle& style = parentLayoutObject.styleRef(); DrawingRecorder recorder(*paintInfo.context, m_svgInlineTextBox, displayItemType, paintInfo.rect); InlineTextBoxPainter(m_svgInlineTextBox).paintDocumentMarkers( paintInfo.context, paintOffset, style, textLayoutObject.scaledFont(), true); if (!m_svgInlineTextBox.textFragments().isEmpty()) paintTextFragments(paintInfo, parentLayoutObject); } }
bool RenderReplaced::shouldPaint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseOutline && paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseMask) return false; if (!paintInfo.shouldPaintWithinRoot(this)) return false; // if we're invisible or haven't received a layout yet, then just bail. if (style()->visibility() != VISIBLE) return false; LayoutPoint adjustedPaintOffset = paintOffset + location(); // Early exit if the element touches the edges. LayoutUnit top = adjustedPaintOffset.y() + visualOverflowRect().y(); LayoutUnit bottom = adjustedPaintOffset.y() + visualOverflowRect().maxY(); if (isSelected() && m_inlineBoxWrapper) { LayoutUnit selTop = paintOffset.y() + m_inlineBoxWrapper->root()->selectionTop(); LayoutUnit selBottom = paintOffset.y() + selTop + m_inlineBoxWrapper->root()->selectionHeight(); top = min(selTop, top); bottom = max(selBottom, bottom); } LayoutRect localRepaintRect = paintInfo.rect; localRepaintRect.inflate(maximalOutlineSize(paintInfo.phase)); if (adjustedPaintOffset.x() + visualOverflowRect().x() >= localRepaintRect.maxX() || adjustedPaintOffset.x() + visualOverflowRect().maxX() <= localRepaintRect.x()) return false; if (top >= localRepaintRect.maxY() || bottom <= localRepaintRect.y()) return false; return true; }
void InlineBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/) { if (!paintInfo.shouldPaintWithinRoot(renderer()) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection)) return; LayoutPoint childPoint = paintOffset; if (parent()->renderer()->style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock(). childPoint = renderer()->containingBlock()->flipForWritingModeForChild(toRenderBox(renderer()), childPoint); // Paint all phases of replaced elements atomically, as though the replaced element established its // own stacking context. (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1 // specification.) bool preservePhase = paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip; PaintInfo info(paintInfo); info.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground; renderer()->paint(info, childPoint); if (!preservePhase) { info.phase = PaintPhaseChildBlockBackgrounds; renderer()->paint(info, childPoint); info.phase = PaintPhaseFloat; renderer()->paint(info, childPoint); info.phase = PaintPhaseForeground; renderer()->paint(info, childPoint); info.phase = PaintPhaseOutline; renderer()->paint(info, childPoint); } }
bool RenderReplaced::shouldPaint(PaintInfo& paintInfo, int& tx, int& ty) { if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseOutline && paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseMask) return false; if (!paintInfo.shouldPaintWithinRoot(this)) return false; // if we're invisible or haven't received a layout yet, then just bail. if (style()->visibility() != VISIBLE) return false; int currentTX = tx + x(); int currentTY = ty + y(); // Early exit if the element touches the edges. int top = currentTY + minYVisualOverflow(); int bottom = currentTY + maxYVisualOverflow(); if (isSelected() && m_inlineBoxWrapper) { int selTop = ty + m_inlineBoxWrapper->root()->selectionTop(); int selBottom = ty + selTop + m_inlineBoxWrapper->root()->selectionHeight(); top = min(selTop, top); bottom = max(selBottom, bottom); } int os = 2 * maximalOutlineSize(paintInfo.phase); if (currentTX + minXVisualOverflow() >= paintInfo.rect.maxX() + os || currentTX + maxXVisualOverflow() <= paintInfo.rect.x() - os) return false; if (top >= paintInfo.rect.maxY() + os || bottom <= paintInfo.rect.y() - os) return false; return true; }
void InlineBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/) { if (!paintInfo.shouldPaintWithinRoot(&renderer()) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection)) return; LayoutPoint childPoint = paintOffset; RenderBlock::paintAsInlineBlock(&renderer(), paintInfo, childPoint); }
void TablePainter::paintBoxDecorationBackground(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (!paintInfo.shouldPaintWithinRoot(&m_layoutTable)) return; LayoutRect rect(paintOffset, m_layoutTable.size()); m_layoutTable.subtractCaptionRect(rect); BoxPainter(m_layoutTable).paintBoxDecorationBackgroundWithRect(paintInfo, paintOffset, rect); }
void FieldsetPainter::paintBoxDecorationBackground(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (!paintInfo.shouldPaintWithinRoot(&m_renderFieldset)) return; LayoutRect paintRect(paintOffset, m_renderFieldset.size()); RenderBox* legend = m_renderFieldset.findLegend(); if (!legend) return BoxPainter(m_renderFieldset).paintBoxDecorationBackground(paintInfo, paintOffset); // FIXME: We need to work with "rl" and "bt" block flow directions. In those // cases the legend is embedded in the right and bottom borders respectively. // https://bugs.webkit.org/show_bug.cgi?id=47236 if (m_renderFieldset.style()->isHorizontalWritingMode()) { LayoutUnit yOff = (legend->location().y() > 0) ? LayoutUnit() : (legend->size().height() - m_renderFieldset.borderTop()) / 2; paintRect.setHeight(paintRect.height() - yOff); paintRect.setY(paintRect.y() + yOff); } else { LayoutUnit xOff = (legend->location().x() > 0) ? LayoutUnit() : (legend->size().width() - m_renderFieldset.borderLeft()) / 2; paintRect.setWidth(paintRect.width() - xOff); paintRect.setX(paintRect.x() + xOff); } RenderDrawingRecorder recorder(paintInfo.context, m_renderFieldset, paintInfo.phase, pixelSnappedIntRect(paintOffset, paintRect.size())); if (recorder.canUseCachedDrawing()) return; BoxDecorationData boxDecorationData(m_renderFieldset, paintInfo.context); if (boxDecorationData.bleedAvoidance() == BackgroundBleedNone) BoxPainter::paintBoxShadow(paintInfo, paintRect, m_renderFieldset.style(), Normal); BoxPainter(m_renderFieldset).paintFillLayers(paintInfo, boxDecorationData.backgroundColor, m_renderFieldset.style()->backgroundLayers(), paintRect); BoxPainter::paintBoxShadow(paintInfo, paintRect, m_renderFieldset.style(), Inset); if (!boxDecorationData.hasBorder) return; // Create a clipping region around the legend and paint the border as normal GraphicsContext* graphicsContext = paintInfo.context; GraphicsContextStateSaver stateSaver(*graphicsContext); // FIXME: We need to work with "rl" and "bt" block flow directions. In those // cases the legend is embedded in the right and bottom borders respectively. // https://bugs.webkit.org/show_bug.cgi?id=47236 if (m_renderFieldset.style()->isHorizontalWritingMode()) { LayoutUnit clipTop = paintRect.y(); LayoutUnit clipHeight = max(static_cast<LayoutUnit>(m_renderFieldset.style()->borderTopWidth()), legend->size().height() - ((legend->size().height() - m_renderFieldset.borderTop()) / 2)); graphicsContext->clipOut(pixelSnappedIntRect(paintRect.x() + legend->location().x(), clipTop, legend->size().width(), clipHeight)); } else { LayoutUnit clipLeft = paintRect.x(); LayoutUnit clipWidth = max(static_cast<LayoutUnit>(m_renderFieldset.style()->borderLeftWidth()), legend->size().width()); graphicsContext->clipOut(pixelSnappedIntRect(clipLeft, paintRect.y() + legend->location().y(), clipWidth, legend->size().height())); } BoxPainter::paintBorder(m_renderFieldset, paintInfo, paintRect, m_renderFieldset.style()); }
void InlineBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/) { if (!paintInfo.shouldPaintWithinRoot(renderer()) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection)) return; LayoutPoint childPoint = paintOffset; if (parent()->renderer()->style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock(). childPoint = renderer()->containingBlock()->flipForWritingModeForChild(toRenderBox(renderer()), childPoint); RenderBlock::paintAsInlineBlock(renderer(), paintInfo, childPoint); }
void RenderFieldset::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (!paintInfo.shouldPaintWithinRoot(*this)) return; LayoutRect paintRect(paintOffset, size()); RenderBox* legend = findLegend(); if (!legend) return RenderBlockFlow::paintBoxDecorations(paintInfo, paintOffset); // FIXME: We need to work with "rl" and "bt" block flow directions. In those // cases the legend is embedded in the right and bottom borders respectively. // https://bugs.webkit.org/show_bug.cgi?id=47236 if (style().isHorizontalWritingMode()) { LayoutUnit yOff = (legend->y() > 0) ? LayoutUnit() : (legend->height() - borderTop()) / 2; paintRect.setHeight(paintRect.height() - yOff); paintRect.setY(paintRect.y() + yOff); } else { LayoutUnit xOff = (legend->x() > 0) ? LayoutUnit() : (legend->width() - borderLeft()) / 2; paintRect.setWidth(paintRect.width() - xOff); paintRect.setX(paintRect.x() + xOff); } if (!boxShadowShouldBeAppliedToBackground(determineBackgroundBleedAvoidance(paintInfo.context))) paintBoxShadow(paintInfo, paintRect, style(), Normal); paintFillLayers(paintInfo, style().visitedDependentColor(CSSPropertyBackgroundColor), style().backgroundLayers(), paintRect); paintBoxShadow(paintInfo, paintRect, style(), Inset); if (!style().hasBorder()) return; // Create a clipping region around the legend and paint the border as normal GraphicsContext* graphicsContext = paintInfo.context; GraphicsContextStateSaver stateSaver(*graphicsContext); // FIXME: We need to work with "rl" and "bt" block flow directions. In those // cases the legend is embedded in the right and bottom borders respectively. // https://bugs.webkit.org/show_bug.cgi?id=47236 LayoutRect clipRect; if (style().isHorizontalWritingMode()) { clipRect.setX(paintRect.x() + legend->x()); clipRect.setY(paintRect.y()); clipRect.setWidth(legend->width()); clipRect.setHeight(std::max<LayoutUnit>(style().borderTopWidth(), legend->height() - ((legend->height() - borderTop()) / 2))); } else { clipRect.setX(paintRect.x()); clipRect.setY(paintRect.y() + legend->y()); clipRect.setWidth(std::max<LayoutUnit>(style().borderLeftWidth(), legend->width())); clipRect.setHeight(legend->height()); } graphicsContext->clipOut(snapRectToDevicePixels(clipRect, document().deviceScaleFactor())); paintBorder(paintInfo, paintRect, style()); }
void BlockPainter::paintInlineBox(InlineBox& inlineBox, const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (!paintInfo.shouldPaintWithinRoot(&inlineBox.layoutObject()) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection)) return; LayoutPoint childPoint = paintOffset; if (inlineBox.parent()->layoutObject().style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock(). childPoint = inlineBox.layoutObject().containingBlock()->flipForWritingModeForChild(&toLayoutBox(inlineBox.layoutObject()), childPoint); paintAsInlineBlock(inlineBox.layoutObject(), paintInfo, childPoint); }
void RenderFieldset::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) { if (!paintInfo.shouldPaintWithinRoot(this)) return; int w = width(); int h = height(); RenderBox* legend = findLegend(); if (!legend) return RenderBlock::paintBoxDecorations(paintInfo, tx, ty); // FIXME: We need to work with "rl" and "bt" block flow directions. In those // cases the legend is embedded in the right and bottom borders respectively. // https://bugs.webkit.org/show_bug.cgi?id=47236 if (style()->isHorizontalWritingMode()) { int yOff = (legend->y() > 0) ? 0 : (legend->height() - borderTop()) / 2; h -= yOff; ty += yOff; } else { int xOff = (legend->x() > 0) ? 0 : (legend->width() - borderLeft()) / 2; w -= xOff; tx += xOff; } paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Normal); paintFillLayers(paintInfo, style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->backgroundLayers(), tx, ty, w, h); paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Inset); if (!style()->hasBorder()) return; // Create a clipping region around the legend and paint the border as normal GraphicsContext* graphicsContext = paintInfo.context; graphicsContext->save(); // FIXME: We need to work with "rl" and "bt" block flow directions. In those // cases the legend is embedded in the right and bottom borders respectively. // https://bugs.webkit.org/show_bug.cgi?id=47236 if (style()->isHorizontalWritingMode()) { int clipTop = ty; int clipHeight = max(static_cast<int>(style()->borderTopWidth()), legend->height()); graphicsContext->clipOut(IntRect(tx + legend->x(), clipTop, legend->width(), clipHeight)); } else { int clipLeft = tx; int clipWidth = max(static_cast<int>(style()->borderLeftWidth()), legend->width()); graphicsContext->clipOut(IntRect(clipLeft, ty + legend->y(), clipWidth, legend->height())); } paintBorder(paintInfo.context, tx, ty, w, h, style(), true, true); graphicsContext->restore(); }
void RenderView::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // If we ever require layout but receive a paint anyway, something has gone horribly wrong. ASSERT(!needsLayout()); // RenderViews should never be called to paint with an offset not on device pixels. ASSERT(LayoutPoint(IntPoint(paintOffset.x(), paintOffset.y())) == paintOffset); // This avoids painting garbage between columns if there is a column gap. if (frameView().pagination().mode != Pagination::Unpaginated && paintInfo.shouldPaintWithinRoot(*this)) paintInfo.context->fillRect(paintInfo.rect, frameView().baseBackgroundColor(), ColorSpaceDeviceRGB); paintObject(paintInfo, paintOffset); }
void RenderFieldset::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (!paintInfo.shouldPaintWithinRoot(this)) return; LayoutRect paintRect(paintOffset, size()); RenderBox* legend = findLegend(); if (!legend) return RenderBlock::paintBoxDecorations(paintInfo, paintOffset); // FIXME: We need to work with "rl" and "bt" block flow directions. In those // cases the legend is embedded in the right and bottom borders respectively. // https://bugs.webkit.org/show_bug.cgi?id=47236 if (style()->isHorizontalWritingMode()) { LayoutUnit yOff = (legend->y() > 0) ? 0 : (legend->height() - borderTop()) / 2; paintRect.setHeight(paintRect.height() - yOff); paintRect.setY(paintRect.y() + yOff); } else { LayoutUnit xOff = (legend->x() > 0) ? 0 : (legend->width() - borderLeft()) / 2; paintRect.setWidth(paintRect.width() - xOff); paintRect.setX(paintRect.x() + xOff); } paintBoxShadow(paintInfo, paintRect, style(), Normal); paintFillLayers(paintInfo, style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->backgroundLayers(), paintRect); paintBoxShadow(paintInfo, paintRect, style(), Inset); if (!style()->hasBorder()) return; // Create a clipping region around the legend and paint the border as normal GraphicsContext* graphicsContext = paintInfo.context; GraphicsContextStateSaver stateSaver(*graphicsContext); // FIXME: We need to work with "rl" and "bt" block flow directions. In those // cases the legend is embedded in the right and bottom borders respectively. // https://bugs.webkit.org/show_bug.cgi?id=47236 if (style()->isHorizontalWritingMode()) { LayoutUnit clipTop = paintRect.y(); LayoutUnit clipHeight = max(static_cast<LayoutUnit>(style()->borderTopWidth()), legend->height()); graphicsContext->clipOut(LayoutRect(paintRect.x() + legend->x(), clipTop, legend->width(), clipHeight)); } else { LayoutUnit clipLeft = paintRect.x(); LayoutUnit clipWidth = max(static_cast<LayoutUnit>(style()->borderLeftWidth()), legend->width()); graphicsContext->clipOut(LayoutRect(clipLeft, paintRect.y() + legend->y(), clipWidth, legend->height())); } paintBorder(paintInfo, paintRect, style()); }
void RenderTableCell::paint(PaintInfo& paintInfo, int tx, int ty) { if (paintInfo.phase == PaintPhaseCollapsedTableBorders && style()->visibility() == VISIBLE) { if (!paintInfo.shouldPaintWithinRoot(this)) return; tx += x(); ty += y(); int os = 2 * maximalOutlineSize(paintInfo.phase); if (ty - table()->outerBorderTop() < paintInfo.rect.maxY() + os && ty + height() + table()->outerBorderBottom() > paintInfo.rect.y() - os) paintCollapsedBorder(paintInfo.context, IntRect(tx, ty, width(), height())); return; } RenderBlock::paint(paintInfo, tx, ty); }
void RootInlineBox::paintCustomHighlight(PaintInfo& paintInfo, int tx, int ty, const AtomicString& highlightType) { if (!paintInfo.shouldPaintWithinRoot(renderer()) || renderer()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseForeground) return; Frame* frame = renderer()->frame(); if (!frame) return; Page* page = frame->page(); if (!page) return; // Get the inflated rect so that we can properly hit test. FloatRect rootRect(tx + x(), ty + selectionTop(), width(), selectionHeight()); FloatRect inflatedRect = page->chrome()->client()->customHighlightRect(renderer()->node(), highlightType, rootRect); if (inflatedRect.intersects(paintInfo.rect)) page->chrome()->client()->paintCustomHighlight(renderer()->node(), highlightType, rootRect, rootRect, false, true); }
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); } }
bool RenderReplaced::shouldPaint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseOutline && paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseMask) return false; if (!paintInfo.shouldPaintWithinRoot(*this)) return false; // if we're invisible or haven't received a layout yet, then just bail. if (style().visibility() != VISIBLE) return false; RenderNamedFlowFragment* namedFlowFragment = currentRenderNamedFlowFragment(); // Check our region range to make sure we need to be painting in this region. if (namedFlowFragment && !namedFlowFragment->flowThread()->objectShouldFragmentInFlowRegion(this, namedFlowFragment)) return false; LayoutPoint adjustedPaintOffset = paintOffset + location(); // Early exit if the element touches the edges. LayoutUnit top = adjustedPaintOffset.y() + visualOverflowRect().y(); LayoutUnit bottom = adjustedPaintOffset.y() + visualOverflowRect().maxY(); if (isSelected() && m_inlineBoxWrapper) { const RootInlineBox& rootBox = m_inlineBoxWrapper->root(); LayoutUnit selTop = paintOffset.y() + rootBox.selectionTop(); LayoutUnit selBottom = paintOffset.y() + selTop + rootBox.selectionHeight(); top = std::min(selTop, top); bottom = std::max(selBottom, bottom); } LayoutRect localRepaintRect = paintInfo.rect; adjustRectWithMaximumOutline(paintInfo.phase, localRepaintRect); if (adjustedPaintOffset.x() + visualOverflowRect().x() >= localRepaintRect.maxX() || adjustedPaintOffset.x() + visualOverflowRect().maxX() <= localRepaintRect.x()) return false; if (top >= localRepaintRect.maxY() || bottom <= localRepaintRect.y()) return false; return true; }
void RenderTableCell::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty) { if (!paintInfo.shouldPaintWithinRoot(this)) return; RenderTable* tableElt = table(); if (!tableElt->collapseBorders() && style()->emptyCells() == HIDE && !firstChild()) return; IntRect paintRect = IntRect(IntPoint(tx, ty), size()); paintBoxShadow(paintInfo, paintRect, style(), Normal); // Paint our cell background. paintBackgroundsBehindCell(paintInfo, tx, ty, this); paintBoxShadow(paintInfo, paintRect, style(), Inset); if (!style()->hasBorder() || tableElt->collapseBorders()) return; paintBorder(paintInfo, paintRect, style()); }
void RenderTableCell::paintBackgroundsBehindCell(PaintInfo& paintInfo, int tx, int ty, RenderObject* backgroundObject) { if (!paintInfo.shouldPaintWithinRoot(this)) return; if (!backgroundObject) return; if (style()->visibility() != VISIBLE) return; RenderTable* tableElt = table(); if (!tableElt->collapseBorders() && style()->emptyCells() == HIDE && !firstChild()) return; if (backgroundObject != this) { tx += x(); ty += y(); } int w = width(); int h = height(); Color c = backgroundObject->style()->visitedDependentColor(CSSPropertyBackgroundColor); const FillLayer* bgLayer = backgroundObject->style()->backgroundLayers(); if (bgLayer->hasImage() || c.isValid()) { // 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 == this || backgroundObject == parent()) && tableElt->collapseBorders(); GraphicsContextStateSaver stateSaver(*paintInfo.context, shouldClip); if (shouldClip) { IntRect clipRect(tx + borderLeft(), ty + borderTop(), w - borderLeft() - borderRight(), h - borderTop() - borderBottom()); paintInfo.context->clip(clipRect); } paintFillLayers(paintInfo, c, bgLayer, IntRect(tx, ty, w, h), BackgroundBleedNone, CompositeSourceOver, backgroundObject); } }
bool LayoutReplaced::shouldPaint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) const { if (paintInfo.phase != PaintPhaseForeground && !shouldPaintSelfOutline(paintInfo.phase) && paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseMask && paintInfo.phase != PaintPhaseClippingMask) return false; if (!paintInfo.shouldPaintWithinRoot(this)) return false; // if we're invisible or haven't received a layout yet, then just bail. if (style()->visibility() != VISIBLE) return false; LayoutRect paintRect(visualOverflowRect()); paintRect.unite(localSelectionRect()); paintRect.moveBy(paintOffset + location()); if (!paintInfo.cullRect().intersectsCullRect(paintRect)) return false; return true; }
void InlineBox::paint(PaintInfo& paintInfo, int tx, int ty) { if (!paintInfo.shouldPaintWithinRoot(renderer()) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection)) return; // Paint all phases of replaced elements atomically, as though the replaced element established its // own stacking context. (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1 // specification.) bool preservePhase = paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip; PaintInfo info(paintInfo); info.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground; renderer()->paint(info, tx, ty); if (!preservePhase) { info.phase = PaintPhaseChildBlockBackgrounds; renderer()->paint(info, tx, ty); info.phase = PaintPhaseFloat; renderer()->paint(info, tx, ty); info.phase = PaintPhaseForeground; renderer()->paint(info, tx, ty); info.phase = PaintPhaseOutline; renderer()->paint(info, tx, ty); } }
void RenderReplaced::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (!shouldPaint(paintInfo, paintOffset)) return; #ifndef NDEBUG SetLayoutNeededForbiddenScope scope(this); #endif LayoutPoint adjustedPaintOffset = paintOffset + location(); if (hasVisibleBoxDecorations() && paintInfo.phase == PaintPhaseForeground) paintBoxDecorations(paintInfo, adjustedPaintOffset); if (paintInfo.phase == PaintPhaseMask) { paintMask(paintInfo, adjustedPaintOffset); return; } LayoutRect paintRect = LayoutRect(adjustedPaintOffset, size()); if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style().outlineWidth()) paintOutline(paintInfo, paintRect); if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection && !canHaveChildren()) return; if (!paintInfo.shouldPaintWithinRoot(*this)) return; bool drawSelectionTint = shouldDrawSelectionTint(); if (paintInfo.phase == PaintPhaseSelection) { if (selectionState() == SelectionNone) return; drawSelectionTint = false; } bool completelyClippedOut = false; if (style().hasBorderRadius()) { LayoutRect borderRect = LayoutRect(adjustedPaintOffset, size()); if (borderRect.isEmpty()) completelyClippedOut = true; else { // Push a clip if we have a border radius, since we want to round the foreground content that gets painted. paintInfo.context().save(); FloatRoundedRect roundedInnerRect = FloatRoundedRect(style().getRoundedInnerBorderFor(paintRect, paddingTop() + borderTop(), paddingBottom() + borderBottom(), paddingLeft() + borderLeft(), paddingRight() + borderRight(), true, true)); clipRoundedInnerRect(paintInfo.context(), paintRect, roundedInnerRect); } } if (!completelyClippedOut) { paintReplaced(paintInfo, adjustedPaintOffset); if (style().hasBorderRadius()) paintInfo.context().restore(); } // The selection tint never gets clipped by border-radius rounding, since we want it to run right up to the edges of // surrounding content. if (drawSelectionTint) { LayoutRect selectionPaintingRect = localSelectionRect(); selectionPaintingRect.moveBy(adjustedPaintOffset); paintInfo.context().fillRect(snappedIntRect(selectionPaintingRect), selectionBackgroundColor()); } }